mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(thresholds): lots of progress on thresholds
This commit is contained in:
@@ -76,26 +76,6 @@ export class AlertTabCtrl {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluatorTypeChanged(evaluator) {
|
|
||||||
// ensure params array is correct length
|
|
||||||
switch (evaluator.type) {
|
|
||||||
case "lt":
|
|
||||||
case "gt": {
|
|
||||||
evaluator.params = [evaluator.params[0]];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "within_range":
|
|
||||||
case "outside_range": {
|
|
||||||
evaluator.params = [evaluator.params[0], evaluator.params[1]];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "no_value": {
|
|
||||||
evaluator.params = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.thresholdUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
notificationAdded() {
|
notificationAdded() {
|
||||||
var model = _.findWhere(this.notifications, {name: this.addNotificationSegment.value});
|
var model = _.findWhere(this.notifications, {name: this.addNotificationSegment.value});
|
||||||
@@ -200,10 +180,35 @@ export class AlertTabCtrl {
|
|||||||
this.initModel();
|
this.initModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
thresholdUpdated() {
|
evaluatorParamsChanged() {
|
||||||
if (ThresholdMapper.alertToGraphThresholds(this.panel)) {
|
ThresholdMapper.alertToGraphThresholds(this.panel);
|
||||||
this.panelCtrl.render();
|
this.panelCtrl.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
severityChanged() {
|
||||||
|
ThresholdMapper.alertToGraphThresholds(this.panel);
|
||||||
|
this.panelCtrl.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluatorTypeChanged(evaluator) {
|
||||||
|
// ensure params array is correct length
|
||||||
|
switch (evaluator.type) {
|
||||||
|
case "lt":
|
||||||
|
case "gt": {
|
||||||
|
evaluator.params = [evaluator.params[0]];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "within_range":
|
||||||
|
case "outside_range": {
|
||||||
|
evaluator.params = [evaluator.params[0], evaluator.params[1]];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "no_value": {
|
||||||
|
evaluator.params = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.evaluatorParamsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
test() {
|
test() {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<span class="gf-form-label">Severity</span>
|
<span class="gf-form-label">Severity</span>
|
||||||
<div class="gf-form-select-wrapper width-13">
|
<div class="gf-form-select-wrapper width-13">
|
||||||
<select class="gf-form-input" ng-model="ctrl.alert.severity" ng-options="f.value as f.text for f in ctrl.severityLevels">
|
<select class="gf-form-input" ng-model="ctrl.alert.severity" ng-options="f.value as f.text for f in ctrl.severityLevels" ng-change="ctrl.severityChanged()">
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,9 +59,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<metric-segment-model property="conditionModel.evaluator.type" options="ctrl.evalFunctions" custom="false" css-class="query-keyword" on-change="ctrl.evaluatorTypeChanged(conditionModel.evaluator)"></metric-segment-model>
|
<metric-segment-model property="conditionModel.evaluator.type" options="ctrl.evalFunctions" custom="false" css-class="query-keyword" on-change="ctrl.evaluatorTypeChanged(conditionModel.evaluator)"></metric-segment-model>
|
||||||
<input class="gf-form-input max-width-7" type="number" ng-hide="conditionModel.evaluator.params.length === 0" ng-model="conditionModel.evaluator.params[0]" ng-change="ctrl.thresholdUpdated()"></input>
|
<input class="gf-form-input max-width-7" type="number" ng-hide="conditionModel.evaluator.params.length === 0" ng-model="conditionModel.evaluator.params[0]" ng-change="ctrl.evaluatorParamsChanged()"></input>
|
||||||
<label class="gf-form-label query-keyword" ng-show="conditionModel.evaluator.params.length === 2">TO</label>
|
<label class="gf-form-label query-keyword" ng-show="conditionModel.evaluator.params.length === 2">TO</label>
|
||||||
<input class="gf-form-input max-width-7" type="number" ng-if="conditionModel.evaluator.params.length === 2" ng-model="conditionModel.evaluator.params[1]" ng-change="ctrl.thresholdUpdated()"></input>
|
<input class="gf-form-input max-width-7" type="number" ng-if="conditionModel.evaluator.params.length === 2" ng-model="conditionModel.evaluator.params[1]" ng-change="ctrl.evaluatorParamsChanged()"></input>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label">
|
<label class="gf-form-label">
|
||||||
|
|||||||
@@ -37,7 +37,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;
|
var thresholdControls = new ThresholdControls(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,10 +161,8 @@ 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';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thresholdControls) {
|
|
||||||
thresholdControls.draw(plot);
|
thresholdControls.draw(plot);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function processOffsetHook(plot, gridMargin) {
|
function processOffsetHook(plot, gridMargin) {
|
||||||
var left = panel.yaxes[0];
|
var left = panel.yaxes[0];
|
||||||
@@ -182,17 +180,7 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// give space to alert editing
|
// give space to alert editing
|
||||||
if (ctrl.editingThresholds) {
|
thresholdControls.prepare(elem);
|
||||||
if (!thresholdControls) {
|
|
||||||
var thresholdMargin = panel.thresholds.length > 1 ? '220px' : '110px';
|
|
||||||
elem.css('margin-right', thresholdMargin);
|
|
||||||
thresholdControls = new ThresholdControls(ctrl);
|
|
||||||
}
|
|
||||||
} else if (thresholdControls) {
|
|
||||||
elem.css('margin-right', '0');
|
|
||||||
thresholdControls.cleanUp();
|
|
||||||
thresholdControls = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var stack = panel.stack ? true : null;
|
var stack = panel.stack ? true : null;
|
||||||
|
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ class GraphCtrl extends MetricsPanelCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addThreshold() {
|
addThreshold() {
|
||||||
this.panel.thresholds.push({value: undefined, color: "rgba(255,0,0,0.2)"});
|
this.panel.thresholds.push({value: undefined, colorMode: "critical", op: 'gt', fill: true, line: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
removeThreshold(index) {
|
removeThreshold(index) {
|
||||||
|
|||||||
@@ -9,26 +9,25 @@ export class ThresholdControls {
|
|||||||
placeholder: any;
|
placeholder: any;
|
||||||
height: any;
|
height: any;
|
||||||
thresholds: any;
|
thresholds: any;
|
||||||
|
needsCleanup: boolean;
|
||||||
|
|
||||||
constructor(private panelCtrl) {
|
constructor(private panelCtrl) {}
|
||||||
this.thresholds = this.panelCtrl.panel.thresholds;
|
|
||||||
|
getHandleHtml(handleIndex, model, valueStr) {
|
||||||
|
var colorClass = 'crit';
|
||||||
|
if (model.colorMode === 'warning') {
|
||||||
|
colorClass = 'warn';
|
||||||
}
|
}
|
||||||
|
|
||||||
getHandleInnerHtml(handleName, op, value) {
|
return `<div class="alert-handle-wrapper alert-handle-wrapper--T${handleIndex}">
|
||||||
if (op === '>') { op = '>'; }
|
<div class="alert-handle-line alert-handle-line--${colorClass}">
|
||||||
if (op === '<') { op = '<'; }
|
</div>
|
||||||
|
<div class="alert-handle" data-handle-index="${handleIndex}">
|
||||||
return `
|
<i class="icon-gf icon-gf-${colorClass} alert-icon-${colorClass}"></i>
|
||||||
<div class="alert-handle-line">
|
<span class="alert-handle-value">${valueStr}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert-handle">
|
|
||||||
${op} ${value}
|
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
|
||||||
|
|
||||||
getFullHandleHtml(handleName, op, value) {
|
|
||||||
var innerTemplate = this.getHandleInnerHtml(handleName, op, value);
|
|
||||||
return `<div class="alert-handle-wrapper alert-handle-wrapper--${handleName}">${innerTemplate}</div>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupDragging(handleElem, threshold, handleIndex) {
|
setupDragging(handleElem, threshold, handleIndex) {
|
||||||
@@ -78,15 +77,18 @@ export class ThresholdControls {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanUp() {
|
initDragging(evt) {
|
||||||
if (this.placeholder) {
|
var handleIndex = $(evt.currentTarget).data("handleIndex");
|
||||||
this.placeholder.find(".alert-handle-wrapper").remove();
|
console.log('alert handle index', handleIndex);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHandle(handleIndex, model, defaultHandleTopPos) {
|
cleanUp() {
|
||||||
var handleName = 'T' + (handleIndex+1);
|
this.placeholder.find(".alert-handle-wrapper").remove();
|
||||||
var handleElem = this.placeholder.find(`.alert-handle-wrapper--${handleName}`);
|
this.needsCleanup = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHandle(handleIndex, defaultHandleTopPos) {
|
||||||
|
var model = this.thresholds[handleIndex];
|
||||||
var value = model.value;
|
var value = model.value;
|
||||||
var valueStr = value;
|
var valueStr = value;
|
||||||
var handleTopPos = 0;
|
var handleTopPos = 0;
|
||||||
@@ -100,29 +102,48 @@ export class ThresholdControls {
|
|||||||
handleTopPos = Math.min(Math.max(valueCanvasPos.top, 0), this.height) - 6;
|
handleTopPos = Math.min(Math.max(valueCanvasPos.top, 0), this.height) - 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handleElem.length === 0) {
|
var handleElem = $(this.getHandleHtml(handleIndex, model, valueStr));
|
||||||
handleElem = $(this.getFullHandleHtml(handleName, model.op, valueStr));
|
|
||||||
this.placeholder.append(handleElem);
|
this.placeholder.append(handleElem);
|
||||||
this.setupDragging(handleElem, model, handleIndex);
|
|
||||||
} else {
|
|
||||||
handleElem.html(this.getHandleInnerHtml(handleName, model.op, valueStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
handleElem.toggleClass('alert-handle-wrapper--no-value', valueStr === '');
|
handleElem.toggleClass('alert-handle-wrapper--no-value', valueStr === '');
|
||||||
handleElem.css({top: handleTopPos});
|
handleElem.css({top: handleTopPos});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prepare(elem) {
|
||||||
|
if (this.panelCtrl.editingThresholds) {
|
||||||
|
var thresholdMargin = this.panelCtrl.panel.thresholds.length > 1 ? '220px' : '110px';
|
||||||
|
elem.css('margin-right', thresholdMargin);
|
||||||
|
} else if (this.needsCleanup) {
|
||||||
|
elem.css('margin-right', '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
draw(plot) {
|
draw(plot) {
|
||||||
|
this.thresholds = this.panelCtrl.panel.thresholds;
|
||||||
this.plot = plot;
|
this.plot = plot;
|
||||||
this.placeholder = plot.getPlaceholder();
|
this.placeholder = plot.getPlaceholder();
|
||||||
|
|
||||||
|
if (this.needsCleanup) {
|
||||||
|
this.cleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no thresholds or not editing alerts skip rendering handles
|
||||||
|
if (this.thresholds.length === 0 || !this.panelCtrl.editingThresholds) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.height = plot.height();
|
this.height = plot.height();
|
||||||
|
|
||||||
if (this.thresholds.length > 0) {
|
if (this.thresholds.length > 0) {
|
||||||
this.renderHandle(0, this.thresholds[0], 10);
|
this.renderHandle(0, 10);
|
||||||
}
|
}
|
||||||
if (this.thresholds.length > 1) {
|
if (this.thresholds.length > 1) {
|
||||||
this.renderHandle(1, this.thresholds[1], this.height-30);
|
this.renderHandle(1, this.height-30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.placeholder.off('mousedown', '.alert-handle');
|
||||||
|
this.placeholder.on('mousedown', '.alert-handle', this.initDragging.bind(this));
|
||||||
|
this.needsCleanup = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,6 +152,9 @@ $btn-link-color: $gray-3;
|
|||||||
|
|
||||||
$iconContainerBackground: $black;
|
$iconContainerBackground: $black;
|
||||||
|
|
||||||
|
$btn-divider-left: $dark-5;
|
||||||
|
$btn-divider-right: $dark-1;
|
||||||
|
|
||||||
// Forms
|
// Forms
|
||||||
// -------------------------
|
// -------------------------
|
||||||
$input-bg: $dark-4;
|
$input-bg: $dark-4;
|
||||||
@@ -185,7 +188,6 @@ $dropdownLinkColorActive: $white;
|
|||||||
$dropdownLinkBackgroundActive: $dark-4;
|
$dropdownLinkBackgroundActive: $dark-4;
|
||||||
$dropdownLinkBackgroundHover: $dark-4;
|
$dropdownLinkBackgroundHover: $dark-4;
|
||||||
|
|
||||||
|
|
||||||
// COMPONENT VARIABLES
|
// COMPONENT VARIABLES
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -157,6 +157,9 @@ $btn-inverse-text-color: $dark-4;
|
|||||||
|
|
||||||
$btn-link-color: $gray-1;
|
$btn-link-color: $gray-1;
|
||||||
|
|
||||||
|
$btn-divider-left: $dark-5;
|
||||||
|
$btn-divider-right: $dark-1;
|
||||||
|
|
||||||
$iconContainerBackground: $white;
|
$iconContainerBackground: $white;
|
||||||
|
|
||||||
// Forms
|
// Forms
|
||||||
|
|||||||
@@ -323,25 +323,56 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
position: relative;
|
position: relative;
|
||||||
float: right;
|
float: right;
|
||||||
padding: 0.4rem 0.6rem 0.4rem 0.4rem;
|
box-shadow: $card-shadow;
|
||||||
background-color: $btn-inverse-bg;
|
background: $card-background;
|
||||||
box-shadow: $search-shadow;
|
cursor: move;
|
||||||
cursor: row-resize;
|
|
||||||
width: 100px;
|
width: 100px;
|
||||||
font-size: $font-size-sm;
|
font-size: $font-size-sm;
|
||||||
box-shadow: 4px 4px 3px 0px $body-bg;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border-width: 0 1px 1px 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: $black;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: $text-muted;
|
color: $text-muted;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $btn-inverse-bg-hl;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-gf {
|
.icon-gf {
|
||||||
font-size: 17px;
|
font-size: 14px;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
float: left;
|
float: left;
|
||||||
|
border-right: 1px solid $btn-divider-left;
|
||||||
|
padding: 0.5rem 0.3rem 0.4rem 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-handle-value {
|
||||||
|
border-left: 1px solid $btn-divider-right;
|
||||||
|
padding: 0.5rem;
|
||||||
|
line-height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--T1 {
|
||||||
|
right: -222px;
|
||||||
|
width: 245px;
|
||||||
|
|
||||||
|
.alert-handle-line {
|
||||||
|
width: 145px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--T0{
|
||||||
|
right: -105px;
|
||||||
|
width: 128px;
|
||||||
|
|
||||||
|
.alert-handle-line {
|
||||||
|
width: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--no-value {
|
||||||
|
.alert-handle-line {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,31 +382,12 @@
|
|||||||
margin-top: 13px;
|
margin-top: 13px;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
|
||||||
|
|
||||||
&--T2 {
|
&--crit {
|
||||||
right: -222px;
|
background-color: rgba(237, 46, 24, 0.60);
|
||||||
width: 238px;
|
|
||||||
|
|
||||||
.alert-handle-line {
|
|
||||||
width: 138px;
|
|
||||||
background-color: $warn;
|
|
||||||
}
|
}
|
||||||
}
|
&--warn {
|
||||||
|
background-color: rgba(247, 149, 32, 0.60);
|
||||||
&--T1{
|
|
||||||
right: -105px;
|
|
||||||
width: 123px;
|
|
||||||
|
|
||||||
.alert-handle-line {
|
|
||||||
width: 23px;
|
|
||||||
background-color: $critical;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--no-value {
|
|
||||||
.alert-handle-line {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user