Torkel Ödegaard преди 8 години
родител
ревизия
2fce88ee62

+ 26 - 0
pkg/services/sqlstore/migrations/annotation_category_mig.go

@@ -0,0 +1,26 @@
+package migrations
+
+import (
+	. "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
+)
+
+func addAnnotationCategoryMig(mg *Migrator) {
+	category := Table{
+		Name: "annotation_category",
+		Columns: []*Column{
+			{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
+			{Name: "org_id", Type: DB_BigInt, Nullable: false},
+			{Name: "user_id", Type: DB_BigInt, Nullable: true},
+			{Name: "name", Type: DB_Text, Nullable: false},
+		},
+		Indices: []*Index{
+			{Cols: []string{"org_id", "name"}, Type: IndexType},
+		},
+	}
+
+	// create table
+	mg.AddMigration("create annotation_category table", NewAddTableMigration(category))
+
+	// create indices
+	mg.AddMigration("add index org_id & name", NewAddIndexMigration(category, category.Indices[0]))
+}

+ 1 - 0
pkg/services/sqlstore/migrations/migrations.go

@@ -26,6 +26,7 @@ func AddMigrations(mg *Migrator) {
 	addAnnotationMig(mg)
 	addStatsMigrations(mg)
 	addTestDataMigrations(mg)
+	// addAnnotationCategoryMig(mg)
 }
 
 func addMigrationLogMigrations(mg *Migrator) {

+ 1 - 1
public/app/features/all.js

@@ -1,7 +1,7 @@
 define([
   './panellinks/module',
   './dashlinks/module',
-  './annotations/annotations_srv',
+  './annotations/all',
   './templating/all',
   './dashboard/all',
   './playlist/all',

+ 8 - 0
public/app/features/annotations/all.ts

@@ -0,0 +1,8 @@
+
+import {AnnotationsSrv} from './annotations_srv';
+import {eventEditor} from './event_editor';
+
+export {
+  AnnotationsSrv,
+  eventEditor
+};

+ 3 - 5
public/app/features/annotations/annotations_srv.ts

@@ -60,7 +60,7 @@ export class AnnotationsSrv {
     var panel = options.panel;
     var dashboard = options.dashboard;
 
-    if (panel && panel.alert) {
+    if (panel) {
       return this.backendSrv.get('/api/annotations', {
         from: options.range.from.valueOf(),
         to: options.range.to.valueOf(),
@@ -133,10 +133,8 @@ export class AnnotationsSrv {
     return this.globalAnnotationsPromise;
   }
 
-  postAnnotation(annotations) {
-    return Promise.all(_.map(annotations, annotation => {
-      return this.backendSrv.post('/api/annotations', annotation);
-    }));
+  postAnnotation(annotation) {
+    return this.backendSrv.post('/api/annotations', annotation);
   }
 
   translateQueryResult(annotation, results) {

+ 60 - 0
public/app/features/annotations/event_editor.ts

@@ -0,0 +1,60 @@
+///<reference path="../../headers/common.d.ts" />
+
+import _ from 'lodash';
+import moment from 'moment';
+import coreModule from 'app/core/core_module';
+import {MetricsPanelCtrl} from 'app/plugins/sdk';
+
+export class AnnotationItem {
+  dashboardId: number;
+  panelId: number;
+  time: Date;
+  timeEnd: Date;
+  isRegion: boolean;
+  title: string;
+  text: string;
+}
+
+export class EventEditorCtrl {
+  panelCtrl: MetricsPanelCtrl;
+  timeFormat = 'YYYY-MM-DD HH:mm:ss';
+  annotation: AnnotationItem;
+  timeRange: {from: number, to: number};
+  form: any;
+
+  /** @ngInject **/
+  constructor() {
+    this.annotation = new AnnotationItem();
+    this.annotation.panelId = this.panelCtrl.panel.id;
+    this.annotation.dashboardId = this.panelCtrl.dashboard.id;
+    this.annotation.text = "hello";
+
+    this.annotation.time = moment(this.timeRange.from);
+    if (this.timeRange.to) {
+      this.annotation.timeEnd = moment(this.timeRange.to);
+      this.annotation.isRegion = true;
+    }
+  }
+
+  save() {
+    if (!this.form.$valid) {
+      return;
+    }
+  }
+}
+
+export function eventEditor() {
+  return {
+    restrict: 'E',
+    controller: EventEditorCtrl,
+    bindToController: true,
+    controllerAs: 'ctrl',
+    templateUrl: 'public/app/features/annotations/partials/event_editor.html',
+    scope: {
+      "panelCtrl": "=",
+      "timeRange": "="
+    }
+  };
+}
+
+coreModule.directive('eventEditor', eventEditor);

+ 39 - 0
public/app/features/annotations/partials/event_editor.html

@@ -0,0 +1,39 @@
+
+<h5 class="section-heading text-center">Add annotation</h5>
+
+<form name="ctrl.form" class="text-center">
+	<div class="gf-form-group" 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>
+		</div>
+		<!-- single event -->
+		<div ng-if="!ctrl.annotation.isRegion">
+			<div class="gf-form-inline">
+				<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>
+				</div>
+			</div>
+		</div>
+		<!-- region event -->
+		<div ng-if="ctrl.annotation.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>
+			</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>
+			</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>
+		</div>
+
+		<div class="gf-form-button-row">
+			<button type="submit" class="btn gf-form-btn btn-success" ng-click="ctrl.save()">Save</button>
+		</div>
+	</div>
+</form>

+ 18 - 32
public/app/features/dashboard/addAnnotationModalCtrl.ts

@@ -4,12 +4,8 @@ import angular from 'angular';
 import moment from 'moment';
 
 export class AddAnnotationModalCtrl {
-  annotationTimeFormat = 'YYYY-MM-DD HH:mm:ss';
-  annotationTimeFrom: any;
-  annotationTimeTo: any = null;
-  annotationTitle: string;
-  annotationTextFrom: string;
-  annotationTextTo: string;
+  timeFormat = 'YYYY-MM-DD HH:mm:ss';
+  annotation: any;
   graphCtrl: any;
 
   /** @ngInject */
@@ -17,41 +13,31 @@ export class AddAnnotationModalCtrl {
     this.graphCtrl = $scope.ctrl;
     $scope.ctrl = this;
 
-    this.annotationTimeFrom = moment($scope.annotationTimeRange.from).format(this.annotationTimeFormat);
-    if ($scope.annotationTimeRange.to) {
-      this.annotationTimeTo = moment($scope.annotationTimeRange.to).format(this.annotationTimeFormat);
-    }
-  }
-
-  addAnnotation() {
     let dashboardId = this.graphCtrl.dashboard.id;
     let panelId = this.graphCtrl.panel.id;
-    let timeFrom = moment(this.annotationTimeFrom, this.annotationTimeFormat).valueOf();
-
-    let annotationFrom = {
+    this.annotation = {
       dashboardId: dashboardId,
       panelId: panelId,
-      time: timeFrom,
-      title: this.annotationTitle,
-      text: this.annotationTextFrom
+      time: null,
+      timeTo: null,
+      title: "",
+      text: ""
     };
-    let annotations = [annotationFrom];
 
-    if (this.annotationTimeTo) {
-      let timeTo = moment(this.annotationTimeTo, this.annotationTimeFormat).valueOf();
-      let annotationTo = {
-        dashboardId: dashboardId,
-        panelId: panelId,
-        time: timeTo,
-        title: this.annotationTitle,
-        text: this.annotationTextTo
-      };
-      annotations.push(annotationTo);
+    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.pushAnnotations(annotations)
+    this.graphCtrl.pushAnnotation(this.annotation)
     .then(response => {
-      console.log(response);
       this.close();
     })
     .catch(error => {

+ 0 - 1
public/app/features/dashboard/all.js

@@ -22,5 +22,4 @@ define([
   './ad_hoc_filters',
   './row/row_ctrl',
   './repeat_option/repeat_option',
-  './event_editor',
 ], function () {});

+ 0 - 22
public/app/features/dashboard/event_editor.ts

@@ -1,22 +0,0 @@
-///<reference path="../../headers/common.d.ts" />
-
-import _ from 'lodash';
-import coreModule from 'app/core/core_module';
-
-export class EventEditorCtrl {
-  /** @ngInject */
-  constructor() {
-  }
-}
-
-export function eventEditor() {
-  return {
-    restrict: 'E',
-    controller: EventEditorCtrl,
-    bindToController: true,
-    controllerAs: 'ctrl',
-    templateUrl: 'public/app/features/dashboard/partials/event_editor.html',
-  };
-}
-
-coreModule.directive('eventEditor', eventEditor);

+ 8 - 21
public/app/features/dashboard/partials/addAnnotationModal.html

@@ -28,38 +28,25 @@
 
             <div class="gf-form">
               <span class="gf-form-label width-8">Title</span>
-              <input type="text" ng-model="ctrl.annotationTitle" class="gf-form-input max-width-20">
+              <input type="text" ng-model="ctrl.annotation.title" class="gf-form-input max-width-20">
             </div>
             <div class="gf-form">
-              <span class="gf-form-label width-8" ng-if="!ctrl.annotationTimeTo">Time</span>
-              <span class="gf-form-label width-8" ng-if="ctrl.annotationTimeTo">Time Start</span>
-              <input type="text" ng-model="ctrl.annotationTimeFrom" class="gf-form-input max-width-20">
+              <span class="gf-form-label width-8" ng-if="!ctrl.annotation.timeTo">Time</span>
+              <span class="gf-form-label width-8" ng-if="ctrl.annotation.timeTo">Time Start</span>
+              <input type="text" ng-model="ctrl.annotation.time" class="gf-form-input max-width-20">
             </div>
-            <div class="gf-form" ng-if="ctrl.annotationTimeTo">
+            <div class="gf-form" ng-if="ctrl.annotation.timeTo">
               <span class="gf-form-label width-8">Time Stop</span>
-              <input type="text" ng-model="ctrl.annotationTimeTo" class="gf-form-input max-width-20">
+              <input type="text" ng-model="ctrl.annotation.timeTo" class="gf-form-input max-width-20">
             </div>
           </div>
 
           <div>
-            <h6 ng-if="!ctrl.annotationTimeTo">Description</h6>
-            <h6 ng-if="ctrl.annotationTimeTo">Description Start</h6>
+            <h6>Description</h6>
           </div>
           <div class="gf-form-group share-modal-options">
             <div class="gf-form">
-              <textarea rows="3" class="gf-form-input width-27" ng-model="ctrl.annotationTextFrom"></textarea>
-            </div>
-          </div>
-
-
-          <div ng-if="ctrl.annotationTimeTo">
-            <div>
-              <h6>Description Stop</h6>
-            </div>
-            <div class="gf-form-group share-modal-options">
-              <div class="gf-form">
-                <textarea rows="3" class="gf-form-input width-27" ng-model="ctrl.annotationTextTo"></textarea>
-              </div>
+              <textarea rows="3" class="gf-form-input width-27" ng-model="ctrl.annotation.text"></textarea>
             </div>
           </div>
 

+ 0 - 27
public/app/features/dashboard/partials/event_editor.html

@@ -1,27 +0,0 @@
-
-<h5 class="section-heading text-center">Create event</h5>
-
-<div class="text-center">
-	<div class="gf-form-group" style="display: inline-block">
-		<div class="gf-form">
-			<span class="gf-form-label width-7">Title</span>
-			<input type="text" ng-model="ctrl.event.title" class="gf-form-input max-width-20">
-		</div>
-		<div class="gf-form">
-			<span class="gf-form-label width-7">Time</span>
-			<input type="text" ng-model="ctrl.event.time" class="gf-form-input max-width-20">
-		</div>
-		<div class="gf-form" ng-if="ctrl.event.isRegion">
-			<span class="gf-form-label width-7">To</span>
-			<input type="text" ng-model="ctrl.event.endTime" class="gf-form-input max-width-20">
-		</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.event.description"  placeholder="Event description"></textarea>
-		</div>
-
-		<div class="gf-form-button-row">
-			<button class="btn gf-form-btn btn-success" ng-click="ctrl.addAnnotation()">Save</button>
-		</div>
-	</div>
-</div>

+ 11 - 21
public/app/plugins/panel/graph/graph.ts

@@ -79,29 +79,13 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
         }
       }, scope);
 
-      appEvents.on('graph-click', (event) => {
-        // Add event only for selected panel
-        let thisPanelEvent = event.panel.id === ctrl.panel.id;
-
-        // Select time for new annotation
-        let createAnnotation = event.pos.ctrlKey || event.pos.metaKey;
-        if (createAnnotation && thisPanelEvent) {
-          let timeRange = {
-            from: event.pos.x,
-            to: null
-          };
-
-          showAddAnnotationView(timeRange);
-        }
-      }, scope);
-
       function showAddAnnotationView(timeRange) {
         popoverSrv.show({
           element: elem[0],
           classNames: 'drop-popover drop-popover--form',
           position: 'bottom center',
           openOn: 'click',
-          template: '<event-editor panelCtrl="ctrl" timeRange="timeRange"></event-editor>',
+          template: '<event-editor panel-ctrl="panelCtrl" time-range="timeRange"></event-editor>',
           model: {
             timeRange: timeRange,
             panelCtrl: ctrl,
@@ -670,10 +654,7 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
 
       elem.bind("plotselected", function (event, ranges) {
         if (ranges.ctrlKey || ranges.metaKey) {
-          // Create new annotation from time range
-          let timeRange = ranges.xaxis;
-          showAddAnnotationView(timeRange);
-          //plot.clearSelection();
+          showAddAnnotationView(ranges.xaxis);
         } else {
           scope.$apply(function() {
             timeSrv.setTime({
@@ -684,6 +665,15 @@ 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});
+        }
+      });
+
       scope.$on('$destroy', function() {
         tooltip.destroy();
         elem.off();

+ 0 - 15
public/app/plugins/panel/graph/module.ts

@@ -306,21 +306,6 @@ class GraphCtrl extends MetricsPanelCtrl {
     alert('selection region while holding down CTRL or CMD');
   }
 
-  // Get annotation info from dialog and push it to backend
-  pushAnnotations(annotations) {
-    return this.annotationsSrv.postAnnotation(annotations);
-  }
-
-  showAddAnnotationModal(timeRange) {
-    let addAnnotationScope = this.$scope.$new();
-    addAnnotationScope.annotationTimeRange = timeRange;
-
-    this.publishAppEvent('show-modal', {
-      src: 'public/app/features/dashboard/partials/addAnnotationModal.html',
-      scope: addAnnotationScope
-    });
-  }
-
   legendValuesOptionChanged() {
     var legend = this.panel.legend;
     legend.values = legend.min || legend.max || legend.avg || legend.current || legend.total;