Skip to content

Commit e3b281d

Browse files
committed
feat(alerting): more work on alerting thresholds
1 parent 5b6fb3b commit e3b281d

File tree

8 files changed

+306
-257
lines changed

8 files changed

+306
-257
lines changed

pkg/services/alerting/extractor.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,9 @@ func (e *DashAlertExtractor) GetAlerts() ([]*m.Alert, error) {
5757

5858
for _, panelObj := range row.Get("panels").MustArray() {
5959
panel := simplejson.NewFromAny(panelObj)
60-
jsonAlert := panel.Get("alert")
60+
jsonAlert, hasAlert := panel.CheckGet("alert")
6161

62-
// check if marked for deletion
63-
deleted := jsonAlert.Get("deleted").MustBool()
64-
if deleted {
65-
e.log.Info("Deleted alert rule found")
62+
if !hasAlert {
6663
continue
6764
}
6865

pkg/services/alerting/extractor_test.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,7 @@ func TestAlertRuleExtraction(t *testing.T) {
149149
],
150150
"title": "Broken influxdb panel",
151151
"transform": "table",
152-
"type": "table",
153-
"alert": {
154-
"deleted": true
155-
}
152+
"type": "table"
156153
}
157154
],
158155
"title": "New row"
@@ -185,7 +182,7 @@ func TestAlertRuleExtraction(t *testing.T) {
185182
return nil
186183
})
187184

188-
alerts, err := extractor.GetRuleModels()
185+
alerts, err := extractor.GetAlerts()
189186

190187
Convey("Get rules without error", func() {
191188
So(err, ShouldBeNil)
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
///<reference path="../../../headers/common.d.ts" />
2+
3+
import 'jquery.flot';
4+
import $ from 'jquery';
5+
import _ from 'lodash';
6+
7+
export class AlertHandleManager {
8+
plot: any;
9+
placeholder: any;
10+
height: any;
11+
alert: any;
12+
13+
constructor(private panelCtrl) {
14+
this.alert = panelCtrl.panel.alert;
15+
}
16+
17+
getHandleInnerHtml(type, op, value) {
18+
if (op === '>') { op = '&gt;'; }
19+
if (op === '<') { op = '&lt;'; }
20+
21+
return `
22+
<div class="alert-handle-line">
23+
</div>
24+
<div class="alert-handle">
25+
<i class="icon-gf icon-gf-${type} alert-icon-${type}"></i>
26+
${op} ${value}
27+
</div>`;
28+
}
29+
30+
getFullHandleHtml(type, op, value) {
31+
var innerTemplate = this.getHandleInnerHtml(type, op, value);
32+
return `
33+
<div class="alert-handle-wrapper alert-handle-wrapper--${type}">
34+
${innerTemplate}
35+
</div>
36+
`;
37+
}
38+
39+
setupDragging(handleElem, levelModel) {
40+
var isMoving = false;
41+
var lastY = null;
42+
var posTop;
43+
var plot = this.plot;
44+
var panelCtrl = this.panelCtrl;
45+
46+
function dragging(evt) {
47+
if (lastY === null) {
48+
lastY = evt.clientY;
49+
} else {
50+
var diff = evt.clientY - lastY;
51+
posTop = posTop + diff;
52+
lastY = evt.clientY;
53+
handleElem.css({top: posTop + diff});
54+
}
55+
}
56+
57+
function stopped() {
58+
isMoving = false;
59+
// calculate graph level
60+
var graphLevel = plot.c2p({left: 0, top: posTop}).y;
61+
console.log('canvasPos:' + posTop + ' Graph level: ' + graphLevel);
62+
graphLevel = parseInt(graphLevel.toFixed(0));
63+
levelModel.level = graphLevel;
64+
console.log(levelModel);
65+
66+
var levelCanvasPos = plot.p2c({x: 0, y: graphLevel});
67+
console.log('canvas pos', levelCanvasPos);
68+
69+
console.log('stopped');
70+
handleElem.off("mousemove", dragging);
71+
handleElem.off("mouseup", dragging);
72+
73+
// trigger digest and render
74+
panelCtrl.$scope.$apply(function() {
75+
panelCtrl.render();
76+
});
77+
}
78+
79+
handleElem.bind('mousedown', function() {
80+
isMoving = true;
81+
lastY = null;
82+
posTop = handleElem.position().top;
83+
console.log('start pos', posTop);
84+
85+
handleElem.on("mousemove", dragging);
86+
handleElem.on("mouseup", stopped);
87+
});
88+
}
89+
90+
cleanUp() {
91+
if (this.placeholder) {
92+
this.placeholder.find(".alert-handle-wrapper").remove();
93+
}
94+
}
95+
96+
renderHandle(type, model, defaultHandleTopPos) {
97+
var handleElem = this.placeholder.find(`.alert-handle-wrapper--${type}`);
98+
var level = model.level;
99+
var levelStr = level;
100+
var handleTopPos = 0;
101+
102+
// handle no value
103+
if (!_.isNumber(level)) {
104+
levelStr = '';
105+
handleTopPos = defaultHandleTopPos;
106+
} else {
107+
var levelCanvasPos = this.plot.p2c({x: 0, y: level});
108+
handleTopPos = Math.min(Math.max(levelCanvasPos.top, 0), this.height) - 6;
109+
}
110+
111+
if (handleElem.length === 0) {
112+
console.log('creating handle');
113+
handleElem = $(this.getFullHandleHtml(type, model.op, levelStr));
114+
this.placeholder.append(handleElem);
115+
this.setupDragging(handleElem, model);
116+
} else {
117+
console.log('reusing handle!');
118+
handleElem.html(this.getHandleInnerHtml(type, model.op, levelStr));
119+
}
120+
121+
handleElem.toggleClass('alert-handle-wrapper--no-value', levelStr === '');
122+
handleElem.css({top: handleTopPos});
123+
}
124+
125+
draw(plot) {
126+
this.plot = plot;
127+
this.placeholder = plot.getPlaceholder();
128+
this.height = plot.height();
129+
130+
this.renderHandle('critical', this.alert.critical, 10);
131+
this.renderHandle('warn', this.alert.warn, this.height-30);
132+
}
133+
134+
}
135+

public/app/plugins/panel/graph/alert_tab_ctrl.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,18 @@ export class AlertTabCtrl {
7373
this.initAlertModel();
7474

7575
// set panel alert edit mode
76-
this.panelCtrl.editingAlert = true;
77-
this.panelCtrl.render();
78-
7976
$scope.$on("$destroy", () => {
8077
this.panelCtrl.editingAlert = false;
8178
this.panelCtrl.render();
8279
});
8380
}
8481

8582
initAlertModel() {
86-
this.alert = this.panel.alert = this.panel.alert || {};
83+
if (!this.panel.alert) {
84+
return;
85+
}
86+
87+
this.alert = this.panel.alert;
8788

8889
// set defaults
8990
_.defaults(this.alert, this.defaultValues);
@@ -105,6 +106,9 @@ export class AlertTabCtrl {
105106
this.query = new QueryPart(this.queryParams, alertQueryDef);
106107
this.convertThresholdsToAlertThresholds();
107108
this.transformDef = _.findWhere(this.transforms, {type: this.alert.transform.type});
109+
110+
this.panelCtrl.editingAlert = true;
111+
this.panelCtrl.render();
108112
}
109113

110114
queryUpdated() {
@@ -151,18 +155,14 @@ export class AlertTabCtrl {
151155
}
152156

153157
delete() {
154-
this.alert = this.panel.alert = {};
155-
this.alert.deleted = true;
156-
this.initAlertModel();
158+
delete this.panel.alert;
159+
this.panelCtrl.editingAlert = false;
160+
this.panelCtrl.render();
157161
}
158162

159163
enable() {
160-
delete this.alert.deleted;
161-
this.alert.enabled = true;
162-
}
163-
164-
disable() {
165-
this.alert.enabled = false;
164+
this.panel.alert = {};
165+
this.initAlertModel();
166166
}
167167

168168
levelsUpdated() {

public/app/plugins/panel/graph/graph.js

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ define([
55
'lodash',
66
'app/core/utils/kbn',
77
'./graph_tooltip',
8+
'./alert_handle',
89
'jquery.flot',
910
'jquery.flot.selection',
1011
'jquery.flot.time',
@@ -13,15 +14,17 @@ define([
1314
'jquery.flot.fillbelow',
1415
'jquery.flot.crosshair',
1516
'./jquery.flot.events',
16-
'./jquery.flot.alerts',
1717
],
18-
function (angular, $, moment, _, kbn, GraphTooltip) {
18+
function (angular, $, moment, _, kbn, GraphTooltip, AlertHandle) {
1919
'use strict';
2020

2121
var module = angular.module('grafana.directives');
2222
var labelWidthCache = {};
2323
var panelWidthCache = {};
2424

25+
// systemjs export
26+
var AlertHandleManager = AlertHandle.AlertHandleManager;
27+
2528
module.directive('grafanaGraph', function($rootScope, timeSrv) {
2629
return {
2730
restrict: 'A',
@@ -35,6 +38,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
3538
var legendSideLastValue = null;
3639
var rootScope = scope.$root;
3740
var panelWidth = 0;
41+
var alertHandles;
3842

3943
rootScope.onAppEvent('setCrosshair', function(event, info) {
4044
// do not need to to this if event is from this panel
@@ -162,6 +166,10 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
162166

163167
rightLabel[0].style.marginTop = (getLabelWidth(panel.yaxes[1].label, rightLabel) / 2) + 'px';
164168
}
169+
170+
if (alertHandles) {
171+
alertHandles.draw(plot);
172+
}
165173
}
166174

167175
function processOffsetHook(plot, gridMargin) {
@@ -178,24 +186,26 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
178186
panelWidth = panelWidthCache[panel.span] = elem.width();
179187
}
180188

181-
if (ctrl.editingAlert) {
182-
elem.css('margin-right', '220px');
183-
} else {
184-
elem.css('margin-right', '');
185-
}
186-
187189
if (shouldAbortRender()) {
188190
return;
189191
}
190192

193+
// give space to alert editing
194+
if (ctrl.editingAlert) {
195+
if (!alertHandles) {
196+
elem.css('margin-right', '220px');
197+
alertHandles = new AlertHandleManager(ctrl);
198+
}
199+
} else if (alertHandles) {
200+
elem.css('margin-right', '0');
201+
alertHandles.cleanUp();
202+
alertHandles = null;
203+
}
204+
191205
var stack = panel.stack ? true : null;
192206

193207
// Populate element
194208
var options = {
195-
alerting: {
196-
editing: ctrl.editingAlert,
197-
alert: panel.alert,
198-
},
199209
hooks: {
200210
draw: [drawHook],
201211
processOffset: [processOffsetHook],
@@ -323,7 +333,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
323333
}
324334

325335
function addGridThresholds(options, panel) {
326-
if (panel.alert && panel.alert.enabled) {
336+
if (panel.alert) {
327337
var crit = panel.alert.critical;
328338
var warn = panel.alert.warn;
329339
var critEdge = Infinity;

0 commit comments

Comments
 (0)