diff --git a/src/datasource-zabbix/zabbixAPI.service.js b/src/datasource-zabbix/zabbixAPI.service.js index f8dd3f1..523f8a1 100644 --- a/src/datasource-zabbix/zabbixAPI.service.js +++ b/src/datasource-zabbix/zabbixAPI.service.js @@ -47,7 +47,6 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) { }, // Handle API errors function(error) { - console.log('Zabbix error: '+error.data); if (isNotAuthorized(error.data)) { return self.loginOnce().then( function() { @@ -114,12 +113,14 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) { //////////////////////////////// // Zabbix API method wrappers // //////////////////////////////// - acknowledgeEvent(eventid,message){ + + acknowledgeEvent(eventid, message) { var params = { - eventids:eventid, - message:message + eventids: eventid, + message: message }; - return this.request('event.acknowledge',params); + + return this.request('event.acknowledge', params); } getGroups() { diff --git a/src/panel-triggers/ack-tooltip.directive.js b/src/panel-triggers/ack-tooltip.directive.js new file mode 100644 index 0000000..3622db4 --- /dev/null +++ b/src/panel-triggers/ack-tooltip.directive.js @@ -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 = ''; + + 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 = '
'; + + if (acknowledges && acknowledges.length) { + tooltip += '' + + '' + + '' + + '' + + ''; + for (let ack of acknowledges) { + tooltip += '' + + '' + + ''; + } + tooltip += '
TimeUserComments
' + ack.time + '' + ack.user + '' + ack.message + '
'; + } else { + tooltip += 'Add acknowledge'; + } + + let addAckButtonTemplate = '
' + + '
'; + tooltip += addAckButtonTemplate; + tooltip += '
'; + + 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 = '
' + + '' + + '' + + '
'; + + 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); + } + }; + }); diff --git a/src/panel-triggers/module.html b/src/panel-triggers/module.html index e16046e..5c28e5f 100644 --- a/src/panel-triggers/module.html +++ b/src/panel-triggers/module.html @@ -31,21 +31,25 @@ +
{{trigger.host}}
+
{{ctrl.triggerStatusMap[trigger.value]}}
+
{{trigger.severity}}
+
{{trigger.description}} @@ -68,52 +72,16 @@ {{trigger.comments}}
- - -
-
- - - - - - - - - - - - - - - - - - - - -
TimeUserComments
- {{ack.time}} - - {{ack.user}} - - {{ack.message}} -
- {{trigger.newAct.time}} - - {{trigger.newAct.user}} -
-
-
+ {{trigger.lastchange}} + {{trigger.age}} + @@ -130,20 +98,12 @@ - - - - - - - - + + diff --git a/src/panel-triggers/module.js b/src/panel-triggers/module.js index 1d952c9..51718b5 100644 --- a/src/panel-triggers/module.js +++ b/src/panel-triggers/module.js @@ -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,7 +60,7 @@ var defaultTimeFormat = "DD MMM YYYY HH:mm:ss"; class TriggerPanelCtrl extends MetricsPanelCtrl { /** @ngInject */ - constructor($scope, $injector, $q, $element, datasourceSrv, templateSrv,contextSrv) { + constructor($scope, $injector, $q, $element, datasourceSrv, templateSrv, contextSrv) { super($scope, $injector); this.datasourceSrv = datasourceSrv; this.templateSrv = templateSrv; @@ -123,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); @@ -172,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; }); @@ -225,41 +230,15 @@ class TriggerPanelCtrl extends MetricsPanelCtrl { trigger.showComment = !trigger.showComment; } - switchAcknowledges(trigger) { - trigger.showAcknowledges = !trigger.showAcknowledges; - } - addAcknowledgeMessage(trigger){ - trigger.showAcknowledges = true; - trigger.newAct={ - time:new Date(), - user:this.contextSrv.user.name+'(Grafana)', - eventid:trigger.lastEvent.eventid, - 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 ); - }); + 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(); }); }); } diff --git a/src/panel-triggers/sass/panel_triggers.scss b/src/panel-triggers/sass/panel_triggers.scss index 478f7dd..156c5dc 100644 --- a/src/panel-triggers/sass/panel_triggers.scss +++ b/src/panel-triggers/sass/panel_triggers.scss @@ -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; + } + } +}