/// import _ from "lodash"; import $ from "jquery"; import { MetricsPanelCtrl } from "app/plugins/sdk"; import { transformDataToTable } from "./transformers"; import { tablePanelEditor } from "./editor"; import { columnOptionsTab } from "./column_options"; import { TableRenderer } from "./renderer"; class TablePanelCtrl extends MetricsPanelCtrl { static templateUrl = "module.html"; pageIndex: number; dataRaw: any; table: any; renderer: any; panelDefaults = { targets: [{}], transform: "timeseries_to_columns", pageSize: null, showHeader: true, styles: [ { type: "date", pattern: "Time", alias: "Time", dateFormat: "YYYY-MM-DD HH:mm:ss" }, { unit: "short", type: "number", alias: "", decimals: 2, colors: [ "rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)" ], colorMode: null, pattern: "/.*/", thresholds: [] } ], columns: [], scroll: true, fontSize: "100%", sort: { col: 0, desc: true } }; /** @ngInject */ constructor( $scope, $injector, templateSrv, private annotationsSrv, private $sanitize, private variableSrv ) { super($scope, $injector); this.pageIndex = 0; if (this.panel.styles === void 0) { this.panel.styles = this.panel.columns; this.panel.columns = this.panel.fields; delete this.panel.columns; delete this.panel.fields; } _.defaults(this.panel, this.panelDefaults); this.events.on("data-received", this.onDataReceived.bind(this)); this.events.on("data-error", this.onDataError.bind(this)); this.events.on("data-snapshot-load", this.onDataReceived.bind(this)); this.events.on("init-edit-mode", this.onInitEditMode.bind(this)); this.events.on("init-panel-actions", this.onInitPanelActions.bind(this)); } onInitEditMode() { this.addEditorTab("Options", tablePanelEditor, 2); this.addEditorTab("Column Styles", columnOptionsTab, 3); } onInitPanelActions(actions) { actions.push({ text: "Export CSV", click: "ctrl.exportCsv()" }); } issueQueries(datasource) { this.pageIndex = 0; if (this.panel.transform === "annotations") { this.setTimeQueryStart(); return this.annotationsSrv .getAnnotations({ dashboard: this.dashboard, panel: this.panel, range: this.range }) .then(annotations => { return { data: annotations }; }); } return super.issueQueries(datasource); } onDataError(err) { this.dataRaw = []; this.render(); } onDataReceived(dataList) { this.dataRaw = dataList; this.pageIndex = 0; // automatically correct transform mode based on data if (this.dataRaw && this.dataRaw.length) { if (this.dataRaw[0].type === "table") { this.panel.transform = "table"; } else { if (this.dataRaw[0].type === "docs") { this.panel.transform = "json"; } else { if ( this.panel.transform === "table" || this.panel.transform === "json" ) { this.panel.transform = "timeseries_to_rows"; } } } } this.render(); } render() { this.table = transformDataToTable(this.dataRaw, this.panel); this.table.sort(this.panel.sort); this.renderer = new TableRenderer( this.panel, this.table, this.dashboard.isTimezoneUtc(), this.$sanitize, this.templateSrv ); return super.render(this.table); } toggleColumnSort(col, colIndex) { // remove sort flag from current column if (this.table.columns[this.panel.sort.col]) { this.table.columns[this.panel.sort.col].sort = false; } if (this.panel.sort.col === colIndex) { if (this.panel.sort.desc) { this.panel.sort.desc = false; } else { this.panel.sort.col = null; } } else { this.panel.sort.col = colIndex; this.panel.sort.desc = true; } this.render(); } exportCsv() { var scope = this.$scope.$new(true); scope.tableData = this.renderer.render_values(); scope.panel = "table"; this.publishAppEvent("show-modal", { templateHtml: '', scope, modalClass: "modal--narrow" }); } link(scope, elem, attrs, ctrl: TablePanelCtrl) { var data; var panel = ctrl.panel; var pageCount = 0; function getTableHeight() { var panelHeight = ctrl.height; if (pageCount > 1) { panelHeight -= 26; } return panelHeight - 31 + "px"; } function appendTableRows(tbodyElem) { ctrl.renderer.setTable(data); tbodyElem.empty(); tbodyElem.html(ctrl.renderer.render(ctrl.pageIndex)); } function switchPage(e) { var el = $(e.currentTarget); ctrl.pageIndex = parseInt(el.text(), 10) - 1; renderPanel(); } function appendPaginationControls(footerElem) { footerElem.empty(); var pageSize = panel.pageSize || 100; pageCount = Math.ceil(data.rows.length / pageSize); if (pageCount === 1) { return; } var startPage = Math.max(ctrl.pageIndex - 3, 0); var endPage = Math.min(pageCount, startPage + 9); var paginationList = $(""); for (var i = startPage; i < endPage; i++) { var activeClass = i === ctrl.pageIndex ? "active" : ""; var pageLinkElem = $( '
  • ' + (i + 1) + "
  • " ); paginationList.append(pageLinkElem); } footerElem.append(paginationList); } function renderPanel() { var panelElem = elem.parents(".panel"); var rootElem = elem.find(".table-panel-scroll"); var tbodyElem = elem.find("tbody"); var footerElem = elem.find(".table-panel-footer"); elem.css({ "font-size": panel.fontSize }); panelElem.addClass("table-panel-wrapper"); appendTableRows(tbodyElem); appendPaginationControls(footerElem); rootElem.css({ "max-height": panel.scroll ? getTableHeight() : "" }); } // hook up link tooltips elem.tooltip({ selector: "[data-link-tooltip]" }); function addFilterClicked(e) { let filterData = $(e.currentTarget).data(); var options = { datasource: panel.datasource, key: data.columns[filterData.column].text, value: data.rows[filterData.row][filterData.column], operator: filterData.operator }; ctrl.variableSrv.setAdhocFilter(options); } elem.on("click", ".table-panel-page-link", switchPage); elem.on("click", ".table-panel-filter-link", addFilterClicked); var unbindDestroy = scope.$on("$destroy", function() { elem.off("click", ".table-panel-page-link"); elem.off("click", ".table-panel-filter-link"); unbindDestroy(); }); ctrl.events.on("render", function(renderData) { data = renderData || data; if (data) { renderPanel(); } ctrl.renderingCompleted(); }); } } export { TablePanelCtrl, TablePanelCtrl as PanelCtrl };