Commit a151de1d by Torkel Ödegaard

progess on adding annotations

parent 0335c1f3
import {AnnotationsSrv} from './annotations_srv';
import {eventEditor} from './event_editor';
import {eventEditor, EventManager} from './event_editor';
export {
AnnotationsSrv,
eventEditor
eventEditor,
EventManager
};
......@@ -17,22 +17,15 @@ export class AnnotationEvent {
export class EventEditorCtrl {
panelCtrl: MetricsPanelCtrl;
annotation: AnnotationEvent;
event: AnnotationEvent;
timeRange: {from: number, to: number};
form: any;
close: any;
/** @ngInject **/
constructor(private annotationsSrv) {
this.annotation = new AnnotationEvent();
this.annotation.panelId = this.panelCtrl.panel.id;
this.annotation.dashboardId = this.panelCtrl.dashboard.id;
this.annotation.time = moment(this.timeRange.from);
if (this.timeRange.to) {
this.annotation.timeEnd = moment(this.timeRange.to);
this.annotation.isRegion = true;
}
this.event.panelId = this.panelCtrl.panel.id;
this.event.dashboardId = this.panelCtrl.dashboard.id;
}
save() {
......@@ -40,15 +33,17 @@ export class EventEditorCtrl {
return;
}
let saveModel = _.cloneDeep(this.annotation);
let saveModel = _.cloneDeep(this.event);
saveModel.time = saveModel.time.valueOf();
saveModel.timeEnd = 0;
if (saveModel.isRegion) {
saveModel.timeEnd = saveModel.timeEnd.valueOf();
}
if (saveModel.timeEnd < saveModel.time) {
console.log('invalid time');
return;
if (saveModel.timeEnd < saveModel.time) {
console.log('invalid time');
return;
}
}
this.annotationsSrv.saveAnnotationEvent(saveModel).then(() => {
......@@ -56,6 +51,10 @@ export class EventEditorCtrl {
this.close();
});
}
timeChanged() {
this.panelCtrl.render();
}
}
export function eventEditor() {
......@@ -67,10 +66,68 @@ export function eventEditor() {
templateUrl: 'public/app/features/annotations/partials/event_editor.html',
scope: {
"panelCtrl": "=",
"timeRange": "=",
"event": "=",
"close": "&",
}
};
}
coreModule.directive('eventEditor', eventEditor);
export class EventManager {
event: AnnotationEvent;
constructor(private panelCtrl: MetricsPanelCtrl,
private elem,
private popoverSrv) {
}
editorClosed() {
console.log('editorClosed');
this.event = null;
this.panelCtrl.render();
}
updateTime(range) {
let newEvent = true;
if (this.event) {
newEvent = false;
} else {
// init new event
this.event = new AnnotationEvent();
this.event.dashboardId = this.panelCtrl.dashboard.id;
this.event.panelId = this.panelCtrl.panel.id;
}
// update time
this.event.time = moment(range.from);
this.event.isRegion = false;
if (range.to) {
this.event.timeEnd = moment(range.to);
this.event.isRegion = true;
}
// newEvent means the editor is not visible
if (!newEvent) {
this.panelCtrl.render();
return;
}
this.popoverSrv.show({
element: this.elem[0],
classNames: 'drop-popover drop-popover--form',
position: 'bottom center',
openOn: null,
template: '<event-editor panel-ctrl="panelCtrl" event="event" close="dismiss()"></event-editor>',
onClose: this.editorClosed.bind(this),
model: {
event: this.event,
panelCtrl: this.panelCtrl,
},
});
this.panelCtrl.render();
}
}
......@@ -5,29 +5,29 @@
<div style="display: inline-block">
<div class="gf-form">
<span class="gf-form-label width-7">Title</span>
<input type="text" ng-model="ctrl.annotation.title" class="gf-form-input max-width-20" required>
<input type="text" ng-model="ctrl.event.title" class="gf-form-input max-width-20" required>
</div>
<!-- single event -->
<div ng-if="!ctrl.annotation.isRegion">
<div ng-if="!ctrl.event.isRegion">
<div class="gf-form">
<span class="gf-form-label width-7">Time</span>
<input type="text" ng-model="ctrl.annotation.time" class="gf-form-input max-width-20" input-datetime required>
<input type="text" ng-model="ctrl.event.time" class="gf-form-input max-width-20" input-datetime required ng-change="ctrl.timeChanged()">
</div>
</div>
<!-- region event -->
<div ng-if="ctrl.annotation.isRegion">
<div ng-if="ctrl.event.isRegion">
<div class="gf-form">
<span class="gf-form-label width-7">Start</span>
<input type="text" ng-model="ctrl.annotation.time" class="gf-form-input max-width-20" input-datetime required>
<input type="text" ng-model="ctrl.event.time" class="gf-form-input max-width-20" input-datetime required ng-change="ctrl.timeChanged()">
</div>
<div class="gf-form">
<span class="gf-form-label width-7">End</span>
<input type="text" ng-model="ctrl.annotation.timeEnd" class="gf-form-input max-width-20" input-datetime required>
<input type="text" ng-model="ctrl.event.timeEnd" class="gf-form-input max-width-20" input-datetime required ng-change="ctrl.timeChanged()">
</div>
</div>
<div class="gf-form gf-form--v-stretch">
<span class="gf-form-label width-7">Description</span>
<textarea class="gf-form-input width-20" rows="3" ng-model="ctrl.annotation.text" placeholder="Event description"></textarea>
<textarea class="gf-form-input width-20" rows="3" ng-model="ctrl.event.text" placeholder="Event description"></textarea>
</div>
<div class="gf-form-button-row">
......
......@@ -17,6 +17,7 @@ import {tickStep} from 'app/core/utils/ticks';
import {appEvents, coreModule} from 'app/core/core';
import GraphTooltip from './graph_tooltip';
import {ThresholdManager} from './threshold_manager';
import {EventManager} from 'app/features/annotations/all';
import {convertValuesToHistogram, getSeriesValues} from './histogram';
coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
......@@ -27,13 +28,14 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
var ctrl = scope.ctrl;
var dashboard = ctrl.dashboard;
var panel = ctrl.panel;
var annotations = [];
var data;
var annotations;
var plot;
var sortedSeries;
var legendSideLastValue = null;
var rootScope = scope.$root;
var panelWidth = 0;
var eventManager = new EventManager(ctrl, elem, popoverSrv);
var thresholdManager = new ThresholdManager(ctrl);
var tooltip = new GraphTooltip(elem, dashboard, scope, function() {
return sortedSeries;
......@@ -54,7 +56,7 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
if (!data) {
return;
}
annotations = ctrl.annotations;
annotations = ctrl.annotations || [];
render_panel();
});
......@@ -79,20 +81,6 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
}
}, scope);
function showAddAnnotationView(timeRange) {
popoverSrv.show({
element: elem[0],
classNames: 'drop-popover drop-popover--form',
position: 'bottom center',
openOn: 'click',
template: '<event-editor panel-ctrl="panelCtrl" time-range="timeRange" close="dismiss()"></event-editor>',
model: {
timeRange: timeRange,
panelCtrl: ctrl,
},
});
}
function getLegendHeight(panelHeight) {
if (!panel.legend.show || panel.legend.rightSide) {
return 0;
......@@ -343,7 +331,7 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
}
thresholdManager.addPlotOptions(options, panel);
addAnnotations(options);
addAnnotationEvents(options);
configureAxisOptions(data, options);
sortedSeries = _.sortBy(data, function(series) { return series.zindex; });
......@@ -475,8 +463,12 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
};
}
function addAnnotations(options) {
if (!annotations || annotations.length === 0) {
function hasAnnotationEvents() {
return eventManager.event || annotations.length > 0 ;
}
function addAnnotationEvents(options) {
if (!hasAnnotationEvents()) {
return;
}
......@@ -501,26 +493,41 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
types['$__execution_error'] = ['$__no_data'];
for (var i = 0; i < annotations.length; i++) {
var item = annotations[i];
if (item.newState) {
console.log(item.newState);
item.eventType = '$__' + item.newState;
continue;
}
var annotationsToShow;
// adding/edditing event, only show that one
if (eventManager.event) {
const event = eventManager.event;
annotationsToShow = [
{
min: event.time.valueOf(),
title: event.title,
description: event.text,
eventType: '$__alerting',
}
];
} else {
// annotations from query
for (var i = 0; i < annotations.length; i++) {
var item = annotations[i];
if (item.newState) {
item.eventType = '$__' + item.newState;
continue;
}
if (!types[item.source.name]) {
types[item.source.name] = {
color: item.source.iconColor,
position: 'BOTTOM',
markerSize: 5,
};
if (!types[item.source.name]) {
types[item.source.name] = {
color: item.source.iconColor,
position: 'BOTTOM',
markerSize: 5,
};
}
}
annotationsToShow = annotations;
}
options.events = {
levels: _.keys(types).length + 1,
data: annotations,
data: annotationsToShow,
types: types,
};
}
......@@ -653,8 +660,10 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
}
elem.bind("plotselected", function (event, ranges) {
if (ranges.ctrlKey || ranges.metaKey) {
showAddAnnotationView(ranges.xaxis);
if (ranges.ctrlKey || ranges.metaKey) {
scope.$apply(() => {
eventManager.updateTime(ranges.xaxis);
});
} else {
scope.$apply(function() {
timeSrv.setTime({
......@@ -666,11 +675,14 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
});
elem.bind("plotclick", function (event, pos, item) {
// Skip if range selected (added in "plotselected" event handler)
let isRangeSelection = pos.x !== pos.x1;
let createAnnotation = !isRangeSelection && (pos.ctrlKey || pos.metaKey);
if (createAnnotation) {
showAddAnnotationView({from: pos.x, to: null});
if (pos.ctrlKey || pos.metaKey || eventManager.event) {
// Skip if range selected (added in "plotselected" event handler)
let isRangeSelection = pos.x !== pos.x1;
if (!isRangeSelection) {
scope.$apply(() => {
eventManager.updateTime({from: pos.x, to: null});
});
}
}
});
......
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