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'); - }); - - }); - - }); -}); -