diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index 8e3dd9d09f2..398a6f50233 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -80,13 +80,16 @@ export class PanelCtrl { return; } - addEditorTab(title, templateUrl) { - this.editorTabs.push({ - title: title, - directiveFn: function() { - return {templateUrl: templateUrl}; - } - }); + addEditorTab(title, directiveFn) { + var editorTab = {title, directiveFn}; + + if (_.isString(directiveFn)) { + editorTab.directiveFn = function() { + return {templateUrl: directiveFn}; + }; + } + + this.editorTabs.push(editorTab); } getMenu() { diff --git a/public/app/plugins/panel/table/controller.ts b/public/app/plugins/panel/table/controller.ts index 376f36fd84d..9b06b437db9 100644 --- a/public/app/plugins/panel/table/controller.ts +++ b/public/app/plugins/panel/table/controller.ts @@ -4,132 +4,131 @@ import angular from 'angular'; import _ from 'lodash'; import moment from 'moment'; import * as FileExport from 'app/core/utils/file_export'; -import PanelMeta from 'app/features/panel/panel_meta2'; +import {MetricsPanelCtrl} from '../../../features/panel/panel'; import {transformDataToTable} from './transformers'; +import {tablePanelEditor} from './editor'; -export class TablePanelCtrl { +var panelDefaults = { + targets: [{}], + transform: 'timeseries_to_columns', + pageSize: null, + showHeader: true, + styles: [ + { + type: 'date', + pattern: 'Time', + dateFormat: 'YYYY-MM-DD HH:mm:ss', + }, + { + unit: 'short', + type: 'number', + 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}, +}; + +export class TablePanelCtrl extends MetricsPanelCtrl { + pageIndex: number; + dataRaw: any; + table: any; /** @ngInject */ - constructor($scope, $rootScope, $q, panelSrv, panelHelper, annotationsSrv) { - $scope.ctrl = this; - $scope.pageIndex = 0; + constructor($scope, $injector, private annotationsSrv) { + super($scope, $injector); + this.pageIndex = 0; - $scope.panelMeta = new PanelMeta({ - panelName: 'Table', - editIcon: "fa fa-table", - fullscreen: true, - metricsEditor: true, - }); + 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; + } - $scope.panelMeta.addEditorTab('Options', 'app/plugins/panel/table/options.html'); - $scope.panelMeta.addEditorTab('Time range', 'app/features/panel/partials/panelTime.html'); - $scope.panelMeta.addExtendedMenuItem('Export CSV', '', 'exportCsv()'); + _.defaults(this.panel, panelDefaults); + } - var panelDefaults = { - targets: [{}], - transform: 'timeseries_to_columns', - pageSize: null, - showHeader: true, - styles: [ - { - type: 'date', - pattern: 'Time', - dateFormat: 'YYYY-MM-DD HH:mm:ss', - }, - { - unit: 'short', - type: 'number', - 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}, - }; + initEditMode() { + super.initEditMode(); + this.addEditorTab('Options', tablePanelEditor); + this.addEditorTab('Time range', 'app/features/panel/partials/panelTime.html'); + } - $scope.init = function() { - if ($scope.panel.styles === void 0) { - $scope.panel.styles = $scope.panel.columns; - $scope.panel.columns = $scope.panel.fields; - delete $scope.panel.columns; - delete $scope.panel.fields; - } + getExtendedMenu() { + var menu = super.getExtendedMenu(); + menu.push({text: 'Export CSV', click: 'exportCsv()'}); + return menu; + } - _.defaults($scope.panel, panelDefaults); - panelSrv.init($scope); - }; + refreshData(datasource) { + this.pageIndex = 0; - $scope.refreshData = function(datasource) { - panelHelper.updateTimeRange($scope); - - $scope.pageIndex = 0; - - if ($scope.panel.transform === 'annotations') { - return annotationsSrv.getAnnotations($scope.dashboard).then(annotations => { - $scope.dataRaw = annotations; - $scope.render(); - }); - } - - return panelHelper.issueMetricQuery($scope, datasource) - .then($scope.dataHandler, function(err) { - $scope.render(); - throw err; + if (this.panel.transform === 'annotations') { + return this.annotationsSrv.getAnnotations(this.dashboard).then(annotations => { + this.dataRaw = annotations; + this.render(); }); - }; + } - $scope.toggleColumnSort = function(col, colIndex) { - if ($scope.panel.sort.col === colIndex) { - if ($scope.panel.sort.desc) { - $scope.panel.sort.desc = false; - } else { - $scope.panel.sort.col = null; - } + return this.issueQueries(datasource) + .then(this.dataHandler.bind(this)) + .catch(err => { + this.render(); + throw err; + }); + } + + toggleColumnSort(col, colIndex) { + if (this.panel.sort.col === colIndex) { + if (this.panel.sort.desc) { + this.panel.sort.desc = false; } else { - $scope.panel.sort.col = colIndex; - $scope.panel.sort.desc = true; + this.panel.sort.col = null; } + } else { + this.panel.sort.col = colIndex; + this.panel.sort.desc = true; + } - $scope.render(); - }; + this.render(); + } - $scope.dataHandler = function(results) { - $scope.dataRaw = results.data; - $scope.pageIndex = 0; - $scope.render(); - }; + dataHandler(results) { + this.dataRaw = results.data; + this.pageIndex = 0; + this.render(); + } - $scope.render = function() { - // automatically correct transform mode - // based on data - if ($scope.dataRaw && $scope.dataRaw.length) { - if ($scope.dataRaw[0].type === 'table') { - $scope.panel.transform = 'table'; + render() { + // 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 ($scope.dataRaw[0].type === 'docs') { - $scope.panel.transform = 'json'; - } else { - if ($scope.panel.transform === 'table' || $scope.panel.transform === 'json') { - $scope.panel.transform = 'timeseries_to_rows'; - } + if (this.panel.transform === 'table' || this.panel.transform === 'json') { + this.panel.transform = 'timeseries_to_rows'; } } } + } - $scope.table = transformDataToTable($scope.dataRaw, $scope.panel); - $scope.table.sort($scope.panel.sort); - panelHelper.broadcastRender($scope, $scope.table, $scope.dataRaw); - }; + this.table = transformDataToTable(this.dataRaw, this.panel); + this.table.sort(this.panel.sort); + this.broadcastRender(this.table); + } - $scope.exportCsv = function() { - FileExport.exportTableDataToCsv($scope.table); - }; - - $scope.init(); + exportCsv() { + FileExport.exportTableDataToCsv(this.table); } } diff --git a/public/app/plugins/panel/table/editor.html b/public/app/plugins/panel/table/editor.html index 0b13c61c884..010c30326d9 100644 --- a/public/app/plugins/panel/table/editor.html +++ b/public/app/plugins/panel/table/editor.html @@ -9,9 +9,9 @@
  • + ng-model="editor.panel.transform" + ng-options="k as v.description for (k, v) in editor.transformers" + ng-change="editor.transformChanged()">
  • @@ -21,14 +21,14 @@
  • Columns
  • -
  • - +
  • + {{column.text}}
  • - +
  • @@ -46,16 +46,16 @@
  • + empty-to-null ng-model="editor.panel.pageSize" ng-change="editor.render()" ng-model-onblur>
  • - +
  • Font size
  • - +
  • @@ -68,11 +68,11 @@
    Column Styles
    -
    +
    • - +
    @@ -81,7 +81,7 @@ Name or regex
  • - +
  • Type @@ -89,8 +89,8 @@
  • @@ -100,7 +100,7 @@ Format
  • - +
  • @@ -113,8 +113,8 @@
  • @@ -122,18 +122,18 @@ ThresholdsComma seperated values
  • - +
  • Colors
  • - - - + + +
  • - invert order + invert order
  • @@ -145,8 +145,8 @@
  • Decimals @@ -161,7 +161,7 @@
  • -
    diff --git a/public/app/plugins/panel/table/editor.ts b/public/app/plugins/panel/table/editor.ts index 42536642d4a..dde691b00f3 100644 --- a/public/app/plugins/panel/table/editor.ts +++ b/public/app/plugins/panel/table/editor.ts @@ -10,105 +10,123 @@ import {transformers} from './transformers'; import kbn from 'app/core/utils/kbn'; export class TablePanelEditorCtrl { + panel: any; + panelCtrl: any; + transformers: any; + colorModes: any; + columnStyles: any; + columnTypes: any; + fontSizes: any; + dateFormats: any; + addColumnSegment: any; + unitFormats: any; + getColumnNames: any; /** @ngInject */ - constructor($scope, $q, uiSegmentSrv) { - $scope.transformers = transformers; - $scope.unitFormats = kbn.getUnitFormats(); - $scope.colorModes = [ + constructor($scope, private $q, private uiSegmentSrv) { + $scope.editor = this; + this.panelCtrl = $scope.ctrl; + this.panel = this.panelCtrl.panel; + this.transformers = transformers; + this.unitFormats = kbn.getUnitFormats(); + this.colorModes = [ {text: 'Disabled', value: null}, {text: 'Cell', value: 'cell'}, {text: 'Value', value: 'value'}, {text: 'Row', value: 'row'}, ]; - $scope.columnTypes = [ + this.columnTypes = [ {text: 'Number', value: 'number'}, {text: 'String', value: 'string'}, {text: 'Date', value: 'date'}, ]; - $scope.fontSizes = ['80%', '90%', '100%', '110%', '120%', '130%', '150%', '160%', '180%', '200%', '220%', '250%']; - $scope.dateFormats = [ + this.fontSizes = ['80%', '90%', '100%', '110%', '120%', '130%', '150%', '160%', '180%', '200%', '220%', '250%']; + this.dateFormats = [ {text: 'YYYY-MM-DD HH:mm:ss', value: 'YYYY-MM-DD HH:mm:ss'}, {text: 'MM/DD/YY h:mm:ss a', value: 'MM/DD/YY h:mm:ss a'}, {text: 'MMMM D, YYYY LT', value: 'MMMM D, YYYY LT'}, ]; - $scope.addColumnSegment = uiSegmentSrv.newPlusButton(); + this.addColumnSegment = uiSegmentSrv.newPlusButton(); - $scope.getColumnOptions = function() { - if (!$scope.dataRaw) { - return $q.when([]); - } - var columns = transformers[$scope.panel.transform].getColumns($scope.dataRaw); - var segments = _.map(columns, (c: any) => uiSegmentSrv.newSegment({value: c.text})); - return $q.when(segments); - }; - - $scope.addColumn = function() { - var columns = transformers[$scope.panel.transform].getColumns($scope.dataRaw); - var column = _.findWhere(columns, {text: $scope.addColumnSegment.value}); - - if (column) { - $scope.panel.columns.push(column); - $scope.render(); - } - - var plusButton = uiSegmentSrv.newPlusButton(); - $scope.addColumnSegment.html = plusButton.html; - $scope.addColumnSegment.value = plusButton.value; - }; - - $scope.transformChanged = function() { - $scope.panel.columns = []; - $scope.render(); - }; - - $scope.removeColumn = function(column) { - $scope.panel.columns = _.without($scope.panel.columns, column); - $scope.render(); - }; - - $scope.setUnitFormat = function(column, subItem) { - column.unit = subItem.value; - $scope.render(); - }; - - $scope.addColumnStyle = function() { - var columnStyleDefaults = { - unit: 'short', - type: 'number', - decimals: 2, - colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], - colorMode: null, - pattern: '/.*/', - dateFormat: 'YYYY-MM-DD HH:mm:ss', - thresholds: [], - }; - - $scope.panel.styles.push(angular.copy(columnStyleDefaults)); - }; - - $scope.removeColumnStyle = function(style) { - $scope.panel.styles = _.without($scope.panel.styles, style); - }; - - $scope.getColumnNames = function() { - if (!$scope.table) { + // this is used from bs-typeahead and needs to be instance bound + this.getColumnNames = () => { + if (!this.panelCtrl.table) { return []; } - return _.map($scope.table.columns, function(col: any) { + return _.map(this.panelCtrl.table.columns, function(col: any) { return col.text; }); }; + } - $scope.invertColorOrder = function(index) { - var ref = $scope.panel.styles[index].colors; - var copy = ref[0]; - ref[0] = ref[2]; - ref[2] = copy; - $scope.render(); + getColumnOptions() { + if (!this.panelCtrl.dataRaw) { + return this.$q.when([]); + } + var columns = this.transformers[this.panel.transform].getColumns(this.panelCtrl.dataRaw); + var segments = _.map(columns, (c: any) => this.uiSegmentSrv.newSegment({value: c.text})); + return this.$q.when(segments); + } + + addColumn() { + var columns = transformers[this.panel.transform].getColumns(this.panelCtrl.dataRaw); + var column = _.findWhere(columns, {text: this.addColumnSegment.value}); + + if (column) { + this.panel.columns.push(column); + this.render(); + } + + var plusButton = this.uiSegmentSrv.newPlusButton(); + this.addColumnSegment.html = plusButton.html; + this.addColumnSegment.value = plusButton.value; + } + + transformChanged() { + this.panel.columns = []; + this.render(); + } + + render() { + this.panelCtrl.render(); + } + + removeColumn(column) { + this.panel.columns = _.without(this.panel.columns, column); + this.panelCtrl.render(); + } + + setUnitFormat(column, subItem) { + column.unit = subItem.value; + this.panelCtrl.render(); + }; + + addColumnStyle() { + var columnStyleDefaults = { + unit: 'short', + type: 'number', + decimals: 2, + colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + colorMode: null, + pattern: '/.*/', + dateFormat: 'YYYY-MM-DD HH:mm:ss', + thresholds: [], }; + this.panel.styles.push(angular.copy(columnStyleDefaults)); + } + + removeColumnStyle(style) { + this.panel.styles = _.without(this.panel.styles, style); + } + + invertColorOrder(index) { + var ref = this.panel.styles[index].colors; + var copy = ref[0]; + ref[0] = ref[2]; + ref[2] = copy; + this.panelCtrl.render(); } } diff --git a/public/app/plugins/panel/table/module.html b/public/app/plugins/panel/table/module.html index 75b9b4ce136..0c69fe6cb9b 100644 --- a/public/app/plugins/panel/table/module.html +++ b/public/app/plugins/panel/table/module.html @@ -1,28 +1,24 @@ -
    - -
    -
    -
    - - - - - - - - -
    -
    - {{col.text}} - - - - -
    -
    -
    -
    - -
    +
    +
    +
    + + + + + + + + +
    +
    + {{col.text}} + + + + +
    +
    +
    +
    + diff --git a/public/app/plugins/panel/table/module.ts b/public/app/plugins/panel/table/module.ts index 834bea42ba5..0903275b802 100644 --- a/public/app/plugins/panel/table/module.ts +++ b/public/app/plugins/panel/table/module.ts @@ -5,103 +5,96 @@ import kbn = require('app/core/utils/kbn'); import _ from 'lodash'; import $ from 'jquery'; import moment from 'moment'; -import angular from 'angular'; +import {PanelDirective} from '../../../features/panel/panel'; import {TablePanelCtrl} from './controller'; import {TableRenderer} from './renderer'; -import {tablePanelEditor} from './editor'; -angular.module('grafana.directives').directive('grafanaPanelTableEditor', tablePanelEditor); +class TablePanel extends PanelDirective { + templateUrl = 'app/plugins/panel/table/module.html'; + controller = TablePanelCtrl; -function tablePanel() { - 'use strict'; - return { - restrict: 'E', - templateUrl: 'app/plugins/panel/table/module.html', - controller: TablePanelCtrl, - link: function(scope, elem) { - var data; - var panel = scope.panel; - var pageCount = 0; - var formaters = []; + link(scope, elem, attrs, ctrl) { + var data; + var panel = ctrl.panel; + var pageCount = 0; + var formaters = []; - function getTableHeight() { - var panelHeight = scope.height || scope.panel.height || scope.row.height; - if (_.isString(panelHeight)) { - panelHeight = parseInt(panelHeight.replace('px', ''), 10); - } - if (pageCount > 1) { - panelHeight -= 28; - } - - return (panelHeight - 60) + 'px'; + function getTableHeight() { + var panelHeight = ctrl.height || ctrl.panel.height || ctrl.row.height; + if (_.isString(panelHeight)) { + panelHeight = parseInt(panelHeight.replace('px', ''), 10); + } + if (pageCount > 1) { + panelHeight -= 28; } - function appendTableRows(tbodyElem) { - var renderer = new TableRenderer(panel, data, scope.dashboard.timezone); - tbodyElem.empty(); - tbodyElem.html(renderer.render(scope.pageIndex)); - } - - function switchPage(e) { - var el = $(e.currentTarget); - scope.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(scope.pageIndex - 3, 0); - var endPage = Math.min(pageCount, startPage + 9); - - var paginationList = $(''); - - for (var i = startPage; i < endPage; i++) { - var activeClass = i === scope.pageIndex ? 'active' : ''; - var pageLinkElem = $('
  • ' + (i+1) + '
  • '); - paginationList.append(pageLinkElem); - } - - footerElem.append(paginationList); - } - - function renderPanel() { - var container = elem.find('.table-panel-container'); - var rootElem = elem.find('.table-panel-scroll'); - var tbodyElem = elem.find('tbody'); - var footerElem = elem.find('.table-panel-footer'); - - appendTableRows(tbodyElem); - - container.css({'font-size': panel.fontSize}); - appendPaginationControls(footerElem); - - rootElem.css({'max-height': panel.scroll ? getTableHeight() : '' }); - } - - elem.on('click', '.table-panel-page-link', switchPage); - - scope.$on('$destroy', function() { - elem.off('click', '.table-panel-page-link'); - }); - - scope.$on('render', function(event, renderData) { - data = renderData || data; - if (!data) { - scope.get_data(); - return; - } - - renderPanel(); - }); + return (panelHeight - 60) + 'px'; } - }; + + function appendTableRows(tbodyElem) { + var renderer = new TableRenderer(panel, data, ctrl.dashboard.timezone); + tbodyElem.empty(); + tbodyElem.html(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() : '' }); + } + + elem.on('click', '.table-panel-page-link', switchPage); + + scope.$on('$destroy', function() { + elem.off('click', '.table-panel-page-link'); + }); + + scope.$on('render', function(event, renderData) { + data = renderData || data; + renderPanel(); + }); + } } -export {tablePanel as panel}; +export { + TablePanel, + TablePanel as Panel +};