Commit dbe5480e by Torkel Ödegaard

create annotations work

parent 2fce88ee
...@@ -75,7 +75,7 @@ func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response ...@@ -75,7 +75,7 @@ func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response
} }
item.Id = 0 item.Id = 0
item.Epoch = cmd.EndTime item.Epoch = cmd.TimeEnd
if err := repo.Save(&item); err != nil { if err := repo.Save(&item); err != nil {
return ApiError(500, "Failed save annotation for region end time", err) return ApiError(500, "Failed save annotation for region end time", err)
......
...@@ -27,7 +27,7 @@ type PostAnnotationsCmd struct { ...@@ -27,7 +27,7 @@ type PostAnnotationsCmd struct {
FillColor string `json:"fillColor"` FillColor string `json:"fillColor"`
IsRegion bool `json:"isRegion"` IsRegion bool `json:"isRegion"`
EndTime int64 `json:"endTime"` TimeEnd int64 `json:"timeEnd"`
} }
type DeleteAnnotationsCmd struct { type DeleteAnnotationsCmd struct {
......
...@@ -7,41 +7,49 @@ import coreModule from 'app/core/core_module'; ...@@ -7,41 +7,49 @@ import coreModule from 'app/core/core_module';
import Drop from 'tether-drop'; import Drop from 'tether-drop';
/** @ngInject **/ /** @ngInject **/
function popoverSrv($compile, $rootScope) { function popoverSrv($compile, $rootScope, $timeout) {
let openDrop = null;
this.close = function() {
if (openDrop) {
openDrop.close();
}
};
this.show = function(options) { this.show = function(options) {
var classNames = 'drop-popover'; if (openDrop) {
var popoverScope = _.extend($rootScope.$new(true), options.model); openDrop.close();
}
var scope = _.extend($rootScope.$new(true), options.model);
var drop; var drop;
if (options.classNames) { var cleanUp = () => {
classNames = options.classNames; setTimeout(() => {
} scope.$destroy();
drop.destroy();
function destroyDrop() { if (options.onClose) {
setTimeout(function() { options.onClose();
if (drop.tether) {
drop.destroy();
} }
}); });
} };
popoverScope.dismiss = function() { scope.dismiss = () => {
popoverScope.$destroy(); drop.close();
destroyDrop();
}; };
var contentElement = document.createElement('div'); var contentElement = document.createElement('div');
contentElement.innerHTML = options.template; contentElement.innerHTML = options.template;
$compile(contentElement)(popoverScope); $compile(contentElement)(scope);
drop = new Drop({ drop = new Drop({
target: options.element, target: options.element,
content: contentElement, content: contentElement,
position: options.position, position: options.position,
classes: classNames, classes: options.classNames || 'drop-popover',
openOn: options.openOn || 'hover', openOn: options.openOn,
hoverCloseDelay: 200, hoverCloseDelay: 200,
tetherOptions: { tetherOptions: {
constraints: [{to: 'scrollParent', attachment: "none both"}] constraints: [{to: 'scrollParent', attachment: "none both"}]
...@@ -49,14 +57,11 @@ function popoverSrv($compile, $rootScope) { ...@@ -49,14 +57,11 @@ function popoverSrv($compile, $rootScope) {
}); });
drop.on('close', () => { drop.on('close', () => {
popoverScope.dismiss({fromDropClose: true}); cleanUp();
destroyDrop();
if (options.onClose) {
options.onClose();
}
}); });
setTimeout(() => { drop.open(); }, 10); openDrop = drop;
$timeout(() => { drop.open(); }, 10);
}; };
} }
......
...@@ -35,6 +35,7 @@ export class AnnotationsSrv { ...@@ -35,6 +35,7 @@ export class AnnotationsSrv {
// combine the annotations and flatten results // combine the annotations and flatten results
var annotations = _.flattenDeep([results[0], results[1]]); var annotations = _.flattenDeep([results[0], results[1]]);
// filter out annotations that do not belong to requesting panel // filter out annotations that do not belong to requesting panel
annotations = _.filter(annotations, item => { annotations = _.filter(annotations, item => {
if (item.panelId && options.panel.id !== item.panelId) { if (item.panelId && options.panel.id !== item.panelId) {
...@@ -60,7 +61,7 @@ export class AnnotationsSrv { ...@@ -60,7 +61,7 @@ export class AnnotationsSrv {
var panel = options.panel; var panel = options.panel;
var dashboard = options.dashboard; var dashboard = options.dashboard;
if (panel) { if (panel && panel.alert) {
return this.backendSrv.get('/api/annotations', { return this.backendSrv.get('/api/annotations', {
from: options.range.from.valueOf(), from: options.range.from.valueOf(),
to: options.range.to.valueOf(), to: options.range.to.valueOf(),
...@@ -133,7 +134,7 @@ export class AnnotationsSrv { ...@@ -133,7 +134,7 @@ export class AnnotationsSrv {
return this.globalAnnotationsPromise; return this.globalAnnotationsPromise;
} }
postAnnotation(annotation) { saveAnnotationEvent(annotation) {
return this.backendSrv.post('/api/annotations', annotation); return this.backendSrv.post('/api/annotations', annotation);
} }
......
...@@ -5,11 +5,11 @@ import moment from 'moment'; ...@@ -5,11 +5,11 @@ import moment from 'moment';
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
import {MetricsPanelCtrl} from 'app/plugins/sdk'; import {MetricsPanelCtrl} from 'app/plugins/sdk';
export class AnnotationItem { export class AnnotationEvent {
dashboardId: number; dashboardId: number;
panelId: number; panelId: number;
time: Date; time: any;
timeEnd: Date; timeEnd: any;
isRegion: boolean; isRegion: boolean;
title: string; title: string;
text: string; text: string;
...@@ -17,14 +17,13 @@ export class AnnotationItem { ...@@ -17,14 +17,13 @@ export class AnnotationItem {
export class EventEditorCtrl { export class EventEditorCtrl {
panelCtrl: MetricsPanelCtrl; panelCtrl: MetricsPanelCtrl;
timeFormat = 'YYYY-MM-DD HH:mm:ss'; annotation: AnnotationEvent;
annotation: AnnotationItem;
timeRange: {from: number, to: number}; timeRange: {from: number, to: number};
form: any; form: any;
/** @ngInject **/ /** @ngInject **/
constructor() { constructor(private annotationsSrv) {
this.annotation = new AnnotationItem(); this.annotation = new AnnotationEvent();
this.annotation.panelId = this.panelCtrl.panel.id; this.annotation.panelId = this.panelCtrl.panel.id;
this.annotation.dashboardId = this.panelCtrl.dashboard.id; this.annotation.dashboardId = this.panelCtrl.dashboard.id;
this.annotation.text = "hello"; this.annotation.text = "hello";
...@@ -40,6 +39,19 @@ export class EventEditorCtrl { ...@@ -40,6 +39,19 @@ export class EventEditorCtrl {
if (!this.form.$valid) { if (!this.form.$valid) {
return; return;
} }
let saveModel = _.cloneDeep(this.annotation);
saveModel.time = saveModel.time.valueOf();
if (saveModel.isRegion) {
saveModel.timeEnd = saveModel.timeEnd.valueOf();
}
if (saveModel.timeEnd < saveModel.time) {
console.log('invalid time');
return;
}
this.annotationsSrv.saveAnnotationEvent(saveModel);
} }
} }
...@@ -52,7 +64,8 @@ export function eventEditor() { ...@@ -52,7 +64,8 @@ export function eventEditor() {
templateUrl: 'public/app/features/annotations/partials/event_editor.html', templateUrl: 'public/app/features/annotations/partials/event_editor.html',
scope: { scope: {
"panelCtrl": "=", "panelCtrl": "=",
"timeRange": "=" "timeRange": "=",
"cancel": "&",
} }
}; };
} }
......
...@@ -9,31 +9,30 @@ ...@@ -9,31 +9,30 @@
</div> </div>
<!-- single event --> <!-- single event -->
<div ng-if="!ctrl.annotation.isRegion"> <div ng-if="!ctrl.annotation.isRegion">
<div class="gf-form-inline"> <div class="gf-form">
<div class="gf-form"> <span class="gf-form-label width-7">Time</span>
<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.annotation.time" class="gf-form-input max-width-20" input-datetime required> </div>
</div> </div>
</div> <!-- region event -->
</div> <div ng-if="ctrl.annotation.isRegion">
<!-- region event --> <div class="gf-form">
<div ng-if="ctrl.annotation.isRegion"> <span class="gf-form-label width-7">Start</span>
<div class="gf-form"> <input type="text" ng-model="ctrl.annotation.time" class="gf-form-input max-width-20" input-datetime required>
<span class="gf-form-label width-7">Start</span> </div>
<input type="text" ng-model="ctrl.annotation.time" class="gf-form-input max-width-20" input-datetime required> <div class="gf-form">
</div> <span class="gf-form-label width-7">End</span>
<div class="gf-form"> <input type="text" ng-model="ctrl.annotation.timeEnd" class="gf-form-input max-width-20" input-datetime required>
<span class="gf-form-label width-7">End</span> </div>
<input type="text" ng-model="ctrl.annotation.timeEnd" class="gf-form-input max-width-20" input-datetime required> </div>
</div> <div class="gf-form gf-form--v-stretch">
</div> <span class="gf-form-label width-7">Description</span>
<div class="gf-form gf-form--v-stretch"> <textarea class="gf-form-input width-20" rows="3" ng-model="ctrl.annotation.text" placeholder="Event description"></textarea>
<span class="gf-form-label width-7">Description</span> </div>
<textarea class="gf-form-input width-20" rows="3" ng-model="ctrl.annotation.text" placeholder="Event description"></textarea>
</div>
<div class="gf-form-button-row"> <div class="gf-form-button-row">
<button type="submit" class="btn gf-form-btn btn-success" ng-click="ctrl.save()">Save</button> <button type="submit" class="btn gf-form-btn btn-success" ng-click="ctrl.save()">Save</button>
</div> <a class="btn-text" ng-click="ctrl.cancel();">Cancel</a>
</div> </div>
</div>
</form> </form>
///<reference path="../../headers/common.d.ts" />
import angular from 'angular';
import moment from 'moment';
export class AddAnnotationModalCtrl {
timeFormat = 'YYYY-MM-DD HH:mm:ss';
annotation: any;
graphCtrl: any;
/** @ngInject */
constructor(private $scope) {
this.graphCtrl = $scope.ctrl;
$scope.ctrl = this;
let dashboardId = this.graphCtrl.dashboard.id;
let panelId = this.graphCtrl.panel.id;
this.annotation = {
dashboardId: dashboardId,
panelId: panelId,
time: null,
timeTo: null,
title: "",
text: ""
};
this.annotation.time = moment($scope.annotationTimeRange.from).format(this.timeFormat);0
if ($scope.annotationTimeRange.to) {
this.annotation.timeTo = moment($scope.annotationTimeRange.to).format(this.timeFormat);
}
}
addAnnotation() {
this.annotation.time = moment(this.annotation.time, this.timeFormat).valueOf();
if (this.annotation.timeTo) {
this.annotation.timeTo = moment(this.annotation.timeTo, this.timeFormat).valueOf();
}
this.graphCtrl.pushAnnotation(this.annotation)
.then(response => {
this.close();
})
.catch(error => {
console.log(error);
this.close();
});
}
close() {
this.$scope.dismiss();
}
}
angular
.module('grafana.controllers')
.controller('AddAnnotationModalCtrl', AddAnnotationModalCtrl);
...@@ -84,8 +84,8 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) { ...@@ -84,8 +84,8 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
element: elem[0], element: elem[0],
classNames: 'drop-popover drop-popover--form', classNames: 'drop-popover drop-popover--form',
position: 'bottom center', position: 'bottom center',
openOn: 'click', openOn: null,
template: '<event-editor panel-ctrl="panelCtrl" time-range="timeRange"></event-editor>', template: '<event-editor panel-ctrl="panelCtrl" time-range="timeRange" cancel="dismiss()"></event-editor>',
model: { model: {
timeRange: timeRange, timeRange: timeRange,
panelCtrl: ctrl, panelCtrl: ctrl,
......
...@@ -48,6 +48,7 @@ function (angular, _, $) { ...@@ -48,6 +48,7 @@ function (angular, _, $) {
element: el[0], element: el[0],
position: 'bottom center', position: 'bottom center',
template: '<gf-color-picker></gf-color-picker>', template: '<gf-color-picker></gf-color-picker>',
openOn: 'hover',
model: { model: {
series: series, series: series,
toggleAxis: function() { toggleAxis: function() {
......
...@@ -67,7 +67,6 @@ ...@@ -67,7 +67,6 @@
.modal-content { .modal-content {
padding: $spacer*2; padding: $spacer*2;
min-height: $spacer*15;
} }
// Remove bottom margin if need be // Remove bottom margin if need be
......
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