diff --git a/public/app/core/time_series2.ts b/public/app/core/time_series2.ts
index c8384b5b40a..ef2e6b9c8b2 100644
--- a/public/app/core/time_series2.ts
+++ b/public/app/core/time_series2.ts
@@ -41,6 +41,7 @@ export default class TimeSeries {
nullPointMode: any;
fillBelowTo: any;
transform: any;
+ flotpairs: any;
constructor(opts) {
this.datapoints = opts.datapoints;
diff --git a/public/app/features/dashboard/dashboardSrv.js b/public/app/features/dashboard/dashboardSrv.js
index 559adff5c54..e4d74c985ba 100644
--- a/public/app/features/dashboard/dashboardSrv.js
+++ b/public/app/features/dashboard/dashboardSrv.js
@@ -234,9 +234,9 @@ function (angular, $, _, moment) {
var i, j, k;
var oldVersion = this.schemaVersion;
var panelUpgrades = [];
- this.schemaVersion = 8;
+ this.schemaVersion = 9;
- if (oldVersion === 8) {
+ if (oldVersion === this.schemaVersion) {
return;
}
@@ -390,6 +390,23 @@ function (angular, $, _, moment) {
});
}
+ // schema version 9 changes
+ if (oldVersion < 9) {
+ // move aliasYAxis changes
+ panelUpgrades.push(function(panel) {
+ if (panel.type !== 'singlestat' && panel.thresholds !== "") { return; }
+
+ if (panel.thresholds) {
+ var k = panel.thresholds.split(",");
+
+ if (k.length >= 3) {
+ k.shift();
+ panel.thresholds = k.join(",");
+ }
+ }
+ });
+ }
+
if (panelUpgrades.length === 0) {
return;
}
diff --git a/public/app/plugins/panel/singlestat/controller.js b/public/app/plugins/panel/singlestat/controller.ts
similarity index 92%
rename from public/app/plugins/panel/singlestat/controller.js
rename to public/app/plugins/panel/singlestat/controller.ts
index 62ae13d0f5f..4b55a4568be 100644
--- a/public/app/plugins/panel/singlestat/controller.js
+++ b/public/app/plugins/panel/singlestat/controller.ts
@@ -1,17 +1,15 @@
-define([
- 'angular',
- 'app/app',
- 'lodash',
- 'app/core/utils/kbn',
- 'app/core/time_series',
- 'app/features/panel/panel_meta',
-],
-function (angular, app, _, kbn, TimeSeries, PanelMeta) {
- 'use strict';
+///
+
+import angular from 'angular';
+import _ from 'lodash';
+import kbn from 'app/core/utils/kbn';
+import PanelMeta from 'app/features/panel/panel_meta2';
+import TimeSeries from '../../../core/time_series2';
+
+export class SingleStatCtrl {
/** @ngInject */
- function SingleStatCtrl($scope, panelSrv, panelHelper) {
-
+ constructor($scope, panelSrv, panelHelper) {
$scope.panelMeta = new PanelMeta({
panelName: 'Singlestat',
editIcon: "fa fa-dashboard",
@@ -57,6 +55,7 @@ function (angular, app, _, kbn, TimeSeries, PanelMeta) {
};
_.defaults($scope.panel, _d);
+
$scope.unitFormats = kbn.getUnitFormats();
$scope.setUnitFormat = function(subItem) {
@@ -104,8 +103,7 @@ function (angular, app, _, kbn, TimeSeries, PanelMeta) {
if (options.background) {
$scope.panel.colorValue = false;
$scope.panel.colors = ['rgba(71, 212, 59, 0.4)', 'rgba(245, 150, 40, 0.73)', 'rgba(225, 40, 40, 0.59)'];
- }
- else {
+ } else {
$scope.panel.colorBackground = false;
$scope.panel.colors = ['rgba(50, 172, 45, 0.97)', 'rgba(237, 129, 40, 0.89)', 'rgba(245, 54, 54, 0.9)'];
}
@@ -151,7 +149,7 @@ function (angular, app, _, kbn, TimeSeries, PanelMeta) {
// reduce starting decimals if not needed
if (Math.floor(value) === value) { dec = 0; }
- var result = {};
+ var result: any = {};
result.decimals = Math.max(0, dec);
result.scaledDecimals = result.decimals - Math.floor(Math.log(size) / Math.LN10) + 2;
@@ -159,7 +157,7 @@ function (angular, app, _, kbn, TimeSeries, PanelMeta) {
};
$scope.render = function() {
- var data = {};
+ var data: any = {};
$scope.setValues(data);
@@ -176,7 +174,7 @@ function (angular, app, _, kbn, TimeSeries, PanelMeta) {
$scope.setValues = function(data) {
data.flotpairs = [];
- if($scope.series.length > 1) {
+ if ($scope.series.length > 1) {
$scope.inspector.error = new Error();
$scope.inspector.error.message = 'Multiple Series Error';
$scope.inspector.error.data = 'Metric query returns ' + $scope.series.length +
@@ -204,7 +202,7 @@ function (angular, app, _, kbn, TimeSeries, PanelMeta) {
}
// check value to text mappings
- for(var i = 0; i < $scope.panel.valueMaps.length; i++) {
+ for (var i = 0; i < $scope.panel.valueMaps.length; i++) {
var map = $scope.panel.valueMaps[i];
// special null case
if (map.value === 'null') {
@@ -239,7 +237,6 @@ function (angular, app, _, kbn, TimeSeries, PanelMeta) {
};
$scope.init();
- }
- return SingleStatCtrl;
-});
+ }
+}
diff --git a/public/app/plugins/panel/singlestat/editor.html b/public/app/plugins/panel/singlestat/editor.html
index f8df6d8adc9..76c264e7b3a 100644
--- a/public/app/plugins/panel/singlestat/editor.html
+++ b/public/app/plugins/panel/singlestat/editor.html
@@ -97,10 +97,10 @@
- ThresholdsComma seperated values
+ ThresholdsDefine two threshold values<br /> 50,80 will produce: <50 = Green, 50:80 = Yellow, >80 = Red
-
+
Colors
diff --git a/public/app/plugins/panel/singlestat/module.js b/public/app/plugins/panel/singlestat/module.js
deleted file mode 100644
index 8ce441818e6..00000000000
--- a/public/app/plugins/panel/singlestat/module.js
+++ /dev/null
@@ -1,235 +0,0 @@
-define([
- './controller',
- 'lodash',
- 'jquery',
- 'jquery.flot',
-],
-function (SingleStatCtrl, _, $) {
- 'use strict';
-
- /** @ngInject */
- function singleStatPanel($location, linkSrv, $timeout, templateSrv) {
- return {
- controller: SingleStatCtrl,
- templateUrl: 'app/plugins/panel/singlestat/module.html',
- link: function(scope, elem) {
- var data, panel, linkInfo, $panelContainer;
- var firstRender = true;
-
- scope.$on('render', function() {
- if (firstRender) {
- var inner = elem.find('.singlestat-panel');
- if (inner.length) {
- elem = inner;
- $panelContainer = elem.parents('.panel-container');
- firstRender = false;
- hookupDrilldownLinkTooltip();
- }
- }
-
- render();
- scope.panelRenderingComplete();
- });
-
- function setElementHeight() {
- try {
- var height = scope.height || panel.height || scope.row.height;
- if (_.isString(height)) {
- height = parseInt(height.replace('px', ''), 10);
- }
-
- height -= 5; // padding
- height -= panel.title ? 24 : 9; // subtract panel title bar
-
- elem.css('height', height + 'px');
-
- return true;
- } catch(e) { // IE throws errors sometimes
- return false;
- }
- }
-
- function applyColoringThresholds(value, valueString) {
- if (!panel.colorValue) {
- return valueString;
- }
-
- var color = getColorForValue(value);
- if (color) {
- return ''+ valueString + '';
- }
-
- return valueString;
- }
-
- function getColorForValue(value) {
- for (var i = data.thresholds.length - 1; i >= 0 ; i--) {
- if (value >= data.thresholds[i]) {
- return data.colorMap[i];
- }
- }
- return null;
- }
-
- function getSpan(className, fontSize, value) {
- value = templateSrv.replace(value);
- return '' +
- value + '';
- }
-
- function getBigValueHtml() {
- var body = '';
-
- if (panel.prefix) { body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, scope.panel.prefix); }
-
- var value = applyColoringThresholds(data.valueRounded, data.valueFormated);
- body += getSpan('singlestat-panel-value', panel.valueFontSize, value);
-
- if (panel.postfix) { body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, panel.postfix); }
-
- body += '
';
-
- return body;
- }
-
- function addSparkline() {
- var panel = scope.panel;
- var width = elem.width() + 20;
- var height = elem.height() || 100;
-
- var plotCanvas = $('');
- var plotCss = {};
- plotCss.position = 'absolute';
-
- if (panel.sparkline.full) {
- plotCss.bottom = '5px';
- plotCss.left = '-5px';
- plotCss.width = (width - 10) + 'px';
- var dynamicHeightMargin = height <= 100 ? 5 : (Math.round((height/100)) * 15) + 5;
- plotCss.height = (height - dynamicHeightMargin) + 'px';
- }
- else {
- plotCss.bottom = "0px";
- plotCss.left = "-5px";
- plotCss.width = (width - 10) + 'px';
- plotCss.height = Math.floor(height * 0.25) + "px";
- }
-
- plotCanvas.css(plotCss);
-
- var options = {
- legend: { show: false },
- series: {
- lines: {
- show: true,
- fill: 1,
- lineWidth: 1,
- fillColor: panel.sparkline.fillColor,
- },
- },
- yaxes: { show: false },
- xaxis: {
- show: false,
- mode: "time",
- min: scope.range.from.valueOf(),
- max: scope.range.to.valueOf(),
- },
- grid: { hoverable: false, show: false },
- };
-
- elem.append(plotCanvas);
-
- var plotSeries = {
- data: data.flotpairs,
- color: panel.sparkline.lineColor
- };
-
- $.plot(plotCanvas, [plotSeries], options);
- }
-
- function render() {
- if (!scope.data) { return; }
-
- data = scope.data;
- panel = scope.panel;
-
- setElementHeight();
-
- var body = getBigValueHtml();
-
- if (panel.colorBackground && !isNaN(data.valueRounded)) {
- var color = getColorForValue(data.valueRounded);
- if (color) {
- $panelContainer.css('background-color', color);
- if (scope.fullscreen) {
- elem.css('background-color', color);
- } else {
- elem.css('background-color', '');
- }
- }
- } else {
- $panelContainer.css('background-color', '');
- elem.css('background-color', '');
- }
-
- elem.html(body);
-
- if (panel.sparkline.show) {
- addSparkline();
- }
-
- elem.toggleClass('pointer', panel.links.length > 0);
-
- if (panel.links.length > 0) {
- linkInfo = linkSrv.getPanelLinkAnchorInfo(panel.links[0], scope.panel.scopedVars);
- } else {
- linkInfo = null;
- }
- }
-
- function hookupDrilldownLinkTooltip() {
- // drilldown link tooltip
- var drilldownTooltip = $('hello
"');
-
- elem.mouseleave(function() {
- if (panel.links.length === 0) { return;}
- drilldownTooltip.detach();
- });
-
- elem.click(function(evt) {
- if (!linkInfo) { return; }
- // ignore title clicks in title
- if ($(evt).parents('.panel-header').length > 0) { return; }
-
- if (linkInfo.target === '_blank') {
- var redirectWindow = window.open(linkInfo.href, '_blank');
- redirectWindow.location;
- return;
- }
-
- if (linkInfo.href.indexOf('http') === 0) {
- window.location.href = linkInfo.href;
- } else {
- $timeout(function() {
- $location.url(linkInfo.href);
- });
- }
-
- drilldownTooltip.detach();
- });
-
- elem.mousemove(function(e) {
- if (!linkInfo) { return;}
-
- drilldownTooltip.text('click to go to: ' + linkInfo.title);
- drilldownTooltip.place_tt(e.pageX+20, e.pageY-15);
- });
- }
- }
- };
- }
-
- return {
- panel: singleStatPanel
- };
-});
diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts
new file mode 100644
index 00000000000..0a171207bcf
--- /dev/null
+++ b/public/app/plugins/panel/singlestat/module.ts
@@ -0,0 +1,232 @@
+///
+
+import _ from 'lodash';
+import $ from 'jquery';
+import angular from 'angular';
+import {SingleStatCtrl} from './controller';
+
+angular.module('grafana.directives').directive('singleStatPanel', singleStatPanel);
+
+function singleStatPanel($location, linkSrv, $timeout, templateSrv) {
+ 'use strict';
+ return {
+ controller: SingleStatCtrl,
+ templateUrl: 'app/plugins/panel/singlestat/module.html',
+ link: function(scope, elem) {
+ var data, panel, linkInfo, $panelContainer;
+ var firstRender = true;
+
+ scope.$on('render', function() {
+ if (firstRender) {
+ var inner = elem.find('.singlestat-panel');
+ if (inner.length) {
+ elem = inner;
+ $panelContainer = elem.parents('.panel-container');
+ firstRender = false;
+ hookupDrilldownLinkTooltip();
+ }
+ }
+
+ render();
+ scope.panelRenderingComplete();
+ });
+
+ function setElementHeight() {
+ try {
+ var height = scope.height || panel.height || scope.row.height;
+ if (_.isString(height)) {
+ height = parseInt(height.replace('px', ''), 10);
+ }
+
+ height -= 5; // padding
+ height -= panel.title ? 24 : 9; // subtract panel title bar
+
+ elem.css('height', height + 'px');
+
+ return true;
+ } catch (e) { // IE throws errors sometimes
+ return false;
+ }
+ }
+
+ function applyColoringThresholds(value, valueString) {
+ if (!panel.colorValue) {
+ return valueString;
+ }
+
+ var color = getColorForValue(data, value);
+ if (color) {
+ return ''+ valueString + '';
+ }
+
+ return valueString;
+ }
+
+ function getSpan(className, fontSize, value) {
+ value = templateSrv.replace(value);
+ return '' +
+ value + '';
+ }
+
+ function getBigValueHtml() {
+ var body = '';
+
+ if (panel.prefix) { body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, scope.panel.prefix); }
+
+ var value = applyColoringThresholds(data.valueRounded, data.valueFormated);
+ body += getSpan('singlestat-panel-value', panel.valueFontSize, value);
+
+ if (panel.postfix) { body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, panel.postfix); }
+
+ body += '
';
+
+ return body;
+ }
+
+ function addSparkline() {
+ var panel = scope.panel;
+ var width = elem.width() + 20;
+ var height = elem.height() || 100;
+
+ var plotCanvas = $('');
+ var plotCss: any = {};
+ plotCss.position = 'absolute';
+
+ if (panel.sparkline.full) {
+ plotCss.bottom = '5px';
+ plotCss.left = '-5px';
+ plotCss.width = (width - 10) + 'px';
+ var dynamicHeightMargin = height <= 100 ? 5 : (Math.round((height/100)) * 15) + 5;
+ plotCss.height = (height - dynamicHeightMargin) + 'px';
+ } else {
+ plotCss.bottom = "0px";
+ plotCss.left = "-5px";
+ plotCss.width = (width - 10) + 'px';
+ plotCss.height = Math.floor(height * 0.25) + "px";
+ }
+
+ plotCanvas.css(plotCss);
+
+ var options = {
+ legend: { show: false },
+ series: {
+ lines: {
+ show: true,
+ fill: 1,
+ lineWidth: 1,
+ fillColor: panel.sparkline.fillColor,
+ },
+ },
+ yaxes: { show: false },
+ xaxis: {
+ show: false,
+ mode: "time",
+ min: scope.range.from.valueOf(),
+ max: scope.range.to.valueOf(),
+ },
+ grid: { hoverable: false, show: false },
+ };
+
+ elem.append(plotCanvas);
+
+ var plotSeries = {
+ data: data.flotpairs,
+ color: panel.sparkline.lineColor
+ };
+
+ $.plot(plotCanvas, [plotSeries], options);
+ }
+
+ function render() {
+ if (!scope.data) { return; }
+
+ data = scope.data;
+ panel = scope.panel;
+
+ setElementHeight();
+
+ var body = getBigValueHtml();
+
+ if (panel.colorBackground && !isNaN(data.valueRounded)) {
+ var color = getColorForValue(data, data.valueRounded);
+ if (color) {
+ $panelContainer.css('background-color', color);
+ if (scope.fullscreen) {
+ elem.css('background-color', color);
+ } else {
+ elem.css('background-color', '');
+ }
+ }
+ } else {
+ $panelContainer.css('background-color', '');
+ elem.css('background-color', '');
+ }
+
+ elem.html(body);
+
+ if (panel.sparkline.show) {
+ addSparkline();
+ }
+
+ elem.toggleClass('pointer', panel.links.length > 0);
+
+ if (panel.links.length > 0) {
+ linkInfo = linkSrv.getPanelLinkAnchorInfo(panel.links[0], scope.panel.scopedVars);
+ } else {
+ linkInfo = null;
+ }
+ }
+
+ function hookupDrilldownLinkTooltip() {
+ // drilldown link tooltip
+ var drilldownTooltip = $('hello
"');
+
+ elem.mouseleave(function() {
+ if (panel.links.length === 0) { return;}
+ drilldownTooltip.detach();
+ });
+
+ elem.click(function(evt) {
+ if (!linkInfo) { return; }
+ // ignore title clicks in title
+ if ($(evt).parents('.panel-header').length > 0) { return; }
+
+ if (linkInfo.target === '_blank') {
+ var redirectWindow = window.open(linkInfo.href, '_blank');
+ redirectWindow.location;
+ return;
+ }
+
+ if (linkInfo.href.indexOf('http') === 0) {
+ window.location.href = linkInfo.href;
+ } else {
+ $timeout(function() {
+ $location.url(linkInfo.href);
+ });
+ }
+
+ drilldownTooltip.detach();
+ });
+
+ elem.mousemove(function(e) {
+ if (!linkInfo) { return;}
+
+ drilldownTooltip.text('click to go to: ' + linkInfo.title);
+ drilldownTooltip.place_tt(e.pageX+20, e.pageY-15);
+ });
+ }
+ }
+ };
+}
+
+function getColorForValue(data, value) {
+ for (var i = data.thresholds.length; i > 0; i--) {
+ if (value >= data.thresholds[i]) {
+ return data.colorMap[i];
+ }
+ }
+
+ return _.first(data.colorMap);
+}
+
+export {singleStatPanel as panel, getColorForValue};
diff --git a/public/app/plugins/panel/singlestat/singleStatPanel.js b/public/app/plugins/panel/singlestat/singleStatPanel.js
deleted file mode 100644
index a176ea974ae..00000000000
--- a/public/app/plugins/panel/singlestat/singleStatPanel.js
+++ /dev/null
@@ -1,221 +0,0 @@
-define([
- 'angular',
- 'app/app',
- 'lodash',
- 'jquery',
- 'jquery.flot',
-],
-function (angular, app, _, $) {
- 'use strict';
-
- var module = angular.module('grafana.panels.singlestat', []);
- app.useModule(module);
-
- module.directive('singlestatPanel', function($location, linkSrv, $timeout, templateSrv) {
-
- return {
- link: function(scope, elem) {
- var data, panel, linkInfo;
- var $panelContainer = elem.parents('.panel-container');
-
- scope.$on('render', function() {
- render();
- scope.panelRenderingComplete();
- });
-
- function setElementHeight() {
- try {
- var height = scope.height || panel.height || scope.row.height;
- if (_.isString(height)) {
- height = parseInt(height.replace('px', ''), 10);
- }
-
- height -= 5; // padding
- height -= panel.title ? 24 : 9; // subtract panel title bar
-
- elem.css('height', height + 'px');
-
- return true;
- } catch(e) { // IE throws errors sometimes
- return false;
- }
- }
-
- function applyColoringThresholds(value, valueString) {
- if (!panel.colorValue) {
- return valueString;
- }
-
- var color = getColorForValue(value);
- if (color) {
- return ''+ valueString + '';
- }
-
- return valueString;
- }
-
- function getColorForValue(value) {
- for (var i = data.thresholds.length - 1; i >= 0 ; i--) {
- if (value >= data.thresholds[i]) {
- return data.colorMap[i];
- }
- }
- return null;
- }
-
- function getSpan(className, fontSize, value) {
- value = templateSrv.replace(value);
- return '' +
- value + '';
- }
-
- function getBigValueHtml() {
- var body = '';
-
- if (panel.prefix) { body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, scope.panel.prefix); }
-
- var value = applyColoringThresholds(data.valueRounded, data.valueFormated);
- body += getSpan('singlestat-panel-value', panel.valueFontSize, value);
-
- if (panel.postfix) { body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, panel.postfix); }
-
- body += '
';
-
- return body;
- }
-
- function addSparkline() {
- var panel = scope.panel;
- var width = elem.width() + 20;
- var height = elem.height() || 100;
-
- var plotCanvas = $('');
- var plotCss = {};
- plotCss.position = 'absolute';
-
- if (panel.sparkline.full) {
- plotCss.bottom = '5px';
- plotCss.left = '-5px';
- plotCss.width = (width - 10) + 'px';
- var dynamicHeightMargin = height <= 100 ? 5 : (Math.round((height/100)) * 15) + 5;
- plotCss.height = (height - dynamicHeightMargin) + 'px';
- }
- else {
- plotCss.bottom = "0px";
- plotCss.left = "-5px";
- plotCss.width = (width - 10) + 'px';
- plotCss.height = Math.floor(height * 0.25) + "px";
- }
-
- plotCanvas.css(plotCss);
-
- var options = {
- legend: { show: false },
- series: {
- lines: {
- show: true,
- fill: 1,
- lineWidth: 1,
- fillColor: panel.sparkline.fillColor,
- },
- },
- yaxes: { show: false },
- xaxis: {
- show: false,
- mode: "time",
- min: scope.range.from.valueOf(),
- max: scope.range.to.valueOf(),
- },
- grid: { hoverable: false, show: false },
- };
-
- elem.append(plotCanvas);
-
- var plotSeries = {
- data: data.flotpairs,
- color: panel.sparkline.lineColor
- };
-
- $.plot(plotCanvas, [plotSeries], options);
- }
-
- function render() {
- if (!scope.data) { return; }
-
- data = scope.data;
- panel = scope.panel;
-
- setElementHeight();
-
- var body = getBigValueHtml();
-
- if (panel.colorBackground && !isNaN(data.valueRounded)) {
- var color = getColorForValue(data.valueRounded);
- if (color) {
- $panelContainer.css('background-color', color);
- if (scope.fullscreen) {
- elem.css('background-color', color);
- } else {
- elem.css('background-color', '');
- }
- }
- } else {
- $panelContainer.css('background-color', '');
- elem.css('background-color', '');
- }
-
- elem.html(body);
-
- if (panel.sparkline.show) {
- addSparkline();
- }
-
- elem.toggleClass('pointer', panel.links.length > 0);
-
- if (panel.links.length > 0) {
- linkInfo = linkSrv.getPanelLinkAnchorInfo(panel.links[0], scope.panel.scopedVars);
- } else {
- linkInfo = null;
- }
- }
-
- // drilldown link tooltip
- var drilldownTooltip = $('hello
"');
-
- elem.mouseleave(function() {
- if (panel.links.length === 0) { return;}
- drilldownTooltip.detach();
- });
-
- elem.click(function() {
- if (!linkInfo) { return; }
-
- if (linkInfo.target === '_blank') {
- var redirectWindow = window.open(linkInfo.href, '_blank');
- redirectWindow.location;
- return;
- }
-
- if (linkInfo.href.indexOf('http') === 0) {
- window.location.href = linkInfo.href;
- } else {
- $timeout(function() {
- $location.url(linkInfo.href);
- });
- }
-
- drilldownTooltip.detach();
- });
-
- elem.mousemove(function(e) {
- if (!linkInfo) { return;}
-
- drilldownTooltip.text('click to go to: ' + linkInfo.title);
-
- drilldownTooltip.place_tt(e.pageX+20, e.pageY-15);
- });
- }
- };
- });
-
-});
diff --git a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts b/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts
new file mode 100644
index 00000000000..8d532d17d80
--- /dev/null
+++ b/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts
@@ -0,0 +1,88 @@
+///
+
+import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
+
+import 'app/features/panel/panel_srv';
+import 'app/features/panel/panel_helper';
+
+import angular from 'angular';
+import helpers from '../../../../../test/specs/helpers';
+import {SingleStatCtrl} from '../controller';
+
+
+angular.module('grafana.controllers').controller('SingleStatCtrl', SingleStatCtrl);
+
+describe('SingleStatCtrl', function() {
+ var ctx = new helpers.ControllerTestContext();
+
+ function singleStatScenario(desc, func) {
+
+ describe(desc, function() {
+
+ ctx.setup = function (setupFunc) {
+
+ beforeEach(angularMocks.module('grafana.services'));
+ beforeEach(angularMocks.module('grafana.controllers'));
+
+ beforeEach(ctx.providePhase());
+ beforeEach(ctx.createControllerPhase('SingleStatCtrl'));
+
+ beforeEach(function() {
+ setupFunc();
+ ctx.datasource.query = sinon.stub().returns(ctx.$q.when({
+ data: [{target: 'test.cpu1', datapoints: ctx.datapoints}]
+ }));
+
+ ctx.scope.refreshData(ctx.datasource);
+ ctx.scope.$digest();
+ ctx.data = ctx.scope.data;
+ });
+ };
+
+ func(ctx);
+ });
+ }
+
+ singleStatScenario('with defaults', function(ctx) {
+ ctx.setup(function() {
+ ctx.datapoints = [[10,1], [20,2]];
+ });
+
+ 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 formated falue', function() {
+ expect(ctx.data.valueFormated).to.be('15');
+ });
+ });
+
+ 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]];
+ });
+
+ it('Should be rounded', function() {
+ expect(ctx.data.value).to.be(99.999495);
+ expect(ctx.data.valueRounded).to.be(100);
+ });
+
+ it('should set formated falue', function() {
+ expect(ctx.data.valueFormated).to.be('100');
+ });
+ });
+
+ singleStatScenario('When value to text mapping is specified', function(ctx) {
+ ctx.setup(function() {
+ ctx.datapoints = [[10,1]];
+ ctx.scope.panel.valueMaps = [{value: '10', text: 'OK'}];
+ });
+
+ it('Should replace value with text', function() {
+ expect(ctx.data.value).to.be(10);
+ expect(ctx.data.valueFormated).to.be('OK');
+ });
+
+ });
+});
diff --git a/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts b/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts
new file mode 100644
index 00000000000..17b34f6bcef
--- /dev/null
+++ b/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts
@@ -0,0 +1,58 @@
+import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
+
+import {getColorForValue} from '../module';
+
+describe('grafanaSingleStat', function() {
+ describe('legacy thresholds', () => {
+ describe('positive thresholds', () => {
+ var data: any = {
+ colorMap: ['green', 'yellow', 'red'],
+ thresholds: [0, 20, 50]
+ };
+
+ it('5 should return green', () => {
+ expect(getColorForValue(data, 5)).to.be('green');
+ });
+
+ it('25 should return green', () => {
+ expect(getColorForValue(data, 25)).to.be('yellow');
+ });
+
+ it('55 should return green', () => {
+ expect(getColorForValue(data, 55)).to.be('red');
+ });
+ });
+ });
+
+
+
+ describe('negative thresholds', () => {
+ var data: any = {
+ colorMap: ['green', 'yellow', 'red'],
+ thresholds: [ -20, 0, 20]
+ };
+
+ it('-30 should return green', () => {
+ expect(getColorForValue(data, -30)).to.be('green');
+ });
+
+ it('1 should return green', () => {
+ expect(getColorForValue(data, 1)).to.be('yellow');
+ });
+
+ it('22 should return green', () => {
+ expect(getColorForValue(data, 22)).to.be('red');
+ });
+ });
+
+ describe('negative thresholds', () => {
+ var data: any = {
+ colorMap: ['green', 'yellow', 'red'],
+ thresholds: [ -40, -27, 20]
+ };
+
+ it('-30 should return green', () => {
+ expect(getColorForValue(data, -26)).to.be('yellow');
+ });
+ });
+});
diff --git a/public/test/specs/dashboardSrv-specs.js b/public/test/specs/dashboardSrv-specs.js
index 5b2fefd384d..4a6c01bdc3b 100644
--- a/public/test/specs/dashboardSrv-specs.js
+++ b/public/test/specs/dashboardSrv-specs.js
@@ -141,6 +141,7 @@ define([
describe('when creating dashboard with old schema', function() {
var model;
var graph;
+ var singlestat;
beforeEach(function() {
model = _dashboardSrv.create({
@@ -155,6 +156,10 @@ define([
{
type: 'graphite', legend: true, aliasYAxis: { test: 2 }, grid: { min: 1, max: 10 },
targets: [{refId: 'A'}, {}],
+ },
+ {
+ type: 'singlestat', legend: true, thresholds: '10,20,30', aliasYAxis: { test: 2 }, grid: { min: 1, max: 10 },
+ targets: [{refId: 'A'}, {}],
}
]
}
@@ -162,6 +167,7 @@ define([
});
graph = model.rows[0].panels[0];
+ singlestat = model.rows[0].panels[1];
});
it('should have title', function() {
@@ -181,6 +187,10 @@ define([
expect(graph.type).to.be('graph');
});
+ it('single stat panel should have two thresholds', function() {
+ expect(singlestat.thresholds).to.be('20,30');
+ });
+
it('queries without refId should get it', function() {
expect(graph.targets[1].refId).to.be('B');
});
@@ -204,7 +214,7 @@ define([
});
it('dashboard schema version should be set to latest', function() {
- expect(model.schemaVersion).to.be(8);
+ expect(model.schemaVersion).to.be(9);
});
});
diff --git a/public/test/specs/singlestat-specs.js b/public/test/specs/singlestat-specs.js
deleted file mode 100644
index 60953345f2d..00000000000
--- a/public/test/specs/singlestat-specs.js
+++ /dev/null
@@ -1,88 +0,0 @@
-define([
- 'angular',
- './helpers',
- 'app/plugins/panel/singlestat/controller',
- 'app/features/panel/panel_srv',
- 'app/features/panel/panel_helper',
-], function(angular, helpers, SingleStatCtrl) {
- 'use strict';
-
- angular.module('grafana.controllers').controller('SingleStatCtrl', SingleStatCtrl);
-
- describe('SingleStatCtrl', function() {
- var ctx = new helpers.ControllerTestContext();
-
- function singleStatScenario(desc, func) {
-
- describe(desc, function() {
-
- ctx.setup = function (setupFunc) {
-
- beforeEach(module('grafana.services'));
- beforeEach(module('grafana.controllers'));
-
- beforeEach(ctx.providePhase());
- beforeEach(ctx.createControllerPhase('SingleStatCtrl'));
-
- beforeEach(function() {
- setupFunc();
- ctx.datasource.query = sinon.stub().returns(ctx.$q.when({
- data: [{target: 'test.cpu1', datapoints: ctx.datapoints}]
- }));
-
- ctx.scope.refreshData(ctx.datasource);
- ctx.scope.$digest();
- ctx.data = ctx.scope.data;
- });
- };
-
- func(ctx);
- });
- }
-
- singleStatScenario('with defaults', function(ctx) {
- ctx.setup(function() {
- ctx.datapoints = [[10,1], [20,2]];
- });
-
- 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 formated falue', function() {
- expect(ctx.data.valueFormated).to.be('15');
- });
- });
-
- 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]];
- });
-
- it('Should be rounded', function() {
- expect(ctx.data.value).to.be(99.999495);
- expect(ctx.data.valueRounded).to.be(100);
- });
-
- it('should set formated falue', function() {
- expect(ctx.data.valueFormated).to.be('100');
- });
- });
-
- singleStatScenario('When value to text mapping is specified', function(ctx) {
- ctx.setup(function() {
- ctx.datapoints = [[10,1]];
- ctx.scope.panel.valueMaps = [{value: '10', text: 'OK'}];
- });
-
- it('Should replace value with text', function() {
- expect(ctx.data.value).to.be(10);
- expect(ctx.data.valueFormated).to.be('OK');
- });
-
- });
-
- });
-});
-