mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(plugins): last refactoring of how panels are implemented, now the same way as plugin editors
This commit is contained in:
@@ -3,14 +3,30 @@
|
|||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
import _ from 'lodash';
|
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) {
|
function getPluginComponentDirective(options) {
|
||||||
return function() {
|
return function() {
|
||||||
return {
|
return {
|
||||||
templateUrl: options.Component.templateUrl,
|
templateUrl: options.Component.templateUrl,
|
||||||
|
template: options.Component.template,
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
controller: options.Component,
|
controller: options.Component,
|
||||||
controllerAs: 'ctrl',
|
controllerAs: 'ctrl',
|
||||||
@@ -20,11 +36,50 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q) {
|
|||||||
if (ctrl.link) {
|
if (ctrl.link) {
|
||||||
ctrl.link(scope, elem, attrs, ctrl);
|
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 = `<grafana-panel ctrl="ctrl">${template}</grafana-panel>`;
|
||||||
|
return componentInfo;
|
||||||
|
});
|
||||||
|
|
||||||
|
return PanelCtrl.templatePromise;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getModule(scope, attrs) {
|
function getModule(scope, attrs) {
|
||||||
switch (attrs.type) {
|
switch (attrs.type) {
|
||||||
// QueryCtrl
|
// QueryCtrl
|
||||||
@@ -82,6 +137,10 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Panel
|
||||||
|
case 'panel': {
|
||||||
|
return loadPanelComponentInfo(scope, attrs);
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return $q.reject({message: "Could not find component type: " + attrs.type });
|
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);
|
registerPluginComponent(scope, elem, attrs, componentInfo);
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
$rootScope.appEvent('alert-error', ['Plugin Error', err.message || err]);
|
$rootScope.appEvent('alert-error', ['Plugin Error', err.message || err]);
|
||||||
|
console.log('Plugin componnet error', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -81,8 +81,8 @@
|
|||||||
|
|
||||||
<div ng-repeat="panel in row.panels track by panel.id" class="panel" ui-draggable="!dashboard.meta.fullscreen" drag="panel.id"
|
<div ng-repeat="panel in row.panels track by panel.id" class="panel" ui-draggable="!dashboard.meta.fullscreen" drag="panel.id"
|
||||||
ui-on-drop="onDrop($data, row, panel)" drag-handle-class="drag-handle" panel-width>
|
ui-on-drop="onDrop($data, row, panel)" drag-handle-class="drag-handle" panel-width>
|
||||||
<panel-loader class="panel-margin" dashboard="dashboard" row="row" panel="panel">
|
<plugin-component type="panel" class="panel-margin">
|
||||||
</panel-loader>
|
</plugin-component>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div panel-drop-zone class="panel panel-drop-zone" ui-on-drop="onDrop($data, row)" data-drop="true">
|
<div panel-drop-zone class="panel panel-drop-zone" ui-on-drop="onDrop($data, row)" data-drop="true">
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ var panelDefaults = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class DashListCtrl extends PanelCtrl {
|
class DashListCtrl extends PanelCtrl {
|
||||||
|
static templateUrl = 'public/app/plugins/panel/dashlist/module.html';
|
||||||
|
|
||||||
dashList: any[];
|
dashList: any[];
|
||||||
modes: any[];
|
modes: any[];
|
||||||
|
|
||||||
@@ -55,10 +57,9 @@ class DashListCtrl extends PanelCtrl {
|
|||||||
|
|
||||||
class DashListPanel extends PanelDirective {
|
class DashListPanel extends PanelDirective {
|
||||||
controller = DashListCtrl;
|
controller = DashListCtrl;
|
||||||
templateUrl = 'public/app/plugins/panel/dashlist/module.html';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DashListCtrl,
|
DashListCtrl as DashListCtrl,
|
||||||
DashListPanel as Panel
|
DashListCtrl as PanelCtrl,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,295 +0,0 @@
|
|||||||
///<reference path="../../../headers/common.d.ts" />
|
|
||||||
|
|
||||||
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}
|
|
||||||
@@ -1,17 +1,301 @@
|
|||||||
|
///<reference path="../../../headers/common.d.ts" />
|
||||||
import {PanelDirective} from '../../../features/panel/panel';
|
|
||||||
import {GraphCtrl} from './graph_ctrl';
|
|
||||||
|
|
||||||
import './graph';
|
import './graph';
|
||||||
import './legend';
|
import './legend';
|
||||||
import './seriesOverridesCtrl';
|
import './seriesOverridesCtrl';
|
||||||
|
|
||||||
class GraphPanel extends PanelDirective {
|
import moment from 'moment';
|
||||||
controller = GraphCtrl;
|
import kbn from 'app/core/utils/kbn';
|
||||||
templateUrl = 'public/app/plugins/panel/graph/module.html';
|
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 {
|
export {GraphCtrl, GraphCtrl as PanelCtrl}
|
||||||
GraphPanel,
|
|
||||||
GraphPanel as Panel
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
|
import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
|
||||||
|
|
||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
import {GraphCtrl} from '../graph_ctrl';
|
import {GraphCtrl} from '../module';
|
||||||
import helpers from '../../../../../test/specs/helpers';
|
import helpers from '../../../../../test/specs/helpers';
|
||||||
|
|
||||||
describe('GraphCtrl', function() {
|
describe('GraphCtrl', function() {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ var panelDefaults = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class TextPanelCtrl extends PanelCtrl {
|
export class TextPanelCtrl extends PanelCtrl {
|
||||||
|
static templateUrl = `public/app/plugins/panel/text/module.html`;
|
||||||
|
|
||||||
converter: any;
|
converter: any;
|
||||||
content: string;
|
content: string;
|
||||||
|
|
||||||
@@ -79,9 +81,4 @@ export class TextPanelCtrl extends PanelCtrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TextPanel extends PanelDirective {
|
export {TextPanelCtrl as PanelCtrl}
|
||||||
templateUrl = `public/app/plugins/panel/text/module.html`;
|
|
||||||
controller = TextPanelCtrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {TextPanel as Panel}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user