Acknowledges: use tooltip instead inner table.
This commit is contained in:
@@ -47,7 +47,6 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) {
|
|||||||
},
|
},
|
||||||
// Handle API errors
|
// Handle API errors
|
||||||
function(error) {
|
function(error) {
|
||||||
console.log('Zabbix error: '+error.data);
|
|
||||||
if (isNotAuthorized(error.data)) {
|
if (isNotAuthorized(error.data)) {
|
||||||
return self.loginOnce().then(
|
return self.loginOnce().then(
|
||||||
function() {
|
function() {
|
||||||
@@ -114,11 +113,13 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) {
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Zabbix API method wrappers //
|
// Zabbix API method wrappers //
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
acknowledgeEvent(eventid, message) {
|
acknowledgeEvent(eventid, message) {
|
||||||
var params = {
|
var params = {
|
||||||
eventids: eventid,
|
eventids: eventid,
|
||||||
message: message
|
message: message
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.request('event.acknowledge', params);
|
return this.request('event.acknowledge', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
113
src/panel-triggers/ack-tooltip.directive.js
Normal file
113
src/panel-triggers/ack-tooltip.directive.js
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -31,21 +31,25 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="trigger in ctrl.triggerList">
|
<tr ng-repeat="trigger in ctrl.triggerList">
|
||||||
|
|
||||||
<td ng-if="ctrl.panel.hostField">
|
<td ng-if="ctrl.panel.hostField">
|
||||||
<div>
|
<div>
|
||||||
<span><strong>{{trigger.host}}</strong></span>
|
<span><strong>{{trigger.host}}</strong></span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td ng-if="ctrl.panel.statusField" style="background-color: {{trigger.color}}; color: white">
|
<td ng-if="ctrl.panel.statusField" style="background-color: {{trigger.color}}; color: white">
|
||||||
<div>
|
<div>
|
||||||
{{ctrl.triggerStatusMap[trigger.value]}}
|
{{ctrl.triggerStatusMap[trigger.value]}}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td ng-if="ctrl.panel.severityField" style="background-color: {{trigger.color}}; color: white">
|
<td ng-if="ctrl.panel.severityField" style="background-color: {{trigger.color}}; color: white">
|
||||||
<div>
|
<div>
|
||||||
{{trigger.severity}}
|
{{trigger.severity}}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td style="background-color: {{trigger.color}}; color: white">
|
<td style="background-color: {{trigger.color}}; color: white">
|
||||||
<div>
|
<div>
|
||||||
{{trigger.description}}
|
{{trigger.description}}
|
||||||
@@ -68,52 +72,16 @@
|
|||||||
<small>{{trigger.comments}}</small>
|
<small>{{trigger.comments}}</small>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
|
||||||
<tr ng-if="trigger.newAct">
|
|
||||||
<td>
|
|
||||||
<small>{{trigger.newAct.time}}</small>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<small>{{trigger.newAct.user}}</small>
|
|
||||||
</td>
|
|
||||||
<td><input ng-model="trigger.newAct.message" size="80" ng-blur="ctrl.acknowledgeTrigger({keyCode:13},trigger,trigger.newAct)" ng-keyup="ctrl.acknowledgeTrigger($event,trigger,trigger.newAct)"/></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td ng-if="ctrl.panel.lastChangeField">
|
<td ng-if="ctrl.panel.lastChangeField">
|
||||||
{{trigger.lastchange}}
|
{{trigger.lastchange}}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td ng-if="ctrl.panel.ageField">
|
<td ng-if="ctrl.panel.ageField">
|
||||||
{{trigger.age}}
|
{{trigger.age}}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td ng-if="ctrl.panel.infoField">
|
<td ng-if="ctrl.panel.infoField">
|
||||||
|
|
||||||
<!-- Trigger Url -->
|
<!-- Trigger Url -->
|
||||||
@@ -130,20 +98,12 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- Trigger acknowledges -->
|
<!-- Trigger acknowledges -->
|
||||||
<a ng-if="trigger.acknowledges"
|
<ack-tooltip
|
||||||
role="button"
|
ack="trigger.acknowledges"
|
||||||
ng-click="ctrl.switchAcknowledges(trigger)"
|
trigger="trigger"
|
||||||
bs-tooltip="'Acknowledges ({{trigger.acknowledges.length}})'">
|
on-ack="ctrl.acknowledgeTrigger"
|
||||||
<i class="fa fa-comments"></i>
|
context="ctrl">
|
||||||
</a>
|
</ack-tooltip>
|
||||||
|
|
||||||
<!-- Acknowledge events -->
|
|
||||||
<a ng-if="trigger.acknowledges === undefined"
|
|
||||||
role="button"
|
|
||||||
ng-click="ctrl.addAcknowledgeMessage(trigger)"
|
|
||||||
bs-tooltip="'acknowledge this event'">
|
|
||||||
<i class="fa fa-comments-o"></i>
|
|
||||||
</a>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import moment from 'moment';
|
|||||||
import * as utils from '../datasource-zabbix/utils';
|
import * as utils from '../datasource-zabbix/utils';
|
||||||
import {MetricsPanelCtrl} from 'app/plugins/sdk';
|
import {MetricsPanelCtrl} from 'app/plugins/sdk';
|
||||||
import {triggerPanelEditor} from './editor';
|
import {triggerPanelEditor} from './editor';
|
||||||
|
import './ack-tooltip.directive';
|
||||||
import './css/panel_triggers.css!';
|
import './css/panel_triggers.css!';
|
||||||
|
|
||||||
var defaultSeverity = [
|
var defaultSeverity = [
|
||||||
@@ -123,11 +124,11 @@ class TriggerPanelCtrl extends MetricsPanelCtrl {
|
|||||||
showEvents)
|
showEvents)
|
||||||
.then(triggers => {
|
.then(triggers => {
|
||||||
return _.map(triggers, trigger => {
|
return _.map(triggers, trigger => {
|
||||||
var triggerObj = trigger;
|
let triggerObj = trigger;
|
||||||
|
|
||||||
// Format last change and age
|
// Format last change and age
|
||||||
trigger.lastchangeUnix = Number(trigger.lastchange);
|
trigger.lastchangeUnix = Number(trigger.lastchange);
|
||||||
var timestamp = moment.unix(trigger.lastchangeUnix);
|
let timestamp = moment.unix(trigger.lastchangeUnix);
|
||||||
if (self.panel.customLastChangeFormat) {
|
if (self.panel.customLastChangeFormat) {
|
||||||
// User defined format
|
// User defined format
|
||||||
triggerObj.lastchange = timestamp.format(self.panel.lastChangeFormat);
|
triggerObj.lastchange = timestamp.format(self.panel.lastChangeFormat);
|
||||||
@@ -172,8 +173,12 @@ class TriggerPanelCtrl extends MetricsPanelCtrl {
|
|||||||
|
|
||||||
if (event) {
|
if (event) {
|
||||||
trigger.acknowledges = _.map(event.acknowledges, ack => {
|
trigger.acknowledges = _.map(event.acknowledges, ack => {
|
||||||
var time = new Date(+ack.clock * 1000);
|
let timestamp = moment.unix(ack.clock);
|
||||||
ack.time = time.toLocaleString();
|
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 + ')';
|
ack.user = ack.alias + ' (' + ack.name + ' ' + ack.surname + ')';
|
||||||
return ack;
|
return ack;
|
||||||
});
|
});
|
||||||
@@ -225,41 +230,15 @@ class TriggerPanelCtrl extends MetricsPanelCtrl {
|
|||||||
trigger.showComment = !trigger.showComment;
|
trigger.showComment = !trigger.showComment;
|
||||||
}
|
}
|
||||||
|
|
||||||
switchAcknowledges(trigger) {
|
acknowledgeTrigger(trigger, message) {
|
||||||
trigger.showAcknowledges = !trigger.showAcknowledges;
|
let self = this;
|
||||||
}
|
let eventid = trigger.lastEvent.eventid;
|
||||||
addAcknowledgeMessage(trigger){
|
let grafana_user = this.contextSrv.user.name;
|
||||||
trigger.showAcknowledges = true;
|
let ack_message = grafana_user + ' (Grafana): ' + message;
|
||||||
trigger.newAct={
|
return this.datasourceSrv.get(this.panel.datasource).then(datasource => {
|
||||||
time:new Date(),
|
let zabbix = datasource.zabbixAPI;
|
||||||
user:this.contextSrv.user.name+'(Grafana)',
|
return zabbix.acknowledgeEvent(eventid, ack_message).then(() => {
|
||||||
eventid:trigger.lastEvent.eventid,
|
self.refresh();
|
||||||
message:''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
acknowledgeTrigger($event,trigger,newAct){
|
|
||||||
if($event.keyCode!=13) return;
|
|
||||||
if(newAct.message.trim() === ""){
|
|
||||||
delete trigger.newAct;
|
|
||||||
trigger.showAcknowledges = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.datasourceSrv.get(this.panel.datasource).then(datasource => {
|
|
||||||
var zabbix = datasource.zabbixAPI;
|
|
||||||
zabbix.acknowledgeEvent(newAct.eventid,newAct.user+': '+newAct.message)
|
|
||||||
.then(rs=>{
|
|
||||||
zabbix.getAcknowledges(rs.eventids).then(events => {
|
|
||||||
_.each(events, event => {
|
|
||||||
trigger.acknowledges = _.map(event.acknowledges, ack => {
|
|
||||||
var time = new Date(+ack.clock * 1000);
|
|
||||||
ack.time = time.toLocaleString();
|
|
||||||
ack.user = ack.alias + ' (' + ack.name + ' ' + ack.surname + ')';
|
|
||||||
return ack;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
delete trigger.newAct;
|
|
||||||
console.log('event id '+ rs.eventids.join() + ' new message added: ' + ack.message );
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,3 +106,37 @@ $grafanaListAccent: lighten($dark-2, 2%);
|
|||||||
height: 0px;
|
height: 0px;
|
||||||
line-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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user