mirror of https://github.com/grafana/grafana
parent
5b6fb3b124
commit
e3b281dbac
@ -0,0 +1,135 @@ |
||||
///<reference path="../../../headers/common.d.ts" />
|
||||
|
||||
import 'jquery.flot'; |
||||
import $ from 'jquery'; |
||||
import _ from 'lodash'; |
||||
|
||||
export class AlertHandleManager { |
||||
plot: any; |
||||
placeholder: any; |
||||
height: any; |
||||
alert: any; |
||||
|
||||
constructor(private panelCtrl) { |
||||
this.alert = panelCtrl.panel.alert; |
||||
} |
||||
|
||||
getHandleInnerHtml(type, op, value) { |
||||
if (op === '>') { op = '>'; } |
||||
if (op === '<') { op = '<'; } |
||||
|
||||
return ` |
||||
<div class="alert-handle-line"> |
||||
</div> |
||||
<div class="alert-handle"> |
||||
<i class="icon-gf icon-gf-${type} alert-icon-${type}"></i> |
||||
${op} ${value} |
||||
</div>`;
|
||||
} |
||||
|
||||
getFullHandleHtml(type, op, value) { |
||||
var innerTemplate = this.getHandleInnerHtml(type, op, value); |
||||
return ` |
||||
<div class="alert-handle-wrapper alert-handle-wrapper--${type}"> |
||||
${innerTemplate} |
||||
</div> |
||||
`;
|
||||
} |
||||
|
||||
setupDragging(handleElem, levelModel) { |
||||
var isMoving = false; |
||||
var lastY = null; |
||||
var posTop; |
||||
var plot = this.plot; |
||||
var panelCtrl = this.panelCtrl; |
||||
|
||||
function dragging(evt) { |
||||
if (lastY === null) { |
||||
lastY = evt.clientY; |
||||
} else { |
||||
var diff = evt.clientY - lastY; |
||||
posTop = posTop + diff; |
||||
lastY = evt.clientY; |
||||
handleElem.css({top: posTop + diff}); |
||||
} |
||||
} |
||||
|
||||
function stopped() { |
||||
isMoving = false; |
||||
// calculate graph level
|
||||
var graphLevel = plot.c2p({left: 0, top: posTop}).y; |
||||
console.log('canvasPos:' + posTop + ' Graph level: ' + graphLevel); |
||||
graphLevel = parseInt(graphLevel.toFixed(0)); |
||||
levelModel.level = graphLevel; |
||||
console.log(levelModel); |
||||
|
||||
var levelCanvasPos = plot.p2c({x: 0, y: graphLevel}); |
||||
console.log('canvas pos', levelCanvasPos); |
||||
|
||||
console.log('stopped'); |
||||
handleElem.off("mousemove", dragging); |
||||
handleElem.off("mouseup", dragging); |
||||
|
||||
// trigger digest and render
|
||||
panelCtrl.$scope.$apply(function() { |
||||
panelCtrl.render(); |
||||
}); |
||||
} |
||||
|
||||
handleElem.bind('mousedown', function() { |
||||
isMoving = true; |
||||
lastY = null; |
||||
posTop = handleElem.position().top; |
||||
console.log('start pos', posTop); |
||||
|
||||
handleElem.on("mousemove", dragging); |
||||
handleElem.on("mouseup", stopped); |
||||
}); |
||||
} |
||||
|
||||
cleanUp() { |
||||
if (this.placeholder) { |
||||
this.placeholder.find(".alert-handle-wrapper").remove(); |
||||
} |
||||
} |
||||
|
||||
renderHandle(type, model, defaultHandleTopPos) { |
||||
var handleElem = this.placeholder.find(`.alert-handle-wrapper--${type}`); |
||||
var level = model.level; |
||||
var levelStr = level; |
||||
var handleTopPos = 0; |
||||
|
||||
// handle no value
|
||||
if (!_.isNumber(level)) { |
||||
levelStr = ''; |
||||
handleTopPos = defaultHandleTopPos; |
||||
} else { |
||||
var levelCanvasPos = this.plot.p2c({x: 0, y: level}); |
||||
handleTopPos = Math.min(Math.max(levelCanvasPos.top, 0), this.height) - 6; |
||||
} |
||||
|
||||
if (handleElem.length === 0) { |
||||
console.log('creating handle'); |
||||
handleElem = $(this.getFullHandleHtml(type, model.op, levelStr)); |
||||
this.placeholder.append(handleElem); |
||||
this.setupDragging(handleElem, model); |
||||
} else { |
||||
console.log('reusing handle!'); |
||||
handleElem.html(this.getHandleInnerHtml(type, model.op, levelStr)); |
||||
} |
||||
|
||||
handleElem.toggleClass('alert-handle-wrapper--no-value', levelStr === ''); |
||||
handleElem.css({top: handleTopPos}); |
||||
} |
||||
|
||||
draw(plot) { |
||||
this.plot = plot; |
||||
this.placeholder = plot.getPlaceholder(); |
||||
this.height = plot.height(); |
||||
|
||||
this.renderHandle('critical', this.alert.critical, 10); |
||||
this.renderHandle('warn', this.alert.warn, this.height-30); |
||||
} |
||||
|
||||
} |
||||
|
||||
@ -1,97 +0,0 @@ |
||||
///<reference path="../../../headers/common.d.ts" />
|
||||
|
||||
import 'jquery.flot'; |
||||
import $ from 'jquery'; |
||||
import _ from 'lodash'; |
||||
|
||||
var options = {}; |
||||
|
||||
function getHandleInnerHtml(type, op, value) { |
||||
if (op === '>') { op = '>'; } |
||||
if (op === '<') { op = '<'; } |
||||
|
||||
return ` |
||||
<div class="alert-handle-line"> |
||||
</div> |
||||
<div class="alert-handle"> |
||||
<i class="icon-gf icon-gf-${type} alert-icon-${type}"></i> |
||||
${op} ${value} |
||||
</div>`;
|
||||
} |
||||
|
||||
function getFullHandleHtml(type, op, value) { |
||||
var innerTemplate = getHandleInnerHtml(type, op, value); |
||||
return ` |
||||
<div class="alert-handle-wrapper alert-handle-wrapper--${type}"> |
||||
${innerTemplate} |
||||
</div> |
||||
`;
|
||||
} |
||||
|
||||
var dragGhostElem = document.createElement('div'); |
||||
|
||||
function dragStartHandler(evt) { |
||||
evt.dataTransfer.setDragImage(dragGhostElem, -99999, -99999); |
||||
} |
||||
|
||||
function dragEndHandler() { |
||||
console.log('drag end'); |
||||
} |
||||
|
||||
function drawAlertHandles(plot) { |
||||
var options = plot.getOptions(); |
||||
var $placeholder = plot.getPlaceholder(); |
||||
|
||||
if (!options.alerting.editing) { |
||||
$placeholder.find(".alert-handle-wrapper").remove(); |
||||
return; |
||||
} |
||||
|
||||
var alert = options.alerting.alert; |
||||
var height = plot.height(); |
||||
|
||||
function renderHandle(type, model) { |
||||
var $handle = $placeholder.find(`.alert-handle-wrapper--${type}`); |
||||
|
||||
if (!_.isNumber(model.level)) { |
||||
$handle.remove(); |
||||
return; |
||||
} |
||||
|
||||
if ($handle.length === 0) { |
||||
console.log('creating handle'); |
||||
$handle = $(getFullHandleHtml(type, model.op, model.level)); |
||||
$handle.attr('draggable', true); |
||||
$handle.bind('dragend', dragEndHandler); |
||||
$handle.bind('dragstart', dragStartHandler); |
||||
$placeholder.append($handle); |
||||
} else { |
||||
console.log('reusing handle!'); |
||||
$handle.html(getHandleInnerHtml(type, model.op, model.level)); |
||||
} |
||||
|
||||
var levelCanvasPos = plot.p2c({x: 0, y: model.level}); |
||||
var levelTopPos = Math.min(Math.max(levelCanvasPos.top, 0), height) - 6; |
||||
$handle.css({top: levelTopPos}); |
||||
} |
||||
|
||||
renderHandle('critical', alert.critical); |
||||
renderHandle('warn', alert.warn); |
||||
} |
||||
|
||||
function shutdown() { |
||||
console.log('shutdown'); |
||||
} |
||||
|
||||
function init(plot, classes) { |
||||
plot.hooks.draw.push(drawAlertHandles); |
||||
plot.hooks.shutdown.push(shutdown); |
||||
} |
||||
|
||||
$.plot.plugins.push({ |
||||
init: init, |
||||
options: options, |
||||
name: 'navigationControl', |
||||
version: '1.4' |
||||
}); |
||||
|
||||
@ -1,116 +1,120 @@ |
||||
<div class="editor-row"> |
||||
<div class="gf-form-group section" > |
||||
<h5 class="section-heading">Alert Query</h5> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form"> |
||||
<query-part-editor |
||||
class="gf-form-label query-part" |
||||
part="ctrl.query" |
||||
part-updated="ctrl.queryUpdated()"> |
||||
</query-part-editor> |
||||
</div> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label">Transform using</span> |
||||
<div class="gf-form-select-wrapper"> |
||||
<select class="gf-form-input" |
||||
ng-model="ctrl.alert.transform.type" |
||||
ng-options="f.type as f.text for f in ctrl.transforms" |
||||
ng-change="ctrl.transformChanged()" |
||||
> |
||||
</select> |
||||
|
||||
<div ng-if="ctrl.panel.alert"> |
||||
<div class="editor-row"> |
||||
<div class="gf-form-group section" > |
||||
<h5 class="section-heading">Alert Query</h5> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form"> |
||||
<query-part-editor |
||||
class="gf-form-label query-part" |
||||
part="ctrl.query" |
||||
part-updated="ctrl.queryUpdated()"> |
||||
</query-part-editor> |
||||
</div> |
||||
</div> |
||||
<div class="gf-form" ng-if="ctrl.transformDef.type === 'aggregation'"> |
||||
<span class="gf-form-label">Method</span> |
||||
<div class="gf-form-select-wrapper"> |
||||
<select class="gf-form-input" |
||||
ng-model="ctrl.alert.transform.method" |
||||
ng-options="f for f in ctrl.aggregators"> |
||||
</select> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label">Transform using</span> |
||||
<div class="gf-form-select-wrapper"> |
||||
<select class="gf-form-input" |
||||
ng-model="ctrl.alert.transform.type" |
||||
ng-options="f.type as f.text for f in ctrl.transforms" |
||||
ng-change="ctrl.transformChanged()" |
||||
> |
||||
</select> |
||||
</div> |
||||
</div> |
||||
<div class="gf-form" ng-if="ctrl.transformDef.type === 'aggregation'"> |
||||
<span class="gf-form-label">Method</span> |
||||
<div class="gf-form-select-wrapper"> |
||||
<select class="gf-form-input" |
||||
ng-model="ctrl.alert.transform.method" |
||||
ng-options="f for f in ctrl.aggregators"> |
||||
</select> |
||||
</div> |
||||
</div> |
||||
<div class="gf-form" ng-if="ctrl.transformDef.type === 'forecast'"> |
||||
<span class="gf-form-label">Timespan</span> |
||||
<input class="gf-form-input max-width-5" type="text" ng-model="ctrl.alert.transform.timespan" ng-change="ctrl.ruleUpdated()"></input> |
||||
</div> |
||||
</div> |
||||
<div class="gf-form" ng-if="ctrl.transformDef.type === 'forecast'"> |
||||
<span class="gf-form-label">Timespan</span> |
||||
<input class="gf-form-input max-width-5" type="text" ng-model="ctrl.alert.transform.timespan" ng-change="ctrl.ruleUpdated()"></input> |
||||
</div> |
||||
|
||||
<div class="gf-form-group section"> |
||||
<h5 class="section-heading">Levels</h5> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label"> |
||||
<i class="icon-gf icon-gf-warn alert-icon-warn"></i> |
||||
Warn if |
||||
</span> |
||||
<metric-segment-model property="ctrl.alert.warn.op" options="ctrl.levelOpList" custom="false" css-class="query-segment-operator"></metric-segment-model> |
||||
<input class="gf-form-input max-width-7" type="number" ng-model="ctrl.alert.warn.level" ng-change="ctrl.levelsUpdated()"></input> |
||||
</div> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label"> |
||||
<i class="icon-gf icon-gf-warn alert-icon-critical"></i> |
||||
Critcal if |
||||
</span> |
||||
<metric-segment-model property="ctrl.alert.critical.op" options="ctrl.levelOpList" custom="false" css-class="query-segment-operator"></metric-segment-model> |
||||
<input class="gf-form-input max-width-7" type="number" ng-model="ctrl.alert.critical.level" ng-change="ctrl.levelsUpdated()"></input> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- <div class="gf-form-group section"> --> |
||||
<!-- <h5 class="section-heading">Levels</h5> --> |
||||
<!-- <div class="gf-form-inline"> --> |
||||
<!-- <div class="gf-form"> --> |
||||
<!-- <span class="gf-form-label"> --> |
||||
<!-- <i class="icon-gf icon-gf-warn alert-icon-warn"></i> --> |
||||
<!-- Warn if --> |
||||
<!-- </span> --> |
||||
<!-- <metric-segment-model property="ctrl.alert.warn.op" options="ctrl.levelOpList" custom="false" css-class="query-segment-operator"></metric-segment-model> --> |
||||
<!-- <input class="gf-form-input max-width-7" type="number" ng-model="ctrl.alert.warn.level" ng-change="ctrl.levelsUpdated()"></input> --> |
||||
<!-- </div> --> |
||||
<!-- <div class="gf-form"> --> |
||||
<!-- <span class="gf-form-label"> --> |
||||
<!-- <i class="icon-gf icon-gf-warn alert-icon-critical"></i> --> |
||||
<!-- Critcal if --> |
||||
<!-- </span> --> |
||||
<!-- <metric-segment-model property="ctrl.alert.critical.op" options="ctrl.levelOpList" custom="false" css-class="query-segment-operator"></metric-segment-model> --> |
||||
<!-- <input class="gf-form-input max-width-7" type="number" ng-model="ctrl.alert.critical.level" ng-change="ctrl.levelsUpdated()"></input> --> |
||||
<!-- </div> --> |
||||
<!-- </div> --> |
||||
<!-- </div> --> |
||||
<!-- </div> --> |
||||
|
||||
<div class="editor-row"> |
||||
<div class="gf-form-group section"> |
||||
<h5 class="section-heading">Execution</h5> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label">Scheduler</span> |
||||
<div class="gf-form-select-wrapper"> |
||||
<select class="gf-form-input" |
||||
ng-model="ctrl.alert.scheduler" |
||||
ng-options="f.value as f.text for f in ctrl.schedulers"> |
||||
</select> |
||||
<div class="editor-row"> |
||||
<div class="gf-form-group section"> |
||||
<h5 class="section-heading">Execution</h5> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label">Scheduler</span> |
||||
<div class="gf-form-select-wrapper"> |
||||
<select class="gf-form-input" |
||||
ng-model="ctrl.alert.scheduler" |
||||
ng-options="f.value as f.text for f in ctrl.schedulers"> |
||||
</select> |
||||
</div> |
||||
</div> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label">Evaluate every</span> |
||||
<input class="gf-form-input max-width-7" type="text" ng-model="ctrl.alert.frequency"></input> |
||||
</div> |
||||
</div> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label">Evaluate every</span> |
||||
<input class="gf-form-input max-width-7" type="text" ng-model="ctrl.alert.frequency"></input> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="gf-form-group section"> |
||||
<h5 class="section-heading">Notifications</h5> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label">Groups</span> |
||||
<bootstrap-tagsinput ng-model="ctrl.alert.notify" tagclass="label label-tag" placeholder="add tags"> |
||||
</bootstrap-tagsinput> |
||||
<div class="gf-form-group section"> |
||||
<h5 class="section-heading">Notifications</h5> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label">Groups</span> |
||||
<bootstrap-tagsinput ng-model="ctrl.alert.notify" tagclass="label label-tag" placeholder="add tags"> |
||||
</bootstrap-tagsinput> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
<div class="gf-form-group section"> |
||||
<h5 class="section-heading">Information</h5> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label width-10">Alert name</span> |
||||
<input type="text" class="gf-form-input width-22" ng-model="ctrl.panel.alerting.name"> |
||||
</div> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form-group section"> |
||||
<h5 class="section-heading">Information</h5> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label width-10" style="margin-top: -73px;">Alert description</span> |
||||
<span class="gf-form-label width-10">Alert name</span> |
||||
<input type="text" class="gf-form-input width-22" ng-model="ctrl.panel.alerting.name"> |
||||
</div> |
||||
<div class="gf-form"> |
||||
<textarea rows="5" ng-model="ctrl.panel.alerting.description" class="gf-form-input width-22"></textarea> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form"> |
||||
<span class="gf-form-label width-10" style="margin-top: -73px;">Alert description</span> |
||||
</div> |
||||
<div class="gf-form"> |
||||
<textarea rows="5" ng-model="ctrl.panel.alerting.description" class="gf-form-input width-22"></textarea> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="editor-row"> |
||||
<div class="gf-form-button-row"> |
||||
<button class="btn btn-danger" ng-click="ctrl.delete()" ng-show="ctrl.alert.enabled">Delete</button> |
||||
<button class="btn btn-success" ng-click="ctrl.enable()" ng-hide="ctrl.alert.enabled">Enable</button> |
||||
<button class="btn btn-secondary" ng-click="ctrl.disable()" ng-show="ctrl.alert.enabled">Disable</button> |
||||
<button class="btn btn-danger" ng-click="ctrl.delete()" ng-show="ctrl.panel.alert">Delete</button> |
||||
<button class="btn btn-inverse" ng-click="ctrl.enable()" ng-hide="ctrl.panel.alert"> |
||||
<i class="icon-gf icon-gf-alert"></i> |
||||
Add Alert |
||||
</button> |
||||
</div> |
||||
</div> |
||||
|
||||
Loading…
Reference in new issue