From 2a8b96b680022a8ef549f58d714146da45c128f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 4 Feb 2016 14:36:19 +0100 Subject: [PATCH] feat(plugins): last refactoring of how panels are implemented, now the same way as plugin editors --- .../app/core/directives/plugin_component.ts | 64 +++- public/app/partials/dashboard.html | 4 +- public/app/plugins/panel/dashlist/module.ts | 7 +- public/app/plugins/panel/graph/graph_ctrl.ts | 295 ----------------- public/app/plugins/panel/graph/module.ts | 304 +++++++++++++++++- .../panel/graph/specs/graph_ctrl_specs.ts | 2 +- public/app/plugins/panel/text/module.ts | 9 +- 7 files changed, 366 insertions(+), 319 deletions(-) delete mode 100644 public/app/plugins/panel/graph/graph_ctrl.ts diff --git a/public/app/core/directives/plugin_component.ts b/public/app/core/directives/plugin_component.ts index 9bfab78074e..020bcb08f0a 100644 --- a/public/app/core/directives/plugin_component.ts +++ b/public/app/core/directives/plugin_component.ts @@ -3,14 +3,30 @@ import angular from 'angular'; import _ from 'lodash'; -import coreModule from '../core_module'; +import config from 'app/core/config'; +import coreModule from 'app/core/core_module'; -function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q) { +/** @ngInject */ +function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $templateCache) { + + function getTemplate(component) { + if (component.template) { + return $q.when(component.template); + } + var cached = $templateCache.get(component.templateUrl); + if (cached) { + return $q.when(cached); + } + return $http.get(component.templateUrl).then(res => { + return res.data; + }); + } function getPluginComponentDirective(options) { return function() { return { templateUrl: options.Component.templateUrl, + template: options.Component.template, restrict: 'E', controller: options.Component, controllerAs: 'ctrl', @@ -20,11 +36,50 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q) { if (ctrl.link) { ctrl.link(scope, elem, attrs, ctrl); } + if (ctrl.init) { + ctrl.init(); + } } }; }; } + function loadPanelComponentInfo(scope, attrs) { + var panelElemName = 'panel-' + scope.panel.type; + let panelInfo = config.panels[scope.panel.type]; + if (!panelInfo) { + // unknown + } + + 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, + }; + + if (!PanelCtrl || PanelCtrl.registered) { + return componentInfo; + }; + + if (PanelCtrl.templatePromise) { + return PanelCtrl.templatePromise.then(res => { + return componentInfo; + }); + } + + PanelCtrl.templatePromise = getTemplate(PanelCtrl).then(template => { + PanelCtrl.templateUrl = null; + PanelCtrl.template = `${template}`; + return componentInfo; + }); + + return PanelCtrl.templatePromise; + }); + } + function getModule(scope, attrs) { switch (attrs.type) { // QueryCtrl @@ -82,6 +137,10 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q) { }; }); } + // Panel + case 'panel': { + return loadPanelComponentInfo(scope, attrs); + } default: { return $q.reject({message: "Could not find component type: " + attrs.type }); } @@ -127,6 +186,7 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q) { registerPluginComponent(scope, elem, attrs, componentInfo); }).catch(err => { $rootScope.appEvent('alert-error', ['Plugin Error', err.message || err]); + console.log('Plugin componnet error', err); }); } }; diff --git a/public/app/partials/dashboard.html b/public/app/partials/dashboard.html index 97db5617a1c..712cff0e849 100644 --- a/public/app/partials/dashboard.html +++ b/public/app/partials/dashboard.html @@ -81,8 +81,8 @@
- - + +
diff --git a/public/app/plugins/panel/dashlist/module.ts b/public/app/plugins/panel/dashlist/module.ts index 8974e90a3f0..5b1c4c89f66 100644 --- a/public/app/plugins/panel/dashlist/module.ts +++ b/public/app/plugins/panel/dashlist/module.ts @@ -13,6 +13,8 @@ var panelDefaults = { }; class DashListCtrl extends PanelCtrl { + static templateUrl = 'public/app/plugins/panel/dashlist/module.html'; + dashList: any[]; modes: any[]; @@ -55,10 +57,9 @@ class DashListCtrl extends PanelCtrl { class DashListPanel extends PanelDirective { controller = DashListCtrl; - templateUrl = 'public/app/plugins/panel/dashlist/module.html'; } export { - DashListCtrl, - DashListPanel as Panel + DashListCtrl as DashListCtrl, + DashListCtrl as PanelCtrl, } diff --git a/public/app/plugins/panel/graph/graph_ctrl.ts b/public/app/plugins/panel/graph/graph_ctrl.ts deleted file mode 100644 index 1a3c4d4edd3..00000000000 --- a/public/app/plugins/panel/graph/graph_ctrl.ts +++ /dev/null @@ -1,295 +0,0 @@ -/// - -import moment from 'moment'; -import kbn from 'app/core/utils/kbn'; -import _ from 'lodash'; -import TimeSeries from '../../../core/time_series2'; -import * as fileExport from '../../../core/utils/file_export'; -import {MetricsPanelCtrl} from '../../../features/panel/panel'; - -var panelDefaults = { - // datasource name, null = default datasource - datasource: null, - // sets client side (flot) or native graphite png renderer (png) - renderer: 'flot', - // Show/hide the x-axis - 'x-axis' : true, - // Show/hide y-axis - 'y-axis' : true, - // y axis formats, [left axis,right axis] - y_formats : ['short', 'short'], - // grid options - grid : { - leftLogBase: 1, - leftMax: null, - rightMax: null, - leftMin: null, - rightMin: null, - rightLogBase: 1, - threshold1: null, - threshold2: null, - threshold1Color: 'rgba(216, 200, 27, 0.27)', - threshold2Color: 'rgba(234, 112, 112, 0.22)' - }, - // show/hide lines - lines : true, - // fill factor - fill : 1, - // line width in pixels - linewidth : 2, - // show hide points - points : false, - // point radius in pixels - pointradius : 5, - // show hide bars - bars : false, - // enable/disable stacking - stack : false, - // stack percentage mode - percentage : false, - // legend options - legend: { - show: true, // disable/enable legend - values: false, // disable/enable legend values - min: false, - max: false, - current: false, - total: false, - avg: false - }, - // how null points should be handled - nullPointMode : 'connected', - // staircase line mode - steppedLine: false, - // tooltip options - tooltip : { - value_type: 'cumulative', - shared: true, - }, - // time overrides - timeFrom: null, - timeShift: null, - // metric queries - targets: [{}], - // series color overrides - aliasColors: {}, - // other style overrides - seriesOverrides: [], -}; - -class GraphCtrl extends MetricsPanelCtrl { - hiddenSeries: any = {}; - seriesList: any = []; - logScales: any; - unitFormats: any; - annotationsPromise: any; - datapointsCount: number; - datapointsOutside: boolean; - datapointsWarning: boolean; - colors: any = []; - - /** @ngInject */ - constructor($scope, $injector, private annotationsSrv) { - super($scope, $injector); - - _.defaults(this.panel, panelDefaults); - _.defaults(this.panel.tooltip, panelDefaults.tooltip); - _.defaults(this.panel.grid, panelDefaults.grid); - _.defaults(this.panel.legend, panelDefaults.legend); - - this.colors = $scope.$root.colors; - } - - initEditMode() { - super.initEditMode(); - - this.icon = "fa fa-bar-chart"; - this.addEditorTab('Axes & Grid', 'public/app/plugins/panel/graph/axisEditor.html', 2); - this.addEditorTab('Display Styles', 'public/app/plugins/panel/graph/styleEditor.html', 3); - - this.logScales = { - 'linear': 1, - 'log (base 2)': 2, - 'log (base 10)': 10, - 'log (base 32)': 32, - 'log (base 1024)': 1024 - }; - this.unitFormats = kbn.getUnitFormats(); - } - - getExtendedMenu() { - var menu = super.getExtendedMenu(); - menu.push({text: 'Export CSV', click: 'ctrl.exportCsv()'}); - menu.push({text: 'Toggle legend', click: 'ctrl.toggleLegend()'}); - return menu; - } - - setUnitFormat(axis, subItem) { - this.panel.y_formats[axis] = subItem.value; - this.render(); - } - - refreshData(datasource) { - this.annotationsPromise = this.annotationsSrv.getAnnotations(this.dashboard); - - return this.issueQueries(datasource) - .then(res => this.dataHandler(res)) - .catch(err => { - this.seriesList = []; - this.render([]); - throw err; - }); - } - - zoomOut(evt) { - this.publishAppEvent('zoom-out', evt); - } - - loadSnapshot(snapshotData) { - this.updateTimeRange(); - this.annotationsPromise = this.annotationsSrv.getAnnotations(this.dashboard); - this.dataHandler(snapshotData); - } - - dataHandler(results) { - // png renderer returns just a url - if (_.isString(results)) { - this.render(results); - return; - } - - this.datapointsWarning = false; - this.datapointsCount = 0; - this.datapointsOutside = false; - this.seriesList = _.map(results.data, (series, i) => this.seriesHandler(series, i)); - this.datapointsWarning = this.datapointsCount === 0 || this.datapointsOutside; - - this.annotationsPromise.then(annotations => { - this.loading = false; - this.seriesList.annotations = annotations; - this.render(this.seriesList); - }, () => { - this.loading = false; - this.render(this.seriesList); - }); - }; - - seriesHandler(seriesData, index) { - var datapoints = seriesData.datapoints; - var alias = seriesData.target; - var colorIndex = index % this.colors.length; - var color = this.panel.aliasColors[alias] || this.colors[colorIndex]; - - var series = new TimeSeries({ - datapoints: datapoints, - alias: alias, - color: color, - }); - - if (datapoints && datapoints.length > 0) { - var last = moment.utc(datapoints[datapoints.length - 1][1]); - var from = moment.utc(this.range.from); - if (last - from < -10000) { - this.datapointsOutside = true; - } - - this.datapointsCount += datapoints.length; - } - - return series; - } - - render(data?: any) { - this.broadcastRender(data); - } - - changeSeriesColor(series, color) { - series.color = color; - this.panel.aliasColors[series.alias] = series.color; - this.render(); - } - - toggleSeries(serie, event) { - if (event.ctrlKey || event.metaKey || event.shiftKey) { - if (this.hiddenSeries[serie.alias]) { - delete this.hiddenSeries[serie.alias]; - } else { - this.hiddenSeries[serie.alias] = true; - } - } else { - this.toggleSeriesExclusiveMode(serie); - } - - this.render(); - } - - toggleSeriesExclusiveMode (serie) { - var hidden = this.hiddenSeries; - - if (hidden[serie.alias]) { - delete hidden[serie.alias]; - } - - // check if every other series is hidden - var alreadyExclusive = _.every(this.seriesList, value => { - if (value.alias === serie.alias) { - return true; - } - - return hidden[value.alias]; - }); - - if (alreadyExclusive) { - // remove all hidden series - _.each(this.seriesList, value => { - delete this.hiddenSeries[value.alias]; - }); - } else { - // hide all but this serie - _.each(this.seriesList, value => { - if (value.alias === serie.alias) { - return; - } - - this.hiddenSeries[value.alias] = true; - }); - } - } - - toggleYAxis(info) { - var override = _.findWhere(this.panel.seriesOverrides, { alias: info.alias }); - if (!override) { - override = { alias: info.alias }; - this.panel.seriesOverrides.push(override); - } - override.yaxis = info.yaxis === 2 ? 1 : 2; - this.render(); - }; - - addSeriesOverride(override) { - this.panel.seriesOverrides.push(override || {}); - } - - removeSeriesOverride(override) { - this.panel.seriesOverrides = _.without(this.panel.seriesOverrides, override); - this.render(); - } - - // Called from panel menu - toggleLegend() { - this.panel.legend.show = !this.panel.legend.show; - this.refresh(); - } - - legendValuesOptionChanged() { - var legend = this.panel.legend; - legend.values = legend.min || legend.max || legend.avg || legend.current || legend.total; - this.render(); - } - - exportCsv() { - fileExport.exportSeriesListToCsv(this.seriesList); - } -} - -export {GraphCtrl} diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts index 72e273e40b1..f2ca91efa2b 100644 --- a/public/app/plugins/panel/graph/module.ts +++ b/public/app/plugins/panel/graph/module.ts @@ -1,17 +1,301 @@ - -import {PanelDirective} from '../../../features/panel/panel'; -import {GraphCtrl} from './graph_ctrl'; +/// import './graph'; import './legend'; import './seriesOverridesCtrl'; -class GraphPanel extends PanelDirective { - controller = GraphCtrl; - templateUrl = 'public/app/plugins/panel/graph/module.html'; +import moment from 'moment'; +import kbn from 'app/core/utils/kbn'; +import _ from 'lodash'; +import TimeSeries from '../../../core/time_series2'; +import * as fileExport from '../../../core/utils/file_export'; +import {MetricsPanelCtrl} from '../../../features/panel/panel'; + +var panelDefaults = { + // datasource name, null = default datasource + datasource: null, + // sets client side (flot) or native graphite png renderer (png) + renderer: 'flot', + // Show/hide the x-axis + 'x-axis' : true, + // Show/hide y-axis + 'y-axis' : true, + // y axis formats, [left axis,right axis] + y_formats : ['short', 'short'], + // grid options + grid : { + leftLogBase: 1, + leftMax: null, + rightMax: null, + leftMin: null, + rightMin: null, + rightLogBase: 1, + threshold1: null, + threshold2: null, + threshold1Color: 'rgba(216, 200, 27, 0.27)', + threshold2Color: 'rgba(234, 112, 112, 0.22)' + }, + // show/hide lines + lines : true, + // fill factor + fill : 1, + // line width in pixels + linewidth : 2, + // show hide points + points : false, + // point radius in pixels + pointradius : 5, + // show hide bars + bars : false, + // enable/disable stacking + stack : false, + // stack percentage mode + percentage : false, + // legend options + legend: { + show: true, // disable/enable legend + values: false, // disable/enable legend values + min: false, + max: false, + current: false, + total: false, + avg: false + }, + // how null points should be handled + nullPointMode : 'connected', + // staircase line mode + steppedLine: false, + // tooltip options + tooltip : { + value_type: 'cumulative', + shared: true, + }, + // time overrides + timeFrom: null, + timeShift: null, + // metric queries + targets: [{}], + // series color overrides + aliasColors: {}, + // other style overrides + seriesOverrides: [], +}; + +class GraphCtrl extends MetricsPanelCtrl { + static templateUrl = 'public/app/plugins/panel/graph/module.html'; + + hiddenSeries: any = {}; + seriesList: any = []; + logScales: any; + unitFormats: any; + annotationsPromise: any; + datapointsCount: number; + datapointsOutside: boolean; + datapointsWarning: boolean; + colors: any = []; + + /** @ngInject */ + constructor($scope, $injector, private annotationsSrv) { + super($scope, $injector); + + _.defaults(this.panel, panelDefaults); + _.defaults(this.panel.tooltip, panelDefaults.tooltip); + _.defaults(this.panel.grid, panelDefaults.grid); + _.defaults(this.panel.legend, panelDefaults.legend); + + this.colors = $scope.$root.colors; + } + + initEditMode() { + super.initEditMode(); + + this.icon = "fa fa-bar-chart"; + this.addEditorTab('Axes & Grid', 'public/app/plugins/panel/graph/axisEditor.html', 2); + this.addEditorTab('Display Styles', 'public/app/plugins/panel/graph/styleEditor.html', 3); + + this.logScales = { + 'linear': 1, + 'log (base 2)': 2, + 'log (base 10)': 10, + 'log (base 32)': 32, + 'log (base 1024)': 1024 + }; + this.unitFormats = kbn.getUnitFormats(); + } + + getExtendedMenu() { + var menu = super.getExtendedMenu(); + menu.push({text: 'Export CSV', click: 'ctrl.exportCsv()'}); + menu.push({text: 'Toggle legend', click: 'ctrl.toggleLegend()'}); + return menu; + } + + setUnitFormat(axis, subItem) { + this.panel.y_formats[axis] = subItem.value; + this.render(); + } + + refreshData(datasource) { + this.annotationsPromise = this.annotationsSrv.getAnnotations(this.dashboard); + + return this.issueQueries(datasource) + .then(res => this.dataHandler(res)) + .catch(err => { + this.seriesList = []; + this.render([]); + throw err; + }); + } + + zoomOut(evt) { + this.publishAppEvent('zoom-out', evt); + } + + loadSnapshot(snapshotData) { + this.updateTimeRange(); + this.annotationsPromise = this.annotationsSrv.getAnnotations(this.dashboard); + this.dataHandler(snapshotData); + } + + dataHandler(results) { + // png renderer returns just a url + if (_.isString(results)) { + this.render(results); + return; + } + + this.datapointsWarning = false; + this.datapointsCount = 0; + this.datapointsOutside = false; + this.seriesList = _.map(results.data, (series, i) => this.seriesHandler(series, i)); + this.datapointsWarning = this.datapointsCount === 0 || this.datapointsOutside; + + this.annotationsPromise.then(annotations => { + this.loading = false; + this.seriesList.annotations = annotations; + this.render(this.seriesList); + }, () => { + this.loading = false; + this.render(this.seriesList); + }); + }; + + seriesHandler(seriesData, index) { + var datapoints = seriesData.datapoints; + var alias = seriesData.target; + var colorIndex = index % this.colors.length; + var color = this.panel.aliasColors[alias] || this.colors[colorIndex]; + + var series = new TimeSeries({ + datapoints: datapoints, + alias: alias, + color: color, + }); + + if (datapoints && datapoints.length > 0) { + var last = moment.utc(datapoints[datapoints.length - 1][1]); + var from = moment.utc(this.range.from); + if (last - from < -10000) { + this.datapointsOutside = true; + } + + this.datapointsCount += datapoints.length; + } + + return series; + } + + render(data?: any) { + this.broadcastRender(data); + } + + changeSeriesColor(series, color) { + series.color = color; + this.panel.aliasColors[series.alias] = series.color; + this.render(); + } + + toggleSeries(serie, event) { + if (event.ctrlKey || event.metaKey || event.shiftKey) { + if (this.hiddenSeries[serie.alias]) { + delete this.hiddenSeries[serie.alias]; + } else { + this.hiddenSeries[serie.alias] = true; + } + } else { + this.toggleSeriesExclusiveMode(serie); + } + + this.render(); + } + + toggleSeriesExclusiveMode (serie) { + var hidden = this.hiddenSeries; + + if (hidden[serie.alias]) { + delete hidden[serie.alias]; + } + + // check if every other series is hidden + var alreadyExclusive = _.every(this.seriesList, value => { + if (value.alias === serie.alias) { + return true; + } + + return hidden[value.alias]; + }); + + if (alreadyExclusive) { + // remove all hidden series + _.each(this.seriesList, value => { + delete this.hiddenSeries[value.alias]; + }); + } else { + // hide all but this serie + _.each(this.seriesList, value => { + if (value.alias === serie.alias) { + return; + } + + this.hiddenSeries[value.alias] = true; + }); + } + } + + toggleYAxis(info) { + var override = _.findWhere(this.panel.seriesOverrides, { alias: info.alias }); + if (!override) { + override = { alias: info.alias }; + this.panel.seriesOverrides.push(override); + } + override.yaxis = info.yaxis === 2 ? 1 : 2; + this.render(); + }; + + addSeriesOverride(override) { + this.panel.seriesOverrides.push(override || {}); + } + + removeSeriesOverride(override) { + this.panel.seriesOverrides = _.without(this.panel.seriesOverrides, override); + this.render(); + } + + // Called from panel menu + toggleLegend() { + this.panel.legend.show = !this.panel.legend.show; + this.refresh(); + } + + legendValuesOptionChanged() { + var legend = this.panel.legend; + legend.values = legend.min || legend.max || legend.avg || legend.current || legend.total; + this.render(); + } + + exportCsv() { + fileExport.exportSeriesListToCsv(this.seriesList); + } } -export { - GraphPanel, - GraphPanel as Panel -} +export {GraphCtrl, GraphCtrl as PanelCtrl} diff --git a/public/app/plugins/panel/graph/specs/graph_ctrl_specs.ts b/public/app/plugins/panel/graph/specs/graph_ctrl_specs.ts index 9bdd7c3df79..de26448ec71 100644 --- a/public/app/plugins/panel/graph/specs/graph_ctrl_specs.ts +++ b/public/app/plugins/panel/graph/specs/graph_ctrl_specs.ts @@ -3,7 +3,7 @@ import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common'; import angular from 'angular'; -import {GraphCtrl} from '../graph_ctrl'; +import {GraphCtrl} from '../module'; import helpers from '../../../../../test/specs/helpers'; describe('GraphCtrl', function() { diff --git a/public/app/plugins/panel/text/module.ts b/public/app/plugins/panel/text/module.ts index 08dbb9d388b..d725fba8e5c 100644 --- a/public/app/plugins/panel/text/module.ts +++ b/public/app/plugins/panel/text/module.ts @@ -10,6 +10,8 @@ var panelDefaults = { }; export class TextPanelCtrl extends PanelCtrl { + static templateUrl = `public/app/plugins/panel/text/module.html`; + converter: any; content: string; @@ -79,9 +81,4 @@ export class TextPanelCtrl extends PanelCtrl { } } -class TextPanel extends PanelDirective { - templateUrl = `public/app/plugins/panel/text/module.html`; - controller = TextPanelCtrl; -} - -export {TextPanel as Panel} +export {TextPanelCtrl as PanelCtrl}