diff --git a/public/app/core/directives/plugin_component.ts b/public/app/core/directives/plugin_component.ts index 020bcb08f0a..94e50bf5c86 100644 --- a/public/app/core/directives/plugin_component.ts +++ b/public/app/core/directives/plugin_component.ts @@ -5,6 +5,7 @@ import _ from 'lodash'; import config from 'app/core/config'; import coreModule from 'app/core/core_module'; +import {UnknownPanelCtrl} from 'app/plugins/panel/unknown/module'; /** @ngInject */ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $templateCache) { @@ -45,20 +46,23 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $ } function loadPanelComponentInfo(scope, attrs) { + var componentInfo: any = { + name: 'panel-plugin-' + scope.panel.type, + bindings: {dashboard: "=", panel: "=", row: "="}, + attrs: {dashboard: "dashboard", panel: "panel", row: "row"}, + }; + var panelElemName = 'panel-' + scope.panel.type; let panelInfo = config.panels[scope.panel.type]; - if (!panelInfo) { - // unknown + var panelCtrlPromise = Promise.resolve(UnknownPanelCtrl); + if (panelInfo) { + panelCtrlPromise = System.import(panelInfo.module).then(function(panelModule) { + return panelModule.PanelCtrl; + }); } - return System.import(panelInfo.module).then(function(panelModule): any { - var PanelCtrl = panelModule.PanelCtrl; - var componentInfo = { - name: 'panel-plugin-' + panelInfo.id, - bindings: {dashboard: "=", panel: "=", row: "="}, - attrs: {dashboard: "dashboard", panel: "panel", row: "row"}, - Component: PanelCtrl, - }; + return panelCtrlPromise.then(function(PanelCtrl: any) { + componentInfo.Component = PanelCtrl; if (!PanelCtrl || PanelCtrl.registered) { return componentInfo; diff --git a/public/app/features/panel/all.js b/public/app/features/panel/all.js index 47fe256e7cf..b3ec16e541f 100644 --- a/public/app/features/panel/all.js +++ b/public/app/features/panel/all.js @@ -2,7 +2,6 @@ define([ './panel_menu', './panel_directive', './solo_panel_ctrl', - './panel_loader', './query_ctrl', './panel_editor_tab', './query_editor_row', diff --git a/public/app/features/panel/panel.ts b/public/app/features/panel/panel.ts index 634591801b6..94aeb3878aa 100644 --- a/public/app/features/panel/panel.ts +++ b/public/app/features/panel/panel.ts @@ -4,12 +4,18 @@ import config from 'app/core/config'; import {PanelCtrl} from './panel_ctrl'; import {MetricsPanelCtrl} from './metrics_panel_ctrl'; -import {PanelDirective} from './panel_directive'; import {QueryCtrl} from './query_ctrl'; +class DefaultPanelCtrl extends PanelCtrl { + /** @ngInject */ + constructor($scope, $injector) { + super($scope, $injector); + } +} + export { PanelCtrl, + DefaultPanelCtrl, MetricsPanelCtrl, - PanelDirective, QueryCtrl, } diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index 63484785d75..757f9f8e43d 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -3,48 +3,6 @@ import angular from 'angular'; import $ from 'jquery'; -import {PanelCtrl} from './panel_ctrl'; - -export class DefaultPanelCtrl extends PanelCtrl { - /** @ngInject */ - constructor($scope, $injector) { - super($scope, $injector); - } -} - -export class PanelDirective { - template: string; - templateUrl: string; - bindToController: boolean; - scope: any; - controller: any; - controllerAs: string; - - getDirective() { - if (!this.controller) { - this.controller = DefaultPanelCtrl; - } - - return { - template: this.template, - templateUrl: this.templateUrl, - controller: this.controller, - controllerAs: 'ctrl', - bindToController: true, - scope: {dashboard: "=", panel: "=", row: "="}, - link: (scope, elem, attrs, ctrl) => { - ctrl.init(); - this.link(scope, elem, attrs, ctrl); - } - }; - } - - link(scope, elem, attrs, ctrl) { - return null; - } -} - - var module = angular.module('grafana.directives'); module.directive('grafanaPanel', function() { diff --git a/public/app/features/panel/panel_loader.ts b/public/app/features/panel/panel_loader.ts deleted file mode 100644 index 0608c37f9fd..00000000000 --- a/public/app/features/panel/panel_loader.ts +++ /dev/null @@ -1,88 +0,0 @@ -/// - -import angular from 'angular'; -import config from 'app/core/config'; - -import {UnknownPanel} from '../../plugins/panel/unknown/module'; - -var directiveModule = angular.module('grafana.directives'); - -/** @ngInject */ -function panelLoader($compile, $http, $q, $injector, $templateCache) { - return { - restrict: 'E', - scope: { - dashboard: "=", - row: "=", - panel: "=" - }, - link: function(scope, elem, attrs) { - - function getTemplate(directive) { - if (directive.template) { - return $q.when(directive.template); - } - var cached = $templateCache.get(directive.templateUrl); - if (cached) { - return $q.when(cached); - } - return $http.get(directive.templateUrl).then(res => { - return res.data; - }); - } - - function addPanelAndCompile(name) { - var child = angular.element(document.createElement(name)); - child.attr('dashboard', 'dashboard'); - child.attr('panel', 'panel'); - child.attr('row', 'row'); - $compile(child)(scope); - - elem.empty(); - elem.append(child); - } - - function addPanel(name, Panel) { - if (Panel.registered) { - addPanelAndCompile(name); - return; - } - - if (Panel.promise) { - Panel.promise.then(() => { - addPanelAndCompile(name); - }); - return; - } - - var panelInstance = $injector.instantiate(Panel); - var directive = panelInstance.getDirective(); - - Panel.promise = getTemplate(directive).then(template => { - directive.templateUrl = null; - directive.template = `${template}`; - directiveModule.directive(attrs.$normalize(name), function() { - return directive; - }); - Panel.registered = true; - addPanelAndCompile(name); - }); - } - - var panelElemName = 'panel-directive-' + scope.panel.type; - let panelInfo = config.panels[scope.panel.type]; - if (!panelInfo) { - addPanel(panelElemName, UnknownPanel); - return; - } - - System.import(panelInfo.module).then(function(panelModule) { - addPanel(panelElemName, panelModule.Panel); - }).catch(err => { - console.log('Panel err: ', err); - }); - } - }; -} - -directiveModule.directive('panelLoader', panelLoader); diff --git a/public/app/plugins/panel/dashlist/module.ts b/public/app/plugins/panel/dashlist/module.ts index 5b1c4c89f66..829c98f39f5 100644 --- a/public/app/plugins/panel/dashlist/module.ts +++ b/public/app/plugins/panel/dashlist/module.ts @@ -2,7 +2,7 @@ import _ from 'lodash'; import config from 'app/core/config'; -import {PanelDirective, PanelCtrl} from '../../../features/panel/panel'; +import {PanelCtrl} from '../../../features/panel/panel'; // Set and populate defaults var panelDefaults = { @@ -55,11 +55,4 @@ class DashListCtrl extends PanelCtrl { } } -class DashListPanel extends PanelDirective { - controller = DashListCtrl; -} - -export { - DashListCtrl as DashListCtrl, - DashListCtrl as PanelCtrl, -} +export {DashListCtrl, DashListCtrl as PanelCtrl} diff --git a/public/app/plugins/panel/singlestat/controller.ts b/public/app/plugins/panel/singlestat/controller.ts deleted file mode 100644 index 78b87e5164d..00000000000 --- a/public/app/plugins/panel/singlestat/controller.ts +++ /dev/null @@ -1,232 +0,0 @@ -/// - -import angular from 'angular'; -import _ from 'lodash'; -import kbn from 'app/core/utils/kbn'; -import TimeSeries from '../../../core/time_series2'; -import {MetricsPanelCtrl} from '../../../features/panel/panel'; - -// Set and populate defaults -var panelDefaults = { - links: [], - datasource: null, - maxDataPoints: 100, - interval: null, - targets: [{}], - cacheTimeout: null, - format: 'none', - prefix: '', - postfix: '', - nullText: null, - valueMaps: [ - { value: 'null', op: '=', text: 'N/A' } - ], - nullPointMode: 'connected', - valueName: 'avg', - prefixFontSize: '50%', - valueFontSize: '80%', - postfixFontSize: '50%', - thresholds: '', - colorBackground: false, - colorValue: false, - colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], - sparkline: { - show: false, - full: false, - lineColor: 'rgb(31, 120, 193)', - fillColor: 'rgba(31, 118, 189, 0.18)', - } -}; - -export class SingleStatCtrl extends MetricsPanelCtrl { - series: any[]; - data: any[]; - fontSizes: any[]; - unitFormats: any[]; - - /** @ngInject */ - constructor($scope, $injector) { - super($scope, $injector); - _.defaults(this.panel, panelDefaults); - } - - initEditMode() { - super.initEditMode(); - this.icon = "fa fa-dashboard"; - this.fontSizes = ['20%', '30%','50%','70%','80%','100%', '110%', '120%', '150%', '170%', '200%']; - this.addEditorTab('Options', 'app/plugins/panel/singlestat/editor.html', 2); - this.unitFormats = kbn.getUnitFormats(); - } - - setUnitFormat(subItem) { - this.panel.format = subItem.value; - this.render(); - } - - refreshData(datasource) { - return this.issueQueries(datasource) - .then(this.dataHandler.bind(this)) - .catch(err => { - this.series = []; - this.render(); - throw err; - }); - } - - loadSnapshot(snapshotData) { - this.updateTimeRange(); - this.dataHandler(snapshotData); - } - - dataHandler(results) { - this.series = _.map(results.data, this.seriesHandler.bind(this)); - this.render(); - } - - seriesHandler(seriesData) { - var series = new TimeSeries({ - datapoints: seriesData.datapoints, - alias: seriesData.target, - }); - - series.flotpairs = series.getFlotPairs(this.panel.nullPointMode); - return series; - } - - setColoring(options) { - if (options.background) { - this.panel.colorValue = false; - this.panel.colors = ['rgba(71, 212, 59, 0.4)', 'rgba(245, 150, 40, 0.73)', 'rgba(225, 40, 40, 0.59)']; - } else { - this.panel.colorBackground = false; - this.panel.colors = ['rgba(50, 172, 45, 0.97)', 'rgba(237, 129, 40, 0.89)', 'rgba(245, 54, 54, 0.9)']; - } - this.render(); - } - - invertColorOrder() { - var tmp = this.panel.colors[0]; - this.panel.colors[0] = this.panel.colors[2]; - this.panel.colors[2] = tmp; - this.render(); - } - - getDecimalsForValue(value) { - if (_.isNumber(this.panel.decimals)) { - return {decimals: this.panel.decimals, scaledDecimals: null}; - } - - var delta = value / 2; - var dec = -Math.floor(Math.log(delta) / Math.LN10); - - var magn = Math.pow(10, -dec), - norm = delta / magn, // norm is between 1.0 and 10.0 - size; - - if (norm < 1.5) { - size = 1; - } else if (norm < 3) { - size = 2; - // special case for 2.5, requires an extra decimal - if (norm > 2.25) { - size = 2.5; - ++dec; - } - } else if (norm < 7.5) { - size = 5; - } else { - size = 10; - } - - size *= magn; - - // reduce starting decimals if not needed - if (Math.floor(value) === value) { dec = 0; } - - var result: any = {}; - result.decimals = Math.max(0, dec); - result.scaledDecimals = result.decimals - Math.floor(Math.log(size) / Math.LN10) + 2; - - return result; - } - - render() { - var data: any = {}; - this.setValues(data); - - data.thresholds = this.panel.thresholds.split(',').map(function(strVale) { - return Number(strVale.trim()); - }); - - data.colorMap = this.panel.colors; - - this.data = data; - this.broadcastRender(); - } - - setValues(data) { - data.flotpairs = []; - - if (this.series.length > 1) { - this.inspector.error = new Error(); - this.inspector.error.message = 'Multiple Series Error'; - this.inspector.error.data = 'Metric query returns ' + this.series.length + - ' series. Single Stat Panel expects a single series.\n\nResponse:\n'+JSON.stringify(this.series); - throw this.inspector.error; - } - - if (this.series && this.series.length > 0) { - var lastPoint = _.last(this.series[0].datapoints); - var lastValue = _.isArray(lastPoint) ? lastPoint[0] : null; - - if (_.isString(lastValue)) { - data.value = 0; - data.valueFormated = lastValue; - data.valueRounded = 0; - } else { - data.value = this.series[0].stats[this.panel.valueName]; - data.flotpairs = this.series[0].flotpairs; - - var decimalInfo = this.getDecimalsForValue(data.value); - var formatFunc = kbn.valueFormats[this.panel.format]; - data.valueFormated = formatFunc(data.value, decimalInfo.decimals, decimalInfo.scaledDecimals); - data.valueRounded = kbn.roundValue(data.value, decimalInfo.decimals); - } - } - - // check value to text mappings - for (var i = 0; i < this.panel.valueMaps.length; i++) { - var map = this.panel.valueMaps[i]; - // special null case - if (map.value === 'null') { - if (data.value === null || data.value === void 0) { - data.valueFormated = map.text; - return; - } - continue; - } - - // value/number to text mapping - var value = parseFloat(map.value); - if (value === data.value) { - data.valueFormated = map.text; - return; - } - } - - if (data.value === null || data.value === void 0) { - data.valueFormated = "no value"; - } - }; - - removeValueMap(map) { - var index = _.indexOf(this.panel.valueMaps, map); - this.panel.valueMaps.splice(index, 1); - this.render(); - }; - - addValueMap() { - this.panel.valueMaps.push({value: '', op: '=', text: '' }); - } -} - diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index e0ea4429b39..8c6498778bd 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -1,18 +1,237 @@ /// +import angular from 'angular'; import _ from 'lodash'; import $ from 'jquery'; import 'jquery.flot'; -import {SingleStatCtrl} from './controller'; -import {PanelDirective} from '../../../features/panel/panel'; -class SingleStatPanel extends PanelDirective { - templateUrl = 'public/app/plugins/panel/singlestat/module.html'; - controller = SingleStatCtrl; +import kbn from 'app/core/utils/kbn'; +import TimeSeries from '../../../core/time_series2'; +import {MetricsPanelCtrl} from '../../../features/panel/panel'; + +// Set and populate defaults +var panelDefaults = { + links: [], + datasource: null, + maxDataPoints: 100, + interval: null, + targets: [{}], + cacheTimeout: null, + format: 'none', + prefix: '', + postfix: '', + nullText: null, + valueMaps: [ + { value: 'null', op: '=', text: 'N/A' } + ], + nullPointMode: 'connected', + valueName: 'avg', + prefixFontSize: '50%', + valueFontSize: '80%', + postfixFontSize: '50%', + thresholds: '', + colorBackground: false, + colorValue: false, + colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + sparkline: { + show: false, + full: false, + lineColor: 'rgb(31, 120, 193)', + fillColor: 'rgba(31, 118, 189, 0.18)', + } +}; + +class SingleStatCtrl extends MetricsPanelCtrl { + static templateUrl = 'public/app/plugins/panel/singlestat/module.html'; + + series: any[]; + data: any[]; + fontSizes: any[]; + unitFormats: any[]; /** @ngInject */ - constructor(private $location, private linkSrv, private $timeout, private templateSrv) { - super(); + constructor($scope, $injector, private $location, private linkSrv, private templateSrv) { + super($scope, $injector); + _.defaults(this.panel, panelDefaults); + } + + initEditMode() { + super.initEditMode(); + this.icon = "fa fa-dashboard"; + this.fontSizes = ['20%', '30%','50%','70%','80%','100%', '110%', '120%', '150%', '170%', '200%']; + this.addEditorTab('Options', 'app/plugins/panel/singlestat/editor.html', 2); + this.unitFormats = kbn.getUnitFormats(); + } + + setUnitFormat(subItem) { + this.panel.format = subItem.value; + this.render(); + } + + refreshData(datasource) { + return this.issueQueries(datasource) + .then(this.dataHandler.bind(this)) + .catch(err => { + this.series = []; + this.render(); + throw err; + }); + } + + loadSnapshot(snapshotData) { + this.updateTimeRange(); + this.dataHandler(snapshotData); + } + + dataHandler(results) { + this.series = _.map(results.data, this.seriesHandler.bind(this)); + this.render(); + } + + seriesHandler(seriesData) { + var series = new TimeSeries({ + datapoints: seriesData.datapoints, + alias: seriesData.target, + }); + + series.flotpairs = series.getFlotPairs(this.panel.nullPointMode); + return series; + } + + setColoring(options) { + if (options.background) { + this.panel.colorValue = false; + this.panel.colors = ['rgba(71, 212, 59, 0.4)', 'rgba(245, 150, 40, 0.73)', 'rgba(225, 40, 40, 0.59)']; + } else { + this.panel.colorBackground = false; + this.panel.colors = ['rgba(50, 172, 45, 0.97)', 'rgba(237, 129, 40, 0.89)', 'rgba(245, 54, 54, 0.9)']; + } + this.render(); + } + + invertColorOrder() { + var tmp = this.panel.colors[0]; + this.panel.colors[0] = this.panel.colors[2]; + this.panel.colors[2] = tmp; + this.render(); + } + + getDecimalsForValue(value) { + if (_.isNumber(this.panel.decimals)) { + return {decimals: this.panel.decimals, scaledDecimals: null}; + } + + var delta = value / 2; + var dec = -Math.floor(Math.log(delta) / Math.LN10); + + var magn = Math.pow(10, -dec), + norm = delta / magn, // norm is between 1.0 and 10.0 + size; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + // special case for 2.5, requires an extra decimal + if (norm > 2.25) { + size = 2.5; + ++dec; + } + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + + // reduce starting decimals if not needed + if (Math.floor(value) === value) { dec = 0; } + + var result: any = {}; + result.decimals = Math.max(0, dec); + result.scaledDecimals = result.decimals - Math.floor(Math.log(size) / Math.LN10) + 2; + + return result; + } + + render() { + var data: any = {}; + this.setValues(data); + + data.thresholds = this.panel.thresholds.split(',').map(function(strVale) { + return Number(strVale.trim()); + }); + + data.colorMap = this.panel.colors; + + this.data = data; + this.broadcastRender(); + } + + setValues(data) { + data.flotpairs = []; + + if (this.series.length > 1) { + this.inspector.error = new Error(); + this.inspector.error.message = 'Multiple Series Error'; + this.inspector.error.data = 'Metric query returns ' + this.series.length + + ' series. Single Stat Panel expects a single series.\n\nResponse:\n'+JSON.stringify(this.series); + throw this.inspector.error; + } + + if (this.series && this.series.length > 0) { + var lastPoint = _.last(this.series[0].datapoints); + var lastValue = _.isArray(lastPoint) ? lastPoint[0] : null; + + if (_.isString(lastValue)) { + data.value = 0; + data.valueFormated = lastValue; + data.valueRounded = 0; + } else { + data.value = this.series[0].stats[this.panel.valueName]; + data.flotpairs = this.series[0].flotpairs; + + var decimalInfo = this.getDecimalsForValue(data.value); + var formatFunc = kbn.valueFormats[this.panel.format]; + data.valueFormated = formatFunc(data.value, decimalInfo.decimals, decimalInfo.scaledDecimals); + data.valueRounded = kbn.roundValue(data.value, decimalInfo.decimals); + } + } + + // check value to text mappings + for (var i = 0; i < this.panel.valueMaps.length; i++) { + var map = this.panel.valueMaps[i]; + // special null case + if (map.value === 'null') { + if (data.value === null || data.value === void 0) { + data.valueFormated = map.text; + return; + } + continue; + } + + // value/number to text mapping + var value = parseFloat(map.value); + if (value === data.value) { + data.valueFormated = map.text; + return; + } + } + + if (data.value === null || data.value === void 0) { + data.valueFormated = "no value"; + } + }; + + removeValueMap(map) { + var index = _.indexOf(this.panel.valueMaps, map); + this.panel.valueMaps.splice(index, 1); + this.render(); + }; + + addValueMap() { + this.panel.valueMaps.push({value: '', op: '=', text: '' }); } link(scope, elem, attrs, ctrl) { @@ -235,7 +454,7 @@ function getColorForValue(data, value) { } export { - SingleStatPanel, - SingleStatPanel as Panel, + SingleStatCtrl, + SingleStatCtrl as PanelCtrl, getColorForValue }; diff --git a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts b/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts index 21cbfb7602c..283389ee400 100644 --- a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts +++ b/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts @@ -4,7 +4,7 @@ import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../.. import angular from 'angular'; import helpers from '../../../../../test/specs/helpers'; -import {SingleStatCtrl} from '../controller'; +import {SingleStatCtrl} from '../module'; describe('SingleStatCtrl', function() { var ctx = new helpers.ControllerTestContext(); diff --git a/public/app/plugins/panel/table/controller.ts b/public/app/plugins/panel/table/controller.ts deleted file mode 100644 index a526a8a8798..00000000000 --- a/public/app/plugins/panel/table/controller.ts +++ /dev/null @@ -1,133 +0,0 @@ -/// - -import angular from 'angular'; -import _ from 'lodash'; -import moment from 'moment'; -import * as FileExport from 'app/core/utils/file_export'; -import {MetricsPanelCtrl} from '../../../features/panel/panel'; -import {transformDataToTable} from './transformers'; -import {tablePanelEditor} from './editor'; - -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, $injector, private annotationsSrv) { - 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, panelDefaults); - } - - initEditMode() { - super.initEditMode(); - this.addEditorTab('Options', tablePanelEditor, 2); - } - - getExtendedMenu() { - var menu = super.getExtendedMenu(); - menu.push({text: 'Export CSV', click: 'ctrl.exportCsv()'}); - return menu; - } - - refreshData(datasource) { - this.pageIndex = 0; - - if (this.panel.transform === 'annotations') { - return this.annotationsSrv.getAnnotations(this.dashboard).then(annotations => { - this.dataRaw = annotations; - this.render(); - }); - } - - 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 { - this.panel.sort.col = null; - } - } else { - this.panel.sort.col = colIndex; - this.panel.sort.desc = true; - } - - this.render(); - } - - dataHandler(results) { - this.dataRaw = results.data; - this.pageIndex = 0; - this.render(); - } - - 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 (this.panel.transform === 'table' || this.panel.transform === 'json') { - this.panel.transform = 'timeseries_to_rows'; - } - } - } - } - - this.table = transformDataToTable(this.dataRaw, this.panel); - this.table.sort(this.panel.sort); - this.broadcastRender(this.table); - } - - exportCsv() { - FileExport.exportTableDataToCsv(this.table); - } -} diff --git a/public/app/plugins/panel/table/module.ts b/public/app/plugins/panel/table/module.ts index bb48da3f08a..a84d2678295 100644 --- a/public/app/plugins/panel/table/module.ts +++ b/public/app/plugins/panel/table/module.ts @@ -1,17 +1,139 @@ /// -import kbn = require('app/core/utils/kbn'); - +import angular from 'angular'; import _ from 'lodash'; import $ from 'jquery'; import moment from 'moment'; -import {PanelDirective} from '../../../features/panel/panel'; -import {TablePanelCtrl} from './controller'; +import * as FileExport from 'app/core/utils/file_export'; +import {MetricsPanelCtrl} from '../../../features/panel/panel'; +import {transformDataToTable} from './transformers'; +import {tablePanelEditor} from './editor'; import {TableRenderer} from './renderer'; -class TablePanel extends PanelDirective { - templateUrl = 'public/app/plugins/panel/table/module.html'; - controller = 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}, +}; + +class TablePanelCtrl extends MetricsPanelCtrl { + static templateUrl = 'public/app/plugins/panel/table/module.html'; + + pageIndex: number; + dataRaw: any; + table: any; + + /** @ngInject */ + constructor($scope, $injector, private annotationsSrv) { + 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, panelDefaults); + } + + initEditMode() { + super.initEditMode(); + this.addEditorTab('Options', tablePanelEditor, 2); + } + + getExtendedMenu() { + var menu = super.getExtendedMenu(); + menu.push({text: 'Export CSV', click: 'ctrl.exportCsv()'}); + return menu; + } + + refreshData(datasource) { + this.pageIndex = 0; + + if (this.panel.transform === 'annotations') { + return this.annotationsSrv.getAnnotations(this.dashboard).then(annotations => { + this.dataRaw = annotations; + this.render(); + }); + } + + 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 { + this.panel.sort.col = null; + } + } else { + this.panel.sort.col = colIndex; + this.panel.sort.desc = true; + } + + this.render(); + } + + dataHandler(results) { + this.dataRaw = results.data; + this.pageIndex = 0; + this.render(); + } + + 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 (this.panel.transform === 'table' || this.panel.transform === 'json') { + this.panel.transform = 'timeseries_to_rows'; + } + } + } + } + + this.table = transformDataToTable(this.dataRaw, this.panel); + this.table.sort(this.panel.sort); + this.broadcastRender(this.table); + } + + exportCsv() { + FileExport.exportTableDataToCsv(this.table); + } link(scope, elem, attrs, ctrl) { var data; @@ -97,6 +219,6 @@ class TablePanel extends PanelDirective { } export { - TablePanel, - TablePanel as Panel + TablePanelCtrl, + TablePanelCtrl as PanelCtrl }; diff --git a/public/app/plugins/panel/text/module.ts b/public/app/plugins/panel/text/module.ts index d725fba8e5c..4cb35b71a4b 100644 --- a/public/app/plugins/panel/text/module.ts +++ b/public/app/plugins/panel/text/module.ts @@ -1,7 +1,7 @@ /// import _ from 'lodash'; -import {PanelDirective, PanelCtrl} from '../../../features/panel/panel'; +import {PanelCtrl} from '../../../features/panel/panel'; // Set and populate defaults var panelDefaults = { diff --git a/public/app/plugins/panel/unknown/module.ts b/public/app/plugins/panel/unknown/module.ts index d1acc57af8a..dad970047bf 100644 --- a/public/app/plugins/panel/unknown/module.ts +++ b/public/app/plugins/panel/unknown/module.ts @@ -1,14 +1,14 @@ /// -import {PanelDirective} from '../../../features/panel/panel'; +import {PanelCtrl} from '../../../features/panel/panel'; -class UnknownPanel extends PanelDirective { - templateUrl = 'public/app/plugins/panel/unknown/module.html'; +export class UnknownPanelCtrl extends PanelCtrl { + static templateUrl = 'public/app/plugins/panel/unknown/module.html'; + + constructor($scope, $injector) { + super($scope, $injector); + } } -export { - UnknownPanel, - UnknownPanel as Panel -}