Commit 74dbd7fb by Torkel Ödegaard

feat(alerting): disable visual thresholds while alert is enabled

parent 7242dc2e
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
}, },
"devDependencies": { "devDependencies": {
"zone.js": "^0.6.6", "zone.js": "^0.6.6",
"autoprefixer": "^6.3.3", "autoprefixer": "^6.4.0",
"es6-promise": "^3.0.2", "es6-promise": "^3.0.2",
"es6-shim": "^0.35.1", "es6-shim": "^0.35.1",
"expect.js": "~0.2.0", "expect.js": "~0.2.0",
......
...@@ -19,9 +19,9 @@ type DefaultAlertEvaluator struct { ...@@ -19,9 +19,9 @@ type DefaultAlertEvaluator struct {
func (e *DefaultAlertEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool { func (e *DefaultAlertEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool {
switch e.Type { switch e.Type {
case ">": case "gt":
return reducedValue > e.Threshold return reducedValue > e.Threshold
case "<": case "lt":
return reducedValue < e.Threshold return reducedValue < e.Threshold
} }
......
...@@ -18,7 +18,7 @@ func TestQueryCondition(t *testing.T) { ...@@ -18,7 +18,7 @@ func TestQueryCondition(t *testing.T) {
queryConditionScenario("Given avg() and > 100", func(ctx *queryConditionTestContext) { queryConditionScenario("Given avg() and > 100", func(ctx *queryConditionTestContext) {
ctx.reducer = `{"type": "avg"}` ctx.reducer = `{"type": "avg"}`
ctx.evaluator = `{"type": ">", "params": [100]}` ctx.evaluator = `{"type": "gt "params": [100]}`
Convey("Can read query condition from json model", func() { Convey("Can read query condition from json model", func() {
ctx.exec() ctx.exec()
......
...@@ -172,7 +172,9 @@ export class AlertTabCtrl { ...@@ -172,7 +172,9 @@ export class AlertTabCtrl {
delete() { delete() {
this.panel.alert = {enabled: false}; this.panel.alert = {enabled: false};
this.initModel(); this.panel.thresholds = [];
this.conditionModels = [];
this.panelCtrl.render();
} }
enable() { enable() {
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import './graph'; import './graph';
import './legend'; import './legend';
import './series_overrides_ctrl'; import './series_overrides_ctrl';
import './thresholds_form';
import template from './template'; import template from './template';
import angular from 'angular'; import angular from 'angular';
...@@ -327,14 +328,6 @@ class GraphCtrl extends MetricsPanelCtrl { ...@@ -327,14 +328,6 @@ class GraphCtrl extends MetricsPanelCtrl {
fileExport.exportSeriesListToCsvColumns(this.seriesList); fileExport.exportSeriesListToCsvColumns(this.seriesList);
} }
addThreshold() {
this.panel.thresholds.push({value: undefined, colorMode: "critical", op: 'gt', fill: true, line: true});
}
removeThreshold(index) {
this.panel.thresholds.splice(index, 1);
this.render();
}
} }
export {GraphCtrl, GraphCtrl as PanelCtrl} export {GraphCtrl, GraphCtrl as PanelCtrl}
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
</a> </a>
</li> </li>
<li ng-class="{active: ctrl.subTabIndex === 2}"> <li ng-class="{active: ctrl.subTabIndex === 2}">
<a ng-click="ctrl.subTabIndex = 2">Thresholds</a> <a ng-click="ctrl.subTabIndex = 2">
Thresholds <span class="muted">({{ctrl.panel.thresholds.length}})</span>
</a>
</li> </li>
</ul> </ul>
</aside> </aside>
...@@ -131,56 +133,7 @@ ...@@ -131,56 +133,7 @@
</div> </div>
<div class="edit-tab-content" ng-if="ctrl.subTabIndex === 2"> <div class="edit-tab-content" ng-if="ctrl.subTabIndex === 2">
<div class="gf-form-group"> <graph-threshold-form panel-ctrl="ctrl"></graph-threshold-form>
<h5>Thresholds</h5>
<div class="gf-form-inline" ng-repeat="threshold in ctrl.panel.thresholds">
<div class="gf-form">
<label class="gf-form-label">T{{$index+1}}</label>
</div>
<div class="gf-form">
<div class="gf-form-select-wrapper">
<select class="gf-form-input" ng-model="threshold.op" ng-options="f for f in ['gt', 'lt']" ng-change="ctrl.render()"></select>
</div>
<input type="number" ng-model="threshold.value" class="gf-form-input width-8" ng-change="ctrl.render()" placeholder="value">
</div>
<div class="gf-form">
<label class="gf-form-label">Color</label>
<div class="gf-form-select-wrapper">
<select class="gf-form-input" ng-model="threshold.colorMode" ng-options="f for f in ['custom', 'critical', 'warning', 'ok']" ng-change="ctrl.render()"></select>
</div>
</div>
<gf-form-switch class="gf-form" label="Fill" checked="threshold.fill" on-change="ctrl.render()"></gf-form-switch>
<div class="gf-form" ng-if="threshold.fill && threshold.colorMode === 'custom'">
<label class="gf-form-label">Fill color</label>
<span class="gf-form-label">
<spectrum-picker ng-model="threshold.fillColor" ng-change="ctrl.render()" ></spectrum-picker>
</span>
</div>
<gf-form-switch class="gf-form" label="Line" checked="threshold.line" on-change="ctrl.render()"></gf-form-switch>
<div class="gf-form" ng-if="threshold.line && threshold.colorMode === 'custom'">
<label class="gf-form-label">Line color</label>
<span class="gf-form-label">
<spectrum-picker ng-model="threshold.lineColor" ng-change="ctrl.render()" ></spectrum-picker>
</span>
</div>
<div class="gf-form">
<label class="gf-form-label">
<i class="fa fa-trash pointer" ng-click="ctrl.removeThreshold($index)"></i>
</label>
</div>
</div>
<div class="gf-form-button-row">
<button class="btn btn-inverse" ng-click="ctrl.addThreshold()">
<i class="fa fa-plus"></i>&nbsp;Add Threshold
</button>
</div>
</div>
</div> </div>
</div> </div>
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
import coreModule from 'app/core/core_module';
export class ThresholdFormCtrl {
panelCtrl: any;
panel: any;
disabled: boolean;
/** @ngInject */
constructor($scope) {
this.panel = this.panelCtrl.panel;
if (this.panel.alert && this.panel.alert.enabled) {
this.disabled = true;
}
$scope.$on("$destroy", () => {
this.panelCtrl.editingThresholds = false;
this.panelCtrl.render();
});
this.panelCtrl.editingThresholds = true;
}
addThreshold() {
this.panel.thresholds.push({value: undefined, colorMode: "critical", op: 'gt', fill: true, line: true});
this.panelCtrl.render();
}
removeThreshold(index) {
this.panel.thresholds.splice(index, 1);
this.panelCtrl.render();
}
render() {
this.panelCtrl.render();
}
}
var template = `
<div class="gf-form-group">
<h5>Thresholds</h5>
<p class="muted" ng-show="ctrl.disabled">
Visual thresholds options <strong>disabled.</strong>
Visit the Alert tab update your thresholds. <br>
To re-enable thresholds, the alert rule must be deleted from this panel.
</p>
<div ng-class="{'thresholds-form-disabled': ctrl.disabled}">
<div class="gf-form-inline" ng-repeat="threshold in ctrl.panel.thresholds">
<div class="gf-form">
<label class="gf-form-label">T{{$index+1}}</label>
</div>
<div class="gf-form">
<div class="gf-form-select-wrapper">
<select class="gf-form-input" ng-model="threshold.op"
ng-options="f for f in ['gt', 'lt']" ng-change="ctrl.render()" ng-disabled="ctrl.disabled"></select>
</div>
<input type="number" ng-model="threshold.value" class="gf-form-input width-8"
ng-change="ctrl.render()" placeholder="value" ng-disabled="ctrl.disabled">
</div>
<div class="gf-form">
<label class="gf-form-label">Color</label>
<div class="gf-form-select-wrapper">
<select class="gf-form-input" ng-model="threshold.colorMode"
ng-options="f for f in ['custom', 'critical', 'warning', 'ok']" ng-change="ctrl.render()" ng-disabled="ctrl.disabled">
</select>
</div>
</div>
<gf-form-switch class="gf-form" label="Fill" checked="threshold.fill"
on-change="ctrl.render()" ng-disabled="ctrl.disabled"></gf-form-switch>
<div class="gf-form" ng-if="threshold.fill && threshold.colorMode === 'custom'">
<label class="gf-form-label">Fill color</label>
<span class="gf-form-label">
<spectrum-picker ng-model="threshold.fillColor" ng-change="ctrl.render()" ></spectrum-picker>
</span>
</div>
<gf-form-switch class="gf-form" label="Line" checked="threshold.line"
on-change="ctrl.render()" ng-disabled="ctrl.disabled"></gf-form-switch>
<div class="gf-form" ng-if="threshold.line && threshold.colorMode === 'custom'">
<label class="gf-form-label">Line color</label>
<span class="gf-form-label">
<spectrum-picker ng-model="threshold.lineColor" ng-change="ctrl.render()" ></spectrum-picker>
</span>
</div>
<div class="gf-form">
<label class="gf-form-label">
<a class="pointer" ng-click="ctrl.removeThreshold($index)" ng-disabled="ctrl.disabled">
<i class="fa fa-trash"></i>
</a>
</label>
</div>
</div>
<div class="gf-form-button-row">
<button class="btn btn-inverse" ng-click="ctrl.addThreshold()" ng-disabled="ctrl.disabled">
<i class="fa fa-plus"></i>&nbsp;Add Threshold
</button>
</div>
</div>
</div>
`;
coreModule.directive('graphThresholdForm', function() {
return {
restrict: 'E',
template: template,
controller: ThresholdFormCtrl,
bindToController: true,
controllerAs: 'ctrl',
scope: {
panelCtrl: "="
}
};
});
...@@ -48,6 +48,11 @@ a.text-success:hover, ...@@ -48,6 +48,11 @@ a.text-success:hover,
a.text-success:focus { color: darken($successText, 10%); } a.text-success:focus { color: darken($successText, 10%); }
a { cursor: pointer; } a { cursor: pointer; }
a[disabled] {
cursor: default;
pointer-events: none !important;
}
.text-left { text-align: left; } .text-left { text-align: left; }
.text-right { text-align: right; } .text-right { text-align: right; }
.text-center { text-align: center; } .text-center { text-align: center; }
......
...@@ -400,3 +400,7 @@ ...@@ -400,3 +400,7 @@
} }
} }
} }
.thresholds-form-disabled {
filter: blur(3px);
}
...@@ -88,4 +88,13 @@ $switch-height: 1.5rem; ...@@ -88,4 +88,13 @@ $switch-height: 1.5rem;
input:checked + label::after { input:checked + label::after {
transform: rotateY(0); transform: rotateY(0);
} }
}
gf-form-switch[disabled] {
.gf-form-label,
.gf-form-switch input + label {
cursor: default;
pointer-events: none !important;
}
} }
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