Commit 6cb1dafb by Torkel Ödegaard

feat(alerting): progress on notifications

parent 8df558de
......@@ -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},
......
......@@ -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',
......
......@@ -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');
......
......@@ -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');
});
}
}
}
......
......@@ -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;
});
});
}
}
......
<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" >
......
<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>
......
<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" >
......
......@@ -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 || {};
......
......@@ -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>
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