diff --git a/public/app/features/annotations/all.ts b/public/app/features/annotations/all.ts index 0be292a7fa1..cde82c24a48 100644 --- a/public/app/features/annotations/all.ts +++ b/public/app/features/annotations/all.ts @@ -1,8 +1,9 @@ import {AnnotationsSrv} from './annotations_srv'; -import {eventEditor} from './event_editor'; +import {eventEditor, EventManager} from './event_editor'; export { AnnotationsSrv, - eventEditor + eventEditor, + EventManager }; diff --git a/public/app/features/annotations/event_editor.ts b/public/app/features/annotations/event_editor.ts index dc811661111..737e48d3776 100644 --- a/public/app/features/annotations/event_editor.ts +++ b/public/app/features/annotations/event_editor.ts @@ -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: '', + onClose: this.editorClosed.bind(this), + model: { + event: this.event, + panelCtrl: this.panelCtrl, + }, + }); + + this.panelCtrl.render(); + } +} + diff --git a/public/app/features/annotations/partials/event_editor.html b/public/app/features/annotations/partials/event_editor.html index 639c0ad6911..6e44b6f768d 100644 --- a/public/app/features/annotations/partials/event_editor.html +++ b/public/app/features/annotations/partials/event_editor.html @@ -5,29 +5,29 @@
Title - +
-
+
Time - +
-
+
Start - +
End - +
Description - +
diff --git a/public/app/plugins/panel/graph/graph.ts b/public/app/plugins/panel/graph/graph.ts index f3a7f78b887..af03bafc4ac 100755 --- a/public/app/plugins/panel/graph/graph.ts +++ b/public/app/plugins/panel/graph/graph.ts @@ -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: '', - 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}); + }); + } } });