diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts
index c8ab03bd688..7003130b64c 100644
--- a/public/app/plugins/panel/singlestat/module.ts
+++ b/public/app/plugins/panel/singlestat/module.ts
@@ -14,6 +14,7 @@ import {MetricsPanelCtrl} from 'app/plugins/sdk';
class SingleStatCtrl extends MetricsPanelCtrl {
static templateUrl = 'module.html';
+ dataType = 'timeseries';
series: any[];
data: any;
fontSizes: any[];
@@ -22,6 +23,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
panel: any;
events: any;
valueNameOptions: any[] = ['min','max','avg', 'current', 'total', 'name', 'first', 'delta', 'diff', 'range'];
+ tableColumnOptions: any;
// Set and populate defaults
panelDefaults = {
@@ -67,7 +69,8 @@ class SingleStatCtrl extends MetricsPanelCtrl {
maxValue: 100,
thresholdMarkers: true,
thresholdLabels: false
- }
+ },
+ tableColumn: ''
};
/** @ngInject */
@@ -98,11 +101,16 @@ class SingleStatCtrl extends MetricsPanelCtrl {
}
onDataReceived(dataList) {
- this.series = dataList.map(this.seriesHandler.bind(this));
-
- var data: any = {};
- this.setValues(data);
-
+ const data: any = {};
+ if (dataList.length > 0 && dataList[0].type === 'table'){
+ this.dataType = 'table';
+ const tableData = dataList.map(this.tableHandler.bind(this));
+ this.setTableValues(tableData, data);
+ } else {
+ this.dataType = 'timeseries';
+ this.series = dataList.map(this.seriesHandler.bind(this));
+ this.setValues(data);
+ }
this.data = data;
this.render();
}
@@ -117,6 +125,61 @@ class SingleStatCtrl extends MetricsPanelCtrl {
return series;
}
+ tableHandler(tableData) {
+ const datapoints = [];
+ const columnNames = {};
+
+ tableData.columns.forEach((column, columnIndex) => {
+ columnNames[columnIndex] = column.text;
+ });
+
+ this.tableColumnOptions = columnNames;
+ if (!_.find(tableData.columns, ['text', this.panel.tableColumn])) {
+ this.setTableColumnToSensibleDefault(tableData);
+ }
+
+ tableData.rows.forEach((row) => {
+ const datapoint = {};
+
+ row.forEach((value, columnIndex) => {
+ const key = columnNames[columnIndex];
+ datapoint[key] = value;
+ });
+
+ datapoints.push(datapoint);
+ });
+
+ return datapoints;
+ }
+
+ setTableColumnToSensibleDefault(tableData) {
+ if (this.tableColumnOptions.length === 1) {
+ this.panel.tableColumn = this.tableColumnOptions[0];
+ } else {
+ this.panel.tableColumn = _.find(tableData.columns, (col) => { return col.type !== 'time'; }).text;
+ }
+ }
+
+ setTableValues(tableData, data) {
+ if (!tableData || tableData.length === 0) {
+ return;
+ }
+
+ if (tableData[0].length === 0 || !tableData[0][0][this.panel.tableColumn]) {
+ return;
+ }
+
+ let highestValue = 0;
+ let lowestValue = Number.MAX_VALUE;
+ const datapoint = tableData[0][0];
+ data.value = datapoint[this.panel.tableColumn];
+
+ var decimalInfo = this.getDecimalsForValue(data.value);
+ var formatFunc = kbn.valueFormats[this.panel.format];
+ data.valueFormatted = formatFunc(datapoint[this.panel.tableColumn], decimalInfo.decimals, decimalInfo.scaledDecimals);
+ data.valueRounded = kbn.roundValue(data.value, this.panel.decimals || 0);
+ }
+
setColoring(options) {
if (options.background) {
this.panel.colorValue = false;
diff --git a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts b/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts
similarity index 67%
rename from public/app/plugins/panel/singlestat/specs/singlestat-specs.ts
rename to public/app/plugins/panel/singlestat/specs/singlestat_specs.ts
index 9c7a979af12..51ade2f9a98 100644
--- a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts
+++ b/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts
@@ -26,11 +26,7 @@ describe('SingleStatCtrl', function() {
beforeEach(function() {
setupFunc();
- var data = [
- {target: 'test.cpu1', datapoints: ctx.datapoints}
- ];
-
- ctx.ctrl.onDataReceived(data);
+ ctx.ctrl.onDataReceived(ctx.data);
ctx.data = ctx.ctrl.data;
});
};
@@ -41,7 +37,9 @@ describe('SingleStatCtrl', function() {
singleStatScenario('with defaults', function(ctx) {
ctx.setup(function() {
- ctx.datapoints = [[10,1], [20,2]];
+ ctx.data = [
+ {target: 'test.cpu1', datapoints: [[10,1], [20,2]]}
+ ];
});
it('Should use series avg as default main value', function() {
@@ -56,7 +54,9 @@ describe('SingleStatCtrl', function() {
singleStatScenario('showing serie name instead of value', function(ctx) {
ctx.setup(function() {
- ctx.datapoints = [[10,1], [20,2]];
+ ctx.data = [
+ {target: 'test.cpu1', datapoints: [[10,1], [20,2]]}
+ ];
ctx.ctrl.panel.valueName = 'name';
});
@@ -72,7 +72,9 @@ describe('SingleStatCtrl', function() {
singleStatScenario('MainValue should use same number for decimals as displayed when checking thresholds', function(ctx) {
ctx.setup(function() {
- ctx.datapoints = [[99.999,1], [99.99999,2]];
+ ctx.data = [
+ {target: 'test.cpu1', datapoints: [[99.999,1], [99.99999,2]]}
+ ];
});
it('Should be rounded', function() {
@@ -87,7 +89,9 @@ describe('SingleStatCtrl', function() {
singleStatScenario('When value to text mapping is specified', function(ctx) {
ctx.setup(function() {
- ctx.datapoints = [[9.9,1]];
+ ctx.data = [
+ {target: 'test.cpu1', datapoints: [[9.9,1]]}
+ ];
ctx.ctrl.panel.valueMaps = [{value: '10', text: 'OK'}];
});
@@ -106,7 +110,9 @@ describe('SingleStatCtrl', function() {
singleStatScenario('When range to text mapping is specifiedfor first range', function(ctx) {
ctx.setup(function() {
- ctx.datapoints = [[41,50]];
+ ctx.data = [
+ {target: 'test.cpu1', datapoints: [[41,50]]}
+ ];
ctx.ctrl.panel.mappingType = 2;
ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
});
@@ -118,7 +124,9 @@ describe('SingleStatCtrl', function() {
singleStatScenario('When range to text mapping is specified for other ranges', function(ctx) {
ctx.setup(function() {
- ctx.datapoints = [[65,75]];
+ ctx.data = [
+ {target: 'test.cpu1', datapoints: [[65,75]]}
+ ];
ctx.ctrl.panel.mappingType = 2;
ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
});
@@ -128,4 +136,60 @@ describe('SingleStatCtrl', function() {
});
});
+ const tableData = [{
+ "columns": [
+ {
+ "text": "Time",
+ "type": "time"
+ },
+ {
+ "text": "test1"
+ },
+ {
+ "text": "mean"
+ },
+ {
+ "text": "test2"
+ }
+ ],
+ "rows": [
+ [
+ 1492759673649,
+ 'ignore1',
+ 15,
+ 'ignore2'
+ ]
+ ],
+ "type": "table"
+ }];
+
+ singleStatScenario('When table data', function(ctx) {
+ ctx.setup(function() {
+ ctx.data = tableData;
+ ctx.ctrl.panel.tableColumn = 'mean';
+ });
+
+ it('Should use series avg as default main value', function() {
+ expect(ctx.data.value).to.be(15);
+ expect(ctx.data.valueRounded).to.be(15);
+ });
+
+ it('should set formatted value', function() {
+ expect(ctx.data.valueFormatted).to.be('15');
+ });
+ });
+
+ singleStatScenario('When table data has multiple columns', function(ctx) {
+ ctx.setup(function() {
+ ctx.data = tableData;
+ ctx.ctrl.panel.tableColumn = '';
+ });
+
+ it('Should set column to first column that is not time', function() {
+ expect(ctx.ctrl.panel.tableColumn).to.be('test1');
+ });
+ });
+
});
+
+