Merge branch 'acknowledges' into develop

This commit is contained in:
Alexander Zobnin
2016-07-31 12:55:37 +03:00
5 changed files with 191 additions and 43 deletions

View File

@@ -114,6 +114,15 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) {
// Zabbix API method wrappers //
////////////////////////////////
acknowledgeEvent(eventid, message) {
var params = {
eventids: eventid,
message: message
};
return this.request('event.acknowledge', params);
}
getGroups() {
var params = {
output: ['name'],

View File

@@ -0,0 +1,113 @@
import angular from 'angular';
import $ from 'jquery';
import Drop from 'tether-drop';
/** @ngInject */
angular
.module('grafana.directives')
.directive('ackTooltip', function($sanitize, $compile) {
let buttonTemplate = '<a bs-tooltip="\'Acknowledges ({{trigger.acknowledges.length}})\'"' +
'<i ng-class="' +
"{'fa fa-comments': trigger.acknowledges.length, " +
"'fa fa-comments-o': !trigger.acknowledges.length, " +
'}"></i></a>';
return {
scope: {
ack: "=",
trigger: "=",
onAck: "=",
context: "="
},
link: function(scope, element) {
let acknowledges = scope.ack;
let $button = $(buttonTemplate);
$button.appendTo(element);
$button.click(function() {
let tooltip = '<div>';
if (acknowledges && acknowledges.length) {
tooltip += '<table class="table"><thead><tr>' +
'<th class="ack-time">Time</th>' +
'<th class="ack-user">User</th>' +
'<th class="ack-comments">Comments</th>' +
'</tr></thead><tbody>';
for (let ack of acknowledges) {
tooltip += '<tr><td>' + ack.time + '</td>' +
'<td>' + ack.user + '</td>' +
'<td>' + ack.message + '</td></tr>';
}
tooltip += '</tbody></table>';
} else {
tooltip += 'Add acknowledge';
}
let addAckButtonTemplate = '<div class="ack-add-button">' +
'<button id="add-acknowledge-btn"' +
'class="btn btn-mini btn-inverse gf-form-button">' +
'<i class="fa fa-plus"></i>' +
'</button></div>';
tooltip += addAckButtonTemplate;
tooltip += '</div>';
let drop = new Drop({
target: element[0],
content: tooltip,
position: "bottom left",
classes: 'drop-popover ack-tooltip',
openOn: 'hover',
hoverCloseDelay: 500,
tetherOptions: {
constraints: [{to: 'window', pin: true, attachment: "both"}]
}
});
drop.open();
drop.on('close', closeDrop);
$('#add-acknowledge-btn').on('click', onAddAckButtonClick);
function onAddAckButtonClick() {
let inputTemplate = '<div class="ack-input-group">' +
'<input type="text" id="ack-message">' +
'<button id="send-ack-button"' +
'class="btn btn-mini btn-inverse gf-form-button">' +
'Acknowledge </button>' +
'<button id="cancel-ack-button"' +
'class="btn btn-mini btn-inverse gf-form-button">' +
'Cancel' +
'</button></input></div>';
let $input = $(inputTemplate);
let $addAckButton = $('.ack-tooltip .ack-add-button');
$addAckButton.replaceWith($input);
$('.ack-tooltip #cancel-ack-button').on('click', onAckCancelButtonClick);
$('.ack-tooltip #send-ack-button').on('click', onAckSendlButtonClick);
}
function onAckCancelButtonClick() {
$('.ack-tooltip .ack-input-group').replaceWith(addAckButtonTemplate);
$('#add-acknowledge-btn').on('click', onAddAckButtonClick);
}
function onAckSendlButtonClick() {
let message = $('.ack-tooltip #ack-message')[0].value;
let onAck = scope.onAck.bind(scope.context);
onAck(scope.trigger, message).then(() => {
closeDrop();
});
}
function closeDrop() {
setTimeout(function() {
drop.destroy();
});
}
});
$compile(element.contents())(scope);
}
};
});

View File

@@ -31,21 +31,25 @@
</thead>
<tbody>
<tr ng-repeat="trigger in ctrl.triggerList">
<td ng-if="ctrl.panel.hostField">
<div>
<span><strong>{{trigger.host}}</strong></span>
</div>
</td>
<td ng-if="ctrl.panel.statusField" style="background-color: {{trigger.color}}; color: white">
<div>
{{ctrl.triggerStatusMap[trigger.value]}}
</div>
</td>
<td ng-if="ctrl.panel.severityField" style="background-color: {{trigger.color}}; color: white">
<div>
{{trigger.severity}}
</div>
</td>
<td style="background-color: {{trigger.color}}; color: white">
<div>
{{trigger.description}}
@@ -68,43 +72,16 @@
<small>{{trigger.comments}}</small>
</div>
</div>
</td>
<!-- Trigger acknowledges -->
<div class="collapse"
id="acknowledges-{{trigger.triggerid}}"
ng-if="trigger.showAcknowledges">
<div style="padding-top: 12px;">
<table class="table table-condensed">
<thead>
<tr>
<th><small>Time</small></th>
<th><small>User</small></th>
<th><small>Comments</small></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="ack in trigger.acknowledges">
<td>
<small>{{ack.time}}</small>
</td>
<td>
<small>{{ack.user}}</small>
</td>
<td>
<small>{{ack.message}}</small>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</td>
<td ng-if="ctrl.panel.lastChangeField">
{{trigger.lastchange}}
</td>
<td ng-if="ctrl.panel.ageField">
{{trigger.age}}
</td>
<td ng-if="ctrl.panel.infoField">
<!-- Trigger Url -->
@@ -121,12 +98,12 @@
</span>
<!-- Trigger acknowledges -->
<a ng-if="trigger.acknowledges"
role="button"
ng-click="ctrl.switchAcknowledges(trigger)"
bs-tooltip="'Acknowledges ({{trigger.acknowledges.length}})'">
<i class="fa fa-comments"></i>
</a>
<ack-tooltip
ack="trigger.acknowledges"
trigger="trigger"
on-ack="ctrl.acknowledgeTrigger"
context="ctrl">
</ack-tooltip>
</td>
</tr>
</tbody>

View File

@@ -16,6 +16,7 @@ import moment from 'moment';
import * as utils from '../datasource-zabbix/utils';
import {MetricsPanelCtrl} from 'app/plugins/sdk';
import {triggerPanelEditor} from './editor';
import './ack-tooltip.directive';
import './css/panel_triggers.css!';
var defaultSeverity = [
@@ -59,10 +60,11 @@ var defaultTimeFormat = "DD MMM YYYY HH:mm:ss";
class TriggerPanelCtrl extends MetricsPanelCtrl {
/** @ngInject */
constructor($scope, $injector, $q, $element, datasourceSrv, templateSrv) {
constructor($scope, $injector, $q, $element, datasourceSrv, templateSrv, contextSrv) {
super($scope, $injector);
this.datasourceSrv = datasourceSrv;
this.templateSrv = templateSrv;
this.contextSrv = contextSrv;
this.triggerStatusMap = triggerStatusMap;
this.defaultTimeFormat = defaultTimeFormat;
@@ -122,11 +124,11 @@ class TriggerPanelCtrl extends MetricsPanelCtrl {
showEvents)
.then(triggers => {
return _.map(triggers, trigger => {
var triggerObj = trigger;
let triggerObj = trigger;
// Format last change and age
trigger.lastchangeUnix = Number(trigger.lastchange);
var timestamp = moment.unix(trigger.lastchangeUnix);
let timestamp = moment.unix(trigger.lastchangeUnix);
if (self.panel.customLastChangeFormat) {
// User defined format
triggerObj.lastchange = timestamp.format(self.panel.lastChangeFormat);
@@ -171,8 +173,12 @@ class TriggerPanelCtrl extends MetricsPanelCtrl {
if (event) {
trigger.acknowledges = _.map(event.acknowledges, ack => {
var time = new Date(+ack.clock * 1000);
ack.time = time.toLocaleString();
let timestamp = moment.unix(ack.clock);
if (self.panel.customLastChangeFormat) {
ack.time = timestamp.format(self.panel.lastChangeFormat);
} else {
ack.time = timestamp.format(self.defaultTimeFormat);
}
ack.user = ack.alias + ' (' + ack.name + ' ' + ack.surname + ')';
return ack;
});
@@ -224,8 +230,17 @@ class TriggerPanelCtrl extends MetricsPanelCtrl {
trigger.showComment = !trigger.showComment;
}
switchAcknowledges(trigger) {
trigger.showAcknowledges = !trigger.showAcknowledges;
acknowledgeTrigger(trigger, message) {
let self = this;
let eventid = trigger.lastEvent.eventid;
let grafana_user = this.contextSrv.user.name;
let ack_message = grafana_user + ' (Grafana): ' + message;
return this.datasourceSrv.get(this.panel.datasource).then(datasource => {
let zabbix = datasource.zabbixAPI;
return zabbix.acknowledgeEvent(eventid, ack_message).then(() => {
self.refresh();
});
});
}
}

View File

@@ -106,3 +106,37 @@ $grafanaListAccent: lighten($dark-2, 2%);
height: 0px;
line-height: 0px;
}
.ack-tooltip {
.drop-content {
// Rewrite tooltip width
max-width: 70rem !important;
min-width: 30rem !important;
}
.ack-comments {
width: 60%;
}
.ack-add-button {
padding-top: 1rem;
}
table td, th {
padding-right: 1rem;
}
.ack-input-group {
padding-top: 1rem;
input {
border: 1px solid;
border-radius: 2px;
width: 50%;
}
button {
margin-left: 1rem;
}
}
}