瀏覽代碼

feat(alerting): progress on notifications

Torkel Ödegaard 9 年之前
父節點
當前提交
6cb1dafb1d

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

@@ -65,7 +65,6 @@ func addAlertMigrations(mg *Migrator) {
 			{Name: "org_id", Type: DB_BigInt, Nullable: false},
 			{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false},
 			{Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false},
-			{Name: "always_execute", Type: DB_Bool, Nullable: false},
 			{Name: "settings", Type: DB_Text, Nullable: false},
 			{Name: "created", Type: DB_DateTime, Nullable: false},
 			{Name: "updated", Type: DB_DateTime, Nullable: false},

+ 1 - 1
public/app/core/routes/routes.ts

@@ -211,7 +211,7 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
     controllerAs: 'ctrl',
     resolve: loadAlertingBundle,
   })
-  .when('/alerting/notification/:notificationId/edit', {
+  .when('/alerting/notification/:id/edit', {
     templateUrl: 'public/app/features/alerting/partials/notification_edit.html',
     controller: 'AlertNotificationEditCtrl',
     controllerAs: 'ctrl',

+ 0 - 1
public/app/features/alerting/alerts_ctrl.ts

@@ -27,7 +27,6 @@ export class AlertListCtrl {
 
   updateFilter() {
     var stats = [];
-
     this.filter.ok && stats.push('OK');
     this.filter.warn && stats.push('Warn');
     this.filter.critical && stats.push('critical');

+ 17 - 27
public/app/features/alerting/notification_edit_ctrl.ts

@@ -6,49 +6,39 @@ import coreModule from '../../core/core_module';
 import config from 'app/core/config';
 
 export class AlertNotificationEditCtrl {
-
-  notification: any;
+  model: any;
 
   /** @ngInject */
-  constructor(private $routeParams, private backendSrv, private $scope) {
-    if ($routeParams.notificationId) {
-      this.loadNotification($routeParams.notificationId);
+  constructor(private $routeParams, private backendSrv, private $scope, private $location) {
+    if ($routeParams.id) {
+      this.loadNotification($routeParams.id);
     } else {
-      this.notification = {
+      this.model = {
         type: 'email',
+        settings: {}
       };
     }
   }
 
-  loadNotification(notificationId) {
-    this.backendSrv.get(`/api/alert-notifications/${notificationId}`).then(result => {
-      console.log(result);
-      this.notification = result;
+  loadNotification(id) {
+    this.backendSrv.get(`/api/alert-notifications/${id}`).then(result => {
+      this.model = result;
     });
   }
 
   isNew() {
-    return this.notification === undefined || this.notification.id === undefined;
+    return this.model.id === undefined;
   }
 
   save() {
-    if (this.notification.id) {
-      console.log('this.notification: ', this.notification);
-      this.backendSrv.put(`/api/alert-notifications/${this.notification.id}`, this.notification)
-        .then(result => {
-          this.notification = result;
-          this.$scope.appEvent('alert-success', ['Notification created!', '']);
-        }, () => {
-          this.$scope.appEvent('alert-error', ['Unable to create notification.', '']);
-        });
+    if (this.model.id) {
+      this.backendSrv.put(`/api/alert-notifications/${this.model.id}`, this.model).then(res => {
+        this.model = res;
+      });
     } else {
-      this.backendSrv.post(`/api/alert-notifications`, this.notification)
-        .then(result => {
-          this.notification = result;
-          this.$scope.appEvent('alert-success', ['Notification updated!', '']);
-        }, () => {
-          this.$scope.appEvent('alert-error', ['Unable to update notification.', '']);
-        });
+      this.backendSrv.post(`/api/alert-notifications`, this.model).then(res => {
+        this.$location.path('alerting/notification/' + res.id + '/edit');
+      });
     }
   }
 }

+ 5 - 9
public/app/features/alerting/notifications_list_ctrl.ts

@@ -20,16 +20,12 @@ export class AlertNotificationsListCtrl {
     });
   }
 
-  deleteNotification(notificationId) {
-    this.backendSrv.delete(`/api/alerts-notification/${notificationId}`)
-      .then(() => {
-        this.notifications = this.notifications.filter(notification => {
-          return notification.id !== notificationId;
-        });
-        this.$scope.appEvent('alert-success', ['Notification deleted', '']);
-      }, () => {
-        this.$scope.appEvent('alert-error', ['Unable to delete notification', '']);
+  deleteNotification(id) {
+    this.backendSrv.delete(`/api/alert-notifications/${id}`).then(() => {
+      this.notifications = this.notifications.filter(notification => {
+        return notification.id !== notificationId;
       });
+    });
   }
 }
 

+ 1 - 1
public/app/features/alerting/partials/alert_list.html

@@ -1,4 +1,4 @@
-<navbar icon="fa fa-fw fa-list" title="Alerting" title-url="alerting">
+<navbar icon="icon-gf icon-gf-monitoring" title="Alerting" title-url="alerting">
 </navbar>
 
 <div class="page-container" >

+ 14 - 9
public/app/features/alerting/partials/notification_edit.html

@@ -1,4 +1,8 @@
-<navbar icon="fa fa-fw fa-list" title="Alerting" title-url="alerting">
+<navbar icon="icon-gf icon-gf-monitoring" title="Alerting" title-url="alerting">
+	<a href="alerting/notifications" class="navbar-page-btn">
+		<i class="fa fa-fw fa-envelope-o"></i>
+		Notifications
+	</a>
 </navbar>
 
 <div class="page-container" >
@@ -9,13 +13,13 @@
 	<div class="gf-form-group">
 		<div class="gf-form">
 			<span class="gf-form-label width-8">Name</span>
-			<input type="text" class="gf-form-input max-width-15" ng-model="ctrl.notification.name" required></input>
+			<input type="text" class="gf-form-input max-width-15" ng-model="ctrl.model.name" required></input>
 		</div>
 		<div class="gf-form">
 			<span class="gf-form-label width-8">Type</span>
 			<div class="gf-form-select-wrapper width-15">
 				<select class="gf-form-input"
-					ng-model="ctrl.notification.type"
+					ng-model="ctrl.model.type"
 					ng-options="t for t in ['webhook', 'email']"
 					ng-change="ctrl.typeChanged(notification, $index)">
 				</select>
@@ -23,27 +27,28 @@
 		</div>
 	</div>
 
-	<div class="gf-form-group" ng-show="ctrl.notification.type === 'webhook'">
+	<div class="gf-form-group" ng-show="ctrl.model.type === 'webhook'">
     <h3 class="page-heading">Webhook settings</h3>
 		<div class="gf-form">
 			<span class="gf-form-label width-6">Url</span>
-			<input type="text" class="gf-form-input max-width-26" ng-model="ctrl.notification.settings.url"></input>
+			<input type="text" class="gf-form-input max-width-26" ng-model="ctrl.model.settings.url"></input>
 		</div>
 		<div class="gf-form-inline">
 			<div class="gf-form">
 				<span class="gf-form-label width-6">Username</span>
-				<input type="text" class="gf-form-input max-width-10" ng-model="ctrl.notification.settings.username"></input>
+				<input type="text" class="gf-form-input max-width-10" ng-model="ctrl.model.settings.username"></input>
 			</div>
 			<div class="gf-form">
 				<span class="gf-form-label width-6">Password</span>
-				<input type="text" class="gf-form-input max-width-10" ng-model="ctrl.notification.settings.password"></input>
+				<input type="text" class="gf-form-input max-width-10" ng-model="ctrl.model.settings.password"></input>
 			</div>
 		</div>
 	</div>
-	<div class="gf-form-group section" ng-show="ctrl.notification.type === 'email'">
+
+	<div class="gf-form-group section" ng-show="ctrl.model.type === 'email'">
     <h3 class="page-heading">Email addresses</h3>
 		<div class="gf-form">
-      <textarea rows="7" class="gf-form-input width-25" ng-ctrl="ctrl.notification.settings.addresses"></textarea>
+      <textarea rows="7" class="gf-form-input width-25" ng-model="ctrl.model.settings.addresses"></textarea>
 		</div>
 	</div>
 

+ 5 - 1
public/app/features/alerting/partials/notifications_list.html

@@ -1,4 +1,8 @@
-<navbar icon="fa fa-fw fa-list" title="Alerting" title-url="alerting">
+<navbar icon="icon-gf icon-gf-monitoring" title="Alerting" title-url="alerting">
+	<a href="alerting/notifications" class="navbar-page-btn">
+		<i class="fa fa-fw fa-envelope-o"></i>
+		Notifications
+	</a>
 </navbar>
 
 <div class="page-container" >

+ 26 - 1
public/app/plugins/panel/graph/alert_tab_ctrl.ts

@@ -49,14 +49,17 @@ export class AlertTabCtrl {
     {text: 'Critical', value: 'critical'},
     {text: 'Warning', value: 'warning'},
   ];
+  addNotificationSegment;
 
   /** @ngInject */
-  constructor($scope, private $timeout, private backendSrv, private dashboardSrv) {
+  constructor($scope, private $timeout, private backendSrv, private dashboardSrv, private uiSegmentSrv) {
     this.panelCtrl = $scope.ctrl;
     this.panel = this.panelCtrl.panel;
     $scope.ctrl = this;
 
     this.metricTargets = this.panel.targets.map(val => val);
+    this.addNotificationSegment = uiSegmentSrv.newPlusButton();
+
     this.initModel();
 
     // set panel alert edit mode
@@ -66,6 +69,28 @@ export class AlertTabCtrl {
     });
   }
 
+  getNotifications() {
+    return this.backendSrv.get('/api/alert-notifications').then(res => {
+      return res.map(item => {
+        return this.uiSegmentSrv.newSegment(item.name);
+      });
+    });
+  }
+
+  notificationAdded() {
+    this.alert.notifications.push({
+      name: this.addNotificationSegment.value
+    });
+
+    // reset plus button
+    this.addNotificationSegment.value = this.uiSegmentSrv.newPlusButton().value;
+    this.addNotificationSegment.html = this.uiSegmentSrv.newPlusButton().html;
+  }
+
+  removeNotification(index) {
+    this.alert.notifications.splice(index, 1);
+  }
+
   initModel() {
     var alert = this.alert = this.panel.alert = this.panel.alert || {};
 

+ 68 - 73
public/app/plugins/panel/graph/partials/tab_alerting.html

@@ -24,53 +24,33 @@
 <!-- </div> -->
 
 <div ng-if="ctrl.alert.enabled">
-  <div class="gf-form-group">
-    <h5 class="section-heading">Alert Rule</h5>
-    <div class="gf-form-inline">
-      <div class="gf-form max-width-30">
-        <span class="gf-form-label width-8">Name</span>
-        <input type="text" class="gf-form-input width-22" ng-model="ctrl.alert.name">
-      </div>
-      <!-- <div class="gf&#45;form"> -->
-      <!--   <span class="gf&#45;form&#45;label width&#45;6">Handler</span> -->
-      <!--   <div class="gf&#45;form&#45;select&#45;wrapper"> -->
-      <!--     <select   class="gf&#45;form&#45;input" -->
-      <!--               ng&#45;model="ctrl.alert.handler" -->
-      <!--               ng&#45;options="f.value as f.text for f in ctrl.handlers"> -->
-      <!--     </select> -->
-      <!--   </div> -->
-      <!-- </div> -->
-      <div class="gf-form">
-        <span class="gf-form-label width-8">Evaluate every</span>
-        <input class="gf-form-input max-width-7" type="text" ng-model="ctrl.alert.frequency"></input>
-      </div>
-    </div>
-    <div class="gf-form-inline">
-      <div class="gf-form max-width-30">
-        <span class="gf-form-label width-8">Notifications</span>
-        <input class="gf-form-input max-width-22" type="text" ng-model="ctrl.alert.notifications"></input>
-      </div>
-      <!--
-        <bootstrap-tagsinput ng-model="ctrl.alert.notify" tagclass="label label-tag" placeholder="add tags">
-        </bootstrap-tagsinput>
-      -->
-      <div class="gf-form">
-        <span class="gf-form-label width-8">Severity</span>
-        <div class="gf-form-select-wrapper">
-          <select   class="gf-form-input"
-                    ng-model="ctrl.alert.severity"
-                    ng-options="f.value as f.text for f in ctrl.severityLevels">
-          </select>
-        </div>
-      </div>
-    </div>
-  </div>
+	<div class="gf-form-group">
+		<h5 class="section-heading">Alert Rule</h5>
+		<div class="gf-form-inline">
+			<div class="gf-form">
+				<span class="gf-form-label">Name</span>
+				<input type="text" class="gf-form-input width-22" ng-model="ctrl.alert.name">
+			</div>
+			<div class="gf-form">
+				<span class="gf-form-label">Evaluate every</span>
+				<input class="gf-form-input max-width-7" type="text" ng-model="ctrl.alert.frequency"></input>
+			</div>
+			<div class="gf-form">
+				<span class="gf-form-label">Severity</span>
+				<div class="gf-form-select-wrapper">
+					<select class="gf-form-input" ng-model="ctrl.alert.severity" ng-options="f.value as f.text for f in ctrl.severityLevels">
+					</select>
+				</div>
+			</div>
+		</div>
+	</div>
 
   <div class="gf-form-group">
     <h5 class="section-heading">Conditions</h5>
     <div class="gf-form-inline" ng-repeat="conditionModel in ctrl.conditionModels">
       <div class="gf-form">
-        <span class="gf-form-label query-keyword">AND</span>
+				<span class="gf-form-label query-keyword width-5" ng-if="$index">AND</span>
+				<span class="gf-form-label query-keyword width-5" ng-if="$index===0">WHEN</span>
       </div>
       <div class="gf-form">
         <query-part-editor
@@ -88,7 +68,7 @@
         </query-part-editor>
       </div>
       <div class="gf-form">
-        <span class="gf-form-label">When Value</span>
+        <span class="gf-form-label">Value</span>
         <metric-segment-model property="conditionModel.evaluator.type" options="ctrl.evalFunctions" custom="false" css-class="query-segment-operator" on-change="ctrl.thresholdUpdated()"></metric-segment-model>
         <input class="gf-form-input max-width-7" type="number" ng-model="conditionModel.evaluator.params[0]" ng-change="ctrl.thresholdsUpdated()"></input>
       </div>
@@ -98,48 +78,63 @@
             <i class="fa fa-trash"></i>
           </a>
         </label>
-      </div>
+			</div>
     </div>
-  </div>
 
-  <div class="gf-form-group">
-    <div class="gf-form-button-row">
-      <div class="dropdown pull-left" ng-if="ctrl.alert.enabled" >
-        <button class="btn btn-inverse dropdown-toggle" data-toggle="dropdown">
-          <i class="fa fa-plus"></i>&nbsp;Add Condition
-        </button>
+		<div class="gf-form">
+			<label class="gf-form-label dropdown">
+				<a class="pointer dropdown-toggle" data-toggle="dropdown">
+					<i class="fa fa-plus"></i>
+				</a>
+				<ul class="dropdown-menu" role="menu">
+					<li ng-repeat="ct in ctrl.conditionTypes" role="menuitem">
+						<a ng-click="ctrl.addCondition(ct.value);">{{ct.text}}</a>
+					</li>
+				</ul>
+			</label>
+		</div>
+	</div>
 
-        <ul class="dropdown-menu" role="menu">
-          <li ng-repeat="ct in ctrl.conditionTypes" role="menuitem">
-            <a ng-click="ctrl.addCondition(ct.value);">{{ct.text}}</a>
-          </li>
-        </ul>
-      </div>
+	<div class="gf-form-group">
+		<h5 class="section-heading">Notifications</h5>
+		<div class="gf-form-inline">
+			<div class="gf-form max-width-30">
+				<span class="gf-form-label" ng-repeat="nc in ctrl.alert.notifications">
+					{{nc.name}}
+					<i class="fa fa-remove pointer" ng-click="ctrl.removeNotification($index)"></i>
+				</span>
+				<metric-segment segment="ctrl.addNotificationSegment" get-options="ctrl.getNotifications()" on-change="ctrl.notificationAdded()"></metric-segment>
+			</div>
+		</div>
+	</div>
 
-      <button class="btn btn-inverse" ng-click="ctrl.test()">
-        Test Rule
-      </button>
+	<div class="gf-form-group">
+		<div class="gf-form-button-row">
+			<button class="btn btn-inverse" ng-click="ctrl.test()">
+				Test Rule
+			</button>
+
+			<button class="btn btn-inverse" ng-click="ctrl.delete()">
+				Delete Alert
+			</button>
+		</div>
+	</div>
 
-      <button class="btn btn-inverse" ng-click="ctrl.delete()">
-        Delete Alert
-      </button>
-    </div>
-  </div>
 </div>
 
 <div class="gf-form-group" ng-if="ctrl.testing">
-  Evaluating rule <i class="fa fa-spinner fa-spin"></i>
+	Evaluating rule <i class="fa fa-spinner fa-spin"></i>
 </div>
 
 <div class="gf-form-group" ng-if="ctrl.testResult">
-  <json-tree root-name="result" object="ctrl.testResult" start-expanded="true"></json-tree>
+	<json-tree root-name="result" object="ctrl.testResult" start-expanded="true"></json-tree>
 </div>
 
 <div class="gf-form-group" ng-if="!ctrl.alert.enabled">
-  <div class="gf-form-button-row">
-    <button class="btn btn-inverse" ng-click="ctrl.enable()">
-      <i class="icon-gf icon-gf-alert"></i>
-      Create Alert
-    </button>
-  </div>
+	<div class="gf-form-button-row">
+		<button class="btn btn-inverse" ng-click="ctrl.enable()">
+			<i class="icon-gf icon-gf-alert"></i>
+			Create Alert
+		</button>
+	</div>
 </div>