mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
create annotations work
This commit is contained in:
parent
2fce88ee62
commit
dbe5480edc
@ -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 {
|
|||||||
|
|
||||||
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';
|
|||||||
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) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
// 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 {
|
|||||||
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 {
|
|||||||
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';
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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() {
|
|||||||
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 @@
|
|||||||
</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>
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
///<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) {
|
|||||||
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, _, $) {
|
|||||||
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 @@
|
|||||||
|
|
||||||
.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
|
||||||
|
Loading…
Reference in New Issue
Block a user