2017-12-21 08:39:31 +01:00
|
|
|
import './graph';
|
|
|
|
|
import './series_overrides_ctrl';
|
|
|
|
|
import './thresholds_form';
|
2018-06-21 14:41:47 +02:00
|
|
|
import './time_regions_form';
|
2017-12-21 08:39:31 +01:00
|
|
|
|
|
|
|
|
import template from './template';
|
|
|
|
|
import _ from 'lodash';
|
2018-11-16 08:31:29 +01:00
|
|
|
|
|
|
|
|
import { MetricsPanelCtrl } from 'app/plugins/sdk';
|
2017-12-21 08:39:31 +01:00
|
|
|
import { DataProcessor } from './data_processor';
|
|
|
|
|
import { axesEditorComponent } from './axes_editor';
|
2016-02-04 14:36:19 +01:00
|
|
|
|
|
|
|
|
class GraphCtrl extends MetricsPanelCtrl {
|
2016-03-20 11:17:53 +01:00
|
|
|
static template = template;
|
2016-02-04 14:36:19 +01:00
|
|
|
|
2018-08-13 16:08:01 +02:00
|
|
|
renderError: boolean;
|
2016-02-04 14:36:19 +01:00
|
|
|
hiddenSeries: any = {};
|
|
|
|
|
seriesList: any = [];
|
2016-09-22 16:05:20 +02:00
|
|
|
dataList: any = [];
|
2016-09-30 17:37:47 +02:00
|
|
|
annotations: any = [];
|
|
|
|
|
alertState: any;
|
|
|
|
|
|
2016-02-04 14:36:19 +01:00
|
|
|
annotationsPromise: any;
|
2017-02-23 15:56:37 +01:00
|
|
|
dataWarning: any;
|
2016-02-04 14:36:19 +01:00
|
|
|
colors: any = [];
|
2016-08-10 15:27:33 +02:00
|
|
|
subTabIndex: number;
|
2016-09-22 16:05:20 +02:00
|
|
|
processor: DataProcessor;
|
2016-02-04 14:36:19 +01:00
|
|
|
|
2016-04-22 15:29:33 +02:00
|
|
|
panelDefaults = {
|
|
|
|
|
// datasource name, null = default datasource
|
|
|
|
|
datasource: null,
|
|
|
|
|
// sets client side (flot) or native graphite png renderer (png)
|
2017-12-21 08:39:31 +01:00
|
|
|
renderer: 'flot',
|
2016-04-22 15:29:33 +02:00
|
|
|
yaxes: [
|
|
|
|
|
{
|
|
|
|
|
label: null,
|
|
|
|
|
show: true,
|
|
|
|
|
logBase: 1,
|
|
|
|
|
min: null,
|
|
|
|
|
max: null,
|
2017-12-21 08:39:31 +01:00
|
|
|
format: 'short',
|
2016-04-22 15:29:33 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: null,
|
|
|
|
|
show: true,
|
|
|
|
|
logBase: 1,
|
|
|
|
|
min: null,
|
|
|
|
|
max: null,
|
2017-12-21 08:39:31 +01:00
|
|
|
format: 'short',
|
|
|
|
|
},
|
2016-04-22 15:29:33 +02:00
|
|
|
],
|
|
|
|
|
xaxis: {
|
2016-08-14 17:33:18 +03:00
|
|
|
show: true,
|
2017-12-21 08:39:31 +01:00
|
|
|
mode: 'time',
|
2016-09-05 11:07:41 +02:00
|
|
|
name: null,
|
|
|
|
|
values: [],
|
2017-12-21 08:39:31 +01:00
|
|
|
buckets: null,
|
2016-04-22 15:29:33 +02:00
|
|
|
},
|
2018-03-20 22:44:48 +05:00
|
|
|
yaxis: {
|
2018-03-22 18:30:23 +01:00
|
|
|
align: false,
|
|
|
|
|
alignLevel: null,
|
2018-03-20 22:44:48 +05:00
|
|
|
},
|
2016-04-22 15:29:33 +02:00
|
|
|
// show/hide lines
|
2017-12-19 16:06:54 +01:00
|
|
|
lines: true,
|
2016-04-22 15:29:33 +02:00
|
|
|
// fill factor
|
2017-12-19 16:06:54 +01:00
|
|
|
fill: 1,
|
2016-04-22 15:29:33 +02:00
|
|
|
// line width in pixels
|
2017-12-19 16:06:54 +01:00
|
|
|
linewidth: 1,
|
2016-07-01 13:16:49 -04:00
|
|
|
// show/hide dashed line
|
2017-12-19 16:06:54 +01:00
|
|
|
dashes: false,
|
2016-07-01 13:16:49 -04:00
|
|
|
// length of a dash
|
2017-12-19 16:06:54 +01:00
|
|
|
dashLength: 10,
|
2016-07-01 13:16:49 -04:00
|
|
|
// length of space between two dashes
|
2018-11-16 08:31:29 +01:00
|
|
|
paceLength: 10,
|
2016-04-22 15:29:33 +02:00
|
|
|
// show hide points
|
2017-12-19 16:06:54 +01:00
|
|
|
points: false,
|
2016-04-22 15:29:33 +02:00
|
|
|
// point radius in pixels
|
2018-11-16 08:31:29 +01:00
|
|
|
pointradius: 2,
|
2016-04-22 15:29:33 +02:00
|
|
|
// show hide bars
|
2017-12-19 16:06:54 +01:00
|
|
|
bars: false,
|
2016-04-22 15:29:33 +02:00
|
|
|
// enable/disable stacking
|
2017-12-19 16:06:54 +01:00
|
|
|
stack: false,
|
2016-04-22 15:29:33 +02:00
|
|
|
// stack percentage mode
|
2017-12-19 16:06:54 +01:00
|
|
|
percentage: false,
|
2016-04-22 15:29:33 +02:00
|
|
|
// legend options
|
|
|
|
|
legend: {
|
|
|
|
|
show: true, // disable/enable legend
|
|
|
|
|
values: false, // disable/enable legend values
|
|
|
|
|
min: false,
|
|
|
|
|
max: false,
|
|
|
|
|
current: false,
|
|
|
|
|
total: false,
|
2017-12-21 08:39:31 +01:00
|
|
|
avg: false,
|
2016-04-22 15:29:33 +02:00
|
|
|
},
|
|
|
|
|
// how null points should be handled
|
2017-12-21 08:39:31 +01:00
|
|
|
nullPointMode: 'null',
|
2016-04-22 15:29:33 +02:00
|
|
|
// staircase line mode
|
|
|
|
|
steppedLine: false,
|
|
|
|
|
// tooltip options
|
2017-12-19 16:06:54 +01:00
|
|
|
tooltip: {
|
2017-12-21 08:39:31 +01:00
|
|
|
value_type: 'individual',
|
2016-04-22 15:29:33 +02:00
|
|
|
shared: true,
|
2017-12-21 08:39:31 +01:00
|
|
|
sort: 0,
|
2016-04-22 15:29:33 +02:00
|
|
|
},
|
|
|
|
|
// time overrides
|
|
|
|
|
timeFrom: null,
|
|
|
|
|
timeShift: null,
|
|
|
|
|
// metric queries
|
|
|
|
|
targets: [{}],
|
|
|
|
|
// series color overrides
|
|
|
|
|
aliasColors: {},
|
|
|
|
|
// other style overrides
|
|
|
|
|
seriesOverrides: [],
|
2017-12-21 08:39:31 +01:00
|
|
|
thresholds: [],
|
2018-06-21 14:41:47 +02:00
|
|
|
timeRegions: [],
|
2016-04-22 15:29:33 +02:00
|
|
|
};
|
|
|
|
|
|
2016-02-04 14:36:19 +01:00
|
|
|
/** @ngInject */
|
|
|
|
|
constructor($scope, $injector, private annotationsSrv) {
|
|
|
|
|
super($scope, $injector);
|
|
|
|
|
|
2016-04-22 15:49:51 +02:00
|
|
|
_.defaults(this.panel, this.panelDefaults);
|
2016-04-22 15:29:33 +02:00
|
|
|
_.defaults(this.panel.tooltip, this.panelDefaults.tooltip);
|
|
|
|
|
_.defaults(this.panel.legend, this.panelDefaults.legend);
|
2016-08-16 19:41:18 +03:00
|
|
|
_.defaults(this.panel.xaxis, this.panelDefaults.xaxis);
|
2016-02-04 14:36:19 +01:00
|
|
|
|
2016-09-22 16:05:20 +02:00
|
|
|
this.processor = new DataProcessor(this.panel);
|
2016-03-22 18:21:21 +01:00
|
|
|
|
2017-12-21 08:39:31 +01:00
|
|
|
this.events.on('render', this.onRender.bind(this));
|
|
|
|
|
this.events.on('data-received', this.onDataReceived.bind(this));
|
|
|
|
|
this.events.on('data-error', this.onDataError.bind(this));
|
|
|
|
|
this.events.on('data-snapshot-load', this.onDataSnapshotLoad.bind(this));
|
|
|
|
|
this.events.on('init-edit-mode', this.onInitEditMode.bind(this));
|
|
|
|
|
this.events.on('init-panel-actions', this.onInitPanelActions.bind(this));
|
2016-02-04 14:36:19 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-23 12:50:56 +01:00
|
|
|
onInitEditMode() {
|
2018-11-20 11:06:36 +01:00
|
|
|
this.addEditorTab('Display options', 'public/app/plugins/panel/graph/tab_display.html');
|
|
|
|
|
this.addEditorTab('Axes', axesEditorComponent);
|
|
|
|
|
this.addEditorTab('Legend', 'public/app/plugins/panel/graph/tab_legend.html');
|
2018-12-07 15:18:43 +01:00
|
|
|
this.addEditorTab('Thresholds & Time Regions', 'public/app/plugins/panel/graph/tab_thresholds_time_regions.html');
|
2016-08-10 15:27:33 +02:00
|
|
|
this.subTabIndex = 0;
|
2016-02-04 14:36:19 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-23 12:50:56 +01:00
|
|
|
onInitPanelActions(actions) {
|
2017-12-21 08:39:31 +01:00
|
|
|
actions.push({ text: 'Export CSV', click: 'ctrl.exportCsv()' });
|
2018-10-19 16:33:23 -04:00
|
|
|
actions.push({ text: 'Toggle legend', click: 'ctrl.toggleLegend()', shortcut: 'p l' });
|
2016-02-04 14:36:19 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-22 18:21:21 +01:00
|
|
|
issueQueries(datasource) {
|
2016-09-09 11:30:55 +02:00
|
|
|
this.annotationsPromise = this.annotationsSrv.getAnnotations({
|
|
|
|
|
dashboard: this.dashboard,
|
|
|
|
|
panel: this.panel,
|
2017-12-21 08:39:31 +01:00
|
|
|
range: this.range,
|
2016-09-09 11:30:55 +02:00
|
|
|
});
|
2018-09-19 15:10:48 -04:00
|
|
|
|
|
|
|
|
/* Wait for annotationSrv requests to get datasources to
|
|
|
|
|
* resolve before issuing queries. This allows the annotations
|
|
|
|
|
* service to fire annotations queries before graph queries
|
|
|
|
|
* (but not wait for completion). This resolves
|
|
|
|
|
* issue 11806.
|
|
|
|
|
*/
|
|
|
|
|
return this.annotationsSrv.datasourcePromises.then(r => {
|
|
|
|
|
return super.issueQueries(datasource);
|
|
|
|
|
});
|
2016-02-04 14:36:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
zoomOut(evt) {
|
2017-12-21 08:39:31 +01:00
|
|
|
this.publishAppEvent('zoom-out', 2);
|
2016-02-04 14:36:19 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-23 11:31:31 +01:00
|
|
|
onDataSnapshotLoad(snapshotData) {
|
2016-09-09 11:30:55 +02:00
|
|
|
this.annotationsPromise = this.annotationsSrv.getAnnotations({
|
|
|
|
|
dashboard: this.dashboard,
|
|
|
|
|
panel: this.panel,
|
2017-12-21 08:39:31 +01:00
|
|
|
range: this.range,
|
2016-09-09 11:30:55 +02:00
|
|
|
});
|
2016-04-14 11:06:48 -04:00
|
|
|
this.onDataReceived(snapshotData);
|
2016-02-04 14:36:19 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-22 18:21:21 +01:00
|
|
|
onDataError(err) {
|
|
|
|
|
this.seriesList = [];
|
2016-09-30 17:37:47 +02:00
|
|
|
this.annotations = [];
|
2016-03-22 18:21:21 +01:00
|
|
|
this.render([]);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-22 21:27:53 +01:00
|
|
|
onDataReceived(dataList) {
|
2016-09-22 16:05:20 +02:00
|
|
|
this.dataList = dataList;
|
2017-12-19 16:06:54 +01:00
|
|
|
this.seriesList = this.processor.getSeriesList({
|
|
|
|
|
dataList: dataList,
|
2017-12-21 08:39:31 +01:00
|
|
|
range: this.range,
|
2017-12-19 16:06:54 +01:00
|
|
|
});
|
2016-09-27 14:39:51 +02:00
|
|
|
|
2017-02-23 15:56:37 +01:00
|
|
|
this.dataWarning = null;
|
|
|
|
|
const datapointsCount = this.seriesList.reduce((prev, series) => {
|
2016-09-27 14:39:51 +02:00
|
|
|
return prev + series.datapoints.length;
|
|
|
|
|
}, 0);
|
|
|
|
|
|
2017-02-23 15:56:37 +01:00
|
|
|
if (datapointsCount === 0) {
|
|
|
|
|
this.dataWarning = {
|
2017-12-21 08:39:31 +01:00
|
|
|
title: 'No data points',
|
|
|
|
|
tip: 'No datapoints returned from data query',
|
2017-02-23 15:56:37 +01:00
|
|
|
};
|
|
|
|
|
} else {
|
2018-08-26 17:14:40 +02:00
|
|
|
for (const series of this.seriesList) {
|
2017-02-23 15:56:37 +01:00
|
|
|
if (series.isOutsideRange) {
|
|
|
|
|
this.dataWarning = {
|
2017-12-21 08:39:31 +01:00
|
|
|
title: 'Data points outside time range',
|
|
|
|
|
tip: 'Can be caused by timezone mismatch or missing time filter in query',
|
2017-02-23 15:56:37 +01:00
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-09-27 14:39:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
2016-02-04 14:36:19 +01:00
|
|
|
|
2017-12-19 16:06:54 +01:00
|
|
|
this.annotationsPromise.then(
|
|
|
|
|
result => {
|
|
|
|
|
this.loading = false;
|
|
|
|
|
this.alertState = result.alertState;
|
|
|
|
|
this.annotations = result.annotations;
|
|
|
|
|
this.render(this.seriesList);
|
|
|
|
|
},
|
|
|
|
|
() => {
|
|
|
|
|
this.loading = false;
|
|
|
|
|
this.render(this.seriesList);
|
|
|
|
|
}
|
|
|
|
|
);
|
2016-03-22 18:21:21 +01:00
|
|
|
}
|
2016-02-04 14:36:19 +01:00
|
|
|
|
2016-04-09 14:37:30 -04:00
|
|
|
onRender() {
|
2017-12-19 16:06:54 +01:00
|
|
|
if (!this.seriesList) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-04-08 17:43:13 -04:00
|
|
|
|
2018-08-26 17:14:40 +02:00
|
|
|
for (const series of this.seriesList) {
|
2016-04-08 17:43:13 -04:00
|
|
|
series.applySeriesOverrides(this.panel.seriesOverrides);
|
2016-04-12 14:26:49 -04:00
|
|
|
|
|
|
|
|
if (series.unit) {
|
2017-12-19 16:06:54 +01:00
|
|
|
this.panel.yaxes[series.yaxis - 1].format = series.unit;
|
2016-04-12 14:26:49 -04:00
|
|
|
}
|
2016-04-08 17:43:13 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-31 03:25:00 -07:00
|
|
|
onColorChange = (series, color) => {
|
2018-05-08 07:18:57 -06:00
|
|
|
series.setColor(color);
|
2016-02-04 14:36:19 +01:00
|
|
|
this.panel.aliasColors[series.alias] = series.color;
|
|
|
|
|
this.render();
|
2018-10-31 03:25:00 -07:00
|
|
|
};
|
2016-02-04 14:36:19 +01:00
|
|
|
|
2018-10-31 03:25:00 -07:00
|
|
|
onToggleSeries = hiddenSeries => {
|
2018-10-19 16:20:00 +03:00
|
|
|
this.hiddenSeries = hiddenSeries;
|
2016-02-04 14:36:19 +01:00
|
|
|
this.render();
|
2018-10-31 03:25:00 -07:00
|
|
|
};
|
2016-02-04 14:36:19 +01:00
|
|
|
|
2018-10-31 03:25:00 -07:00
|
|
|
onToggleSort = (sortBy, sortDesc) => {
|
2018-09-04 12:49:13 +03:00
|
|
|
this.panel.legend.sort = sortBy;
|
|
|
|
|
this.panel.legend.sortDesc = sortDesc;
|
|
|
|
|
this.render();
|
2018-10-31 03:25:00 -07:00
|
|
|
};
|
2018-09-04 12:49:13 +03:00
|
|
|
|
2018-10-31 03:25:00 -07:00
|
|
|
onToggleAxis = info => {
|
2018-08-30 08:58:43 +02:00
|
|
|
let override = _.find(this.panel.seriesOverrides, { alias: info.alias });
|
2016-02-04 14:36:19 +01:00
|
|
|
if (!override) {
|
|
|
|
|
override = { alias: info.alias };
|
|
|
|
|
this.panel.seriesOverrides.push(override);
|
|
|
|
|
}
|
2018-10-19 16:20:00 +03:00
|
|
|
override.yaxis = info.yaxis;
|
2016-02-04 14:36:19 +01:00
|
|
|
this.render();
|
2018-10-31 03:25:00 -07:00
|
|
|
};
|
2016-02-04 14:36:19 +01:00
|
|
|
|
|
|
|
|
addSeriesOverride(override) {
|
|
|
|
|
this.panel.seriesOverrides.push(override || {});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
removeSeriesOverride(override) {
|
2017-12-21 08:39:31 +01:00
|
|
|
this.panel.seriesOverrides = _.without(this.panel.seriesOverrides, override);
|
2016-02-04 14:36:19 +01:00
|
|
|
this.render();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toggleLegend() {
|
|
|
|
|
this.panel.legend.show = !this.panel.legend.show;
|
|
|
|
|
this.refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
legendValuesOptionChanged() {
|
2018-08-29 14:27:29 +02:00
|
|
|
const legend = this.panel.legend;
|
2017-12-21 08:39:31 +01:00
|
|
|
legend.values = legend.min || legend.max || legend.avg || legend.current || legend.total;
|
2016-02-04 14:36:19 +01:00
|
|
|
this.render();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exportCsv() {
|
2018-08-29 14:27:29 +02:00
|
|
|
const scope = this.$scope.$new(true);
|
2017-05-03 17:28:01 +02:00
|
|
|
scope.seriesList = this.seriesList;
|
2017-12-21 08:39:31 +01:00
|
|
|
this.publishAppEvent('show-modal', {
|
2017-05-04 15:09:48 +02:00
|
|
|
templateHtml: '<export-data-modal data="seriesList"></export-data-modal>',
|
2017-05-03 17:28:01 +02:00
|
|
|
scope,
|
2017-12-21 08:39:31 +01:00
|
|
|
modalClass: 'modal--narrow',
|
2017-05-03 17:28:01 +02:00
|
|
|
});
|
2016-02-15 19:02:41 +01:00
|
|
|
}
|
2016-08-25 21:53:49 +03:00
|
|
|
}
|
|
|
|
|
|
2017-12-19 16:06:54 +01:00
|
|
|
export { GraphCtrl, GraphCtrl as PanelCtrl };
|