Commit 06210a4a by Torkel Ödegaard

feat(thresholds): refactoring and adding many unit tests

parent 895cff78
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* **Templating**: Update panel repeats for variables that change on time refresh, closes [#5021](https://github.com/grafana/grafana/issues/5021) * **Templating**: Update panel repeats for variables that change on time refresh, closes [#5021](https://github.com/grafana/grafana/issues/5021)
* **Elasticsearch**: Support to set Precision Threshold for Unique Count metric, closes [#4689](https://github.com/grafana/grafana/issues/4689) * **Elasticsearch**: Support to set Precision Threshold for Unique Count metric, closes [#4689](https://github.com/grafana/grafana/issues/4689)
#b 3.1.1 (unreleased / v3.1.x branch) # 3.1.1 (unreleased / v3.1.x branch)
* **IFrame embedding**: Fixed issue of using full iframe height, fixes [#5605](https://github.com/grafana/grafana/issues/5606) * **IFrame embedding**: Fixed issue of using full iframe height, fixes [#5605](https://github.com/grafana/grafana/issues/5606)
* **Panel PNG rendering**: Fixed issue detecting render completion, fixes [#5605](https://github.com/grafana/grafana/issues/5606) * **Panel PNG rendering**: Fixed issue detecting render completion, fixes [#5605](https://github.com/grafana/grafana/issues/5606)
* **Elasticsearch**: Fixed issue with templating query and json parse error, fixes [#5615](https://github.com/grafana/grafana/issues/5615) * **Elasticsearch**: Fixed issue with templating query and json parse error, fixes [#5615](https://github.com/grafana/grafana/issues/5615)
......
...@@ -129,7 +129,8 @@ export class AlertTabCtrl { ...@@ -129,7 +129,8 @@ export class AlertTabCtrl {
graphThresholdChanged(evt) { graphThresholdChanged(evt) {
for (var condition of this.alert.conditions) { for (var condition of this.alert.conditions) {
if (condition.type === 'query') { if (condition.type === 'query') {
condition.evaluator.params[0] = evt.threshold.value; condition.evaluator.params[evt.handleIndex] = evt.threshold.value;
this.evaluatorParamsChanged();
break; break;
} }
} }
...@@ -140,7 +141,7 @@ export class AlertTabCtrl { ...@@ -140,7 +141,7 @@ export class AlertTabCtrl {
type: 'query', type: 'query',
query: {params: ['A', '5m', 'now']}, query: {params: ['A', '5m', 'now']},
reducer: {type: 'avg', params: []}, reducer: {type: 'avg', params: []},
evaluator: {type: '>', params: [null]}, evaluator: {type: 'gt', params: [null]},
}; };
} }
...@@ -171,7 +172,7 @@ export class AlertTabCtrl { ...@@ -171,7 +172,7 @@ export class AlertTabCtrl {
} }
delete() { delete() {
this.alert.enabled = false; this.panel.alert = {enabled: false};
this.initModel(); this.initModel();
} }
......
...@@ -5,7 +5,7 @@ define([ ...@@ -5,7 +5,7 @@ define([
'lodash', 'lodash',
'app/core/utils/kbn', 'app/core/utils/kbn',
'./graph_tooltip', './graph_tooltip',
'./thresholds', './threshold_manager',
'jquery.flot', 'jquery.flot',
'jquery.flot.selection', 'jquery.flot.selection',
'jquery.flot.time', 'jquery.flot.time',
...@@ -15,15 +15,12 @@ define([ ...@@ -15,15 +15,12 @@ define([
'jquery.flot.crosshair', 'jquery.flot.crosshair',
'./jquery.flot.events', './jquery.flot.events',
], ],
function (angular, $, moment, _, kbn, GraphTooltip, thresholds) { function (angular, $, moment, _, kbn, GraphTooltip, thresholdManExports) {
'use strict'; 'use strict';
var module = angular.module('grafana.directives'); var module = angular.module('grafana.directives');
var labelWidthCache = {}; var labelWidthCache = {};
// systemjs export
var ThresholdControls = thresholds.ThresholdControls;
module.directive('grafanaGraph', function($rootScope, timeSrv) { module.directive('grafanaGraph', function($rootScope, timeSrv) {
return { return {
restrict: 'A', restrict: 'A',
...@@ -37,7 +34,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) { ...@@ -37,7 +34,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) {
var legendSideLastValue = null; var legendSideLastValue = null;
var rootScope = scope.$root; var rootScope = scope.$root;
var panelWidth = 0; var panelWidth = 0;
var thresholdControls = new ThresholdControls(ctrl); var thresholdManager = new thresholdManExports.ThresholdManager(ctrl);
rootScope.onAppEvent('setCrosshair', function(event, info) { rootScope.onAppEvent('setCrosshair', function(event, info) {
// do not need to to this if event is from this panel // do not need to to this if event is from this panel
...@@ -161,7 +158,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) { ...@@ -161,7 +158,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) {
rightLabel[0].style.marginTop = (getLabelWidth(panel.yaxes[1].label, rightLabel) / 2) + 'px'; rightLabel[0].style.marginTop = (getLabelWidth(panel.yaxes[1].label, rightLabel) / 2) + 'px';
} }
thresholdControls.draw(plot); thresholdManager.draw(plot);
} }
function processOffsetHook(plot, gridMargin) { function processOffsetHook(plot, gridMargin) {
...@@ -180,7 +177,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) { ...@@ -180,7 +177,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) {
} }
// give space to alert editing // give space to alert editing
thresholdControls.prepare(elem); thresholdManager.prepare(elem);
var stack = panel.stack ? true : null; var stack = panel.stack ? true : null;
...@@ -252,7 +249,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) { ...@@ -252,7 +249,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) {
} }
addTimeAxis(options); addTimeAxis(options);
addGridThresholds(options, panel); thresholdManager.addPlotOptions(options, panel);
addAnnotations(options); addAnnotations(options);
configureAxisOptions(data, options); configureAxisOptions(data, options);
...@@ -315,82 +312,6 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) { ...@@ -315,82 +312,6 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) {
}; };
} }
function addGridThresholds(options, panel) {
if (!panel.thresholds || panel.thresholds.length === 0) {
return;
}
var gtLimit = Infinity;
var ltLimit = -Infinity;
var i, threshold, other;
for (i = 0; i < panel.thresholds.length; i++) {
threshold = panel.thresholds[i];
if (!_.isNumber(threshold.value)) {
continue;
}
var limit;
switch(threshold.op) {
case 'gt': {
limit = gtLimit;
// if next threshold is less then op and greater value, then use that as limit
if (panel.thresholds.length > i+1) {
other = panel.thresholds[i+1];
if (other.value > threshold.value) {
limit = other.value;
ltLimit = limit;
}
}
break;
}
case 'lt': {
limit = ltLimit;
// if next threshold is less then op and greater value, then use that as limit
if (panel.thresholds.length > i+1) {
other = panel.thresholds[i+1];
if (other.value < threshold.value) {
limit = other.value;
gtLimit = limit;
}
}
break;
}
}
switch(threshold.colorMode) {
case 'critical': {
threshold.fillColor = 'rgba(234, 112, 112, 0.12)';
threshold.lineColor = 'rgba(237, 46, 24, 0.60)';
break;
}
case 'warning': {
threshold.fillColor = 'rgba(235, 138, 14, 0.12)';
threshold.lineColor = 'rgba(247, 149, 32, 0.60)';
break;
}
case 'ok': {
threshold.fillColor = 'rgba(11, 237, 50, 0.090)';
threshold.lineColor = 'rgba(6,163,69, 0.60)';
break;
}
case 'custom': {
threshold.fillColor = threshold.fillColor;
threshold.lineColor = threshold.lineColor;
break;
}
}
// fill
if (threshold.fill) {
options.grid.markings.push({yaxis: {from: threshold.value, to: limit}, color: threshold.fillColor});
}
if (threshold.line) {
options.grid.markings.push({yaxis: {from: threshold.value, to: threshold.value}, color: threshold.lineColor});
}
}
}
function addAnnotations(options) { function addAnnotations(options) {
if(!annotations || annotations.length === 0) { if(!annotations || annotations.length === 0) {
return; return;
......
...@@ -112,37 +112,6 @@ describe('grafanaGraph', function() { ...@@ -112,37 +112,6 @@ describe('grafanaGraph', function() {
}); });
}); });
graphScenario('grid thresholds 100, 200', function(ctx) {
ctx.setup(function(ctrl) {
ctrl.panel.thresholds = [
{op: "gt", value: 300, fillColor: 'red', lineColor: 'blue', fill: true, line: true},
{op: "gt", value: 200, fillColor: '#ed2e18', fill: true}
];
});
it('should add fill for threshold with fill: true', function() {
var markings = ctx.plotOptions.grid.markings;
expect(markings[0].yaxis.from).to.be(300);
expect(markings[0].yaxis.to).to.be(Infinity);
expect(markings[0].color).to.be('red');
});
it('should add line', function() {
var markings = ctx.plotOptions.grid.markings;
expect(markings[1].yaxis.from).to.be(300);
expect(markings[1].yaxis.to).to.be(300);
expect(markings[1].color).to.be('blue');
});
it('should add fill for second thresholds to previous threshold', function() {
var markings = ctx.plotOptions.grid.markings;
expect(markings[2].yaxis.from).to.be(200);
expect(markings[2].yaxis.to).to.be(300);
});
});
graphScenario('when logBase is log 10', function(ctx) { graphScenario('when logBase is log 10', function(ctx) {
ctx.setup(function(ctrl) { ctx.setup(function(ctrl) {
ctrl.panel.yaxes[0].logBase = 10; ctrl.panel.yaxes[0].logBase = 10;
......
///<reference path="../../../../headers/common.d.ts" />
import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
import {ThresholdManager} from '../threshold_manager';
describe('ThresholdManager', function() {
function plotOptionsScenario(desc, func) {
describe(desc, function() {
var ctx: any = {
panel: {
thresholds: [],
},
options: {
grid: {markings: []},
},
panelCtrl: {},
};
ctx.setup = function(thresholds) {
ctx.panel.thresholds = thresholds;
var manager = new ThresholdManager(ctx.panelCtrl);
manager.addPlotOptions(ctx.options, ctx.panel);
};
func(ctx);
});
}
describe("When creating plot markings", () => {
plotOptionsScenario("for simple gt threshold", ctx => {
ctx.setup([
{op: 'gt', value: 300, fill: true, line: true, colorMode: 'critical'},
]);
it('should add fill for threshold with fill: true', function() {
var markings = ctx.options.grid.markings;
expect(markings[0].yaxis.from).to.be(300);
expect(markings[0].yaxis.to).to.be(Infinity);
expect(markings[0].color).to.be('rgba(234, 112, 112, 0.12)');
});
it('should add line', function() {
var markings = ctx.options.grid.markings;
expect(markings[1].yaxis.from).to.be(300);
expect(markings[1].yaxis.to).to.be(300);
expect(markings[1].color).to.be('rgba(237, 46, 24, 0.60)');
});
});
plotOptionsScenario("for two gt thresholds", ctx => {
ctx.setup([
{op: 'gt', value: 200, fill: true, colorMode: 'warning'},
{op: 'gt', value: 300, fill: true, colorMode: 'critical'},
]);
it('should add fill for first thresholds to next threshold', function() {
var markings = ctx.options.grid.markings;
expect(markings[0].yaxis.from).to.be(200);
expect(markings[0].yaxis.to).to.be(300);
});
it('should add fill for last thresholds to infinity', function() {
var markings = ctx.options.grid.markings;
expect(markings[1].yaxis.from).to.be(300);
expect(markings[1].yaxis.to).to.be(Infinity);
});
});
plotOptionsScenario("for lt then gt threshold (inside)", ctx => {
ctx.setup([
{op: 'lt', value: 300, fill: true, colorMode: 'critical'},
{op: 'gt', value: 200, fill: true, colorMode: 'critical'},
]);
it('should add fill for first thresholds to next threshold', function() {
var markings = ctx.options.grid.markings;
expect(markings[0].yaxis.from).to.be(300);
expect(markings[0].yaxis.to).to.be(200);
});
it('should add fill for last thresholds to itself', function() {
var markings = ctx.options.grid.markings;
expect(markings[1].yaxis.from).to.be(200);
expect(markings[1].yaxis.to).to.be(200);
});
});
plotOptionsScenario("for gt then lt threshold (outside)", ctx => {
ctx.setup([
{op: 'gt', value: 300, fill: true, colorMode: 'critical'},
{op: 'lt', value: 200, fill: true, colorMode: 'critical'},
]);
it('should add fill for first thresholds to next threshold', function() {
var markings = ctx.options.grid.markings;
expect(markings[0].yaxis.from).to.be(300);
expect(markings[0].yaxis.to).to.be(Infinity);
});
it('should add fill for last thresholds to itself', function() {
var markings = ctx.options.grid.markings;
expect(markings[1].yaxis.from).to.be(200);
expect(markings[1].yaxis.to).to.be(-Infinity);
});
});
});
});
...@@ -4,7 +4,7 @@ import 'jquery.flot'; ...@@ -4,7 +4,7 @@ import 'jquery.flot';
import $ from 'jquery'; import $ from 'jquery';
import _ from 'lodash'; import _ from 'lodash';
export class ThresholdControls { export class ThresholdManager {
plot: any; plot: any;
placeholder: any; placeholder: any;
height: any; height: any;
...@@ -69,7 +69,7 @@ export class ThresholdControls { ...@@ -69,7 +69,7 @@ export class ThresholdControls {
// trigger digest and render // trigger digest and render
panelCtrl.$scope.$apply(function() { panelCtrl.$scope.$apply(function() {
panelCtrl.render(); panelCtrl.render();
panelCtrl.events.emit('threshold-changed', {threshold: model, index: handleIndex}); panelCtrl.events.emit('threshold-changed', {threshold: model, handleIndex: handleIndex});
}); });
} }
...@@ -145,5 +145,82 @@ export class ThresholdControls { ...@@ -145,5 +145,82 @@ export class ThresholdControls {
this.placeholder.on('mousedown', '.alert-handle', this.initDragging.bind(this)); this.placeholder.on('mousedown', '.alert-handle', this.initDragging.bind(this));
this.needsCleanup = true; this.needsCleanup = true;
} }
addPlotOptions(options, panel) {
if (!panel.thresholds || panel.thresholds.length === 0) {
return;
}
var gtLimit = Infinity;
var ltLimit = -Infinity;
var i, threshold, other;
for (i = 0; i < panel.thresholds.length; i++) {
threshold = panel.thresholds[i];
if (!_.isNumber(threshold.value)) {
continue;
}
var limit;
switch (threshold.op) {
case 'gt': {
limit = gtLimit;
// if next threshold is less then op and greater value, then use that as limit
if (panel.thresholds.length > i+1) {
other = panel.thresholds[i+1];
if (other.value > threshold.value) {
limit = other.value;
ltLimit = limit;
}
}
break;
}
case 'lt': {
limit = ltLimit;
// if next threshold is less then op and greater value, then use that as limit
if (panel.thresholds.length > i+1) {
other = panel.thresholds[i+1];
if (other.value < threshold.value) {
limit = other.value;
gtLimit = limit;
}
}
break;
}
}
switch (threshold.colorMode) {
case 'critical': {
threshold.fillColor = 'rgba(234, 112, 112, 0.12)';
threshold.lineColor = 'rgba(237, 46, 24, 0.60)';
break;
}
case 'warning': {
threshold.fillColor = 'rgba(235, 138, 14, 0.12)';
threshold.lineColor = 'rgba(247, 149, 32, 0.60)';
break;
}
case 'ok': {
threshold.fillColor = 'rgba(11, 237, 50, 0.090)';
threshold.lineColor = 'rgba(6,163,69, 0.60)';
break;
}
case 'custom': {
threshold.fillColor = threshold.fillColor;
threshold.lineColor = threshold.lineColor;
break;
}
}
// fill
if (threshold.fill) {
options.grid.markings.push({yaxis: {from: threshold.value, to: limit}, color: threshold.fillColor});
}
if (threshold.line) {
options.grid.markings.push({yaxis: {from: threshold.value, to: threshold.value}, color: threshold.lineColor});
}
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment