Merge branch 'triggers-panel-scroll'

This commit is contained in:
Alexander Zobnin
2017-02-10 17:07:08 +03:00
21 changed files with 859 additions and 473 deletions

View File

@@ -140,9 +140,9 @@ module.exports = function(grunt) {
'clean',
'copy:src_to_dist',
'copy:pluginDef',
'jshint',
'jscs',
'sass',
'babel:dist'
'babel',
'jshint',
'jscs'
]);
};

View File

@@ -154,7 +154,7 @@ System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './za
}
}, {
key: 'getTriggers',
value: function getTriggers(groupFilter, hostFilter, appFilter, showTriggers) {
value: function getTriggers(groupFilter, hostFilter, appFilter, showTriggers, hideHostsInMaintenance) {
var _this5 = this;
var promises = [this.getGroups(groupFilter), this.getHosts(groupFilter, hostFilter), this.getApps(groupFilter, hostFilter, appFilter)];
@@ -177,7 +177,7 @@ System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './za
return query;
}).then(function (query) {
return _this5.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers);
return _this5.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers, hideHostsInMaintenance);
});
}
}]);

File diff suppressed because one or more lines are too long

View File

@@ -286,7 +286,7 @@ System.register(['angular', 'lodash', './utils', './zabbixAPICore.service'], fun
}
}, {
key: 'getTriggers',
value: function getTriggers(groupids, hostids, applicationids, showTriggers, timeFrom, timeTo) {
value: function getTriggers(groupids, hostids, applicationids, showTriggers, hideHostsInMaintenance, timeFrom, timeTo) {
var params = {
output: 'extend',
groupids: groupids,
@@ -311,6 +311,10 @@ System.register(['angular', 'lodash', './utils', './zabbixAPICore.service'], fun
params.filter.value = showTriggers;
}
if (hideHostsInMaintenance) {
params.maintenance = false;
}
if (timeFrom || timeTo) {
params.lastChangeSince = timeFrom;
params.lastChangeTill = timeTo;

File diff suppressed because one or more lines are too long

View File

@@ -82,7 +82,7 @@
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label width-8">Acknowledged</label>
<div class="gf-form-select-wrapper">
<div class="gf-form-select-wrapper width-12">
<select class="gf-form-input"
ng-model="editor.panel.showTriggers"
ng-options="f for f in editor.ackFilters"
@@ -90,19 +90,17 @@
</select>
</div>
</div>
<div class="gf-form">
<label class="gf-form-label width-12">Limit triggers number to</label>
<input class="gf-form-input width-5"
type="number"
ng-model="editor.panel.limit"
ng-model-onblur
ng-change="editor.panelCtrl.refresh()">
</div>
<gf-form-switch class="gf-form"
label-class="width-13"
label="Hide hosts in maintenance"
checked="editor.panel.hideHostsInMaintenance"
on-change="ctrl.refresh()">
</gf-form-switch>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label width-8">Sort by</label>
<div class="gf-form-select-wrapper">
<div class="gf-form-select-wrapper width-12">
<select class="gf-form-input"
ng-model="editor.panel.sortTriggersBy"
ng-options="f.text for f in editor.sortByFields track by f.value"
@@ -112,7 +110,7 @@
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Show events</label>
<div class="gf-form-select-wrapper">
<div class="gf-form-select-wrapper width-9">
<select class="gf-form-input"
ng-model="editor.panel.showEvents"
ng-options="f.text for f in editor.showEventsFields track by f.value"
@@ -121,6 +119,41 @@
</div>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label width-8">Page size</label>
<input class="gf-form-input width-6"
type="number"
ng-model="editor.panel.pageSize"
ng-model-onblur
ng-change="editor.panelCtrl.refresh()">
</div>
<gf-form-switch class="gf-form"
label-class="width-8"
label="Enable scroll"
checked="editor.panel.scroll"
on-change="ctrl.render()">
</gf-form-switch>
</div>
<div class="gf-form-inline">
<div class="gf-form max-width-14">
<label class="gf-form-label width-8">Font size</label>
<div class="gf-form-select-wrapper max-width-8">
<select class="gf-form-input"
ng-model="editor.panel.fontSize"
ng-options="f for f in editor.fontSizes"
ng-change="editor.panelCtrl.render()"></select>
</div>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Limit triggers</label>
<input class="gf-form-input width-5"
type="number"
ng-model="editor.panel.limit"
ng-model-onblur
ng-change="editor.panelCtrl.refresh()">
</div>
</div>
</div>
<div class="section gf-form-group">

View File

@@ -78,10 +78,9 @@ System.register(['lodash', '../datasource-zabbix/utils', '../datasource-zabbix/c
return _this.onVariableChange();
});
this.fontSizes = ['80%', '90%', '100%', '110%', '120%', '130%', '150%', '160%', '180%', '200%', '220%', '250%'];
this.ackFilters = ['all triggers', 'unacknowledged', 'acknowledged'];
this.sortByFields = [{ text: 'last change', value: 'lastchange' }, { text: 'severity', value: 'priority' }];
this.showEventsFields = [{ text: 'All', value: [0, 1] }, { text: 'OK', value: [0] }, { text: 'Problems', value: 1 }];
// Load scope defaults

File diff suppressed because one or more lines are too long

View File

@@ -35,7 +35,7 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="trigger in ctrl.triggerList">
<tr ng-repeat="trigger in ctrl.currentTriggersPage">
<td ng-if="ctrl.panel.hostField">
<div>

View File

@@ -1,9 +1,9 @@
'use strict';
System.register(['lodash', 'moment', '../datasource-zabbix/utils', 'app/plugins/sdk', './editor', './ack-tooltip.directive', './css/panel_triggers.css!'], function (_export, _context) {
System.register(['lodash', 'jquery', 'moment', '../datasource-zabbix/utils', 'app/plugins/sdk', './editor', './ack-tooltip.directive', './css/panel_triggers.css!'], function (_export, _context) {
"use strict";
var _, moment, utils, MetricsPanelCtrl, triggerPanelEditor, _createClass, defaultSeverity, panelDefaults, triggerStatusMap, defaultTimeFormat, TriggerPanelCtrl;
var _, $, moment, utils, PanelCtrl, triggerPanelEditor, _createClass, defaultSeverity, panelDefaults, triggerStatusMap, defaultTimeFormat, TriggerPanelCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
@@ -35,7 +35,7 @@ System.register(['lodash', 'moment', '../datasource-zabbix/utils', 'app/plugins/
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
function filterTriggers(triggers, triggerFilter) {
function _filterTriggers(triggers, triggerFilter) {
if (utils.isRegex(triggerFilter)) {
return _.filter(triggers, function (trigger) {
return utils.buildRegex(triggerFilter).test(trigger.description);
@@ -50,12 +50,14 @@ System.register(['lodash', 'moment', '../datasource-zabbix/utils', 'app/plugins/
return {
setters: [function (_lodash) {
_ = _lodash.default;
}, function (_jquery) {
$ = _jquery.default;
}, function (_moment) {
moment = _moment.default;
}, function (_datasourceZabbixUtils) {
utils = _datasourceZabbixUtils;
}, function (_appPluginsSdk) {
MetricsPanelCtrl = _appPluginsSdk.MetricsPanelCtrl;
PanelCtrl = _appPluginsSdk.PanelCtrl;
}, function (_editor) {
triggerPanelEditor = _editor.triggerPanelEditor;
}, function (_ackTooltipDirective) {}, function (_cssPanel_triggersCss) {}],
@@ -95,11 +97,15 @@ System.register(['lodash', 'moment', '../datasource-zabbix/utils', 'app/plugins/
infoField: true,
limit: 10,
showTriggers: 'all triggers',
hideHostsInMaintenance: false,
sortTriggersBy: { text: 'last change', value: 'lastchange' },
showEvents: { text: 'Problems', value: '1' },
triggerSeverity: defaultSeverity,
okEventColor: 'rgba(0, 245, 153, 0.45)',
ackEventColor: 'rgba(0, 0, 0, 0)'
ackEventColor: 'rgba(0, 0, 0, 0)',
scroll: true,
pageSize: 10,
fontSize: '100%'
};
triggerStatusMap = {
'0': 'OK',
@@ -107,8 +113,8 @@ System.register(['lodash', 'moment', '../datasource-zabbix/utils', 'app/plugins/
};
defaultTimeFormat = "DD MMM YYYY HH:mm:ss";
_export('PanelCtrl', _export('TriggerPanelCtrl', TriggerPanelCtrl = function (_MetricsPanelCtrl) {
_inherits(TriggerPanelCtrl, _MetricsPanelCtrl);
_export('PanelCtrl', _export('TriggerPanelCtrl', TriggerPanelCtrl = function (_PanelCtrl) {
_inherits(TriggerPanelCtrl, _PanelCtrl);
/** @ngInject */
function TriggerPanelCtrl($scope, $injector, $element, datasourceSrv, templateSrv, contextSrv) {
@@ -121,171 +127,184 @@ System.register(['lodash', 'moment', '../datasource-zabbix/utils', 'app/plugins/
_this.contextSrv = contextSrv;
_this.triggerStatusMap = triggerStatusMap;
_this.defaultTimeFormat = defaultTimeFormat;
_this.pageIndex = 0;
_this.triggerList = [];
_this.currentTriggersPage = [];
// Load panel defaults
// _.cloneDeep() need for prevent changing shared defaultSeverity.
// Load object "by value" istead "by reference".
_.defaults(_this.panel, _.cloneDeep(panelDefaults));
_this.triggerList = [];
_this.refreshData();
_this.events.on('init-edit-mode', _this.onInitEditMode.bind(_this));
_this.events.on('refresh', _this.onRefresh.bind(_this));
return _this;
}
/**
* Override onInitMetricsPanelEditMode() method from MetricsPanelCtrl.
* We don't need metric editor from Metrics Panel.
*/
_createClass(TriggerPanelCtrl, [{
key: 'onInitMetricsPanelEditMode',
value: function onInitMetricsPanelEditMode() {
key: 'onInitEditMode',
value: function onInitEditMode() {
this.addEditorTab('Options', triggerPanelEditor, 2);
}
}, {
key: 'refresh',
value: function refresh() {
this.onMetricsPanelRefresh();
}
}, {
key: 'onMetricsPanelRefresh',
value: function onMetricsPanelRefresh() {
// ignore fetching data if another panel is in fullscreen
if (this.otherPanelInFullscreenMode()) {
return;
}
key: 'onRefresh',
value: function onRefresh() {
var _this2 = this;
this.refreshData();
// clear loading/error state
delete this.error;
this.loading = true;
return this.refreshData().then(function (triggerList) {
// Limit triggers number
_this2.triggerList = triggerList.slice(0, _this2.panel.limit);
_this2.getCurrentTriggersPage();
// Notify panel that request is finished
_this2.loading = false;
_this2.render(_this2.triggerList);
});
}
}, {
key: 'refreshData',
value: function refreshData() {
// clear loading/error state
delete this.error;
this.loading = true;
this.setTimeQueryStart();
return this.getTriggers().then(this.getAcknowledges.bind(this)).then(this.filterTriggers.bind(this));
}
}, {
key: 'getTriggers',
value: function getTriggers() {
var _this3 = this;
var self = this;
// Load datasource
return this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
var zabbix = datasource.zabbix;
var showEvents = self.panel.showEvents.value;
var triggerFilter = self.panel.triggers;
_this3.zabbix = zabbix;
var showEvents = _this3.panel.showEvents.value;
var triggerFilter = _this3.panel.triggers;
var hideHostsInMaintenance = _this3.panel.hideHostsInMaintenance;
// Replace template variables
var groupFilter = datasource.replaceTemplateVars(triggerFilter.group.filter);
var hostFilter = datasource.replaceTemplateVars(triggerFilter.host.filter);
var appFilter = datasource.replaceTemplateVars(triggerFilter.application.filter);
var getTriggers = zabbix.getTriggers(groupFilter, hostFilter, appFilter, showEvents);
var getTriggers = zabbix.getTriggers(groupFilter, hostFilter, appFilter, showEvents, hideHostsInMaintenance);
return getTriggers.then(function (triggers) {
return _.map(triggers, function (trigger) {
var triggerObj = trigger;
// Format last change and age
trigger.lastchangeUnix = Number(trigger.lastchange);
var timestamp = moment.unix(trigger.lastchangeUnix);
if (self.panel.customLastChangeFormat) {
// User defined format
triggerObj.lastchange = timestamp.format(self.panel.lastChangeFormat);
} else {
triggerObj.lastchange = timestamp.format(self.defaultTimeFormat);
}
triggerObj.age = timestamp.fromNow(true);
// Set host that the trigger belongs
if (trigger.hosts.length) {
triggerObj.host = trigger.hosts[0].name;
triggerObj.hostTechName = trigger.hosts[0].host;
}
// Set color
if (trigger.value === '1') {
// Problem state
triggerObj.color = self.panel.triggerSeverity[trigger.priority].color;
} else {
// OK state
triggerObj.color = self.panel.okEventColor;
}
triggerObj.severity = self.panel.triggerSeverity[trigger.priority].severity;
return triggerObj;
});
}).then(function (triggerList) {
// Request acknowledges for trigger
var eventids = _.map(triggerList, function (trigger) {
return trigger.lastEvent.eventid;
});
return zabbix.getAcknowledges(eventids).then(function (events) {
// Map events to triggers
_.each(triggerList, function (trigger) {
var event = _.find(events, function (event) {
return event.eventid === trigger.lastEvent.eventid;
});
if (event) {
trigger.acknowledges = _.map(event.acknowledges, function (ack) {
var 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;
});
// Mark acknowledged triggers with different color
if (self.panel.markAckEvents && trigger.acknowledges.length) {
trigger.color = self.panel.ackEventColor;
}
}
});
// Filter triggers by description
var triggerFilter = self.panel.triggers.trigger.filter;
if (triggerFilter) {
triggerList = filterTriggers(triggerList, triggerFilter);
}
// Filter acknowledged triggers
if (self.panel.showTriggers === 'unacknowledged') {
triggerList = _.filter(triggerList, function (trigger) {
return !trigger.acknowledges;
});
} else if (self.panel.showTriggers === 'acknowledged') {
triggerList = _.filter(triggerList, 'acknowledges');
} else {
triggerList = triggerList;
}
// Filter triggers by severity
triggerList = _.filter(triggerList, function (trigger) {
return self.panel.triggerSeverity[trigger.priority].show;
});
// Sort triggers
if (self.panel.sortTriggersBy.value === 'priority') {
triggerList = _.sortBy(triggerList, 'priority').reverse();
} else {
triggerList = _.sortBy(triggerList, 'lastchangeUnix').reverse();
}
// Limit triggers number
self.triggerList = triggerList.slice(0, self.panel.limit);
// Notify panel that request is finished
self.setTimeQueryEnd();
self.loading = false;
});
return _.map(triggers, _this3.formatTrigger.bind(_this3));
});
});
}
}, {
key: 'getAcknowledges',
value: function getAcknowledges(triggerList) {
var _this4 = this;
// Request acknowledges for trigger
var eventids = _.map(triggerList, function (trigger) {
return trigger.lastEvent.eventid;
});
return this.zabbix.getAcknowledges(eventids).then(function (events) {
// Map events to triggers
_.each(triggerList, function (trigger) {
var event = _.find(events, function (event) {
return event.eventid === trigger.lastEvent.eventid;
});
if (event) {
trigger.acknowledges = _.map(event.acknowledges, function (ack) {
var timestamp = moment.unix(ack.clock);
if (_this4.panel.customLastChangeFormat) {
ack.time = timestamp.format(_this4.panel.lastChangeFormat);
} else {
ack.time = timestamp.format(_this4.defaultTimeFormat);
}
ack.user = ack.alias + ' (' + ack.name + ' ' + ack.surname + ')';
return ack;
});
// Mark acknowledged triggers with different color
if (_this4.panel.markAckEvents && trigger.acknowledges.length) {
trigger.color = _this4.panel.ackEventColor;
}
}
});
return triggerList;
});
}
}, {
key: 'filterTriggers',
value: function filterTriggers(triggerList) {
var _this5 = this;
// Filter triggers by description
var triggerFilter = this.panel.triggers.trigger.filter;
if (triggerFilter) {
triggerList = _filterTriggers(triggerList, triggerFilter);
}
// Filter acknowledged triggers
if (this.panel.showTriggers === 'unacknowledged') {
triggerList = _.filter(triggerList, function (trigger) {
return !trigger.acknowledges;
});
} else if (this.panel.showTriggers === 'acknowledged') {
triggerList = _.filter(triggerList, 'acknowledges');
} else {
triggerList = triggerList;
}
// Filter triggers by severity
triggerList = _.filter(triggerList, function (trigger) {
return _this5.panel.triggerSeverity[trigger.priority].show;
});
// Sort triggers
if (this.panel.sortTriggersBy.value === 'priority') {
triggerList = _.sortBy(triggerList, 'priority').reverse();
} else {
triggerList = _.sortBy(triggerList, 'lastchangeUnix').reverse();
}
return triggerList;
}
}, {
key: 'formatTrigger',
value: function formatTrigger(trigger) {
var triggerObj = trigger;
// Format last change and age
trigger.lastchangeUnix = Number(trigger.lastchange);
var timestamp = moment.unix(trigger.lastchangeUnix);
if (this.panel.customLastChangeFormat) {
// User defined format
triggerObj.lastchange = timestamp.format(this.panel.lastChangeFormat);
} else {
triggerObj.lastchange = timestamp.format(this.defaultTimeFormat);
}
triggerObj.age = timestamp.fromNow(true);
// Set host that the trigger belongs
if (trigger.hosts.length) {
triggerObj.host = trigger.hosts[0].name;
triggerObj.hostTechName = trigger.hosts[0].host;
}
// Set color
if (trigger.value === '1') {
// Problem state
triggerObj.color = this.panel.triggerSeverity[trigger.priority].color;
} else {
// OK state
triggerObj.color = this.panel.okEventColor;
}
triggerObj.severity = this.panel.triggerSeverity[trigger.priority].severity;
return triggerObj;
}
}, {
key: 'switchComment',
value: function switchComment(trigger) {
@@ -294,22 +313,108 @@ System.register(['lodash', 'moment', '../datasource-zabbix/utils', 'app/plugins/
}, {
key: 'acknowledgeTrigger',
value: function acknowledgeTrigger(trigger, message) {
var _this2 = this;
var eventid = trigger.lastEvent.eventid;
var grafana_user = this.contextSrv.user.name;
var ack_message = grafana_user + ' (Grafana): ' + message;
return this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
var zabbixAPI = datasource.zabbix.zabbixAPI;
return zabbixAPI.acknowledgeEvent(eventid, ack_message).then(function () {
_this2.refresh();
});
return zabbixAPI.acknowledgeEvent(eventid, ack_message);
}).then(this.onRefresh.bind(this));
}
}, {
key: 'getCurrentTriggersPage',
value: function getCurrentTriggersPage() {
var pageSize = this.panel.pageSize || 10;
var startPos = this.pageIndex * pageSize;
var endPos = Math.min(startPos + pageSize, this.triggerList.length);
this.currentTriggersPage = this.triggerList.slice(startPos, endPos);
return this.currentTriggersPage;
}
}, {
key: 'link',
value: function link(scope, elem, attrs, ctrl) {
var data;
var panel = ctrl.panel;
var pageCount = 0;
data = ctrl.triggerList;
function getTableHeight() {
var panelHeight = ctrl.height;
if (pageCount > 1) {
panelHeight -= 26;
}
return panelHeight - 31 + 'px';
}
function switchPage(e) {
var el = $(e.currentTarget);
ctrl.pageIndex = parseInt(el.text(), 10) - 1;
var pageSize = ctrl.panel.pageSize || 10;
var startPos = ctrl.pageIndex * pageSize;
var endPos = Math.min(startPos + pageSize, ctrl.triggerList.length);
ctrl.currentTriggersPage = ctrl.triggerList.slice(startPos, endPos);
scope.$apply();
renderPanel();
}
function appendPaginationControls(footerElem) {
footerElem.empty();
var pageSize = ctrl.panel.pageSize || 5;
pageCount = Math.ceil(data.length / pageSize);
if (pageCount === 1) {
return;
}
var startPage = Math.max(ctrl.pageIndex - 3, 0);
var endPage = Math.min(pageCount, startPage + 9);
var paginationList = $('<ul></ul>');
for (var i = startPage; i < endPage; i++) {
var activeClass = i === ctrl.pageIndex ? 'active' : '';
var pageLinkElem = $('<li><a class="triggers-panel-page-link pointer ' + activeClass + '">' + (i + 1) + '</a></li>');
paginationList.append(pageLinkElem);
}
footerElem.append(paginationList);
}
function renderPanel() {
var panelElem = elem.parents('.panel');
var rootElem = elem.find('.triggers-panel-scroll');
var footerElem = elem.find('.triggers-panel-footer');
elem.css({ 'font-size': panel.fontSize });
panelElem.addClass('triggers-panel-wrapper');
appendPaginationControls(footerElem);
rootElem.css({ 'max-height': panel.scroll ? getTableHeight() : '' });
}
elem.on('click', '.triggers-panel-page-link', switchPage);
var unbindDestroy = scope.$on('$destroy', function () {
elem.off('click', '.triggers-panel-page-link');
unbindDestroy();
});
ctrl.events.on('render', function (renderData) {
data = renderData || data;
if (data) {
renderPanel();
}
ctrl.renderingCompleted();
});
}
}]);
return TriggerPanelCtrl;
}(MetricsPanelCtrl)));
}(PanelCtrl)));
TriggerPanelCtrl.templateUrl = 'panel-triggers/module.html';
_export('TriggerPanelCtrl', TriggerPanelCtrl);

File diff suppressed because one or more lines are too long

View File

@@ -172,7 +172,7 @@ function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy) {
}, {
key: 'getTriggers',
value: function getTriggers(groupFilter, hostFilter, appFilter, showTriggers) {
value: function getTriggers(groupFilter, hostFilter, appFilter, showTriggers, hideHostsInMaintenance) {
var _this5 = this;
var promises = [this.getGroups(groupFilter), this.getHosts(groupFilter, hostFilter), this.getApps(groupFilter, hostFilter, appFilter)];
@@ -195,7 +195,7 @@ function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy) {
return query;
}).then(function (query) {
return _this5.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers);
return _this5.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers, hideHostsInMaintenance);
});
}
}]);

View File

@@ -356,7 +356,7 @@ function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
}
}, {
key: 'getTriggers',
value: function getTriggers(groupids, hostids, applicationids, showTriggers, timeFrom, timeTo) {
value: function getTriggers(groupids, hostids, applicationids, showTriggers, hideHostsInMaintenance, timeFrom, timeTo) {
var params = {
output: 'extend',
groupids: groupids,
@@ -381,6 +381,10 @@ function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
params.filter.value = showTriggers;
}
if (hideHostsInMaintenance) {
params.maintenance = false;
}
if (timeFrom || timeTo) {
params.lastChangeSince = timeFrom;
params.lastChangeTill = timeTo;

View File

@@ -61,10 +61,9 @@ var TriggerPanelEditorCtrl = function () {
return _this.onVariableChange();
});
this.fontSizes = ['80%', '90%', '100%', '110%', '120%', '130%', '150%', '160%', '180%', '200%', '220%', '250%'];
this.ackFilters = ['all triggers', 'unacknowledged', 'acknowledged'];
this.sortByFields = [{ text: 'last change', value: 'lastchange' }, { text: 'severity', value: 'priority' }];
this.showEventsFields = [{ text: 'All', value: [0, 1] }, { text: 'OK', value: [0] }, { text: 'Problems', value: 1 }];
// Load scope defaults

View File

@@ -11,6 +11,10 @@ var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _jquery = require('jquery');
var _jquery2 = _interopRequireDefault(_jquery);
var _moment = require('moment');
var _moment2 = _interopRequireDefault(_moment);
@@ -66,11 +70,15 @@ var panelDefaults = {
infoField: true,
limit: 10,
showTriggers: 'all triggers',
hideHostsInMaintenance: false,
sortTriggersBy: { text: 'last change', value: 'lastchange' },
showEvents: { text: 'Problems', value: '1' },
triggerSeverity: defaultSeverity,
okEventColor: 'rgba(0, 245, 153, 0.45)',
ackEventColor: 'rgba(0, 0, 0, 0)'
ackEventColor: 'rgba(0, 0, 0, 0)',
scroll: true,
pageSize: 10,
fontSize: '100%'
};
var triggerStatusMap = {
@@ -80,8 +88,8 @@ var triggerStatusMap = {
var defaultTimeFormat = "DD MMM YYYY HH:mm:ss";
var TriggerPanelCtrl = function (_MetricsPanelCtrl) {
_inherits(TriggerPanelCtrl, _MetricsPanelCtrl);
var TriggerPanelCtrl = function (_PanelCtrl) {
_inherits(TriggerPanelCtrl, _PanelCtrl);
/** @ngInject */
function TriggerPanelCtrl($scope, $injector, $element, datasourceSrv, templateSrv, contextSrv) {
@@ -94,171 +102,184 @@ var TriggerPanelCtrl = function (_MetricsPanelCtrl) {
_this.contextSrv = contextSrv;
_this.triggerStatusMap = triggerStatusMap;
_this.defaultTimeFormat = defaultTimeFormat;
_this.pageIndex = 0;
_this.triggerList = [];
_this.currentTriggersPage = [];
// Load panel defaults
// _.cloneDeep() need for prevent changing shared defaultSeverity.
// Load object "by value" istead "by reference".
_lodash2.default.defaults(_this.panel, _lodash2.default.cloneDeep(panelDefaults));
_this.triggerList = [];
_this.refreshData();
_this.events.on('init-edit-mode', _this.onInitEditMode.bind(_this));
_this.events.on('refresh', _this.onRefresh.bind(_this));
return _this;
}
/**
* Override onInitMetricsPanelEditMode() method from MetricsPanelCtrl.
* We don't need metric editor from Metrics Panel.
*/
_createClass(TriggerPanelCtrl, [{
key: 'onInitMetricsPanelEditMode',
value: function onInitMetricsPanelEditMode() {
key: 'onInitEditMode',
value: function onInitEditMode() {
this.addEditorTab('Options', _editor.triggerPanelEditor, 2);
}
}, {
key: 'refresh',
value: function refresh() {
this.onMetricsPanelRefresh();
}
}, {
key: 'onMetricsPanelRefresh',
value: function onMetricsPanelRefresh() {
// ignore fetching data if another panel is in fullscreen
if (this.otherPanelInFullscreenMode()) {
return;
}
key: 'onRefresh',
value: function onRefresh() {
var _this2 = this;
this.refreshData();
// clear loading/error state
delete this.error;
this.loading = true;
return this.refreshData().then(function (triggerList) {
// Limit triggers number
_this2.triggerList = triggerList.slice(0, _this2.panel.limit);
_this2.getCurrentTriggersPage();
// Notify panel that request is finished
_this2.loading = false;
_this2.render(_this2.triggerList);
});
}
}, {
key: 'refreshData',
value: function refreshData() {
// clear loading/error state
delete this.error;
this.loading = true;
this.setTimeQueryStart();
return this.getTriggers().then(this.getAcknowledges.bind(this)).then(this.filterTriggers.bind(this));
}
}, {
key: 'getTriggers',
value: function getTriggers() {
var _this3 = this;
var self = this;
// Load datasource
return this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
var zabbix = datasource.zabbix;
var showEvents = self.panel.showEvents.value;
var triggerFilter = self.panel.triggers;
_this3.zabbix = zabbix;
var showEvents = _this3.panel.showEvents.value;
var triggerFilter = _this3.panel.triggers;
var hideHostsInMaintenance = _this3.panel.hideHostsInMaintenance;
// Replace template variables
var groupFilter = datasource.replaceTemplateVars(triggerFilter.group.filter);
var hostFilter = datasource.replaceTemplateVars(triggerFilter.host.filter);
var appFilter = datasource.replaceTemplateVars(triggerFilter.application.filter);
var getTriggers = zabbix.getTriggers(groupFilter, hostFilter, appFilter, showEvents);
var getTriggers = zabbix.getTriggers(groupFilter, hostFilter, appFilter, showEvents, hideHostsInMaintenance);
return getTriggers.then(function (triggers) {
return _lodash2.default.map(triggers, function (trigger) {
var triggerObj = trigger;
// Format last change and age
trigger.lastchangeUnix = Number(trigger.lastchange);
var timestamp = _moment2.default.unix(trigger.lastchangeUnix);
if (self.panel.customLastChangeFormat) {
// User defined format
triggerObj.lastchange = timestamp.format(self.panel.lastChangeFormat);
} else {
triggerObj.lastchange = timestamp.format(self.defaultTimeFormat);
}
triggerObj.age = timestamp.fromNow(true);
// Set host that the trigger belongs
if (trigger.hosts.length) {
triggerObj.host = trigger.hosts[0].name;
triggerObj.hostTechName = trigger.hosts[0].host;
}
// Set color
if (trigger.value === '1') {
// Problem state
triggerObj.color = self.panel.triggerSeverity[trigger.priority].color;
} else {
// OK state
triggerObj.color = self.panel.okEventColor;
}
triggerObj.severity = self.panel.triggerSeverity[trigger.priority].severity;
return triggerObj;
});
}).then(function (triggerList) {
// Request acknowledges for trigger
var eventids = _lodash2.default.map(triggerList, function (trigger) {
return trigger.lastEvent.eventid;
});
return zabbix.getAcknowledges(eventids).then(function (events) {
// Map events to triggers
_lodash2.default.each(triggerList, function (trigger) {
var event = _lodash2.default.find(events, function (event) {
return event.eventid === trigger.lastEvent.eventid;
});
if (event) {
trigger.acknowledges = _lodash2.default.map(event.acknowledges, function (ack) {
var timestamp = _moment2.default.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;
});
// Mark acknowledged triggers with different color
if (self.panel.markAckEvents && trigger.acknowledges.length) {
trigger.color = self.panel.ackEventColor;
}
}
});
// Filter triggers by description
var triggerFilter = self.panel.triggers.trigger.filter;
if (triggerFilter) {
triggerList = filterTriggers(triggerList, triggerFilter);
}
// Filter acknowledged triggers
if (self.panel.showTriggers === 'unacknowledged') {
triggerList = _lodash2.default.filter(triggerList, function (trigger) {
return !trigger.acknowledges;
});
} else if (self.panel.showTriggers === 'acknowledged') {
triggerList = _lodash2.default.filter(triggerList, 'acknowledges');
} else {
triggerList = triggerList;
}
// Filter triggers by severity
triggerList = _lodash2.default.filter(triggerList, function (trigger) {
return self.panel.triggerSeverity[trigger.priority].show;
});
// Sort triggers
if (self.panel.sortTriggersBy.value === 'priority') {
triggerList = _lodash2.default.sortBy(triggerList, 'priority').reverse();
} else {
triggerList = _lodash2.default.sortBy(triggerList, 'lastchangeUnix').reverse();
}
// Limit triggers number
self.triggerList = triggerList.slice(0, self.panel.limit);
// Notify panel that request is finished
self.setTimeQueryEnd();
self.loading = false;
});
return _lodash2.default.map(triggers, _this3.formatTrigger.bind(_this3));
});
});
}
}, {
key: 'getAcknowledges',
value: function getAcknowledges(triggerList) {
var _this4 = this;
// Request acknowledges for trigger
var eventids = _lodash2.default.map(triggerList, function (trigger) {
return trigger.lastEvent.eventid;
});
return this.zabbix.getAcknowledges(eventids).then(function (events) {
// Map events to triggers
_lodash2.default.each(triggerList, function (trigger) {
var event = _lodash2.default.find(events, function (event) {
return event.eventid === trigger.lastEvent.eventid;
});
if (event) {
trigger.acknowledges = _lodash2.default.map(event.acknowledges, function (ack) {
var timestamp = _moment2.default.unix(ack.clock);
if (_this4.panel.customLastChangeFormat) {
ack.time = timestamp.format(_this4.panel.lastChangeFormat);
} else {
ack.time = timestamp.format(_this4.defaultTimeFormat);
}
ack.user = ack.alias + ' (' + ack.name + ' ' + ack.surname + ')';
return ack;
});
// Mark acknowledged triggers with different color
if (_this4.panel.markAckEvents && trigger.acknowledges.length) {
trigger.color = _this4.panel.ackEventColor;
}
}
});
return triggerList;
});
}
}, {
key: 'filterTriggers',
value: function filterTriggers(triggerList) {
var _this5 = this;
// Filter triggers by description
var triggerFilter = this.panel.triggers.trigger.filter;
if (triggerFilter) {
triggerList = _filterTriggers(triggerList, triggerFilter);
}
// Filter acknowledged triggers
if (this.panel.showTriggers === 'unacknowledged') {
triggerList = _lodash2.default.filter(triggerList, function (trigger) {
return !trigger.acknowledges;
});
} else if (this.panel.showTriggers === 'acknowledged') {
triggerList = _lodash2.default.filter(triggerList, 'acknowledges');
} else {
triggerList = triggerList;
}
// Filter triggers by severity
triggerList = _lodash2.default.filter(triggerList, function (trigger) {
return _this5.panel.triggerSeverity[trigger.priority].show;
});
// Sort triggers
if (this.panel.sortTriggersBy.value === 'priority') {
triggerList = _lodash2.default.sortBy(triggerList, 'priority').reverse();
} else {
triggerList = _lodash2.default.sortBy(triggerList, 'lastchangeUnix').reverse();
}
return triggerList;
}
}, {
key: 'formatTrigger',
value: function formatTrigger(trigger) {
var triggerObj = trigger;
// Format last change and age
trigger.lastchangeUnix = Number(trigger.lastchange);
var timestamp = _moment2.default.unix(trigger.lastchangeUnix);
if (this.panel.customLastChangeFormat) {
// User defined format
triggerObj.lastchange = timestamp.format(this.panel.lastChangeFormat);
} else {
triggerObj.lastchange = timestamp.format(this.defaultTimeFormat);
}
triggerObj.age = timestamp.fromNow(true);
// Set host that the trigger belongs
if (trigger.hosts.length) {
triggerObj.host = trigger.hosts[0].name;
triggerObj.hostTechName = trigger.hosts[0].host;
}
// Set color
if (trigger.value === '1') {
// Problem state
triggerObj.color = this.panel.triggerSeverity[trigger.priority].color;
} else {
// OK state
triggerObj.color = this.panel.okEventColor;
}
triggerObj.severity = this.panel.triggerSeverity[trigger.priority].severity;
return triggerObj;
}
}, {
key: 'switchComment',
value: function switchComment(trigger) {
@@ -267,26 +288,112 @@ var TriggerPanelCtrl = function (_MetricsPanelCtrl) {
}, {
key: 'acknowledgeTrigger',
value: function acknowledgeTrigger(trigger, message) {
var _this2 = this;
var eventid = trigger.lastEvent.eventid;
var grafana_user = this.contextSrv.user.name;
var ack_message = grafana_user + ' (Grafana): ' + message;
return this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
var zabbixAPI = datasource.zabbix.zabbixAPI;
return zabbixAPI.acknowledgeEvent(eventid, ack_message).then(function () {
_this2.refresh();
});
return zabbixAPI.acknowledgeEvent(eventid, ack_message);
}).then(this.onRefresh.bind(this));
}
}, {
key: 'getCurrentTriggersPage',
value: function getCurrentTriggersPage() {
var pageSize = this.panel.pageSize || 10;
var startPos = this.pageIndex * pageSize;
var endPos = Math.min(startPos + pageSize, this.triggerList.length);
this.currentTriggersPage = this.triggerList.slice(startPos, endPos);
return this.currentTriggersPage;
}
}, {
key: 'link',
value: function link(scope, elem, attrs, ctrl) {
var data;
var panel = ctrl.panel;
var pageCount = 0;
data = ctrl.triggerList;
function getTableHeight() {
var panelHeight = ctrl.height;
if (pageCount > 1) {
panelHeight -= 26;
}
return panelHeight - 31 + 'px';
}
function switchPage(e) {
var el = (0, _jquery2.default)(e.currentTarget);
ctrl.pageIndex = parseInt(el.text(), 10) - 1;
var pageSize = ctrl.panel.pageSize || 10;
var startPos = ctrl.pageIndex * pageSize;
var endPos = Math.min(startPos + pageSize, ctrl.triggerList.length);
ctrl.currentTriggersPage = ctrl.triggerList.slice(startPos, endPos);
scope.$apply();
renderPanel();
}
function appendPaginationControls(footerElem) {
footerElem.empty();
var pageSize = ctrl.panel.pageSize || 5;
pageCount = Math.ceil(data.length / pageSize);
if (pageCount === 1) {
return;
}
var startPage = Math.max(ctrl.pageIndex - 3, 0);
var endPage = Math.min(pageCount, startPage + 9);
var paginationList = (0, _jquery2.default)('<ul></ul>');
for (var i = startPage; i < endPage; i++) {
var activeClass = i === ctrl.pageIndex ? 'active' : '';
var pageLinkElem = (0, _jquery2.default)('<li><a class="triggers-panel-page-link pointer ' + activeClass + '">' + (i + 1) + '</a></li>');
paginationList.append(pageLinkElem);
}
footerElem.append(paginationList);
}
function renderPanel() {
var panelElem = elem.parents('.panel');
var rootElem = elem.find('.triggers-panel-scroll');
var footerElem = elem.find('.triggers-panel-footer');
elem.css({ 'font-size': panel.fontSize });
panelElem.addClass('triggers-panel-wrapper');
appendPaginationControls(footerElem);
rootElem.css({ 'max-height': panel.scroll ? getTableHeight() : '' });
}
elem.on('click', '.triggers-panel-page-link', switchPage);
var unbindDestroy = scope.$on('$destroy', function () {
elem.off('click', '.triggers-panel-page-link');
unbindDestroy();
});
ctrl.events.on('render', function (renderData) {
data = renderData || data;
if (data) {
renderPanel();
}
ctrl.renderingCompleted();
});
}
}]);
return TriggerPanelCtrl;
}(_sdk.MetricsPanelCtrl);
}(_sdk.PanelCtrl);
TriggerPanelCtrl.templateUrl = 'panel-triggers/module.html';
function filterTriggers(triggers, triggerFilter) {
function _filterTriggers(triggers, triggerFilter) {
if (utils.isRegex(triggerFilter)) {
return _lodash2.default.filter(triggers, function (trigger) {
return utils.buildRegex(triggerFilter).test(trigger.description);

View File

@@ -120,7 +120,7 @@ function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy) {
/**
* Build query - convert target filters to array of Zabbix items
*/
getTriggers(groupFilter, hostFilter, appFilter, showTriggers) {
getTriggers(groupFilter, hostFilter, appFilter, showTriggers, hideHostsInMaintenance) {
let promises = [
this.getGroups(groupFilter),
this.getHosts(groupFilter, hostFilter),
@@ -147,7 +147,7 @@ function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy) {
return query;
}).then(query => {
return this.zabbixAPI
.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers);
.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers, hideHostsInMaintenance);
});
}
}

View File

@@ -316,7 +316,7 @@ function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
return this.request('service.getsla', params);
}
getTriggers(groupids, hostids, applicationids, showTriggers, timeFrom, timeTo) {
getTriggers(groupids, hostids, applicationids, showTriggers, hideHostsInMaintenance, timeFrom, timeTo) {
var params = {
output: 'extend',
groupids: groupids,
@@ -341,6 +341,10 @@ function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
params.filter.value = showTriggers;
}
if (hideHostsInMaintenance) {
params.maintenance = false;
}
if (timeFrom || timeTo) {
params.lastChangeSince = timeFrom;
params.lastChangeTill = timeTo;

View File

@@ -82,7 +82,7 @@
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label width-8">Acknowledged</label>
<div class="gf-form-select-wrapper">
<div class="gf-form-select-wrapper width-12">
<select class="gf-form-input"
ng-model="editor.panel.showTriggers"
ng-options="f for f in editor.ackFilters"
@@ -90,19 +90,17 @@
</select>
</div>
</div>
<div class="gf-form">
<label class="gf-form-label width-12">Limit triggers number to</label>
<input class="gf-form-input width-5"
type="number"
ng-model="editor.panel.limit"
ng-model-onblur
ng-change="editor.panelCtrl.refresh()">
</div>
<gf-form-switch class="gf-form"
label-class="width-13"
label="Hide hosts in maintenance"
checked="editor.panel.hideHostsInMaintenance"
on-change="ctrl.refresh()">
</gf-form-switch>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label width-8">Sort by</label>
<div class="gf-form-select-wrapper">
<div class="gf-form-select-wrapper width-12">
<select class="gf-form-input"
ng-model="editor.panel.sortTriggersBy"
ng-options="f.text for f in editor.sortByFields track by f.value"
@@ -112,7 +110,7 @@
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Show events</label>
<div class="gf-form-select-wrapper">
<div class="gf-form-select-wrapper width-9">
<select class="gf-form-input"
ng-model="editor.panel.showEvents"
ng-options="f.text for f in editor.showEventsFields track by f.value"
@@ -121,6 +119,41 @@
</div>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label width-8">Page size</label>
<input class="gf-form-input width-6"
type="number"
ng-model="editor.panel.pageSize"
ng-model-onblur
ng-change="editor.panelCtrl.refresh()">
</div>
<gf-form-switch class="gf-form"
label-class="width-8"
label="Enable scroll"
checked="editor.panel.scroll"
on-change="ctrl.render()">
</gf-form-switch>
</div>
<div class="gf-form-inline">
<div class="gf-form max-width-14">
<label class="gf-form-label width-8">Font size</label>
<div class="gf-form-select-wrapper max-width-8">
<select class="gf-form-input"
ng-model="editor.panel.fontSize"
ng-options="f for f in editor.fontSizes"
ng-change="editor.panelCtrl.render()"></select>
</div>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Limit triggers</label>
<input class="gf-form-input width-5"
type="number"
ng-model="editor.panel.limit"
ng-model-onblur
ng-change="editor.panelCtrl.refresh()">
</div>
</div>
</div>
<div class="section gf-form-group">

View File

@@ -36,17 +36,16 @@ class TriggerPanelEditorCtrl {
// Update metric suggestion when template variable was changed
$rootScope.$on('template-variable-value-updated', () => this.onVariableChange());
this.fontSizes = ['80%', '90%', '100%', '110%', '120%', '130%', '150%', '160%', '180%', '200%', '220%', '250%'];
this.ackFilters = [
'all triggers',
'unacknowledged',
'acknowledged'
];
this.sortByFields = [
{ text: 'last change', value: 'lastchange' },
{ text: 'severity', value: 'priority' }
];
this.showEventsFields = [
{ text: 'All', value: [0,1] },
{ text: 'OK', value: [0] },

View File

@@ -35,7 +35,7 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="trigger in ctrl.triggerList">
<tr ng-repeat="trigger in ctrl.currentTriggersPage">
<td ng-if="ctrl.panel.hostField">
<div>

View File

@@ -12,9 +12,10 @@
*/
import _ from 'lodash';
import $ from 'jquery';
import moment from 'moment';
import * as utils from '../datasource-zabbix/utils';
import {MetricsPanelCtrl} from 'app/plugins/sdk';
import {PanelCtrl} from 'app/plugins/sdk';
import {triggerPanelEditor} from './editor';
import './ack-tooltip.directive';
import './css/panel_triggers.css!';
@@ -44,11 +45,15 @@ var panelDefaults = {
infoField: true,
limit: 10,
showTriggers: 'all triggers',
hideHostsInMaintenance: false,
sortTriggersBy: { text: 'last change', value: 'lastchange' },
showEvents: { text: 'Problems', value: '1' },
triggerSeverity: defaultSeverity,
okEventColor: 'rgba(0, 245, 153, 0.45)',
ackEventColor: 'rgba(0, 0, 0, 0)'
ackEventColor: 'rgba(0, 0, 0, 0)',
scroll: true,
pageSize: 10,
fontSize: '100%',
};
var triggerStatusMap = {
@@ -58,7 +63,7 @@ var triggerStatusMap = {
var defaultTimeFormat = "DD MMM YYYY HH:mm:ss";
class TriggerPanelCtrl extends MetricsPanelCtrl {
class TriggerPanelCtrl extends PanelCtrl {
/** @ngInject */
constructor($scope, $injector, $element, datasourceSrv, templateSrv, contextSrv) {
@@ -68,165 +73,173 @@ class TriggerPanelCtrl extends MetricsPanelCtrl {
this.contextSrv = contextSrv;
this.triggerStatusMap = triggerStatusMap;
this.defaultTimeFormat = defaultTimeFormat;
this.pageIndex = 0;
this.triggerList = [];
this.currentTriggersPage = [];
// Load panel defaults
// _.cloneDeep() need for prevent changing shared defaultSeverity.
// Load object "by value" istead "by reference".
_.defaults(this.panel, _.cloneDeep(panelDefaults));
this.triggerList = [];
this.refreshData();
this.events.on('init-edit-mode', this.onInitEditMode.bind(this));
this.events.on('refresh', this.onRefresh.bind(this));
}
/**
* Override onInitMetricsPanelEditMode() method from MetricsPanelCtrl.
* We don't need metric editor from Metrics Panel.
*/
onInitMetricsPanelEditMode() {
onInitEditMode() {
this.addEditorTab('Options', triggerPanelEditor, 2);
}
refresh() {
this.onMetricsPanelRefresh();
}
onMetricsPanelRefresh() {
// ignore fetching data if another panel is in fullscreen
if (this.otherPanelInFullscreenMode()) { return; }
this.refreshData();
}
refreshData() {
onRefresh() {
// clear loading/error state
delete this.error;
this.loading = true;
this.setTimeQueryStart();
var self = this;
return this.refreshData()
.then(triggerList => {
// Limit triggers number
this.triggerList = triggerList.slice(0, this.panel.limit);
// Load datasource
this.getCurrentTriggersPage();
// Notify panel that request is finished
this.loading = false;
this.render(this.triggerList);
});
}
refreshData() {
return this.getTriggers()
.then(this.getAcknowledges.bind(this))
.then(this.filterTriggers.bind(this));
}
getTriggers() {
return this.datasourceSrv.get(this.panel.datasource)
.then(datasource => {
var zabbix = datasource.zabbix;
var showEvents = self.panel.showEvents.value;
var triggerFilter = self.panel.triggers;
this.zabbix = zabbix;
var showEvents = this.panel.showEvents.value;
var triggerFilter = this.panel.triggers;
var hideHostsInMaintenance = this.panel.hideHostsInMaintenance;
// Replace template variables
var groupFilter = datasource.replaceTemplateVars(triggerFilter.group.filter);
var hostFilter = datasource.replaceTemplateVars(triggerFilter.host.filter);
var appFilter = datasource.replaceTemplateVars(triggerFilter.application.filter);
var getTriggers = zabbix.getTriggers(groupFilter, hostFilter, appFilter, showEvents);
var getTriggers = zabbix.getTriggers(groupFilter, hostFilter, appFilter, showEvents, hideHostsInMaintenance);
return getTriggers.then(triggers => {
return _.map(triggers, trigger => {
let triggerObj = trigger;
// Format last change and age
trigger.lastchangeUnix = Number(trigger.lastchange);
let timestamp = moment.unix(trigger.lastchangeUnix);
if (self.panel.customLastChangeFormat) {
// User defined format
triggerObj.lastchange = timestamp.format(self.panel.lastChangeFormat);
} else {
triggerObj.lastchange = timestamp.format(self.defaultTimeFormat);
}
triggerObj.age = timestamp.fromNow(true);
// Set host that the trigger belongs
if (trigger.hosts.length) {
triggerObj.host = trigger.hosts[0].name;
triggerObj.hostTechName = trigger.hosts[0].host;
}
// Set color
if (trigger.value === '1') {
// Problem state
triggerObj.color = self.panel.triggerSeverity[trigger.priority].color;
} else {
// OK state
triggerObj.color = self.panel.okEventColor;
}
triggerObj.severity = self.panel.triggerSeverity[trigger.priority].severity;
return triggerObj;
});
})
.then(triggerList => {
// Request acknowledges for trigger
var eventids = _.map(triggerList, trigger => {
return trigger.lastEvent.eventid;
});
return zabbix.getAcknowledges(eventids)
.then(events => {
// Map events to triggers
_.each(triggerList, trigger => {
var event = _.find(events, event => {
return event.eventid === trigger.lastEvent.eventid;
});
if (event) {
trigger.acknowledges = _.map(event.acknowledges, ack => {
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;
});
// Mark acknowledged triggers with different color
if (self.panel.markAckEvents && trigger.acknowledges.length) {
trigger.color = self.panel.ackEventColor;
}
}
});
// Filter triggers by description
var triggerFilter = self.panel.triggers.trigger.filter;
if (triggerFilter) {
triggerList = filterTriggers(triggerList, triggerFilter);
}
// Filter acknowledged triggers
if (self.panel.showTriggers === 'unacknowledged') {
triggerList = _.filter(triggerList, trigger => {
return !trigger.acknowledges;
});
} else if (self.panel.showTriggers === 'acknowledged') {
triggerList = _.filter(triggerList, 'acknowledges');
} else {
triggerList = triggerList;
}
// Filter triggers by severity
triggerList = _.filter(triggerList, trigger => {
return self.panel.triggerSeverity[trigger.priority].show;
});
// Sort triggers
if (self.panel.sortTriggersBy.value === 'priority') {
triggerList = _.sortBy(triggerList, 'priority').reverse();
} else {
triggerList = _.sortBy(triggerList, 'lastchangeUnix').reverse();
}
// Limit triggers number
self.triggerList = triggerList.slice(0, self.panel.limit);
// Notify panel that request is finished
self.setTimeQueryEnd();
self.loading = false;
});
return _.map(triggers, this.formatTrigger.bind(this));
});
});
}
getAcknowledges(triggerList) {
// Request acknowledges for trigger
var eventids = _.map(triggerList, trigger => {
return trigger.lastEvent.eventid;
});
return this.zabbix.getAcknowledges(eventids)
.then(events => {
// Map events to triggers
_.each(triggerList, trigger => {
var event = _.find(events, event => {
return event.eventid === trigger.lastEvent.eventid;
});
if (event) {
trigger.acknowledges = _.map(event.acknowledges, ack => {
let timestamp = moment.unix(ack.clock);
if (this.panel.customLastChangeFormat) {
ack.time = timestamp.format(this.panel.lastChangeFormat);
} else {
ack.time = timestamp.format(this.defaultTimeFormat);
}
ack.user = ack.alias + ' (' + ack.name + ' ' + ack.surname + ')';
return ack;
});
// Mark acknowledged triggers with different color
if (this.panel.markAckEvents && trigger.acknowledges.length) {
trigger.color = this.panel.ackEventColor;
}
}
});
return triggerList;
});
}
filterTriggers(triggerList) {
// Filter triggers by description
var triggerFilter = this.panel.triggers.trigger.filter;
if (triggerFilter) {
triggerList = filterTriggers(triggerList, triggerFilter);
}
// Filter acknowledged triggers
if (this.panel.showTriggers === 'unacknowledged') {
triggerList = _.filter(triggerList, trigger => {
return !trigger.acknowledges;
});
} else if (this.panel.showTriggers === 'acknowledged') {
triggerList = _.filter(triggerList, 'acknowledges');
} else {
triggerList = triggerList;
}
// Filter triggers by severity
triggerList = _.filter(triggerList, trigger => {
return this.panel.triggerSeverity[trigger.priority].show;
});
// Sort triggers
if (this.panel.sortTriggersBy.value === 'priority') {
triggerList = _.sortBy(triggerList, 'priority').reverse();
} else {
triggerList = _.sortBy(triggerList, 'lastchangeUnix').reverse();
}
return triggerList;
}
formatTrigger(trigger) {
let triggerObj = trigger;
// Format last change and age
trigger.lastchangeUnix = Number(trigger.lastchange);
let timestamp = moment.unix(trigger.lastchangeUnix);
if (this.panel.customLastChangeFormat) {
// User defined format
triggerObj.lastchange = timestamp.format(this.panel.lastChangeFormat);
} else {
triggerObj.lastchange = timestamp.format(this.defaultTimeFormat);
}
triggerObj.age = timestamp.fromNow(true);
// Set host that the trigger belongs
if (trigger.hosts.length) {
triggerObj.host = trigger.hosts[0].name;
triggerObj.hostTechName = trigger.hosts[0].host;
}
// Set color
if (trigger.value === '1') {
// Problem state
triggerObj.color = this.panel.triggerSeverity[trigger.priority].color;
} else {
// OK state
triggerObj.color = this.panel.okEventColor;
}
triggerObj.severity = this.panel.triggerSeverity[trigger.priority].severity;
return triggerObj;
}
switchComment(trigger) {
trigger.showComment = !trigger.showComment;
}
@@ -238,10 +251,96 @@ class TriggerPanelCtrl extends MetricsPanelCtrl {
return this.datasourceSrv.get(this.panel.datasource)
.then(datasource => {
let zabbixAPI = datasource.zabbix.zabbixAPI;
return zabbixAPI.acknowledgeEvent(eventid, ack_message)
.then(() => {
this.refresh();
});
return zabbixAPI.acknowledgeEvent(eventid, ack_message);
})
.then(this.onRefresh.bind(this));
}
getCurrentTriggersPage() {
let pageSize = this.panel.pageSize || 10;
let startPos = this.pageIndex * pageSize;
let endPos = Math.min(startPos + pageSize, this.triggerList.length);
this.currentTriggersPage = this.triggerList.slice(startPos, endPos);
return this.currentTriggersPage;
}
link(scope, elem, attrs, ctrl) {
var data;
var panel = ctrl.panel;
var pageCount = 0;
data = ctrl.triggerList;
function getTableHeight() {
var panelHeight = ctrl.height;
if (pageCount > 1) {
panelHeight -= 26;
}
return (panelHeight - 31) + 'px';
}
function switchPage(e) {
let el = $(e.currentTarget);
ctrl.pageIndex = (parseInt(el.text(), 10)-1);
let pageSize = ctrl.panel.pageSize || 10;
let startPos = ctrl.pageIndex * pageSize;
let endPos = Math.min(startPos + pageSize, ctrl.triggerList.length);
ctrl.currentTriggersPage = ctrl.triggerList.slice(startPos, endPos);
scope.$apply();
renderPanel();
}
function appendPaginationControls(footerElem) {
footerElem.empty();
var pageSize = ctrl.panel.pageSize || 5;
pageCount = Math.ceil(data.length / pageSize);
if (pageCount === 1) {
return;
}
var startPage = Math.max(ctrl.pageIndex - 3, 0);
var endPage = Math.min(pageCount, startPage + 9);
var paginationList = $('<ul></ul>');
for (var i = startPage; i < endPage; i++) {
var activeClass = i === ctrl.pageIndex ? 'active' : '';
var pageLinkElem = $('<li><a class="triggers-panel-page-link pointer ' + activeClass + '">' + (i+1) + '</a></li>');
paginationList.append(pageLinkElem);
}
footerElem.append(paginationList);
}
function renderPanel() {
var panelElem = elem.parents('.panel');
var rootElem = elem.find('.triggers-panel-scroll');
var footerElem = elem.find('.triggers-panel-footer');
elem.css({'font-size': panel.fontSize});
panelElem.addClass('triggers-panel-wrapper');
appendPaginationControls(footerElem);
rootElem.css({'max-height': panel.scroll ? getTableHeight() : '' });
}
elem.on('click', '.triggers-panel-page-link', switchPage);
var unbindDestroy = scope.$on('$destroy', function() {
elem.off('click', '.triggers-panel-page-link');
unbindDestroy();
});
ctrl.events.on('render', (renderData) => {
data = renderData || data;
if (data) {
renderPanel();
}
ctrl.renderingCompleted();
});
}
}