diff --git a/public/app/plugins/panel/graph/alert_tab_ctrl.ts b/public/app/plugins/panel/graph/alert_tab_ctrl.ts index 7e3c8d7b963..4ee59248257 100644 --- a/public/app/plugins/panel/graph/alert_tab_ctrl.ts +++ b/public/app/plugins/panel/graph/alert_tab_ctrl.ts @@ -22,7 +22,7 @@ var alertQueryDef = new QueryPartDef({ export class AlertTabCtrl { panel: any; panelCtrl: any; - metricTargets = [{ refId: '- select query -' } ]; + metricTargets; handlers = [{text: 'Grafana', value: 1}, {text: 'External', value: 0}]; transforms = [ { @@ -36,6 +36,7 @@ export class AlertTabCtrl { ]; aggregators = ['avg', 'sum', 'min', 'max', 'last']; alert: any; + thresholds: any; query: any; queryParams: any; transformDef: any; @@ -45,24 +46,6 @@ export class AlertTabCtrl { {text: '=', value: '='}, ]; - defaultValues = { - frequency: '60s', - notify: [], - enabled: false, - handler: 1, - warn: { op: '>', level: undefined }, - critical: { op: '>', level: undefined }, - query: { - refId: 'A', - from: '5m', - to: 'now', - }, - transform: { - type: 'aggregation', - method: 'avg' - } - }; - /** @ngInject */ constructor($scope, private $timeout) { this.panelCtrl = $scope.ctrl; @@ -70,7 +53,7 @@ export class AlertTabCtrl { $scope.ctrl = this; this.metricTargets = this.panel.targets.map(val => val); - this.initAlertModel(); + this.initModel(); // set panel alert edit mode $scope.$on("$destroy", () => { @@ -79,32 +62,63 @@ export class AlertTabCtrl { }); } - initAlertModel() { - if (!this.panel.alert) { + getThresholdWithDefaults(thresholds, type, copyFrom) { + var threshold = thresholds[type] || {}; + var defaultValue = (copyFrom[type] || {}).value || undefined; + + threshold.op = threshold.op || '>'; + threshold.value = threshold.value || defaultValue; + return threshold; + } + + initThresholdsOnlyMode() { + if (!this.panel.thresholds) { return; } - this.alert = this.panel.alert; + this.thresholds = this.panel.thresholds; - // set defaults - _.defaults(this.alert, this.defaultValues); + // set threshold defaults + this.thresholds.warn = this.getThresholdWithDefaults(this.thresholds, 'warn', {}); + this.thresholds.crit = this.getThresholdWithDefaults(this.thresholds, 'crit', {}); - var defaultName = (this.panelCtrl.dashboard.title + ' ' + this.panel.title + ' alert'); - this.alert.name = this.alert.name || defaultName; - this.alert.description = this.alert.description || defaultName; + this.panelCtrl.editingAlert = true; + this.panelCtrl.render(); + } + + initModel() { + var alert = this.alert = this.panel.alert = this.panel.alert || {}; + + // set threshold defaults + alert.thresholds = alert.thresholds || {}; + alert.thresholds.warn = this.getThresholdWithDefaults(alert.thresholds, 'warn', this.panel.thresholds); + alert.thresholds.crit = this.getThresholdWithDefaults(alert.thresholds, 'crit', this.panel.thresholds); + + alert.frequency = alert.frequency || '60s'; + alert.handler = alert.handler || 1; + alert.notifications = alert.notifications || []; + + alert.query = alert.query || {}; + alert.query.refId = alert.query.refId || 'A'; + alert.query.from = alert.query.from || '5m'; + alert.query.to = alert.query.to || 'now'; + + alert.transform = alert.transform || {}; + alert.transform.type = alert.transform.type || 'aggregation'; + alert.transform.method = alert.transform.method || 'avg'; + + var defaultName = this.panel.title + ' alert'; + alert.name = alert.name || defaultName; + alert.description = alert.description || defaultName; // great temp working model this.queryParams = { - params: [ - this.alert.query.refId, - this.alert.query.from, - this.alert.query.to - ] + params: [alert.query.refId, alert.query.from, alert.query.to] }; // init the query part components model this.query = new QueryPart(this.queryParams, alertQueryDef); - this.transformDef = _.findWhere(this.transforms, {type: this.alert.transform.type}); + this.transformDef = _.findWhere(this.transforms, {type: alert.transform.type}); this.panelCtrl.editingAlert = true; this.panelCtrl.render(); @@ -135,22 +149,26 @@ export class AlertTabCtrl { } } - operatorChanged() { - this.panelCtrl.render(); - } - delete() { + delete this.alert; delete this.panel.alert; - this.panelCtrl.editingAlert = false; - this.panelCtrl.render(); + // clear thresholds + if (this.panel.thresholds) { + this.panel.thresholds = {}; + } + this.initModel(); } enable() { + if (this.thresholds) { + delete this.thresholds; + this.panelCtrl. + } this.panel.alert = {}; - this.initAlertModel(); + this.initModel(); } - levelsUpdated() { + thresholdsUpdated() { this.panelCtrl.render(); } } diff --git a/public/app/plugins/panel/graph/graph.js b/public/app/plugins/panel/graph/graph.js index 599bbe554bf..381565e8f3f 100755 --- a/public/app/plugins/panel/graph/graph.js +++ b/public/app/plugins/panel/graph/graph.js @@ -5,7 +5,7 @@ define([ 'lodash', 'app/core/utils/kbn', './graph_tooltip', - './alert_handle', + './thresholds', 'jquery.flot', 'jquery.flot.selection', 'jquery.flot.time', @@ -15,7 +15,7 @@ define([ 'jquery.flot.crosshair', './jquery.flot.events', ], -function (angular, $, moment, _, kbn, GraphTooltip, AlertHandle) { +function (angular, $, moment, _, kbn, GraphTooltip, thresholds) { 'use strict'; var module = angular.module('grafana.directives'); @@ -23,7 +23,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, AlertHandle) { var panelWidthCache = {}; // systemjs export - var AlertHandleManager = AlertHandle.AlertHandleManager; + var ThresholdControls = thresholds.ThresholdControls; module.directive('grafanaGraph', function($rootScope, timeSrv) { return { @@ -38,7 +38,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, AlertHandle) { var legendSideLastValue = null; var rootScope = scope.$root; var panelWidth = 0; - var alertHandles; + var thresholdControls; rootScope.onAppEvent('setCrosshair', function(event, info) { // do not need to to this if event is from this panel @@ -167,8 +167,8 @@ function (angular, $, moment, _, kbn, GraphTooltip, AlertHandle) { rightLabel[0].style.marginTop = (getLabelWidth(panel.yaxes[1].label, rightLabel) / 2) + 'px'; } - if (alertHandles) { - alertHandles.draw(plot); + if (thresholdControls) { + thresholdControls.draw(plot); } } @@ -192,14 +192,14 @@ function (angular, $, moment, _, kbn, GraphTooltip, AlertHandle) { // give space to alert editing if (ctrl.editingAlert) { - if (!alertHandles) { + if (!thresholdControls) { elem.css('margin-right', '220px'); - alertHandles = new AlertHandleManager(ctrl); + thresholdControls = new ThresholdControls(ctrl); } - } else if (alertHandles) { + } else if (thresholdControls) { elem.css('margin-right', '0'); - alertHandles.cleanUp(); - alertHandles = null; + thresholdControls.cleanUp(); + thresholdControls = null; } var stack = panel.stack ? true : null; @@ -333,70 +333,73 @@ function (angular, $, moment, _, kbn, GraphTooltip, AlertHandle) { } function addGridThresholds(options, panel) { + var thresholds = panel.thresholds; + + // use alert thresholds if there are any if (panel.alert) { - var crit = panel.alert.critical; - var warn = panel.alert.warn; - var critEdge = Infinity; - var warnEdge = crit.level; - - if (_.isNumber(crit.level)) { - if (crit.op === '<') { - critEdge = -Infinity; - } - - // fill - options.grid.markings.push({ - yaxis: {from: crit.level, to: critEdge}, - color: 'rgba(234, 112, 112, 0.10)', - }); - - // line - options.grid.markings.push({ - yaxis: {from: crit.level, to: crit.level}, - color: '#ed2e18' - }); - } - - if (_.isNumber(warn.level)) { - // if (warn.op === '<') { - // } - - // fill - options.grid.markings.push({ - yaxis: {from: warn.level, to: warnEdge}, - color: 'rgba(216, 200, 27, 0.10)', - }); - - // line - options.grid.markings.push({ - yaxis: {from: warn.level, to: warn.level}, - color: '#F79520' - }); - } - - return; + thresholds = panel.alert.thresholds; } - if (_.isNumber(panel.grid.threshold1)) { - var limit1 = panel.grid.thresholdLine ? panel.grid.threshold1 : (panel.grid.threshold2 || null); + var crit = thresholds.crit; + var warn = thresholds.warn; + var critEdge = Infinity; + var warnEdge = crit.value; + + if (_.isNumber(crit.value)) { + if (crit.op === '<') { + critEdge = -Infinity; + } + + // fill options.grid.markings.push({ - yaxis: { from: panel.grid.threshold1, to: limit1 }, - color: panel.grid.threshold1Color + yaxis: {from: crit.value, to: critEdge}, + color: 'rgba(234, 112, 112, 0.10)', }); - if (_.isNumber(panel.grid.threshold2)) { - var limit2; - if (panel.grid.thresholdLine) { - limit2 = panel.grid.threshold2; - } else { - limit2 = panel.grid.threshold1 > panel.grid.threshold2 ? -Infinity : +Infinity; - } - options.grid.markings.push({ - yaxis: { from: panel.grid.threshold2, to: limit2 }, - color: panel.grid.threshold2Color - }); - } + // line + options.grid.markings.push({ + yaxis: {from: crit.value, to: crit.value}, + color: '#ed2e18' + }); } + + if (_.isNumber(warn.value)) { + // if (warn.op === '<') { + // } + + // fill + options.grid.markings.push({ + yaxis: {from: warn.value, to: warnEdge}, + color: 'rgba(216, 200, 27, 0.10)', + }); + + // line + options.grid.markings.push({ + yaxis: {from: warn.value, to: warn.value}, + color: '#F79520' + }); + } + + // if (_.isNumber(panel.grid.threshold1)) { + // var limit1 = panel.grid.thresholdLine ? panel.grid.threshold1 : (panel.grid.threshold2 || null); + // options.grid.markings.push({ + // yaxis: { from: panel.grid.threshold1, to: limit1 }, + // color: panel.grid.threshold1Color + // }); + // + // if (_.isNumber(panel.grid.threshold2)) { + // var limit2; + // if (panel.grid.thresholdLine) { + // limit2 = panel.grid.threshold2; + // } else { + // limit2 = panel.grid.threshold1 > panel.grid.threshold2 ? -Infinity : +Infinity; + // } + // options.grid.markings.push({ + // yaxis: { from: panel.grid.threshold2, to: limit2 }, + // color: panel.grid.threshold2Color + // }); + // } + // } } function addAnnotations(options) { diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts index c79fd421995..481b6223e33 100644 --- a/public/app/plugins/panel/graph/module.ts +++ b/public/app/plugins/panel/graph/module.ts @@ -54,11 +54,9 @@ class GraphCtrl extends MetricsPanelCtrl { xaxis: { show: true }, - grid : { - threshold1: null, - threshold2: null, - threshold1Color: 'rgba(216, 200, 27, 0.27)', - threshold2Color: 'rgba(234, 112, 112, 0.22)' + thresholds: { + warn: {op: '>', level: undefined}, + crit: {op: '>', level: undefined}, }, // show/hide lines lines : true, @@ -115,7 +113,7 @@ class GraphCtrl extends MetricsPanelCtrl { _.defaults(this.panel, this.panelDefaults); _.defaults(this.panel.tooltip, this.panelDefaults.tooltip); - _.defaults(this.panel.grid, this.panelDefaults.grid); + _.defaults(this.panel.thresholds, this.panelDefaults.thresholds); _.defaults(this.panel.legend, this.panelDefaults.legend); this.colors = $scope.$root.colors; @@ -132,6 +130,7 @@ class GraphCtrl extends MetricsPanelCtrl { this.addEditorTab('Axes', 'public/app/plugins/panel/graph/tab_axes.html', 2); this.addEditorTab('Legend', 'public/app/plugins/panel/graph/tab_legend.html', 3); this.addEditorTab('Display', 'public/app/plugins/panel/graph/tab_display.html', 4); + if (config.alertingEnabled) { this.addEditorTab('Alerting', graphAlertEditor, 5); } diff --git a/public/app/plugins/panel/graph/partials/tab_alerting.html b/public/app/plugins/panel/graph/partials/tab_alerting.html index 0b6ed66f066..38873ec829e 100644 --- a/public/app/plugins/panel/graph/partials/tab_alerting.html +++ b/public/app/plugins/panel/graph/partials/tab_alerting.html @@ -1,5 +1,29 @@ -