diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..7ad0b88
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,3 @@
+# Don't diff files in dist/
+*.map binary
+dist/** binary
diff --git a/.gitignore b/.gitignore
index 5593838..1a27ba2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,7 +23,7 @@ awsconfig
/tmp
vendor/phantomjs/phantomjs
-dist/
+# dist/
# locally required config files
public/css/*.min.css
diff --git a/dist/README.md b/dist/README.md
new file mode 100644
index 0000000..57f6e97
--- /dev/null
+++ b/dist/README.md
@@ -0,0 +1,24 @@
+## Zabbix plugin for Grafana
+Zabbix plugin allows to show different type of data from [Zabbix](http://www.zabbix.com/)
+monitoring system.
+
+### Live Demo
+
+Check out the [live demo](http://play.grafana-zabbix.org/) with dashboard examples.
+
+### Features
+
+#### Flexible metric editor
+ * Regex-based metric filtering
+ * Client-side data processing functions
+ * Template variables support
+
+#### Templated dashboards support
+Group, host, application or item names can be replaced with a template variable. This allows you to create generic dashboards that can quickly be changed to show stats for a specific cluster, server or application.
+
+#### Annotations support
+ * Display zabbix events on graphs
+ * Show acknowledges for problems
+
+#### Triggers panel
+Panel for showing Zabbix triggers (like Last 20 issues) with some customizable features.
diff --git a/dist/components/config.html b/dist/components/config.html
new file mode 100644
index 0000000..4c4b34c
--- /dev/null
+++ b/dist/components/config.html
@@ -0,0 +1 @@
+
Zabbix Plugin Config
diff --git a/dist/components/config.js b/dist/components/config.js
new file mode 100644
index 0000000..e13e8eb
--- /dev/null
+++ b/dist/components/config.js
@@ -0,0 +1,27 @@
+'use strict';
+
+System.register([], function (_export, _context) {
+ "use strict";
+
+ var ZabbixAppConfigCtrl;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ return {
+ setters: [],
+ execute: function () {
+ _export('ZabbixAppConfigCtrl', ZabbixAppConfigCtrl = function ZabbixAppConfigCtrl() {
+ _classCallCheck(this, ZabbixAppConfigCtrl);
+ });
+
+ _export('ZabbixAppConfigCtrl', ZabbixAppConfigCtrl);
+
+ ZabbixAppConfigCtrl.templateUrl = 'components/config.html';
+ }
+ };
+});
+//# sourceMappingURL=config.js.map
diff --git a/dist/components/config.js.map b/dist/components/config.js.map
new file mode 100644
index 0000000..69b4032
--- /dev/null
+++ b/dist/components/config.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/components/config.js"],"names":["ZabbixAppConfigCtrl","templateUrl"],"mappings":";;;;;;;;;;;;;;;;qCAAaA,mB,GACX,+BAAc;AAAA;AAAG,O;;;;AAEnBA,0BAAoBC,WAApB,GAAkC,wBAAlC","file":"config.js","sourcesContent":["export class ZabbixAppConfigCtrl {\n constructor() { }\n}\nZabbixAppConfigCtrl.templateUrl = 'components/config.html';\n"]}
\ No newline at end of file
diff --git a/dist/dashboards/template_linux_server.json b/dist/dashboards/template_linux_server.json
new file mode 100644
index 0000000..3cb9afa
--- /dev/null
+++ b/dist/dashboards/template_linux_server.json
@@ -0,0 +1,569 @@
+{
+ "id": null,
+ "title": "Template Linux Server",
+ "originalTitle": "Template Linux Server",
+ "tags": [
+ "zabbix",
+ "example"
+ ],
+ "style": "dark",
+ "timezone": "browser",
+ "editable": true,
+ "hideControls": false,
+ "sharedCrosshair": false,
+ "rows": [
+ {
+ "collapse": false,
+ "editable": true,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+ "CPU iowait time": "#B7DBAB",
+ "CPU system time": "#BF1B00",
+ "CPU user time": "#EAB839"
+ },
+ "bars": false,
+ "datasource": null,
+ "editable": true,
+ "error": false,
+ "fill": 3,
+ "grid": {
+ "threshold1": null,
+ "threshold1Color": "rgba(216, 200, 27, 0.27)",
+ "threshold2": null,
+ "threshold2Color": "rgba(234, 112, 112, 0.22)"
+ },
+ "id": 1,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "application": {
+ "filter": "CPU"
+ },
+ "functions": [],
+ "group": {
+ "filter": "$group"
+ },
+ "host": {
+ "filter": "$host"
+ },
+ "item": {
+ "filter": "/CPU/"
+ },
+ "mode": 0,
+ "refId": "A"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "show": true
+ },
+ "yaxes": [
+ {
+ "format": "percent",
+ "logBase": 1,
+ "max": 100,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+ "Processor load (1 min average per core)": "#1F78C1"
+ },
+ "bars": false,
+ "datasource": null,
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {
+ "threshold1": null,
+ "threshold1Color": "rgba(216, 200, 27, 0.27)",
+ "threshold2": null,
+ "threshold2Color": "rgba(234, 112, 112, 0.22)"
+ },
+ "id": 2,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "application": {
+ "filter": "CPU"
+ },
+ "functions": [],
+ "group": {
+ "filter": "$group"
+ },
+ "host": {
+ "filter": "$host"
+ },
+ "item": {
+ "filter": "Processor load (15 min average per core)"
+ },
+ "mode": 0,
+ "refId": "A"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "System load",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "show": true
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "showTitle": true,
+ "title": "CPU"
+ },
+ {
+ "collapse": false,
+ "editable": true,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": null,
+ "editable": true,
+ "error": false,
+ "fill": 3,
+ "grid": {
+ "threshold1": null,
+ "threshold1Color": "rgba(216, 200, 27, 0.27)",
+ "threshold2": null,
+ "threshold2Color": "rgba(234, 112, 112, 0.22)"
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "minSpan": 4,
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": "netif",
+ "scopedVars": {
+ "netif": {
+ "text": "eth0",
+ "value": "eth0",
+ "selected": false
+ }
+ },
+ "seriesOverrides": [
+ {
+ "alias": "/Incoming/",
+ "transform": "negative-Y"
+ }
+ ],
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "application": {
+ "filter": ""
+ },
+ "functions": [],
+ "group": {
+ "filter": "$group"
+ },
+ "host": {
+ "filter": "$host"
+ },
+ "item": {
+ "filter": "/$netif/"
+ },
+ "mode": 0,
+ "refId": "A"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network traffic on $netif",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "show": true
+ },
+ "yaxes": [
+ {
+ "format": "bps",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": null,
+ "editable": true,
+ "error": false,
+ "fill": 3,
+ "grid": {
+ "threshold1": null,
+ "threshold1Color": "rgba(216, 200, 27, 0.27)",
+ "threshold2": null,
+ "threshold2Color": "rgba(234, 112, 112, 0.22)"
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "minSpan": 4,
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "scopedVars": {
+ "netif": {
+ "text": "eth1",
+ "value": "eth1",
+ "selected": false
+ }
+ },
+ "seriesOverrides": [
+ {
+ "alias": "/Incoming/",
+ "transform": "negative-Y"
+ }
+ ],
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "application": {
+ "filter": ""
+ },
+ "functions": [],
+ "group": {
+ "filter": "$group"
+ },
+ "host": {
+ "filter": "$host"
+ },
+ "item": {
+ "filter": "/$netif/"
+ },
+ "mode": 0,
+ "refId": "A"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network traffic on $netif",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "show": true
+ },
+ "yaxes": [
+ {
+ "format": "bps",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "repeatIteration": 1460635040618,
+ "repeatPanelId": 3
+ }
+ ],
+ "showTitle": true,
+ "title": "Network"
+ }
+ ],
+ "time": {
+ "from": "now-3h",
+ "to": "now"
+ },
+ "timepicker": {
+ "now": true,
+ "refresh_intervals": [
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "3h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "templating": {
+ "list": [
+ {
+ "allFormat": "regex values",
+ "current": {
+ "text": "Frontend",
+ "value": "Frontend"
+ },
+ "datasource": null,
+ "hide": 0,
+ "includeAll": false,
+ "label": "Group",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "group",
+ "options": [
+ {
+ "text": "Backend",
+ "value": "Backend",
+ "selected": false
+ },
+ {
+ "text": "Database servers",
+ "value": "Database servers",
+ "selected": false
+ },
+ {
+ "text": "Frontend",
+ "value": "Frontend",
+ "selected": true
+ },
+ {
+ "text": "Linux servers",
+ "value": "Linux servers",
+ "selected": false
+ },
+ {
+ "text": "Network",
+ "value": "Network",
+ "selected": false
+ },
+ {
+ "text": "Workstations",
+ "value": "Workstations",
+ "selected": false
+ },
+ {
+ "text": "Zabbix servers",
+ "value": "Zabbix servers",
+ "selected": false
+ }
+ ],
+ "query": "*",
+ "refresh": 1,
+ "refresh_on_load": false,
+ "regex": "",
+ "type": "query"
+ },
+ {
+ "allFormat": "glob",
+ "current": {
+ "text": "frontend01",
+ "value": "frontend01"
+ },
+ "datasource": null,
+ "hide": 0,
+ "includeAll": false,
+ "label": "Host",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "host",
+ "options": [
+ {
+ "text": "frontend01",
+ "value": "frontend01",
+ "selected": true
+ },
+ {
+ "text": "frontend02",
+ "value": "frontend02",
+ "selected": false
+ }
+ ],
+ "query": "$group.*",
+ "refresh": 1,
+ "refresh_on_load": false,
+ "regex": "",
+ "type": "query"
+ },
+ {
+ "allFormat": "regex values",
+ "current": {
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": null,
+ "hide": 0,
+ "hideLabel": false,
+ "includeAll": true,
+ "label": "Network interface",
+ "multi": true,
+ "multiFormat": "regex values",
+ "name": "netif",
+ "options": [
+ {
+ "text": "All",
+ "value": "$__all",
+ "selected": true
+ },
+ {
+ "text": "eth0",
+ "value": "eth0",
+ "selected": false
+ },
+ {
+ "text": "eth1",
+ "value": "eth1",
+ "selected": false
+ }
+ ],
+ "query": "*.$host.Network interfaces.*",
+ "refresh": 1,
+ "refresh_on_load": false,
+ "regex": "/(?:Incoming|Outgoing) network traffic on (.*)/",
+ "type": "query"
+ }
+ ]
+ },
+ "annotations": {
+ "list": []
+ },
+ "schemaVersion": 12,
+ "version": 8,
+ "links": []
+}
diff --git a/dist/dashboards/zabbix_server_dashboard.json b/dist/dashboards/zabbix_server_dashboard.json
new file mode 100644
index 0000000..b9a8cb0
--- /dev/null
+++ b/dist/dashboards/zabbix_server_dashboard.json
@@ -0,0 +1,633 @@
+{
+ "id": null,
+ "title": "Zabbix Server Dashboard",
+ "originalTitle": "Zabbix Server Dashboard",
+ "tags": [
+ "zabbix",
+ "example"
+ ],
+ "style": "dark",
+ "timezone": "browser",
+ "editable": true,
+ "hideControls": false,
+ "sharedCrosshair": false,
+ "rows": [
+ {
+ "collapse": false,
+ "editable": true,
+ "height": "100px",
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "rgba(245, 54, 54, 0.9)",
+ "rgba(237, 129, 40, 0.89)",
+ "rgba(50, 172, 45, 0.97)"
+ ],
+ "datasource": null,
+ "editable": true,
+ "error": false,
+ "format": "none",
+ "id": 3,
+ "interval": null,
+ "isNew": true,
+ "links": [],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "span": 4,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "targets": [
+ {
+ "application": {
+ "filter": "General"
+ },
+ "functions": [],
+ "group": {
+ "filter": "Zabbix servers"
+ },
+ "host": {
+ "filter": "Zabbix server"
+ },
+ "item": {
+ "filter": "Host name"
+ },
+ "mode": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Host name",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "rgba(245, 54, 54, 0.9)",
+ "rgba(237, 129, 40, 0.89)",
+ "rgba(50, 172, 45, 0.97)"
+ ],
+ "datasource": null,
+ "decimals": 0,
+ "editable": true,
+ "error": false,
+ "format": "s",
+ "id": 4,
+ "interval": null,
+ "isNew": true,
+ "links": [],
+ "maxDataPoints": "",
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "span": 4,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "targets": [
+ {
+ "application": {
+ "filter": "General"
+ },
+ "functions": [],
+ "group": {
+ "filter": "Zabbix servers"
+ },
+ "host": {
+ "filter": "Zabbix server"
+ },
+ "item": {
+ "filter": "System uptime"
+ },
+ "mode": 0,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Uptime",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "rgba(245, 54, 54, 0.9)",
+ "rgba(237, 129, 40, 0.89)",
+ "rgba(50, 172, 45, 0.97)"
+ ],
+ "datasource": null,
+ "editable": true,
+ "error": false,
+ "format": "none",
+ "id": 5,
+ "interval": null,
+ "isNew": true,
+ "links": [],
+ "maxDataPoints": "",
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "span": 4,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "targets": [
+ {
+ "application": {
+ "filter": "Zabbix server"
+ },
+ "functions": [],
+ "group": {
+ "filter": "Zabbix servers"
+ },
+ "host": {
+ "filter": "Zabbix server"
+ },
+ "item": {
+ "filter": "/Required performance of Zabbix server/"
+ },
+ "mode": 0,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Required performance, NVPS",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ }
+ ],
+ "title": "General"
+ },
+ {
+ "collapse": false,
+ "editable": true,
+ "height": "300px",
+ "panels": [
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": null,
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {
+ "threshold1": null,
+ "threshold1Color": "rgba(216, 200, 27, 0.27)",
+ "threshold2": null,
+ "threshold2Color": "rgba(234, 112, 112, 0.22)"
+ },
+ "id": 1,
+ "isNew": true,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "/user/",
+ "color": "#1F78C1"
+ },
+ {
+ "alias": "/system/",
+ "color": "#BF1B00"
+ },
+ {
+ "alias": "/iowait/",
+ "color": "#E5AC0E"
+ }
+ ],
+ "span": 7,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "application": {
+ "filter": "CPU"
+ },
+ "functions": [],
+ "group": {
+ "filter": "Zabbix servers"
+ },
+ "host": {
+ "filter": "Zabbix server"
+ },
+ "item": {
+ "filter": "/CPU (?!idle)/"
+ },
+ "mode": 0,
+ "refId": "A"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "show": true
+ },
+ "yaxes": [
+ {
+ "format": "percent",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "columns": [
+ {
+ "text": "Current",
+ "value": "current"
+ },
+ {
+ "text": "Avg",
+ "value": "avg"
+ }
+ ],
+ "editable": true,
+ "error": false,
+ "fontSize": "100%",
+ "id": 2,
+ "isNew": true,
+ "links": [],
+ "pageSize": null,
+ "scroll": true,
+ "showHeader": true,
+ "sort": {
+ "col": 2,
+ "desc": true
+ },
+ "span": 5,
+ "styles": [
+ {
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "date"
+ },
+ {
+ "colorMode": "cell",
+ "colors": [
+ "rgb(41, 170, 106)",
+ "rgba(239, 148, 21, 0.89)",
+ "rgba(239, 10, 10, 0.9)"
+ ],
+ "decimals": 1,
+ "pattern": "/.*/",
+ "thresholds": [
+ "50",
+ "80"
+ ],
+ "type": "number",
+ "unit": "percent"
+ }
+ ],
+ "targets": [
+ {
+ "application": {
+ "filter": "Zabbix server"
+ },
+ "functions": [],
+ "group": {
+ "filter": "Zabbix servers"
+ },
+ "host": {
+ "filter": "Zabbix server"
+ },
+ "item": {
+ "filter": "/Zabbix busy/"
+ },
+ "mode": 0,
+ "refId": "A"
+ }
+ ],
+ "title": "Zabbix processes",
+ "transform": "timeseries_aggregations",
+ "type": "table"
+ }
+ ],
+ "title": "Row"
+ },
+ {
+ "title": "New row",
+ "height": "380",
+ "editable": true,
+ "collapse": false,
+ "panels": [
+ {
+ "title": "Zabbix busy processes",
+ "error": false,
+ "span": 7.069277691711851,
+ "editable": true,
+ "type": "graph",
+ "isNew": true,
+ "id": 6,
+ "targets": [
+ {
+ "refId": "A",
+ "mode": 0,
+ "group": {
+ "filter": "Zabbix servers"
+ },
+ "host": {
+ "filter": "Zabbix server"
+ },
+ "application": {
+ "filter": "Zabbix server"
+ },
+ "item": {
+ "filter": "/Zabbix busy/"
+ },
+ "functions": []
+ }
+ ],
+ "datasource": null,
+ "renderer": "flot",
+ "yaxes": [
+ {
+ "label": null,
+ "show": true,
+ "logBase": 1,
+ "min": null,
+ "max": null,
+ "format": "percent"
+ },
+ {
+ "label": null,
+ "show": true,
+ "logBase": 1,
+ "min": null,
+ "max": null,
+ "format": "short"
+ }
+ ],
+ "xaxis": {
+ "show": true
+ },
+ "grid": {
+ "threshold1": null,
+ "threshold2": null,
+ "threshold1Color": "rgba(216, 200, 27, 0.27)",
+ "threshold2Color": "rgba(234, 112, 112, 0.22)"
+ },
+ "lines": true,
+ "fill": 0,
+ "linewidth": 2,
+ "points": false,
+ "pointradius": 5,
+ "bars": false,
+ "stack": false,
+ "percentage": false,
+ "legend": {
+ "show": true,
+ "values": false,
+ "min": false,
+ "max": false,
+ "current": false,
+ "total": false,
+ "avg": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "alignAsTable": true,
+ "rightSide": true
+ },
+ "nullPointMode": "connected",
+ "steppedLine": false,
+ "tooltip": {
+ "value_type": "cumulative",
+ "shared": true,
+ "msResolution": false
+ },
+ "timeFrom": null,
+ "timeShift": null,
+ "aliasColors": {},
+ "seriesOverrides": [],
+ "links": []
+ },
+ {
+ "title": "Zabbix Queue",
+ "error": false,
+ "span": 4.930722308288148,
+ "editable": true,
+ "type": "graph",
+ "isNew": true,
+ "id": 7,
+ "targets": [
+ {
+ "refId": "A",
+ "mode": 0,
+ "group": {
+ "filter": "Zabbix servers"
+ },
+ "host": {
+ "filter": "Zabbix server"
+ },
+ "application": {
+ "filter": "Zabbix server"
+ },
+ "item": {
+ "filter": "Zabbix queue"
+ },
+ "functions": []
+ },
+ {
+ "refId": "B",
+ "mode": 0,
+ "group": {
+ "filter": "Zabbix servers"
+ },
+ "host": {
+ "filter": "Zabbix server"
+ },
+ "application": {
+ "filter": "Zabbix server"
+ },
+ "item": {
+ "filter": "/Values processed/"
+ },
+ "functions": []
+ }
+ ],
+ "datasource": null,
+ "renderer": "flot",
+ "yaxes": [
+ {
+ "label": null,
+ "show": true,
+ "logBase": 1,
+ "min": null,
+ "max": null,
+ "format": "short"
+ },
+ {
+ "label": null,
+ "show": true,
+ "logBase": 1,
+ "min": null,
+ "max": null,
+ "format": "short"
+ }
+ ],
+ "xaxis": {
+ "show": true
+ },
+ "grid": {
+ "threshold1": null,
+ "threshold2": null,
+ "threshold1Color": "rgba(216, 200, 27, 0.27)",
+ "threshold2Color": "rgba(234, 112, 112, 0.22)"
+ },
+ "lines": true,
+ "fill": 0,
+ "linewidth": 2,
+ "points": false,
+ "pointradius": 5,
+ "bars": false,
+ "stack": false,
+ "percentage": false,
+ "legend": {
+ "show": true,
+ "values": false,
+ "min": false,
+ "max": false,
+ "current": false,
+ "total": false,
+ "avg": false
+ },
+ "nullPointMode": "connected",
+ "steppedLine": false,
+ "tooltip": {
+ "value_type": "cumulative",
+ "shared": true,
+ "msResolution": false
+ },
+ "timeFrom": null,
+ "timeShift": null,
+ "aliasColors": {},
+ "seriesOverrides": [],
+ "links": []
+ }
+ ]
+ }
+ ],
+ "time": {
+ "from": "now-6h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "templating": {
+ "list": []
+ },
+ "annotations": {
+ "list": []
+ },
+ "schemaVersion": 12,
+ "version": 6,
+ "links": []
+}
diff --git a/dist/datasource-zabbix/add-metric-function.directive.js b/dist/datasource-zabbix/add-metric-function.directive.js
new file mode 100644
index 0000000..04812b5
--- /dev/null
+++ b/dist/datasource-zabbix/add-metric-function.directive.js
@@ -0,0 +1,116 @@
+'use strict';
+
+System.register(['angular', 'lodash', 'jquery', './metricFunctions'], function (_export, _context) {
+ "use strict";
+
+ var angular, _, $, metricFunctions;
+
+ function getAllFunctionNames(categories) {
+ return _.reduce(categories, function (list, category) {
+ _.each(category, function (func) {
+ list.push(func.name);
+ });
+ return list;
+ }, []);
+ }
+
+ function createFunctionDropDownMenu(categories) {
+ return _.map(categories, function (list, category) {
+ return {
+ text: category,
+ submenu: _.map(list, function (value) {
+ return {
+ text: value.name,
+ click: "ctrl.addFunction('" + value.name + "')"
+ };
+ })
+ };
+ });
+ }
+ return {
+ setters: [function (_angular) {
+ angular = _angular.default;
+ }, function (_lodash) {
+ _ = _lodash.default;
+ }, function (_jquery) {
+ $ = _jquery.default;
+ }, function (_metricFunctions) {
+ metricFunctions = _metricFunctions;
+ }],
+ execute: function () {
+
+ /** @ngInject */
+ angular.module('grafana.directives').directive('addMetricFunction', function ($compile) {
+ var inputTemplate = ' ';
+
+ var buttonTemplate = '' + ' ';
+
+ return {
+ link: function link($scope, elem) {
+ var categories = metricFunctions.getCategories();
+ var allFunctions = getAllFunctionNames(categories);
+
+ $scope.functionMenu = createFunctionDropDownMenu(categories);
+
+ var $input = $(inputTemplate);
+ var $button = $(buttonTemplate);
+ $input.appendTo(elem);
+ $button.appendTo(elem);
+
+ $input.attr('data-provide', 'typeahead');
+ $input.typeahead({
+ source: allFunctions,
+ minLength: 1,
+ items: 10,
+ updater: function updater(value) {
+ var funcDef = metricFunctions.getFuncDef(value);
+ if (!funcDef) {
+ // try find close match
+ value = value.toLowerCase();
+ funcDef = _.find(allFunctions, function (funcName) {
+ return funcName.toLowerCase().indexOf(value) === 0;
+ });
+
+ if (!funcDef) {
+ return;
+ }
+ }
+
+ $scope.$apply(function () {
+ $scope.addFunction(funcDef);
+ });
+
+ $input.trigger('blur');
+ return '';
+ }
+ });
+
+ $button.click(function () {
+ $button.hide();
+ $input.show();
+ $input.focus();
+ });
+
+ $input.keyup(function () {
+ elem.toggleClass('open', $input.val() === '');
+ });
+
+ $input.blur(function () {
+ // clicking the function dropdown menu wont
+ // work if you remove class at once
+ setTimeout(function () {
+ $input.val('');
+ $input.hide();
+ $button.show();
+ elem.removeClass('open');
+ }, 200);
+ });
+
+ $compile(elem.contents())($scope);
+ }
+ };
+ });
+ }
+ };
+});
+//# sourceMappingURL=add-metric-function.directive.js.map
diff --git a/dist/datasource-zabbix/add-metric-function.directive.js.map b/dist/datasource-zabbix/add-metric-function.directive.js.map
new file mode 100644
index 0000000..24912c0
--- /dev/null
+++ b/dist/datasource-zabbix/add-metric-function.directive.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/add-metric-function.directive.js"],"names":["getAllFunctionNames","categories","_","reduce","list","category","each","func","push","name","createFunctionDropDownMenu","map","text","submenu","value","click","angular","$","metricFunctions","module","directive","$compile","inputTemplate","buttonTemplate","link","$scope","elem","getCategories","allFunctions","functionMenu","$input","$button","appendTo","attr","typeahead","source","minLength","items","updater","funcDef","getFuncDef","toLowerCase","find","funcName","indexOf","$apply","addFunction","trigger","hide","show","focus","keyup","toggleClass","val","blur","setTimeout","removeClass","contents"],"mappings":"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","file":"add-metric-function.directive.js","sourcesContent":["import angular from 'angular';\nimport _ from 'lodash';\nimport $ from 'jquery';\nimport * as metricFunctions from './metricFunctions';\n\n/** @ngInject */\nangular\n .module('grafana.directives')\n .directive('addMetricFunction', function($compile) {\n var inputTemplate = ' ';\n\n var buttonTemplate = '' +\n ' ';\n\n return {\n link: function($scope, elem) {\n var categories = metricFunctions.getCategories();\n var allFunctions = getAllFunctionNames(categories);\n\n $scope.functionMenu = createFunctionDropDownMenu(categories);\n\n var $input = $(inputTemplate);\n var $button = $(buttonTemplate);\n $input.appendTo(elem);\n $button.appendTo(elem);\n\n $input.attr('data-provide', 'typeahead');\n $input.typeahead({\n source: allFunctions,\n minLength: 1,\n items: 10,\n updater: function (value) {\n var funcDef = metricFunctions.getFuncDef(value);\n if (!funcDef) {\n // try find close match\n value = value.toLowerCase();\n funcDef = _.find(allFunctions, function(funcName) {\n return funcName.toLowerCase().indexOf(value) === 0;\n });\n\n if (!funcDef) { return; }\n }\n\n $scope.$apply(function() {\n $scope.addFunction(funcDef);\n });\n\n $input.trigger('blur');\n return '';\n }\n });\n\n $button.click(function() {\n $button.hide();\n $input.show();\n $input.focus();\n });\n\n $input.keyup(function() {\n elem.toggleClass('open', $input.val() === '');\n });\n\n $input.blur(function() {\n // clicking the function dropdown menu wont\n // work if you remove class at once\n setTimeout(function() {\n $input.val('');\n $input.hide();\n $button.show();\n elem.removeClass('open');\n }, 200);\n });\n\n $compile(elem.contents())($scope);\n }\n };\n });\n\nfunction getAllFunctionNames(categories) {\n return _.reduce(categories, function(list, category) {\n _.each(category, function(func) {\n list.push(func.name);\n });\n return list;\n }, []);\n}\n\nfunction createFunctionDropDownMenu(categories) {\n return _.map(categories, function(list, category) {\n return {\n text: category,\n submenu: _.map(list, function(value) {\n return {\n text: value.name,\n click: \"ctrl.addFunction('\" + value.name + \"')\",\n };\n })\n };\n });\n}\n\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/css/query-editor.css b/dist/datasource-zabbix/css/query-editor.css
new file mode 100644
index 0000000..3edd27d
--- /dev/null
+++ b/dist/datasource-zabbix/css/query-editor.css
@@ -0,0 +1,7 @@
+.zbx-regex {
+ color: #CCA300;
+}
+
+.zbx-variable {
+ color: #33B5E5;
+}
diff --git a/dist/datasource-zabbix/dataProcessor.js b/dist/datasource-zabbix/dataProcessor.js
new file mode 100644
index 0000000..12312de
--- /dev/null
+++ b/dist/datasource-zabbix/dataProcessor.js
@@ -0,0 +1,287 @@
+'use strict';
+
+System.register(['lodash', './utils'], function (_export, _context) {
+ "use strict";
+
+ var _, utils, metricFunctions, aggregationFunctions;
+
+ /**
+ * Downsample datapoints series
+ */
+ function downsampleSeries(datapoints, time_to, ms_interval, func) {
+ var downsampledSeries = [];
+ var timeWindow = {
+ from: time_to * 1000 - ms_interval,
+ to: time_to * 1000
+ };
+
+ var points_sum = 0;
+ var points_num = 0;
+ var value_avg = 0;
+ var frame = [];
+
+ for (var i = datapoints.length - 1; i >= 0; i -= 1) {
+ if (timeWindow.from < datapoints[i][1] && datapoints[i][1] <= timeWindow.to) {
+ points_sum += datapoints[i][0];
+ points_num++;
+ frame.push(datapoints[i][0]);
+ } else {
+ value_avg = points_num ? points_sum / points_num : 0;
+
+ if (func === "max") {
+ downsampledSeries.push([_.max(frame), timeWindow.to]);
+ } else if (func === "min") {
+ downsampledSeries.push([_.min(frame), timeWindow.to]);
+ }
+
+ // avg by default
+ else {
+ downsampledSeries.push([value_avg, timeWindow.to]);
+ }
+
+ // Shift time window
+ timeWindow.to = timeWindow.from;
+ timeWindow.from -= ms_interval;
+
+ points_sum = 0;
+ points_num = 0;
+ frame = [];
+
+ // Process point again
+ i++;
+ }
+ }
+ return downsampledSeries.reverse();
+ }
+
+ /**
+ * Group points by given time interval
+ * datapoints: [[, ], ...]
+ */
+ function groupBy(interval, groupByCallback, datapoints) {
+ var ms_interval = utils.parseInterval(interval);
+
+ // Calculate frame timestamps
+ var frames = _.groupBy(datapoints, function (point) {
+ // Calculate time for group of points
+ return Math.floor(point[1] / ms_interval) * ms_interval;
+ });
+
+ // frame: { '': [[, ], ...] }
+ // return [{ '': }, { '': }, ...]
+ var grouped = _.mapValues(frames, function (frame) {
+ var points = _.map(frame, function (point) {
+ return point[0];
+ });
+ return groupByCallback(points);
+ });
+
+ // Convert points to Grafana format
+ return sortByTime(_.map(grouped, function (value, timestamp) {
+ return [Number(value), Number(timestamp)];
+ }));
+ }function sumSeries(timeseries) {
+
+ // Calculate new points for interpolation
+ var new_timestamps = _.uniq(_.map(_.flatten(timeseries, true), function (point) {
+ return point[1];
+ }));
+ new_timestamps = _.sortBy(new_timestamps);
+
+ var interpolated_timeseries = _.map(timeseries, function (series) {
+ var timestamps = _.map(series, function (point) {
+ return point[1];
+ });
+ var new_points = _.map(_.difference(new_timestamps, timestamps), function (timestamp) {
+ return [null, timestamp];
+ });
+ var new_series = series.concat(new_points);
+ return sortByTime(new_series);
+ });
+
+ _.each(interpolated_timeseries, interpolateSeries);
+
+ var new_timeseries = [];
+ var sum;
+ for (var i = new_timestamps.length - 1; i >= 0; i--) {
+ sum = 0;
+ for (var j = interpolated_timeseries.length - 1; j >= 0; j--) {
+ sum += interpolated_timeseries[j][i][0];
+ }
+ new_timeseries.push([sum, new_timestamps[i]]);
+ }
+
+ return sortByTime(new_timeseries);
+ }function limit(order, n, orderByFunc, timeseries) {
+ var orderByCallback = aggregationFunctions[orderByFunc];
+ var sortByIteratee = function sortByIteratee(ts) {
+ var values = _.map(ts.datapoints, function (point) {
+ return point[0];
+ });
+ return orderByCallback(values);
+ };
+ var sortedTimeseries = _.sortBy(timeseries, sortByIteratee);
+ if (order === 'bottom') {
+ return sortedTimeseries.slice(0, n);
+ } else {
+ return sortedTimeseries.slice(-n);
+ }
+ }function AVERAGE(values) {
+ var sum = 0;
+ _.each(values, function (value) {
+ sum += value;
+ });
+ return sum / values.length;
+ }function MIN(values) {
+ return _.min(values);
+ }function MAX(values) {
+ return _.max(values);
+ }function MEDIAN(values) {
+ var sorted = _.sortBy(values);
+ return sorted[Math.floor(sorted.length / 2)];
+ }function setAlias(alias, timeseries) {
+ timeseries.target = alias;
+ return timeseries;
+ }function setAliasByRegex(alias, timeseries) {
+ timeseries.target = extractText(timeseries.target, alias);
+ return timeseries;
+ }function extractText(str, pattern) {
+ var extractPattern = new RegExp(pattern);
+ var extractedValue = extractPattern.exec(str);
+ extractedValue = extractedValue[0];
+ return extractedValue;
+ }function scale(factor, datapoints) {
+ return _.map(datapoints, function (point) {
+ return [point[0] * factor, point[1]];
+ });
+ }function delta(datapoints) {
+ var newSeries = [];
+ var deltaValue = void 0;
+ for (var i = 1; i < datapoints.length; i++) {
+ deltaValue = datapoints[i][0] - datapoints[i - 1][0];
+ newSeries.push([deltaValue, datapoints[i][1]]);
+ }
+ return newSeries;
+ }function groupByWrapper(interval, groupFunc, datapoints) {
+ var groupByCallback = aggregationFunctions[groupFunc];
+ return groupBy(interval, groupByCallback, datapoints);
+ }function aggregateByWrapper(interval, aggregateFunc, datapoints) {
+ // Flatten all points in frame and then just use groupBy()
+ var flattenedPoints = _.flatten(datapoints, true);
+ var groupByCallback = aggregationFunctions[aggregateFunc];
+ return groupBy(interval, groupByCallback, flattenedPoints);
+ }function aggregateWrapper(groupByCallback, interval, datapoints) {
+ var flattenedPoints = _.flatten(datapoints, true);
+ return groupBy(interval, groupByCallback, flattenedPoints);
+ }function sortByTime(series) {
+ return _.sortBy(series, function (point) {
+ return point[1];
+ });
+ }
+
+ /**
+ * Interpolate series with gaps
+ */
+ function interpolateSeries(series) {
+ var left, right;
+
+ // Interpolate series
+ for (var i = series.length - 1; i >= 0; i--) {
+ if (!series[i][0]) {
+ left = findNearestLeft(series, series[i]);
+ right = findNearestRight(series, series[i]);
+ if (!left) {
+ left = right;
+ }
+ if (!right) {
+ right = left;
+ }
+ series[i][0] = linearInterpolation(series[i][1], left, right);
+ }
+ }
+ return series;
+ }function linearInterpolation(timestamp, left, right) {
+ if (left[1] === right[1]) {
+ return (left[0] + right[0]) / 2;
+ } else {
+ return left[0] + (right[0] - left[0]) / (right[1] - left[1]) * (timestamp - left[1]);
+ }
+ }function findNearestRight(series, point) {
+ var point_index = _.indexOf(series, point);
+ var nearestRight;
+ for (var i = point_index; i < series.length; i++) {
+ if (series[i][0] !== null) {
+ return series[i];
+ }
+ }
+ return nearestRight;
+ }function findNearestLeft(series, point) {
+ var point_index = _.indexOf(series, point);
+ var nearestLeft;
+ for (var i = point_index; i > 0; i--) {
+ if (series[i][0] !== null) {
+ return series[i];
+ }
+ }
+ return nearestLeft;
+ }function timeShift(interval, range) {
+ var shift = utils.parseTimeShiftInterval(interval) / 1000;
+ return range.map(function (time) {
+ return time - shift;
+ });
+ }function unShiftTimeSeries(interval, datapoints) {
+ var unshift = utils.parseTimeShiftInterval(interval);
+ return datapoints.map(function (dp) {
+ return [dp[0], dp[1] + unshift];
+ });
+ }return {
+ setters: [function (_lodash) {
+ _ = _lodash.default;
+ }, function (_utils) {
+ utils = _utils;
+ }],
+ execute: function () {
+ metricFunctions = {
+ groupBy: groupByWrapper,
+ scale: scale,
+ delta: delta,
+ aggregateBy: aggregateByWrapper,
+ average: _.partial(aggregateWrapper, AVERAGE),
+ min: _.partial(aggregateWrapper, MIN),
+ max: _.partial(aggregateWrapper, MAX),
+ median: _.partial(aggregateWrapper, MEDIAN),
+ sumSeries: sumSeries,
+ top: _.partial(limit, 'top'),
+ bottom: _.partial(limit, 'bottom'),
+ timeShift: timeShift,
+ setAlias: setAlias,
+ setAliasByRegex: setAliasByRegex
+ };
+ aggregationFunctions = {
+ avg: AVERAGE,
+ min: MIN,
+ max: MAX,
+ median: MEDIAN
+ };
+
+ _export('default', {
+ downsampleSeries: downsampleSeries,
+ groupBy: groupBy,
+ AVERAGE: AVERAGE,
+ MIN: MIN,
+ MAX: MAX,
+ MEDIAN: MEDIAN,
+ unShiftTimeSeries: unShiftTimeSeries,
+
+ get aggregationFunctions() {
+ return aggregationFunctions;
+ },
+
+ get metricFunctions() {
+ return metricFunctions;
+ }
+ });
+ }
+ };
+});
+//# sourceMappingURL=dataProcessor.js.map
diff --git a/dist/datasource-zabbix/dataProcessor.js.map b/dist/datasource-zabbix/dataProcessor.js.map
new file mode 100644
index 0000000..7c84bff
--- /dev/null
+++ b/dist/datasource-zabbix/dataProcessor.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/dataProcessor.js"],"names":["downsampleSeries","datapoints","time_to","ms_interval","func","downsampledSeries","timeWindow","from","to","points_sum","points_num","value_avg","frame","i","length","push","_","max","min","reverse","groupBy","interval","groupByCallback","utils","parseInterval","frames","point","Math","floor","grouped","mapValues","points","map","sortByTime","value","timestamp","Number","sumSeries","timeseries","new_timestamps","uniq","flatten","sortBy","interpolated_timeseries","series","timestamps","new_points","difference","new_series","concat","each","interpolateSeries","new_timeseries","sum","j","limit","order","n","orderByFunc","orderByCallback","aggregationFunctions","sortByIteratee","ts","values","sortedTimeseries","slice","AVERAGE","MIN","MAX","MEDIAN","sorted","setAlias","alias","target","setAliasByRegex","extractText","str","pattern","extractPattern","RegExp","extractedValue","exec","scale","factor","delta","newSeries","deltaValue","groupByWrapper","groupFunc","aggregateByWrapper","aggregateFunc","flattenedPoints","aggregateWrapper","left","right","findNearestLeft","findNearestRight","linearInterpolation","point_index","indexOf","nearestRight","nearestLeft","timeShift","range","shift","parseTimeShiftInterval","time","unShiftTimeSeries","unshift","dp","metricFunctions","aggregateBy","average","partial","median","top","bottom","avg"],"mappings":"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","file":"dataProcessor.js","sourcesContent":["import _ from 'lodash';\nimport * as utils from './utils';\n\n/**\n * Downsample datapoints series\n */\nfunction downsampleSeries(datapoints, time_to, ms_interval, func) {\n var downsampledSeries = [];\n var timeWindow = {\n from: time_to * 1000 - ms_interval,\n to: time_to * 1000\n };\n\n var points_sum = 0;\n var points_num = 0;\n var value_avg = 0;\n var frame = [];\n\n for (var i = datapoints.length - 1; i >= 0; i -= 1) {\n if (timeWindow.from < datapoints[i][1] && datapoints[i][1] <= timeWindow.to) {\n points_sum += datapoints[i][0];\n points_num++;\n frame.push(datapoints[i][0]);\n }\n else {\n value_avg = points_num ? points_sum / points_num : 0;\n\n if (func === \"max\") {\n downsampledSeries.push([_.max(frame), timeWindow.to]);\n }\n else if (func === \"min\") {\n downsampledSeries.push([_.min(frame), timeWindow.to]);\n }\n\n // avg by default\n else {\n downsampledSeries.push([value_avg, timeWindow.to]);\n }\n\n // Shift time window\n timeWindow.to = timeWindow.from;\n timeWindow.from -= ms_interval;\n\n points_sum = 0;\n points_num = 0;\n frame = [];\n\n // Process point again\n i++;\n }\n }\n return downsampledSeries.reverse();\n}\n\n/**\n * Group points by given time interval\n * datapoints: [[, ], ...]\n */\nfunction groupBy(interval, groupByCallback, datapoints) {\n var ms_interval = utils.parseInterval(interval);\n\n // Calculate frame timestamps\n var frames = _.groupBy(datapoints, function(point) {\n // Calculate time for group of points\n return Math.floor(point[1] / ms_interval) * ms_interval;\n });\n\n // frame: { '': [[, ], ...] }\n // return [{ '': }, { '': }, ...]\n var grouped = _.mapValues(frames, function(frame) {\n var points = _.map(frame, function(point) {\n return point[0];\n });\n return groupByCallback(points);\n });\n\n // Convert points to Grafana format\n return sortByTime(_.map(grouped, function(value, timestamp) {\n return [Number(value), Number(timestamp)];\n }));\n}\n\nfunction sumSeries(timeseries) {\n\n // Calculate new points for interpolation\n var new_timestamps = _.uniq(_.map(_.flatten(timeseries, true), function(point) {\n return point[1];\n }));\n new_timestamps = _.sortBy(new_timestamps);\n\n var interpolated_timeseries = _.map(timeseries, function(series) {\n var timestamps = _.map(series, function(point) {\n return point[1];\n });\n var new_points = _.map(_.difference(new_timestamps, timestamps), function(timestamp) {\n return [null, timestamp];\n });\n var new_series = series.concat(new_points);\n return sortByTime(new_series);\n });\n\n _.each(interpolated_timeseries, interpolateSeries);\n\n var new_timeseries = [];\n var sum;\n for (var i = new_timestamps.length - 1; i >= 0; i--) {\n sum = 0;\n for (var j = interpolated_timeseries.length - 1; j >= 0; j--) {\n sum += interpolated_timeseries[j][i][0];\n }\n new_timeseries.push([sum, new_timestamps[i]]);\n }\n\n return sortByTime(new_timeseries);\n}\n\nfunction limit(order, n, orderByFunc, timeseries) {\n let orderByCallback = aggregationFunctions[orderByFunc];\n let sortByIteratee = (ts) => {\n let values = _.map(ts.datapoints, (point) => {\n return point[0];\n });\n return orderByCallback(values);\n };\n let sortedTimeseries = _.sortBy(timeseries, sortByIteratee);\n if (order === 'bottom') {\n return sortedTimeseries.slice(0, n);\n } else {\n return sortedTimeseries.slice(-n);\n }\n}\n\nfunction AVERAGE(values) {\n var sum = 0;\n _.each(values, function(value) {\n sum += value;\n });\n return sum / values.length;\n}\n\nfunction MIN(values) {\n return _.min(values);\n}\n\nfunction MAX(values) {\n return _.max(values);\n}\n\nfunction MEDIAN(values) {\n var sorted = _.sortBy(values);\n return sorted[Math.floor(sorted.length / 2)];\n}\n\nfunction setAlias(alias, timeseries) {\n timeseries.target = alias;\n return timeseries;\n}\n\nfunction setAliasByRegex(alias, timeseries) {\n timeseries.target = extractText(timeseries.target, alias);\n return timeseries;\n}\n\nfunction extractText(str, pattern) {\n var extractPattern = new RegExp(pattern);\n var extractedValue = extractPattern.exec(str);\n extractedValue = extractedValue[0];\n return extractedValue;\n}\n\nfunction scale(factor, datapoints) {\n return _.map(datapoints, point => {\n return [\n point[0] * factor,\n point[1]\n ];\n });\n}\n\nfunction delta(datapoints) {\n let newSeries = [];\n let deltaValue;\n for (var i = 1; i < datapoints.length; i++) {\n deltaValue = datapoints[i][0] - datapoints[i - 1][0];\n newSeries.push([deltaValue, datapoints[i][1]]);\n }\n return newSeries;\n}\n\nfunction groupByWrapper(interval, groupFunc, datapoints) {\n var groupByCallback = aggregationFunctions[groupFunc];\n return groupBy(interval, groupByCallback, datapoints);\n}\n\nfunction aggregateByWrapper(interval, aggregateFunc, datapoints) {\n // Flatten all points in frame and then just use groupBy()\n var flattenedPoints = _.flatten(datapoints, true);\n var groupByCallback = aggregationFunctions[aggregateFunc];\n return groupBy(interval, groupByCallback, flattenedPoints);\n}\n\nfunction aggregateWrapper(groupByCallback, interval, datapoints) {\n var flattenedPoints = _.flatten(datapoints, true);\n return groupBy(interval, groupByCallback, flattenedPoints);\n}\n\nfunction sortByTime(series) {\n return _.sortBy(series, function(point) {\n return point[1];\n });\n}\n\n/**\n * Interpolate series with gaps\n */\nfunction interpolateSeries(series) {\n var left, right;\n\n // Interpolate series\n for (var i = series.length - 1; i >= 0; i--) {\n if (!series[i][0]) {\n left = findNearestLeft(series, series[i]);\n right = findNearestRight(series, series[i]);\n if (!left) {\n left = right;\n }\n if (!right) {\n right = left;\n }\n series[i][0] = linearInterpolation(series[i][1], left, right);\n }\n }\n return series;\n}\n\nfunction linearInterpolation(timestamp, left, right) {\n if (left[1] === right[1]) {\n return (left[0] + right[0]) / 2;\n } else {\n return (left[0] + (right[0] - left[0]) / (right[1] - left[1]) * (timestamp - left[1]));\n }\n}\n\nfunction findNearestRight(series, point) {\n var point_index = _.indexOf(series, point);\n var nearestRight;\n for (var i = point_index; i < series.length; i++) {\n if (series[i][0] !== null) {\n return series[i];\n }\n }\n return nearestRight;\n}\n\nfunction findNearestLeft(series, point) {\n var point_index = _.indexOf(series, point);\n var nearestLeft;\n for (var i = point_index; i > 0; i--) {\n if (series[i][0] !== null) {\n return series[i];\n }\n }\n return nearestLeft;\n}\n\nfunction timeShift(interval, range) {\n let shift = utils.parseTimeShiftInterval(interval) / 1000;\n return range.map(time => {\n return time - shift;\n });\n}\n\nfunction unShiftTimeSeries(interval, datapoints) {\n let unshift = utils.parseTimeShiftInterval(interval);\n return datapoints.map(dp => {\n return [\n dp[0],\n dp[1] + unshift\n ];\n });\n}\n\nlet metricFunctions = {\n groupBy: groupByWrapper,\n scale: scale,\n delta: delta,\n aggregateBy: aggregateByWrapper,\n average: _.partial(aggregateWrapper, AVERAGE),\n min: _.partial(aggregateWrapper, MIN),\n max: _.partial(aggregateWrapper, MAX),\n median: _.partial(aggregateWrapper, MEDIAN),\n sumSeries: sumSeries,\n top: _.partial(limit, 'top'),\n bottom: _.partial(limit, 'bottom'),\n timeShift: timeShift,\n setAlias: setAlias,\n setAliasByRegex: setAliasByRegex\n};\n\nlet aggregationFunctions = {\n avg: AVERAGE,\n min: MIN,\n max: MAX,\n median: MEDIAN\n};\n\nexport default {\n downsampleSeries: downsampleSeries,\n groupBy: groupBy,\n AVERAGE: AVERAGE,\n MIN: MIN,\n MAX: MAX,\n MEDIAN: MEDIAN,\n unShiftTimeSeries: unShiftTimeSeries,\n\n get aggregationFunctions() {\n return aggregationFunctions;\n },\n\n get metricFunctions() {\n return metricFunctions;\n }\n};\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/datasource.js b/dist/datasource-zabbix/datasource.js
new file mode 100644
index 0000000..8c9c645
--- /dev/null
+++ b/dist/datasource-zabbix/datasource.js
@@ -0,0 +1,597 @@
+'use strict';
+
+System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations', './metricFunctions', './dataProcessor', './responseHandler', './zabbix.js', './zabbixAPICore.service.js'], function (_export, _context) {
+ "use strict";
+
+ var _, dateMath, utils, migrations, metricFunctions, dataProcessor, responseHandler, ZabbixAPIError, _slicedToArray, _createClass, ZabbixAPIDatasource;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function bindFunctionDefs(functionDefs, category) {
+ var aggregationFunctions = _.map(metricFunctions.getCategories()[category], 'name');
+ var aggFuncDefs = _.filter(functionDefs, function (func) {
+ return _.includes(aggregationFunctions, func.def.name);
+ });
+
+ return _.map(aggFuncDefs, function (func) {
+ var funcInstance = metricFunctions.createFuncInstance(func.def, func.params);
+ return funcInstance.bindFunction(dataProcessor.metricFunctions);
+ });
+ }
+
+ function downsampleSeries(timeseries_data, options) {
+ return _.map(timeseries_data, function (timeseries) {
+ if (timeseries.datapoints.length > options.maxDataPoints) {
+ timeseries.datapoints = dataProcessor.groupBy(options.interval, dataProcessor.AVERAGE, timeseries.datapoints);
+ }
+ return timeseries;
+ });
+ }
+
+ function formatMetric(metricObj) {
+ return {
+ text: metricObj.name,
+ expandable: false
+ };
+ }
+
+ /**
+ * Custom formatter for template variables.
+ * Default Grafana "regex" formatter returns
+ * value1|value2
+ * This formatter returns
+ * (value1|value2)
+ * This format needed for using in complex regex with
+ * template variables, for example
+ * /CPU $cpu_item.*time/ where $cpu_item is system,user,iowait
+ */
+ function zabbixTemplateFormat(value) {
+ if (typeof value === 'string') {
+ return utils.escapeRegex(value);
+ }
+
+ var escapedValues = _.map(value, utils.escapeRegex);
+ return '(' + escapedValues.join('|') + ')';
+ }
+
+ /**
+ * If template variables are used in request, replace it using regex format
+ * and wrap with '/' for proper multi-value work. Example:
+ * $variable selected as a, b, c
+ * We use filter $variable
+ * $variable -> a|b|c -> /a|b|c/
+ * /$variable/ -> /a|b|c/ -> /a|b|c/
+ */
+ function replaceTemplateVars(templateSrv, target, scopedVars) {
+ var replacedTarget = templateSrv.replace(target, scopedVars, zabbixTemplateFormat);
+ if (target !== replacedTarget && !utils.isRegex(replacedTarget)) {
+ replacedTarget = '/^' + replacedTarget + '$/';
+ }
+ return replacedTarget;
+ }
+
+ function extractText(str, pattern, useCaptureGroups) {
+ var extractPattern = new RegExp(pattern);
+ var extractedValue = extractPattern.exec(str);
+ if (extractedValue) {
+ if (useCaptureGroups) {
+ extractedValue = extractedValue[1];
+ } else {
+ extractedValue = extractedValue[0];
+ }
+ }
+ return extractedValue;
+ }
+
+ // Apply function one by one:
+ // sequence([a(), b(), c()]) = c(b(a()));
+ function sequence(funcsArray) {
+ return function (result) {
+ for (var i = 0; i < funcsArray.length; i++) {
+ result = funcsArray[i].call(this, result);
+ }
+ return result;
+ };
+ }
+
+ return {
+ setters: [function (_lodash) {
+ _ = _lodash.default;
+ }, function (_appCoreUtilsDatemath) {
+ dateMath = _appCoreUtilsDatemath;
+ }, function (_utils) {
+ utils = _utils;
+ }, function (_migrations) {
+ migrations = _migrations;
+ }, function (_metricFunctions) {
+ metricFunctions = _metricFunctions;
+ }, function (_dataProcessor) {
+ dataProcessor = _dataProcessor.default;
+ }, function (_responseHandler) {
+ responseHandler = _responseHandler.default;
+ }, function (_zabbixJs) {}, function (_zabbixAPICoreServiceJs) {
+ ZabbixAPIError = _zabbixAPICoreServiceJs.ZabbixAPIError;
+ }],
+ execute: function () {
+ _slicedToArray = function () {
+ function sliceIterator(arr, i) {
+ var _arr = [];
+ var _n = true;
+ var _d = false;
+ var _e = undefined;
+
+ try {
+ for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
+ _arr.push(_s.value);
+
+ if (i && _arr.length === i) break;
+ }
+ } catch (err) {
+ _d = true;
+ _e = err;
+ } finally {
+ try {
+ if (!_n && _i["return"]) _i["return"]();
+ } finally {
+ if (_d) throw _e;
+ }
+ }
+
+ return _arr;
+ }
+
+ return function (arr, i) {
+ if (Array.isArray(arr)) {
+ return arr;
+ } else if (Symbol.iterator in Object(arr)) {
+ return sliceIterator(arr, i);
+ } else {
+ throw new TypeError("Invalid attempt to destructure non-iterable instance");
+ }
+ };
+ }();
+
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ _export('ZabbixAPIDatasource', ZabbixAPIDatasource = function () {
+
+ /** @ngInject */
+ function ZabbixAPIDatasource(instanceSettings, templateSrv, alertSrv, Zabbix) {
+ _classCallCheck(this, ZabbixAPIDatasource);
+
+ this.templateSrv = templateSrv;
+ this.alertSrv = alertSrv;
+
+ // General data source settings
+ this.name = instanceSettings.name;
+ this.url = instanceSettings.url;
+ this.basicAuth = instanceSettings.basicAuth;
+ this.withCredentials = instanceSettings.withCredentials;
+
+ // Zabbix API credentials
+ this.username = instanceSettings.jsonData.username;
+ this.password = instanceSettings.jsonData.password;
+
+ // Use trends instead history since specified time
+ this.trends = instanceSettings.jsonData.trends;
+ this.trendsFrom = instanceSettings.jsonData.trendsFrom || '7d';
+
+ // Set cache update interval
+ var ttl = instanceSettings.jsonData.cacheTTL || '1h';
+ this.cacheTTL = utils.parseInterval(ttl);
+
+ this.zabbix = new Zabbix(this.url, this.username, this.password, this.basicAuth, this.withCredentials, this.cacheTTL);
+
+ // Use custom format for template variables
+ this.replaceTemplateVars = _.partial(replaceTemplateVars, this.templateSrv);
+ }
+
+ ////////////////////////
+ // Datasource methods //
+ ////////////////////////
+
+ /**
+ * Query panel data. Calls for each panel in dashboard.
+ * @param {Object} options Contains time range, targets and other info.
+ * @return {Object} Grafana metrics object with timeseries data for each target.
+ */
+
+
+ _createClass(ZabbixAPIDatasource, [{
+ key: 'query',
+ value: function query(options) {
+ var _this = this;
+
+ var timeFrom = Math.ceil(dateMath.parse(options.range.from) / 1000);
+ var timeTo = Math.ceil(dateMath.parse(options.range.to) / 1000);
+
+ var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000);
+ var useTrends = timeFrom <= useTrendsFrom && this.trends;
+
+ // Create request for each target
+ var promises = _.map(options.targets, function (target) {
+ // Prevent changes of original object
+ target = _.cloneDeep(target);
+ _this.replaceTargetVariables(target, options);
+
+ // Apply Time-related functions (timeShift(), etc)
+ var timeFunctions = bindFunctionDefs(target.functions, 'Time');
+ if (timeFunctions.length) {
+ var _sequence = sequence(timeFunctions)([timeFrom, timeTo]),
+ _sequence2 = _slicedToArray(_sequence, 2),
+ time_from = _sequence2[0],
+ time_to = _sequence2[1];
+
+ timeFrom = time_from;
+ timeTo = time_to;
+ }
+
+ // Metrics or Text query mode
+ if (target.mode !== 1) {
+ // Migrate old targets
+ target = migrations.migrate(target);
+
+ // Don't request undefined and hidden targets
+ if (target.hide || !target.group || !target.host || !target.item) {
+ return [];
+ }
+
+ if (!target.mode || target.mode === 0) {
+ return _this.queryNumericData(target, timeFrom, timeTo, useTrends);
+ } else if (target.mode === 2) {
+ return _this.queryTextData(target, timeFrom, timeTo);
+ }
+ }
+
+ // IT services mode
+ else if (target.mode === 1) {
+ // Don't show undefined and hidden targets
+ if (target.hide || !target.itservice || !target.slaProperty) {
+ return [];
+ }
+
+ return _this.zabbix.getSLA(target.itservice.serviceid, timeFrom, timeTo).then(function (slaObject) {
+ return responseHandler.handleSLAResponse(target.itservice, target.slaProperty, slaObject);
+ });
+ }
+ });
+
+ // Data for panel (all targets)
+ return Promise.all(_.flatten(promises)).then(_.flatten).then(function (timeseries_data) {
+ return downsampleSeries(timeseries_data, options);
+ }).then(function (data) {
+ return { data: data };
+ });
+ }
+ }, {
+ key: 'queryNumericData',
+ value: function queryNumericData(target, timeFrom, timeTo, useTrends) {
+ var _this2 = this;
+
+ var options = {
+ itemtype: 'num'
+ };
+ return this.zabbix.getItemsFromTarget(target, options).then(function (items) {
+ var getHistoryPromise = void 0;
+
+ if (useTrends) {
+ (function () {
+ var valueType = _this2.getTrendValueType(target);
+ getHistoryPromise = _this2.zabbix.getTrend(items, timeFrom, timeTo).then(function (history) {
+ return responseHandler.handleTrends(history, items, valueType);
+ });
+ })();
+ } else {
+ // Use history
+ getHistoryPromise = _this2.zabbix.getHistory(items, timeFrom, timeTo).then(function (history) {
+ return responseHandler.handleHistory(history, items);
+ });
+ }
+
+ return getHistoryPromise.then(function (timeseries_data) {
+ return _this2.applyDataProcessingFunctions(timeseries_data, target);
+ });
+ });
+ }
+ }, {
+ key: 'getTrendValueType',
+ value: function getTrendValueType(target) {
+ // Find trendValue() function and get specified trend value
+ var trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name');
+ var trendValueFunc = _.find(target.functions, function (func) {
+ return _.includes(trendFunctions, func.def.name);
+ });
+ return trendValueFunc ? trendValueFunc.params[0] : "avg";
+ }
+ }, {
+ key: 'applyDataProcessingFunctions',
+ value: function applyDataProcessingFunctions(timeseries_data, target) {
+ var transformFunctions = bindFunctionDefs(target.functions, 'Transform');
+ var aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate');
+ var filterFunctions = bindFunctionDefs(target.functions, 'Filter');
+ var aliasFunctions = bindFunctionDefs(target.functions, 'Alias');
+
+ // Apply transformation functions
+ timeseries_data = _.map(timeseries_data, function (timeseries) {
+ timeseries.datapoints = sequence(transformFunctions)(timeseries.datapoints);
+ return timeseries;
+ });
+
+ // Apply filter functions
+ if (filterFunctions.length) {
+ timeseries_data = sequence(filterFunctions)(timeseries_data);
+ }
+
+ // Apply aggregations
+ if (aggregationFunctions.length) {
+ (function () {
+ var dp = _.map(timeseries_data, 'datapoints');
+ dp = sequence(aggregationFunctions)(dp);
+
+ var aggFuncNames = _.map(metricFunctions.getCategories()['Aggregate'], 'name');
+ var lastAgg = _.findLast(target.functions, function (func) {
+ return _.includes(aggFuncNames, func.def.name);
+ });
+
+ timeseries_data = [{
+ target: lastAgg.text,
+ datapoints: dp
+ }];
+ })();
+ }
+
+ // Apply alias functions
+ _.forEach(timeseries_data, sequence(aliasFunctions));
+
+ // Apply Time-related functions (timeShift(), etc)
+ // Find timeShift() function and get specified trend value
+ this.applyTimeShiftFunction(timeseries_data, target);
+
+ return timeseries_data;
+ }
+ }, {
+ key: 'applyTimeShiftFunction',
+ value: function applyTimeShiftFunction(timeseries_data, target) {
+ // Find timeShift() function and get specified interval
+ var timeShiftFunc = _.find(target.functions, function (func) {
+ return func.def.name === 'timeShift';
+ });
+ if (timeShiftFunc) {
+ (function () {
+ var shift = timeShiftFunc.params[0];
+ _.forEach(timeseries_data, function (series) {
+ series.datapoints = dataProcessor.unShiftTimeSeries(shift, series.datapoints);
+ });
+ })();
+ }
+ }
+ }, {
+ key: 'queryTextData',
+ value: function queryTextData(target, timeFrom, timeTo) {
+ var _this3 = this;
+
+ var options = {
+ itemtype: 'text'
+ };
+ return this.zabbix.getItemsFromTarget(target, options).then(function (items) {
+ if (items.length) {
+ return _this3.zabbix.getHistory(items, timeFrom, timeTo).then(function (history) {
+ return responseHandler.convertHistory(history, items, false, function (point) {
+ var value = point.value;
+
+ // Regex-based extractor
+ if (target.textFilter) {
+ value = extractText(point.value, target.textFilter, target.useCaptureGroups);
+ }
+
+ return [value, point.clock * 1000];
+ });
+ });
+ } else {
+ return Promise.resolve([]);
+ }
+ });
+ }
+ }, {
+ key: 'testDatasource',
+ value: function testDatasource() {
+ var _this4 = this;
+
+ var zabbixVersion = void 0;
+ return this.zabbix.getVersion().then(function (version) {
+ zabbixVersion = version;
+ return _this4.zabbix.login();
+ }).then(function () {
+ return {
+ status: "success",
+ title: "Success",
+ message: "Zabbix API version: " + zabbixVersion
+ };
+ }).catch(function (error) {
+ if (error instanceof ZabbixAPIError) {
+ return {
+ status: "error",
+ title: error.message,
+ message: error.data
+ };
+ } else {
+ return {
+ status: "error",
+ title: "Connection failed",
+ message: "Could not connect to given url"
+ };
+ }
+ });
+ }
+ }, {
+ key: 'metricFindQuery',
+ value: function metricFindQuery(query) {
+ var _this5 = this;
+
+ var result = void 0;
+ var parts = [];
+
+ // Split query. Query structure: group.host.app.item
+ _.each(query.split('.'), function (part) {
+ part = _this5.replaceTemplateVars(part, {});
+
+ // Replace wildcard to regex
+ if (part === '*') {
+ part = '/.*/';
+ }
+ parts.push(part);
+ });
+ var template = _.zipObject(['group', 'host', 'app', 'item'], parts);
+
+ // Get items
+ if (parts.length === 4) {
+ // Search for all items, even it's not belong to any application
+ if (template.app === '/.*/') {
+ template.app = '';
+ }
+ result = this.zabbix.getItems(template.group, template.host, template.app, template.item);
+ } else if (parts.length === 3) {
+ // Get applications
+ result = this.zabbix.getApps(template.group, template.host, template.app);
+ } else if (parts.length === 2) {
+ // Get hosts
+ result = this.zabbix.getHosts(template.group, template.host);
+ } else if (parts.length === 1) {
+ // Get groups
+ result = this.zabbix.getGroups(template.group);
+ } else {
+ result = Promise.resolve([]);
+ }
+
+ return result.then(function (metrics) {
+ return metrics.map(formatMetric);
+ });
+ }
+ }, {
+ key: 'annotationQuery',
+ value: function annotationQuery(options) {
+ var _this6 = this;
+
+ var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000);
+ var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000);
+ var annotation = options.annotation;
+ var showOkEvents = annotation.showOkEvents ? [0, 1] : 1;
+
+ // Show all triggers
+ var showTriggers = [0, 1];
+
+ var getTriggers = this.zabbix.getTriggers(this.replaceTemplateVars(annotation.group, {}), this.replaceTemplateVars(annotation.host, {}), this.replaceTemplateVars(annotation.application, {}), showTriggers);
+
+ return getTriggers.then(function (triggers) {
+
+ // Filter triggers by description
+ if (utils.isRegex(annotation.trigger)) {
+ triggers = _.filter(triggers, function (trigger) {
+ return utils.buildRegex(annotation.trigger).test(trigger.description);
+ });
+ } else if (annotation.trigger) {
+ triggers = _.filter(triggers, function (trigger) {
+ return trigger.description === annotation.trigger;
+ });
+ }
+
+ // Remove events below the chose severity
+ triggers = _.filter(triggers, function (trigger) {
+ return Number(trigger.priority) >= Number(annotation.minseverity);
+ });
+
+ var objectids = _.map(triggers, 'triggerid');
+ return _this6.zabbix.getEvents(objectids, timeFrom, timeTo, showOkEvents).then(function (events) {
+ var indexedTriggers = _.keyBy(triggers, 'triggerid');
+
+ // Hide acknowledged events if option enabled
+ if (annotation.hideAcknowledged) {
+ events = _.filter(events, function (event) {
+ return !event.acknowledges.length;
+ });
+ }
+
+ return _.map(events, function (event) {
+ var tags = void 0;
+ if (annotation.showHostname) {
+ tags = _.map(event.hosts, 'name');
+ }
+
+ // Show event type (OK or Problem)
+ var title = Number(event.value) ? 'Problem' : 'OK';
+
+ var formatted_acknowledges = utils.formatAcknowledges(event.acknowledges);
+ return {
+ annotation: annotation,
+ time: event.clock * 1000,
+ title: title,
+ tags: tags,
+ text: indexedTriggers[event.objectid].description + formatted_acknowledges
+ };
+ });
+ });
+ });
+ }
+ }, {
+ key: 'replaceTargetVariables',
+ value: function replaceTargetVariables(target, options) {
+ var _this7 = this;
+
+ var parts = ['group', 'host', 'application', 'item'];
+ parts.forEach(function (p) {
+ if (target[p] && target[p].filter) {
+ target[p].filter = _this7.replaceTemplateVars(target[p].filter, options.scopedVars);
+ }
+ });
+ target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars);
+
+ _.forEach(target.functions, function (func) {
+ func.params = func.params.map(function (param) {
+ if (typeof param === 'number') {
+ return +_this7.templateSrv.replace(param.toString(), options.scopedVars);
+ } else {
+ return _this7.templateSrv.replace(param, options.scopedVars);
+ }
+ });
+ });
+ }
+ }]);
+
+ return ZabbixAPIDatasource;
+ }());
+
+ _export('ZabbixAPIDatasource', ZabbixAPIDatasource);
+
+ _export('zabbixTemplateFormat', zabbixTemplateFormat);
+
+ // Fix for backward compatibility with lodash 2.4
+ if (!_.includes) {
+ _.includes = _.contains;
+ }
+ if (!_.keyBy) {
+ _.keyBy = _.indexBy;
+ }
+ }
+ };
+});
+//# sourceMappingURL=datasource.js.map
diff --git a/dist/datasource-zabbix/datasource.js.map b/dist/datasource-zabbix/datasource.js.map
new file mode 100644
index 0000000..fca55f1
--- /dev/null
+++ b/dist/datasource-zabbix/datasource.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/datasource.js"],"names":["bindFunctionDefs","functionDefs","category","aggregationFunctions","_","map","metricFunctions","getCategories","aggFuncDefs","filter","func","includes","def","name","funcInstance","createFuncInstance","params","bindFunction","dataProcessor","downsampleSeries","timeseries_data","options","timeseries","datapoints","length","maxDataPoints","groupBy","interval","AVERAGE","formatMetric","metricObj","text","expandable","zabbixTemplateFormat","value","utils","escapeRegex","escapedValues","join","replaceTemplateVars","templateSrv","target","scopedVars","replacedTarget","replace","isRegex","extractText","str","pattern","useCaptureGroups","extractPattern","RegExp","extractedValue","exec","sequence","funcsArray","result","i","call","dateMath","migrations","responseHandler","ZabbixAPIError","ZabbixAPIDatasource","instanceSettings","alertSrv","Zabbix","url","basicAuth","withCredentials","username","jsonData","password","trends","trendsFrom","ttl","cacheTTL","parseInterval","zabbix","partial","timeFrom","Math","ceil","parse","range","from","timeTo","to","useTrendsFrom","useTrends","promises","targets","cloneDeep","replaceTargetVariables","timeFunctions","functions","time_from","time_to","mode","migrate","hide","group","host","item","queryNumericData","queryTextData","itservice","slaProperty","getSLA","serviceid","then","handleSLAResponse","slaObject","Promise","all","flatten","data","itemtype","getItemsFromTarget","getHistoryPromise","valueType","getTrendValueType","getTrend","items","handleTrends","history","getHistory","handleHistory","applyDataProcessingFunctions","trendFunctions","trendValueFunc","find","transformFunctions","filterFunctions","aliasFunctions","dp","aggFuncNames","lastAgg","findLast","forEach","applyTimeShiftFunction","timeShiftFunc","shift","series","unShiftTimeSeries","convertHistory","point","textFilter","clock","resolve","zabbixVersion","getVersion","version","login","status","title","message","catch","error","query","parts","each","split","part","push","template","zipObject","app","getItems","getApps","getHosts","getGroups","metrics","rangeRaw","annotation","showOkEvents","showTriggers","getTriggers","application","trigger","triggers","buildRegex","test","description","Number","priority","minseverity","objectids","getEvents","indexedTriggers","keyBy","hideAcknowledged","events","event","acknowledges","tags","showHostname","hosts","formatted_acknowledges","formatAcknowledges","time","objectid","p","param","toString","contains","indexBy"],"mappings":"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","file":"datasource.js","sourcesContent":["//import angular from 'angular';\nimport _ from 'lodash';\nimport * as dateMath from 'app/core/utils/datemath';\nimport * as utils from './utils';\nimport * as migrations from './migrations';\nimport * as metricFunctions from './metricFunctions';\nimport dataProcessor from './dataProcessor';\nimport responseHandler from './responseHandler';\nimport './zabbix.js';\nimport {ZabbixAPIError} from './zabbixAPICore.service.js';\n\nclass ZabbixAPIDatasource {\n\n /** @ngInject */\n constructor(instanceSettings, templateSrv, alertSrv, Zabbix) {\n this.templateSrv = templateSrv;\n this.alertSrv = alertSrv;\n\n // General data source settings\n this.name = instanceSettings.name;\n this.url = instanceSettings.url;\n this.basicAuth = instanceSettings.basicAuth;\n this.withCredentials = instanceSettings.withCredentials;\n\n // Zabbix API credentials\n this.username = instanceSettings.jsonData.username;\n this.password = instanceSettings.jsonData.password;\n\n // Use trends instead history since specified time\n this.trends = instanceSettings.jsonData.trends;\n this.trendsFrom = instanceSettings.jsonData.trendsFrom || '7d';\n\n // Set cache update interval\n var ttl = instanceSettings.jsonData.cacheTTL || '1h';\n this.cacheTTL = utils.parseInterval(ttl);\n\n this.zabbix = new Zabbix(this.url, this.username, this.password, this.basicAuth, this.withCredentials, this.cacheTTL);\n\n // Use custom format for template variables\n this.replaceTemplateVars = _.partial(replaceTemplateVars, this.templateSrv);\n }\n\n ////////////////////////\n // Datasource methods //\n ////////////////////////\n\n /**\n * Query panel data. Calls for each panel in dashboard.\n * @param {Object} options Contains time range, targets and other info.\n * @return {Object} Grafana metrics object with timeseries data for each target.\n */\n query(options) {\n let timeFrom = Math.ceil(dateMath.parse(options.range.from) / 1000);\n let timeTo = Math.ceil(dateMath.parse(options.range.to) / 1000);\n\n let useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000);\n let useTrends = (timeFrom <= useTrendsFrom) && this.trends;\n\n // Create request for each target\n let promises = _.map(options.targets, target => {\n // Prevent changes of original object\n target = _.cloneDeep(target);\n this.replaceTargetVariables(target, options);\n\n // Apply Time-related functions (timeShift(), etc)\n let timeFunctions = bindFunctionDefs(target.functions, 'Time');\n if (timeFunctions.length) {\n const [time_from, time_to] = sequence(timeFunctions)([timeFrom, timeTo]);\n timeFrom = time_from;\n timeTo = time_to;\n }\n\n // Metrics or Text query mode\n if (target.mode !== 1) {\n // Migrate old targets\n target = migrations.migrate(target);\n\n // Don't request undefined and hidden targets\n if (target.hide || !target.group || !target.host || !target.item) {\n return [];\n }\n\n if (!target.mode || target.mode === 0) {\n return this.queryNumericData(target, timeFrom, timeTo, useTrends);\n } else if (target.mode === 2) {\n return this.queryTextData(target, timeFrom, timeTo);\n }\n }\n\n // IT services mode\n else if (target.mode === 1) {\n // Don't show undefined and hidden targets\n if (target.hide || !target.itservice || !target.slaProperty) {\n return [];\n }\n\n return this.zabbix.getSLA(target.itservice.serviceid, timeFrom, timeTo)\n .then(slaObject => {\n return responseHandler.handleSLAResponse(target.itservice, target.slaProperty, slaObject);\n });\n }\n });\n\n // Data for panel (all targets)\n return Promise.all(_.flatten(promises))\n .then(_.flatten)\n .then(timeseries_data => {\n return downsampleSeries(timeseries_data, options);\n })\n .then(data => {\n return { data: data };\n });\n }\n\n queryNumericData(target, timeFrom, timeTo, useTrends) {\n let options = {\n itemtype: 'num'\n };\n return this.zabbix.getItemsFromTarget(target, options)\n .then(items => {\n let getHistoryPromise;\n\n if (useTrends) {\n let valueType = this.getTrendValueType(target);\n getHistoryPromise = this.zabbix.getTrend(items, timeFrom, timeTo)\n .then(history => {\n return responseHandler.handleTrends(history, items, valueType);\n });\n } else {\n // Use history\n getHistoryPromise = this.zabbix.getHistory(items, timeFrom, timeTo)\n .then(history => {\n return responseHandler.handleHistory(history, items);\n });\n }\n\n return getHistoryPromise.then(timeseries_data => {\n return this.applyDataProcessingFunctions(timeseries_data, target);\n });\n });\n }\n\n getTrendValueType(target) {\n // Find trendValue() function and get specified trend value\n var trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name');\n var trendValueFunc = _.find(target.functions, func => {\n return _.includes(trendFunctions, func.def.name);\n });\n return trendValueFunc ? trendValueFunc.params[0] : \"avg\";\n }\n\n applyDataProcessingFunctions(timeseries_data, target) {\n let transformFunctions = bindFunctionDefs(target.functions, 'Transform');\n let aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate');\n let filterFunctions = bindFunctionDefs(target.functions, 'Filter');\n let aliasFunctions = bindFunctionDefs(target.functions, 'Alias');\n\n // Apply transformation functions\n timeseries_data = _.map(timeseries_data, timeseries => {\n timeseries.datapoints = sequence(transformFunctions)(timeseries.datapoints);\n return timeseries;\n });\n\n // Apply filter functions\n if (filterFunctions.length) {\n timeseries_data = sequence(filterFunctions)(timeseries_data);\n }\n\n // Apply aggregations\n if (aggregationFunctions.length) {\n let dp = _.map(timeseries_data, 'datapoints');\n dp = sequence(aggregationFunctions)(dp);\n\n let aggFuncNames = _.map(metricFunctions.getCategories()['Aggregate'], 'name');\n let lastAgg = _.findLast(target.functions, func => {\n return _.includes(aggFuncNames, func.def.name);\n });\n\n timeseries_data = [{\n target: lastAgg.text,\n datapoints: dp\n }];\n }\n\n // Apply alias functions\n _.forEach(timeseries_data, sequence(aliasFunctions));\n\n // Apply Time-related functions (timeShift(), etc)\n // Find timeShift() function and get specified trend value\n this.applyTimeShiftFunction(timeseries_data, target);\n\n return timeseries_data;\n }\n\n applyTimeShiftFunction(timeseries_data, target) {\n // Find timeShift() function and get specified interval\n let timeShiftFunc = _.find(target.functions, (func) => {\n return func.def.name === 'timeShift';\n });\n if (timeShiftFunc) {\n let shift = timeShiftFunc.params[0];\n _.forEach(timeseries_data, (series) => {\n series.datapoints = dataProcessor.unShiftTimeSeries(shift, series.datapoints);\n });\n }\n }\n\n queryTextData(target, timeFrom, timeTo) {\n let options = {\n itemtype: 'text'\n };\n return this.zabbix.getItemsFromTarget(target, options)\n .then(items => {\n if (items.length) {\n return this.zabbix.getHistory(items, timeFrom, timeTo)\n .then(history => {\n return responseHandler.convertHistory(history, items, false, (point) => {\n let value = point.value;\n\n // Regex-based extractor\n if (target.textFilter) {\n value = extractText(point.value, target.textFilter, target.useCaptureGroups);\n }\n\n return [value, point.clock * 1000];\n });\n });\n } else {\n return Promise.resolve([]);\n }\n });\n }\n\n /**\n * Test connection to Zabbix API\n * @return {object} Connection status and Zabbix API version\n */\n testDatasource() {\n let zabbixVersion;\n return this.zabbix.getVersion()\n .then(version => {\n zabbixVersion = version;\n return this.zabbix.login();\n })\n .then(() => {\n return {\n status: \"success\",\n title: \"Success\",\n message: \"Zabbix API version: \" + zabbixVersion\n };\n })\n .catch(error => {\n if (error instanceof ZabbixAPIError) {\n return {\n status: \"error\",\n title: error.message,\n message: error.data\n };\n } else {\n return {\n status: \"error\",\n title: \"Connection failed\",\n message: \"Could not connect to given url\"\n };\n }\n });\n }\n\n ////////////////\n // Templating //\n ////////////////\n\n /**\n * Find metrics from templated request.\n *\n * @param {string} query Query from Templating\n * @return {string} Metric name - group, host, app or item or list\n * of metrics in \"{metric1,metcic2,...,metricN}\" format.\n */\n metricFindQuery(query) {\n let result;\n let parts = [];\n\n // Split query. Query structure: group.host.app.item\n _.each(query.split('.'), part => {\n part = this.replaceTemplateVars(part, {});\n\n // Replace wildcard to regex\n if (part === '*') {\n part = '/.*/';\n }\n parts.push(part);\n });\n let template = _.zipObject(['group', 'host', 'app', 'item'], parts);\n\n // Get items\n if (parts.length === 4) {\n // Search for all items, even it's not belong to any application\n if (template.app === '/.*/') {\n template.app = '';\n }\n result = this.zabbix.getItems(template.group, template.host, template.app, template.item);\n } else if (parts.length === 3) {\n // Get applications\n result = this.zabbix.getApps(template.group, template.host, template.app);\n } else if (parts.length === 2) {\n // Get hosts\n result = this.zabbix.getHosts(template.group, template.host);\n } else if (parts.length === 1) {\n // Get groups\n result = this.zabbix.getGroups(template.group);\n } else {\n result = Promise.resolve([]);\n }\n\n return result.then(metrics => {\n return metrics.map(formatMetric);\n });\n }\n\n /////////////////\n // Annotations //\n /////////////////\n\n annotationQuery(options) {\n var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000);\n var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000);\n var annotation = options.annotation;\n var showOkEvents = annotation.showOkEvents ? [0, 1] : 1;\n\n // Show all triggers\n var showTriggers = [0, 1];\n\n var getTriggers = this.zabbix\n .getTriggers(this.replaceTemplateVars(annotation.group, {}),\n this.replaceTemplateVars(annotation.host, {}),\n this.replaceTemplateVars(annotation.application, {}),\n showTriggers);\n\n return getTriggers.then(triggers => {\n\n // Filter triggers by description\n if (utils.isRegex(annotation.trigger)) {\n triggers = _.filter(triggers, trigger => {\n return utils.buildRegex(annotation.trigger).test(trigger.description);\n });\n } else if (annotation.trigger) {\n triggers = _.filter(triggers, trigger => {\n return trigger.description === annotation.trigger;\n });\n }\n\n // Remove events below the chose severity\n triggers = _.filter(triggers, trigger => {\n return Number(trigger.priority) >= Number(annotation.minseverity);\n });\n\n var objectids = _.map(triggers, 'triggerid');\n return this.zabbix\n .getEvents(objectids, timeFrom, timeTo, showOkEvents)\n .then(events => {\n var indexedTriggers = _.keyBy(triggers, 'triggerid');\n\n // Hide acknowledged events if option enabled\n if (annotation.hideAcknowledged) {\n events = _.filter(events, event => {\n return !event.acknowledges.length;\n });\n }\n\n return _.map(events, event => {\n let tags;\n if (annotation.showHostname) {\n tags = _.map(event.hosts, 'name');\n }\n\n // Show event type (OK or Problem)\n let title = Number(event.value) ? 'Problem' : 'OK';\n\n let formatted_acknowledges = utils.formatAcknowledges(event.acknowledges);\n return {\n annotation: annotation,\n time: event.clock * 1000,\n title: title,\n tags: tags,\n text: indexedTriggers[event.objectid].description + formatted_acknowledges\n };\n });\n });\n });\n }\n\n // Replace template variables\n replaceTargetVariables(target, options) {\n let parts = ['group', 'host', 'application', 'item'];\n parts.forEach(p => {\n if (target[p] && target[p].filter) {\n target[p].filter = this.replaceTemplateVars(target[p].filter, options.scopedVars);\n }\n });\n target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars);\n\n _.forEach(target.functions, func => {\n func.params = func.params.map(param => {\n if (typeof param === 'number') {\n return +this.templateSrv.replace(param.toString(), options.scopedVars);\n } else {\n return this.templateSrv.replace(param, options.scopedVars);\n }\n });\n });\n }\n\n}\n\nfunction bindFunctionDefs(functionDefs, category) {\n var aggregationFunctions = _.map(metricFunctions.getCategories()[category], 'name');\n var aggFuncDefs = _.filter(functionDefs, function(func) {\n return _.includes(aggregationFunctions, func.def.name);\n });\n\n return _.map(aggFuncDefs, function(func) {\n var funcInstance = metricFunctions.createFuncInstance(func.def, func.params);\n return funcInstance.bindFunction(dataProcessor.metricFunctions);\n });\n}\n\nfunction downsampleSeries(timeseries_data, options) {\n return _.map(timeseries_data, timeseries => {\n if (timeseries.datapoints.length > options.maxDataPoints) {\n timeseries.datapoints = dataProcessor\n .groupBy(options.interval, dataProcessor.AVERAGE, timeseries.datapoints);\n }\n return timeseries;\n });\n}\n\nfunction formatMetric(metricObj) {\n return {\n text: metricObj.name,\n expandable: false\n };\n}\n\n/**\n * Custom formatter for template variables.\n * Default Grafana \"regex\" formatter returns\n * value1|value2\n * This formatter returns\n * (value1|value2)\n * This format needed for using in complex regex with\n * template variables, for example\n * /CPU $cpu_item.*time/ where $cpu_item is system,user,iowait\n */\nfunction zabbixTemplateFormat(value) {\n if (typeof value === 'string') {\n return utils.escapeRegex(value);\n }\n\n var escapedValues = _.map(value, utils.escapeRegex);\n return '(' + escapedValues.join('|') + ')';\n}\n\n/**\n * If template variables are used in request, replace it using regex format\n * and wrap with '/' for proper multi-value work. Example:\n * $variable selected as a, b, c\n * We use filter $variable\n * $variable -> a|b|c -> /a|b|c/\n * /$variable/ -> /a|b|c/ -> /a|b|c/\n */\nfunction replaceTemplateVars(templateSrv, target, scopedVars) {\n var replacedTarget = templateSrv.replace(target, scopedVars, zabbixTemplateFormat);\n if (target !== replacedTarget && !utils.isRegex(replacedTarget)) {\n replacedTarget = '/^' + replacedTarget + '$/';\n }\n return replacedTarget;\n}\n\nfunction extractText(str, pattern, useCaptureGroups) {\n let extractPattern = new RegExp(pattern);\n let extractedValue = extractPattern.exec(str);\n if (extractedValue) {\n if (useCaptureGroups) {\n extractedValue = extractedValue[1];\n } else {\n extractedValue = extractedValue[0];\n }\n }\n return extractedValue;\n}\n\n// Apply function one by one:\n// sequence([a(), b(), c()]) = c(b(a()));\nfunction sequence(funcsArray) {\n return function(result) {\n for (var i = 0; i < funcsArray.length; i++) {\n result = funcsArray[i].call(this, result);\n }\n return result;\n };\n}\n\nexport {ZabbixAPIDatasource, zabbixTemplateFormat};\n\n// Fix for backward compatibility with lodash 2.4\nif (!_.includes) {_.includes = _.contains;}\nif (!_.keyBy) {_.keyBy = _.indexBy;}\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/img/zabbix_app_logo.svg b/dist/datasource-zabbix/img/zabbix_app_logo.svg
new file mode 100644
index 0000000..237247d
--- /dev/null
+++ b/dist/datasource-zabbix/img/zabbix_app_logo.svg
@@ -0,0 +1,107 @@
+
+
+
+image/svg+xml
\ No newline at end of file
diff --git a/dist/datasource-zabbix/metric-function-editor.directive.js b/dist/datasource-zabbix/metric-function-editor.directive.js
new file mode 100644
index 0000000..334e6d4
--- /dev/null
+++ b/dist/datasource-zabbix/metric-function-editor.directive.js
@@ -0,0 +1,251 @@
+'use strict';
+
+System.register(['angular', 'lodash', 'jquery'], function (_export, _context) {
+ "use strict";
+
+ var angular, _, $;
+
+ return {
+ setters: [function (_angular) {
+ angular = _angular.default;
+ }, function (_lodash) {
+ _ = _lodash.default;
+ }, function (_jquery) {
+ $ = _jquery.default;
+ }],
+ execute: function () {
+
+ /** @ngInject */
+ angular.module('grafana.directives').directive('metricFunctionEditor', function ($compile, templateSrv) {
+
+ var funcSpanTemplate = '{{func.def.name}} ( ';
+ var paramTemplate = ' ';
+
+ var funcControlsTemplate = '' + ' ' + ' ' + ' ' + ' ' + '
';
+
+ return {
+ restrict: 'A',
+ link: function postLink($scope, elem) {
+ var $funcLink = $(funcSpanTemplate);
+ var $funcControls = $(funcControlsTemplate);
+ var ctrl = $scope.ctrl;
+ var func = $scope.func;
+ var funcDef = func.def;
+ var scheduledRelink = false;
+ var paramCountAtLink = 0;
+
+ function clickFuncParam(paramIndex) {
+ /*jshint validthis:true */
+
+ var $link = $(this);
+ var $input = $link.next();
+
+ $input.val(func.params[paramIndex]);
+ $input.css('width', $link.width() + 16 + 'px');
+
+ $link.hide();
+ $input.show();
+ $input.focus();
+ $input.select();
+
+ var typeahead = $input.data('typeahead');
+ if (typeahead) {
+ $input.val('');
+ typeahead.lookup();
+ }
+ }
+
+ function scheduledRelinkIfNeeded() {
+ if (paramCountAtLink === func.params.length) {
+ return;
+ }
+
+ if (!scheduledRelink) {
+ scheduledRelink = true;
+ setTimeout(function () {
+ relink();
+ scheduledRelink = false;
+ }, 200);
+ }
+ }
+
+ function inputBlur(paramIndex) {
+ /*jshint validthis:true */
+ var $input = $(this);
+ var $link = $input.prev();
+ var newValue = $input.val();
+
+ if (newValue !== '' || func.def.params[paramIndex].optional) {
+ $link.html(templateSrv.highlightVariablesAsHtml(newValue));
+
+ func.updateParam($input.val(), paramIndex);
+ scheduledRelinkIfNeeded();
+
+ $scope.$apply(function () {
+ ctrl.targetChanged();
+ });
+
+ $input.hide();
+ $link.show();
+ }
+ }
+
+ function inputKeyPress(paramIndex, e) {
+ /*jshint validthis:true */
+ if (e.which === 13) {
+ inputBlur.call(this, paramIndex);
+ }
+ }
+
+ function inputKeyDown() {
+ /*jshint validthis:true */
+ this.style.width = (3 + this.value.length) * 8 + 'px';
+ }
+
+ function addTypeahead($input, paramIndex) {
+ $input.attr('data-provide', 'typeahead');
+
+ var options = funcDef.params[paramIndex].options;
+ if (funcDef.params[paramIndex].type === 'int' || funcDef.params[paramIndex].type === 'float') {
+ options = _.map(options, function (val) {
+ return val.toString();
+ });
+ }
+
+ $input.typeahead({
+ source: options,
+ minLength: 0,
+ items: 20,
+ updater: function updater(value) {
+ setTimeout(function () {
+ inputBlur.call($input[0], paramIndex);
+ }, 0);
+ return value;
+ }
+ });
+
+ var typeahead = $input.data('typeahead');
+ typeahead.lookup = function () {
+ this.query = this.$element.val() || '';
+ return this.process(this.source);
+ };
+ }
+
+ function toggleFuncControls() {
+ var targetDiv = elem.closest('.tight-form');
+
+ if (elem.hasClass('show-function-controls')) {
+ elem.removeClass('show-function-controls');
+ targetDiv.removeClass('has-open-function');
+ $funcControls.hide();
+ return;
+ }
+
+ elem.addClass('show-function-controls');
+ targetDiv.addClass('has-open-function');
+
+ $funcControls.show();
+ }
+
+ function addElementsAndCompile() {
+ $funcControls.appendTo(elem);
+ $funcLink.appendTo(elem);
+
+ _.each(funcDef.params, function (param, index) {
+ if (param.optional && func.params.length <= index) {
+ return;
+ }
+
+ if (index > 0) {
+ $(', ').appendTo(elem);
+ }
+
+ var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);
+ var $paramLink = $('' + paramValue + ' ');
+ var $input = $(paramTemplate);
+
+ paramCountAtLink++;
+
+ $paramLink.appendTo(elem);
+ $input.appendTo(elem);
+
+ $input.blur(_.partial(inputBlur, index));
+ $input.keyup(inputKeyDown);
+ $input.keypress(_.partial(inputKeyPress, index));
+ $paramLink.click(_.partial(clickFuncParam, index));
+
+ if (funcDef.params[index].options) {
+ addTypeahead($input, index);
+ }
+ });
+
+ $(') ').appendTo(elem);
+
+ $compile(elem.contents())($scope);
+ }
+
+ function ifJustAddedFocusFistParam() {
+ if ($scope.func.added) {
+ $scope.func.added = false;
+ setTimeout(function () {
+ elem.find('.graphite-func-param-link').first().click();
+ }, 10);
+ }
+ }
+
+ function registerFuncControlsToggle() {
+ $funcLink.click(toggleFuncControls);
+ }
+
+ function registerFuncControlsActions() {
+ $funcControls.click(function (e) {
+ var $target = $(e.target);
+ if ($target.hasClass('fa-remove')) {
+ toggleFuncControls();
+ $scope.$apply(function () {
+ ctrl.removeFunction($scope.func);
+ });
+ return;
+ }
+
+ if ($target.hasClass('fa-arrow-left')) {
+ $scope.$apply(function () {
+ _.move($scope.target.functions, $scope.$index, $scope.$index - 1);
+ ctrl.targetChanged();
+ });
+ return;
+ }
+
+ if ($target.hasClass('fa-arrow-right')) {
+ $scope.$apply(function () {
+ _.move($scope.target.functions, $scope.$index, $scope.$index + 1);
+ ctrl.targetChanged();
+ });
+ return;
+ }
+
+ if ($target.hasClass('fa-question-circle')) {
+ var docSite = "http://docs.grafana-zabbix.org/reference/functions/";
+ window.open(docSite + '#' + funcDef.name.toLowerCase(), '_blank');
+ return;
+ }
+ });
+ }
+
+ function relink() {
+ elem.children().remove();
+
+ addElementsAndCompile();
+ ifJustAddedFocusFistParam();
+ registerFuncControlsToggle();
+ registerFuncControlsActions();
+ }
+
+ relink();
+ }
+ };
+ });
+ }
+ };
+});
+//# sourceMappingURL=metric-function-editor.directive.js.map
diff --git a/dist/datasource-zabbix/metric-function-editor.directive.js.map b/dist/datasource-zabbix/metric-function-editor.directive.js.map
new file mode 100644
index 0000000..ca5b8ba
--- /dev/null
+++ b/dist/datasource-zabbix/metric-function-editor.directive.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/metric-function-editor.directive.js"],"names":["angular","_","$","module","directive","$compile","templateSrv","funcSpanTemplate","paramTemplate","funcControlsTemplate","restrict","link","postLink","$scope","elem","$funcLink","$funcControls","ctrl","func","funcDef","def","scheduledRelink","paramCountAtLink","clickFuncParam","paramIndex","$link","$input","next","val","params","css","width","hide","show","focus","select","typeahead","data","lookup","scheduledRelinkIfNeeded","length","setTimeout","relink","inputBlur","prev","newValue","optional","html","highlightVariablesAsHtml","updateParam","$apply","targetChanged","inputKeyPress","e","which","call","inputKeyDown","style","value","addTypeahead","attr","options","type","map","toString","source","minLength","items","updater","query","$element","process","toggleFuncControls","targetDiv","closest","hasClass","removeClass","addClass","addElementsAndCompile","appendTo","each","param","index","paramValue","$paramLink","blur","partial","keyup","keypress","click","contents","ifJustAddedFocusFistParam","added","find","first","registerFuncControlsToggle","registerFuncControlsActions","$target","target","removeFunction","move","functions","$index","docSite","window","open","name","toLowerCase","children","remove"],"mappings":"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","file":"metric-function-editor.directive.js","sourcesContent":["import angular from 'angular';\nimport _ from 'lodash';\nimport $ from 'jquery';\n\n/** @ngInject */\nangular\n .module('grafana.directives')\n .directive('metricFunctionEditor', function($compile, templateSrv) {\n\n var funcSpanTemplate = '{{func.def.name}} ( ';\n var paramTemplate = ' ';\n\n var funcControlsTemplate =\n '' +\n ' ' +\n ' ' +\n ' ' +\n ' ' +\n '
';\n\n return {\n restrict: 'A',\n link: function postLink($scope, elem) {\n var $funcLink = $(funcSpanTemplate);\n var $funcControls = $(funcControlsTemplate);\n var ctrl = $scope.ctrl;\n var func = $scope.func;\n var funcDef = func.def;\n var scheduledRelink = false;\n var paramCountAtLink = 0;\n\n function clickFuncParam(paramIndex) {\n /*jshint validthis:true */\n\n var $link = $(this);\n var $input = $link.next();\n\n $input.val(func.params[paramIndex]);\n $input.css('width', ($link.width() + 16) + 'px');\n\n $link.hide();\n $input.show();\n $input.focus();\n $input.select();\n\n var typeahead = $input.data('typeahead');\n if (typeahead) {\n $input.val('');\n typeahead.lookup();\n }\n }\n\n function scheduledRelinkIfNeeded() {\n if (paramCountAtLink === func.params.length) {\n return;\n }\n\n if (!scheduledRelink) {\n scheduledRelink = true;\n setTimeout(function() {\n relink();\n scheduledRelink = false;\n }, 200);\n }\n }\n\n function inputBlur(paramIndex) {\n /*jshint validthis:true */\n var $input = $(this);\n var $link = $input.prev();\n var newValue = $input.val();\n\n if (newValue !== '' || func.def.params[paramIndex].optional) {\n $link.html(templateSrv.highlightVariablesAsHtml(newValue));\n\n func.updateParam($input.val(), paramIndex);\n scheduledRelinkIfNeeded();\n\n $scope.$apply(function() {\n ctrl.targetChanged();\n });\n\n $input.hide();\n $link.show();\n }\n }\n\n function inputKeyPress(paramIndex, e) {\n /*jshint validthis:true */\n if(e.which === 13) {\n inputBlur.call(this, paramIndex);\n }\n }\n\n function inputKeyDown() {\n /*jshint validthis:true */\n this.style.width = (3 + this.value.length) * 8 + 'px';\n }\n\n function addTypeahead($input, paramIndex) {\n $input.attr('data-provide', 'typeahead');\n\n var options = funcDef.params[paramIndex].options;\n if (funcDef.params[paramIndex].type === 'int' ||\n funcDef.params[paramIndex].type === 'float') {\n options = _.map(options, function(val) { return val.toString(); });\n }\n\n $input.typeahead({\n source: options,\n minLength: 0,\n items: 20,\n updater: function (value) {\n setTimeout(function() {\n inputBlur.call($input[0], paramIndex);\n }, 0);\n return value;\n }\n });\n\n var typeahead = $input.data('typeahead');\n typeahead.lookup = function () {\n this.query = this.$element.val() || '';\n return this.process(this.source);\n };\n }\n\n function toggleFuncControls() {\n var targetDiv = elem.closest('.tight-form');\n\n if (elem.hasClass('show-function-controls')) {\n elem.removeClass('show-function-controls');\n targetDiv.removeClass('has-open-function');\n $funcControls.hide();\n return;\n }\n\n elem.addClass('show-function-controls');\n targetDiv.addClass('has-open-function');\n\n $funcControls.show();\n }\n\n function addElementsAndCompile() {\n $funcControls.appendTo(elem);\n $funcLink.appendTo(elem);\n\n _.each(funcDef.params, function(param, index) {\n if (param.optional && func.params.length <= index) {\n return;\n }\n\n if (index > 0) {\n $(', ').appendTo(elem);\n }\n\n var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);\n var $paramLink = $('' + paramValue + ' ');\n var $input = $(paramTemplate);\n\n paramCountAtLink++;\n\n $paramLink.appendTo(elem);\n $input.appendTo(elem);\n\n $input.blur(_.partial(inputBlur, index));\n $input.keyup(inputKeyDown);\n $input.keypress(_.partial(inputKeyPress, index));\n $paramLink.click(_.partial(clickFuncParam, index));\n\n if (funcDef.params[index].options) {\n addTypeahead($input, index);\n }\n\n });\n\n $(') ').appendTo(elem);\n\n $compile(elem.contents())($scope);\n }\n\n function ifJustAddedFocusFistParam() {\n if ($scope.func.added) {\n $scope.func.added = false;\n setTimeout(function() {\n elem.find('.graphite-func-param-link').first().click();\n }, 10);\n }\n }\n\n function registerFuncControlsToggle() {\n $funcLink.click(toggleFuncControls);\n }\n\n function registerFuncControlsActions() {\n $funcControls.click(function(e) {\n var $target = $(e.target);\n if ($target.hasClass('fa-remove')) {\n toggleFuncControls();\n $scope.$apply(function() {\n ctrl.removeFunction($scope.func);\n });\n return;\n }\n\n if ($target.hasClass('fa-arrow-left')) {\n $scope.$apply(function() {\n _.move($scope.target.functions, $scope.$index, $scope.$index - 1);\n ctrl.targetChanged();\n });\n return;\n }\n\n if ($target.hasClass('fa-arrow-right')) {\n $scope.$apply(function() {\n _.move($scope.target.functions, $scope.$index, $scope.$index + 1);\n ctrl.targetChanged();\n });\n return;\n }\n\n if ($target.hasClass('fa-question-circle')) {\n var docSite = \"http://docs.grafana-zabbix.org/reference/functions/\";\n window.open(docSite + '#' + funcDef.name.toLowerCase(),'_blank');\n return;\n }\n });\n }\n\n function relink() {\n elem.children().remove();\n\n addElementsAndCompile();\n ifJustAddedFocusFistParam();\n registerFuncControlsToggle();\n registerFuncControlsActions();\n }\n\n relink();\n }\n };\n\n });\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/metricFunctions.js b/dist/datasource-zabbix/metricFunctions.js
new file mode 100644
index 0000000..b03340c
--- /dev/null
+++ b/dist/datasource-zabbix/metricFunctions.js
@@ -0,0 +1,315 @@
+'use strict';
+
+System.register(['lodash', 'jquery'], function (_export, _context) {
+ "use strict";
+
+ var _, $, _createClass, index, categories, FuncInstance;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function addFuncDef(funcDef) {
+ funcDef.params = funcDef.params || [];
+ funcDef.defaultParams = funcDef.defaultParams || [];
+
+ if (funcDef.category) {
+ categories[funcDef.category].push(funcDef);
+ }
+ index[funcDef.name] = funcDef;
+ index[funcDef.shortName || funcDef.name] = funcDef;
+ }
+
+ // Transform
+
+ function createFuncInstance(funcDef, params) {
+ if (_.isString(funcDef)) {
+ if (!index[funcDef]) {
+ throw { message: 'Method not found ' + name };
+ }
+ funcDef = index[funcDef];
+ }
+ return new FuncInstance(funcDef, params);
+ }
+
+ _export('createFuncInstance', createFuncInstance);
+
+ function getFuncDef(name) {
+ return index[name];
+ }
+
+ _export('getFuncDef', getFuncDef);
+
+ function getCategories() {
+ return categories;
+ }
+
+ _export('getCategories', getCategories);
+
+ return {
+ setters: [function (_lodash) {
+ _ = _lodash.default;
+ }, function (_jquery) {
+ $ = _jquery.default;
+ }],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ index = [];
+ categories = {
+ Transform: [],
+ Aggregate: [],
+ Filter: [],
+ Trends: [],
+ Time: [],
+ Alias: []
+ };
+ addFuncDef({
+ name: 'groupBy',
+ category: 'Transform',
+ params: [{ name: 'interval', type: 'string' }, { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
+ defaultParams: ['1m', 'avg']
+ });
+
+ addFuncDef({
+ name: 'scale',
+ category: 'Transform',
+ params: [{ name: 'factor', type: 'float', options: [100, 0.01, 10, -1] }],
+ defaultParams: [100]
+ });
+
+ addFuncDef({
+ name: 'delta',
+ category: 'Transform',
+ params: [],
+ defaultParams: []
+ });
+
+ // Aggregate
+
+ addFuncDef({
+ name: 'sumSeries',
+ category: 'Aggregate',
+ params: [],
+ defaultParams: []
+ });
+
+ addFuncDef({
+ name: 'median',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }],
+ defaultParams: ['1m']
+ });
+
+ addFuncDef({
+ name: 'average',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }],
+ defaultParams: ['1m']
+ });
+
+ addFuncDef({
+ name: 'min',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }],
+ defaultParams: ['1m']
+ });
+
+ addFuncDef({
+ name: 'max',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }],
+ defaultParams: ['1m']
+ });
+
+ addFuncDef({
+ name: 'aggregateBy',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }, { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
+ defaultParams: ['1m', 'avg']
+ });
+
+ // Filter
+
+ addFuncDef({
+ name: 'top',
+ category: 'Filter',
+ params: [{ name: 'number', type: 'int' }, { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
+ defaultParams: [5, 'avg']
+ });
+
+ addFuncDef({
+ name: 'bottom',
+ category: 'Filter',
+ params: [{ name: 'number', type: 'int' }, { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
+ defaultParams: [5, 'avg']
+ });
+
+ // Trends
+
+ addFuncDef({
+ name: 'trendValue',
+ category: 'Trends',
+ params: [{ name: 'type', type: 'string', options: ['avg', 'min', 'max'] }],
+ defaultParams: ['avg']
+ });
+
+ // Time
+
+ addFuncDef({
+ name: 'timeShift',
+ category: 'Time',
+ params: [{ name: 'interval', type: 'string', options: ['24h', '7d', '1M', '+24h', '-24h'] }],
+ defaultParams: ['24h']
+ });
+
+ //Alias
+
+ addFuncDef({
+ name: 'setAlias',
+ category: 'Alias',
+ params: [{ name: 'alias', type: 'string' }],
+ defaultParams: []
+ });
+
+ addFuncDef({
+ name: 'setAliasByRegex',
+ category: 'Alias',
+ params: [{ name: 'aliasByRegex', type: 'string' }],
+ defaultParams: []
+ });
+
+ _.each(categories, function (funcList, catName) {
+ categories[catName] = _.sortBy(funcList, 'name');
+ });
+
+ FuncInstance = function () {
+ function FuncInstance(funcDef, params) {
+ _classCallCheck(this, FuncInstance);
+
+ this.def = funcDef;
+
+ if (params) {
+ this.params = params;
+ } else {
+ // Create with default params
+ this.params = [];
+ this.params = funcDef.defaultParams.slice(0);
+ }
+
+ this.updateText();
+ }
+
+ _createClass(FuncInstance, [{
+ key: 'bindFunction',
+ value: function bindFunction(metricFunctions) {
+ var func = metricFunctions[this.def.name];
+ if (func) {
+
+ // Bind function arguments
+ var bindedFunc = func;
+ var param;
+ for (var i = 0; i < this.params.length; i++) {
+ param = this.params[i];
+
+ // Convert numeric params
+ if (this.def.params[i].type === 'int' || this.def.params[i].type === 'float') {
+ param = Number(param);
+ }
+ bindedFunc = _.partial(bindedFunc, param);
+ }
+ return bindedFunc;
+ } else {
+ throw { message: 'Method not found ' + this.def.name };
+ }
+ }
+ }, {
+ key: 'render',
+ value: function render(metricExp) {
+ var str = this.def.name + '(';
+ var parameters = _.map(this.params, function (value, index) {
+
+ var paramType = this.def.params[index].type;
+ if (paramType === 'int' || paramType === 'float' || paramType === 'value_or_series' || paramType === 'boolean') {
+ return value;
+ } else if (paramType === 'int_or_interval' && $.isNumeric(value)) {
+ return value;
+ }
+
+ return "'" + value + "'";
+ }, this);
+
+ if (metricExp) {
+ parameters.unshift(metricExp);
+ }
+
+ return str + parameters.join(', ') + ')';
+ }
+ }, {
+ key: '_hasMultipleParamsInString',
+ value: function _hasMultipleParamsInString(strValue, index) {
+ if (strValue.indexOf(',') === -1) {
+ return false;
+ }
+
+ return this.def.params[index + 1] && this.def.params[index + 1].optional;
+ }
+ }, {
+ key: 'updateParam',
+ value: function updateParam(strValue, index) {
+ // handle optional parameters
+ // if string contains ',' and next param is optional, split and update both
+ if (this._hasMultipleParamsInString(strValue, index)) {
+ _.each(strValue.split(','), function (partVal, idx) {
+ this.updateParam(partVal.trim(), idx);
+ }, this);
+ return;
+ }
+
+ if (strValue === '' && this.def.params[index].optional) {
+ this.params.splice(index, 1);
+ } else {
+ this.params[index] = strValue;
+ }
+
+ this.updateText();
+ }
+ }, {
+ key: 'updateText',
+ value: function updateText() {
+ if (this.params.length === 0) {
+ this.text = this.def.name + '()';
+ return;
+ }
+
+ var text = this.def.name + '(';
+ text += this.params.join(', ');
+ text += ')';
+ this.text = text;
+ }
+ }]);
+
+ return FuncInstance;
+ }();
+ }
+ };
+});
+//# sourceMappingURL=metricFunctions.js.map
diff --git a/dist/datasource-zabbix/metricFunctions.js.map b/dist/datasource-zabbix/metricFunctions.js.map
new file mode 100644
index 0000000..4f89c5e
--- /dev/null
+++ b/dist/datasource-zabbix/metricFunctions.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/metricFunctions.js"],"names":["addFuncDef","funcDef","params","defaultParams","category","categories","push","index","name","shortName","createFuncInstance","_","isString","message","FuncInstance","getFuncDef","getCategories","$","Transform","Aggregate","Filter","Trends","Time","Alias","type","options","each","funcList","catName","sortBy","def","slice","updateText","metricFunctions","func","bindedFunc","param","i","length","Number","partial","metricExp","str","parameters","map","value","paramType","isNumeric","unshift","join","strValue","indexOf","optional","_hasMultipleParamsInString","split","partVal","idx","updateParam","trim","splice","text"],"mappings":"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","file":"metricFunctions.js","sourcesContent":["import _ from 'lodash';\nimport $ from 'jquery';\n\nvar index = [];\nvar categories = {\n Transform: [],\n Aggregate: [],\n Filter: [],\n Trends: [],\n Time: [],\n Alias: []\n};\n\nfunction addFuncDef(funcDef) {\n funcDef.params = funcDef.params || [];\n funcDef.defaultParams = funcDef.defaultParams || [];\n\n if (funcDef.category) {\n categories[funcDef.category].push(funcDef);\n }\n index[funcDef.name] = funcDef;\n index[funcDef.shortName || funcDef.name] = funcDef;\n}\n\n// Transform\n\naddFuncDef({\n name: 'groupBy',\n category: 'Transform',\n params: [\n { name: 'interval', type: 'string'},\n { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }\n ],\n defaultParams: ['1m', 'avg'],\n});\n\naddFuncDef({\n name: 'scale',\n category: 'Transform',\n params: [\n { name: 'factor', type: 'float', options: [100, 0.01, 10, -1]}\n ],\n defaultParams: [100],\n});\n\naddFuncDef({\n name: 'delta',\n category: 'Transform',\n params: [],\n defaultParams: [],\n});\n\n// Aggregate\n\naddFuncDef({\n name: 'sumSeries',\n category: 'Aggregate',\n params: [],\n defaultParams: [],\n});\n\naddFuncDef({\n name: 'median',\n category: 'Aggregate',\n params: [\n { name: 'interval', type: 'string'}\n ],\n defaultParams: ['1m'],\n});\n\naddFuncDef({\n name: 'average',\n category: 'Aggregate',\n params: [\n { name: 'interval', type: 'string' }\n ],\n defaultParams: ['1m'],\n});\n\naddFuncDef({\n name: 'min',\n category: 'Aggregate',\n params: [\n { name: 'interval', type: 'string' }\n ],\n defaultParams: ['1m'],\n});\n\naddFuncDef({\n name: 'max',\n category: 'Aggregate',\n params: [\n { name: 'interval', type: 'string' }\n ],\n defaultParams: ['1m'],\n});\n\naddFuncDef({\n name: 'aggregateBy',\n category: 'Aggregate',\n params: [\n { name: 'interval', type: 'string' },\n { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }\n ],\n defaultParams: ['1m', 'avg'],\n});\n\n// Filter\n\naddFuncDef({\n name: 'top',\n category: 'Filter',\n params: [\n { name: 'number', type: 'int' },\n { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }\n ],\n defaultParams: [5, 'avg'],\n});\n\naddFuncDef({\n name: 'bottom',\n category: 'Filter',\n params: [\n { name: 'number', type: 'int' },\n { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }\n ],\n defaultParams: [5, 'avg'],\n});\n\n// Trends\n\naddFuncDef({\n name: 'trendValue',\n category: 'Trends',\n params: [\n { name: 'type', type: 'string', options: ['avg', 'min', 'max'] }\n ],\n defaultParams: ['avg'],\n});\n\n// Time\n\naddFuncDef({\n name: 'timeShift',\n category: 'Time',\n params: [\n { name: 'interval', type: 'string', options: ['24h', '7d', '1M', '+24h', '-24h']}\n ],\n defaultParams: ['24h'],\n});\n\n//Alias\n\naddFuncDef({\n name: 'setAlias',\n category: 'Alias',\n params: [\n { name: 'alias', type: 'string' }\n ],\n defaultParams: []\n});\n\naddFuncDef({\n name: 'setAliasByRegex',\n category: 'Alias',\n params: [\n { name: 'aliasByRegex', type: 'string' }\n ],\n defaultParams: []\n});\n\n_.each(categories, function(funcList, catName) {\n categories[catName] = _.sortBy(funcList, 'name');\n});\n\nclass FuncInstance {\n constructor(funcDef, params) {\n this.def = funcDef;\n\n if (params) {\n this.params = params;\n } else {\n // Create with default params\n this.params = [];\n this.params = funcDef.defaultParams.slice(0);\n }\n\n this.updateText();\n }\n\n bindFunction(metricFunctions) {\n var func = metricFunctions[this.def.name];\n if (func) {\n\n // Bind function arguments\n var bindedFunc = func;\n var param;\n for (var i = 0; i < this.params.length; i++) {\n param = this.params[i];\n\n // Convert numeric params\n if (this.def.params[i].type === 'int' ||\n this.def.params[i].type === 'float') {\n param = Number(param);\n }\n bindedFunc = _.partial(bindedFunc, param);\n }\n return bindedFunc;\n } else {\n throw { message: 'Method not found ' + this.def.name };\n }\n }\n\n render(metricExp) {\n var str = this.def.name + '(';\n var parameters = _.map(this.params, function(value, index) {\n\n var paramType = this.def.params[index].type;\n if (paramType === 'int' ||\n paramType === 'float' ||\n paramType === 'value_or_series' ||\n paramType === 'boolean') {\n return value;\n }\n else if (paramType === 'int_or_interval' && $.isNumeric(value)) {\n return value;\n }\n\n return \"'\" + value + \"'\";\n\n }, this);\n\n if (metricExp) {\n parameters.unshift(metricExp);\n }\n\n return str + parameters.join(', ') + ')';\n }\n\n _hasMultipleParamsInString(strValue, index) {\n if (strValue.indexOf(',') === -1) {\n return false;\n }\n\n return this.def.params[index + 1] && this.def.params[index + 1].optional;\n }\n\n updateParam(strValue, index) {\n // handle optional parameters\n // if string contains ',' and next param is optional, split and update both\n if (this._hasMultipleParamsInString(strValue, index)) {\n _.each(strValue.split(','), function(partVal, idx) {\n this.updateParam(partVal.trim(), idx);\n }, this);\n return;\n }\n\n if (strValue === '' && this.def.params[index].optional) {\n this.params.splice(index, 1);\n }\n else {\n this.params[index] = strValue;\n }\n\n this.updateText();\n }\n\n updateText() {\n if (this.params.length === 0) {\n this.text = this.def.name + '()';\n return;\n }\n\n var text = this.def.name + '(';\n text += this.params.join(', ');\n text += ')';\n this.text = text;\n }\n}\n\nexport function createFuncInstance(funcDef, params) {\n if (_.isString(funcDef)) {\n if (!index[funcDef]) {\n throw { message: 'Method not found ' + name };\n }\n funcDef = index[funcDef];\n }\n return new FuncInstance(funcDef, params);\n}\n\nexport function getFuncDef(name) {\n return index[name];\n}\n\nexport function getCategories() {\n return categories;\n}\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/migrations.js b/dist/datasource-zabbix/migrations.js
new file mode 100644
index 0000000..1b10639
--- /dev/null
+++ b/dist/datasource-zabbix/migrations.js
@@ -0,0 +1,55 @@
+"use strict";
+
+System.register([], function (_export, _context) {
+ "use strict";
+
+ /**
+ * Query format migration.
+ * This module can detect query format version and make migration.
+ */
+
+ function isGrafana2target(target) {
+ if (!target.mode || target.mode === 0 || target.mode === 2) {
+ if ((target.hostFilter || target.itemFilter || target.downsampleFunction || target.host && target.host.host) && target.item.filter === undefined && target.host.filter === undefined) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ _export("isGrafana2target", isGrafana2target);
+
+ function migrateFrom2To3version(target) {
+ target.group.filter = target.group.name === "*" ? "/.*/" : target.group.name;
+ target.host.filter = target.host.name === "*" ? convertToRegex(target.hostFilter) : target.host.name;
+ target.application.filter = target.application.name === "*" ? "" : target.application.name;
+ target.item.filter = target.item.name === "All" ? convertToRegex(target.itemFilter) : target.item.name;
+ return target;
+ }
+ _export("migrateFrom2To3version", migrateFrom2To3version);
+
+ function migrate(target) {
+ if (isGrafana2target(target)) {
+ return migrateFrom2To3version(target);
+ } else {
+ return target;
+ }
+ }
+
+ _export("migrate", migrate);
+
+ function convertToRegex(str) {
+ if (str) {
+ return '/' + str + '/';
+ } else {
+ return '/.*/';
+ }
+ }return {
+ setters: [],
+ execute: function () {}
+ };
+});
+//# sourceMappingURL=migrations.js.map
diff --git a/dist/datasource-zabbix/migrations.js.map b/dist/datasource-zabbix/migrations.js.map
new file mode 100644
index 0000000..35917d4
--- /dev/null
+++ b/dist/datasource-zabbix/migrations.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/migrations.js"],"names":["isGrafana2target","target","mode","hostFilter","itemFilter","downsampleFunction","host","item","filter","undefined","migrateFrom2To3version","group","name","convertToRegex","application","migrate","str"],"mappings":";;;;;AAAA;;;;;AAKO,WAASA,gBAAT,CAA0BC,MAA1B,EAAkC;AACvC,QAAI,CAACA,OAAOC,IAAR,IAAgBD,OAAOC,IAAP,KAAgB,CAAhC,IAAqCD,OAAOC,IAAP,KAAgB,CAAzD,EAA4D;AAC1D,UAAI,CAACD,OAAOE,UAAP,IAAqBF,OAAOG,UAA5B,IAA0CH,OAAOI,kBAAjD,IACAJ,OAAOK,IAAP,IAAeL,OAAOK,IAAP,CAAYA,IAD5B,KAECL,OAAOM,IAAP,CAAYC,MAAZ,KAAuBC,SAAvB,IAAoCR,OAAOK,IAAP,CAAYE,MAAZ,KAAuBC,SAFhE,EAE4E;AAC1E,eAAO,IAAP;AACD,OAJD,MAIO;AACL,eAAO,KAAP;AACD;AACF,KARD,MAQO;AACL,aAAO,KAAP;AACD;AACF;;8BAZeT,gB;;AAcT,WAASU,sBAAT,CAAgCT,MAAhC,EAAwC;AAC7CA,WAAOU,KAAP,CAAaH,MAAb,GAAsBP,OAAOU,KAAP,CAAaC,IAAb,KAAsB,GAAtB,GAA4B,MAA5B,GAAqCX,OAAOU,KAAP,CAAaC,IAAxE;AACAX,WAAOK,IAAP,CAAYE,MAAZ,GAAqBP,OAAOK,IAAP,CAAYM,IAAZ,KAAqB,GAArB,GAA2BC,eAAeZ,OAAOE,UAAtB,CAA3B,GAA+DF,OAAOK,IAAP,CAAYM,IAAhG;AACAX,WAAOa,WAAP,CAAmBN,MAAnB,GAA4BP,OAAOa,WAAP,CAAmBF,IAAnB,KAA4B,GAA5B,GAAkC,EAAlC,GAAuCX,OAAOa,WAAP,CAAmBF,IAAtF;AACAX,WAAOM,IAAP,CAAYC,MAAZ,GAAqBP,OAAOM,IAAP,CAAYK,IAAZ,KAAqB,KAArB,GAA6BC,eAAeZ,OAAOG,UAAtB,CAA7B,GAAiEH,OAAOM,IAAP,CAAYK,IAAlG;AACA,WAAOX,MAAP;AACD;oCANeS,sB;;AAQT,WAASK,OAAT,CAAiBd,MAAjB,EAAyB;AAC9B,QAAID,iBAAiBC,MAAjB,CAAJ,EAA8B;AAC5B,aAAOS,uBAAuBT,MAAvB,CAAP;AACD,KAFD,MAEO;AACL,aAAOA,MAAP;AACD;AACF;;qBANec,O;;AAQhB,WAASF,cAAT,CAAwBG,GAAxB,EAA6B;AAC3B,QAAIA,GAAJ,EAAS;AACP,aAAO,MAAMA,GAAN,GAAY,GAAnB;AACD,KAFD,MAEO;AACL,aAAO,MAAP;AACD;AACF,G","file":"migrations.js","sourcesContent":["/**\n * Query format migration.\n * This module can detect query format version and make migration.\n */\n\nexport function isGrafana2target(target) {\n if (!target.mode || target.mode === 0 || target.mode === 2) {\n if ((target.hostFilter || target.itemFilter || target.downsampleFunction ||\n (target.host && target.host.host)) &&\n (target.item.filter === undefined && target.host.filter === undefined)) {\n return true;\n } else {\n return false;\n }\n } else {\n return false;\n }\n}\n\nexport function migrateFrom2To3version(target) {\n target.group.filter = target.group.name === \"*\" ? \"/.*/\" : target.group.name;\n target.host.filter = target.host.name === \"*\" ? convertToRegex(target.hostFilter) : target.host.name;\n target.application.filter = target.application.name === \"*\" ? \"\" : target.application.name;\n target.item.filter = target.item.name === \"All\" ? convertToRegex(target.itemFilter) : target.item.name;\n return target;\n}\n\nexport function migrate(target) {\n if (isGrafana2target(target)) {\n return migrateFrom2To3version(target);\n } else {\n return target;\n }\n}\n\nfunction convertToRegex(str) {\n if (str) {\n return '/' + str + '/';\n } else {\n return '/.*/';\n }\n}\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/module.js b/dist/datasource-zabbix/module.js
new file mode 100644
index 0000000..2b772d3
--- /dev/null
+++ b/dist/datasource-zabbix/module.js
@@ -0,0 +1,51 @@
+'use strict';
+
+System.register(['./datasource', './query.controller'], function (_export, _context) {
+ "use strict";
+
+ var ZabbixAPIDatasource, ZabbixQueryController, ZabbixConfigController, ZabbixQueryOptionsController, ZabbixAnnotationsQueryController;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ return {
+ setters: [function (_datasource) {
+ ZabbixAPIDatasource = _datasource.ZabbixAPIDatasource;
+ }, function (_queryController) {
+ ZabbixQueryController = _queryController.ZabbixQueryController;
+ }],
+ execute: function () {
+ _export('ConfigCtrl', ZabbixConfigController = function ZabbixConfigController() {
+ _classCallCheck(this, ZabbixConfigController);
+ });
+
+ ZabbixConfigController.templateUrl = 'datasource-zabbix/partials/config.html';
+
+ _export('QueryOptionsCtrl', ZabbixQueryOptionsController = function ZabbixQueryOptionsController() {
+ _classCallCheck(this, ZabbixQueryOptionsController);
+ });
+
+ ZabbixQueryOptionsController.templateUrl = 'datasource-zabbix/partials/query.options.html';
+
+ _export('AnnotationsQueryCtrl', ZabbixAnnotationsQueryController = function ZabbixAnnotationsQueryController() {
+ _classCallCheck(this, ZabbixAnnotationsQueryController);
+ });
+
+ ZabbixAnnotationsQueryController.templateUrl = 'datasource-zabbix/partials/annotations.editor.html';
+
+ _export('Datasource', ZabbixAPIDatasource);
+
+ _export('ConfigCtrl', ZabbixConfigController);
+
+ _export('QueryCtrl', ZabbixQueryController);
+
+ _export('QueryOptionsCtrl', ZabbixQueryOptionsController);
+
+ _export('AnnotationsQueryCtrl', ZabbixAnnotationsQueryController);
+ }
+ };
+});
+//# sourceMappingURL=module.js.map
diff --git a/dist/datasource-zabbix/module.js.map b/dist/datasource-zabbix/module.js.map
new file mode 100644
index 0000000..776f7e4
--- /dev/null
+++ b/dist/datasource-zabbix/module.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/module.js"],"names":["ZabbixAPIDatasource","ZabbixQueryController","ZabbixConfigController","templateUrl","ZabbixQueryOptionsController","ZabbixAnnotationsQueryController"],"mappings":";;;;;;;;;;;;;;;AAAQA,yB,eAAAA,mB;;AACAC,2B,oBAAAA,qB;;;4BAEFC,sB;;;;AACNA,6BAAuBC,WAAvB,GAAqC,wCAArC;;kCAEMC,4B;;;;AACNA,mCAA6BD,WAA7B,GAA2C,+CAA3C;;sCAEME,gC;;;;AACNA,uCAAiCF,WAAjC,GAA+C,oDAA/C;;4BAGEH,mB;;4BACAE,sB;;2BACAD,qB;;kCACAG,4B;;sCACAC,gC","file":"module.js","sourcesContent":["import {ZabbixAPIDatasource} from './datasource';\nimport {ZabbixQueryController} from './query.controller';\n\nclass ZabbixConfigController {}\nZabbixConfigController.templateUrl = 'datasource-zabbix/partials/config.html';\n\nclass ZabbixQueryOptionsController {}\nZabbixQueryOptionsController.templateUrl = 'datasource-zabbix/partials/query.options.html';\n\nclass ZabbixAnnotationsQueryController {}\nZabbixAnnotationsQueryController.templateUrl = 'datasource-zabbix/partials/annotations.editor.html';\n\nexport {\n ZabbixAPIDatasource as Datasource,\n ZabbixConfigController as ConfigCtrl,\n ZabbixQueryController as QueryCtrl,\n ZabbixQueryOptionsController as QueryOptionsCtrl,\n ZabbixAnnotationsQueryController as AnnotationsQueryCtrl\n};\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/partials/annotations.editor.html b/dist/datasource-zabbix/partials/annotations.editor.html
new file mode 100644
index 0000000..6e2e495
--- /dev/null
+++ b/dist/datasource-zabbix/partials/annotations.editor.html
@@ -0,0 +1,65 @@
+
+
+
diff --git a/dist/datasource-zabbix/partials/config.html b/dist/datasource-zabbix/partials/config.html
new file mode 100644
index 0000000..56d9129
--- /dev/null
+++ b/dist/datasource-zabbix/partials/config.html
@@ -0,0 +1,60 @@
+
+
+
+
diff --git a/dist/datasource-zabbix/partials/query.editor.html b/dist/datasource-zabbix/partials/query.editor.html
new file mode 100644
index 0000000..5a7df44
--- /dev/null
+++ b/dist/datasource-zabbix/partials/query.editor.html
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dist/datasource-zabbix/partials/query.options.html b/dist/datasource-zabbix/partials/query.options.html
new file mode 100644
index 0000000..9224822
--- /dev/null
+++ b/dist/datasource-zabbix/partials/query.options.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
Max data points
+
+ Grafana-Zabbix plugin uses maxDataPoints parameter to consolidate the real number of values down to this
+ number
+
+ If there are more real values, then by default they will be consolidated using averages
+ This could hide real peaks and max values in your series
+ Point consolidation will effect series legend values (min,max,total,current)
+ If you override maxDataPoint and set a high value performance can be severely effected
+
+
+
+
+
IT services
+
+ Select "IT services" in targets menu to activate IT services mode.
+
+
+
+
+
IT service property
+
+ Zabbix returns the following availability information about IT service
+ Status - current status of the IT service
+ SLA - SLA for the given time interval
+ OK time - time the service was in OK state, in seconds
+ Problem time - time the service was in problem state, in seconds
+ Down time - time the service was in scheduled downtime, in seconds
+
+
+
+
+
Text filter
+
+ Use regex to extract a part of the returned value.
+
+
+
+
diff --git a/dist/datasource-zabbix/plugin.json b/dist/datasource-zabbix/plugin.json
new file mode 100644
index 0000000..c7cfe7f
--- /dev/null
+++ b/dist/datasource-zabbix/plugin.json
@@ -0,0 +1,19 @@
+{
+ "type": "datasource",
+ "name": "Zabbix",
+ "id": "alexanderzobnin-zabbix-datasource",
+
+ "metrics": true,
+ "annotations": true,
+
+ "info": {
+ "author": {
+ "name": "Alexander Zobnin",
+ "url": "https://github.com/alexanderzobnin/grafana-zabbix"
+ },
+ "logos": {
+ "small": "img/zabbix_app_logo.svg",
+ "large": "img/zabbix_app_logo.svg"
+ }
+ }
+}
diff --git a/dist/datasource-zabbix/query.controller.js b/dist/datasource-zabbix/query.controller.js
new file mode 100644
index 0000000..0b2cb4e
--- /dev/null
+++ b/dist/datasource-zabbix/query.controller.js
@@ -0,0 +1,376 @@
+'use strict';
+
+System.register(['app/plugins/sdk', 'angular', 'lodash', './utils', './metricFunctions', './migrations', './add-metric-function.directive', './metric-function-editor.directive', './css/query-editor.css!'], function (_export, _context) {
+ "use strict";
+
+ var QueryCtrl, angular, _, utils, metricFunctions, migrations, _createClass, ZabbixQueryController;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function _possibleConstructorReturn(self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
+
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ }
+
+ function _inherits(subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ }
+
+ // Get list of metric names for bs-typeahead directive
+ function getMetricNames(scope, metricList) {
+ return _.uniq(_.map(scope.metric[metricList], 'name'));
+ }
+ return {
+ setters: [function (_appPluginsSdk) {
+ QueryCtrl = _appPluginsSdk.QueryCtrl;
+ }, function (_angular) {
+ angular = _angular.default;
+ }, function (_lodash) {
+ _ = _lodash.default;
+ }, function (_utils) {
+ utils = _utils;
+ }, function (_metricFunctions) {
+ metricFunctions = _metricFunctions;
+ }, function (_migrations) {
+ migrations = _migrations;
+ }, function (_addMetricFunctionDirective) {}, function (_metricFunctionEditorDirective) {}, function (_cssQueryEditorCss) {}],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ _export('ZabbixQueryController', ZabbixQueryController = function (_QueryCtrl) {
+ _inherits(ZabbixQueryController, _QueryCtrl);
+
+ // ZabbixQueryCtrl constructor
+ function ZabbixQueryController($scope, $injector, $rootScope, $sce, templateSrv) {
+ _classCallCheck(this, ZabbixQueryController);
+
+ var _this = _possibleConstructorReturn(this, (ZabbixQueryController.__proto__ || Object.getPrototypeOf(ZabbixQueryController)).call(this, $scope, $injector));
+
+ _this.zabbix = _this.datasource.zabbix;
+
+ // Use custom format for template variables
+ _this.replaceTemplateVars = _this.datasource.replaceTemplateVars;
+ _this.templateSrv = templateSrv;
+
+ _this.editorModes = {
+ 0: { value: 'num', text: 'Metrics', mode: 0 },
+ 1: { value: 'itservice', text: 'IT Services', mode: 1 },
+ 2: { value: 'text', text: 'Text', mode: 2 }
+ };
+
+ // Map functions for bs-typeahead
+ _this.getGroupNames = _.partial(getMetricNames, _this, 'groupList');
+ _this.getHostNames = _.partial(getMetricNames, _this, 'hostList');
+ _this.getApplicationNames = _.partial(getMetricNames, _this, 'appList');
+ _this.getItemNames = _.partial(getMetricNames, _this, 'itemList');
+
+ // Update metric suggestion when template variable was changed
+ $rootScope.$on('template-variable-value-updated', function () {
+ return _this.onVariableChange();
+ });
+
+ // Update metrics when item selected from dropdown
+ $scope.$on('typeahead-updated', function () {
+ _this.onTargetBlur();
+ });
+
+ _this.init = function () {
+ var target = this.target;
+
+ // Migrate old targets
+ target = migrations.migrate(target);
+
+ var scopeDefaults = {
+ metric: {},
+ oldTarget: _.cloneDeep(this.target),
+ queryOptionsText: this.renderQueryOptionsText()
+ };
+ _.defaults(this, scopeDefaults);
+
+ // Load default values
+ var targetDefaults = {
+ mode: 0,
+ group: { filter: "" },
+ host: { filter: "" },
+ application: { filter: "" },
+ item: { filter: "" },
+ functions: [],
+ options: {
+ showDisabledItems: false
+ }
+ };
+ _.defaults(target, targetDefaults);
+
+ // Create function instances from saved JSON
+ target.functions = _.map(target.functions, function (func) {
+ return metricFunctions.createFuncInstance(func.def, func.params);
+ });
+
+ if (target.mode === 0 || target.mode === 2) {
+
+ this.downsampleFunctionList = [{ name: "avg", value: "avg" }, { name: "min", value: "min" }, { name: "max", value: "max" }];
+
+ this.initFilters();
+ } else if (target.mode === 1) {
+ this.slaPropertyList = [{ name: "Status", property: "status" }, { name: "SLA", property: "sla" }, { name: "OK time", property: "okTime" }, { name: "Problem time", property: "problemTime" }, { name: "Down time", property: "downtimeTime" }];
+ this.itserviceList = [{ name: "test" }];
+ this.updateITServiceList();
+ }
+ };
+
+ _this.init();
+ return _this;
+ }
+
+ _createClass(ZabbixQueryController, [{
+ key: 'initFilters',
+ value: function initFilters() {
+ var itemtype = this.editorModes[this.target.mode].value;
+ return Promise.all([this.suggestGroups(), this.suggestHosts(), this.suggestApps(), this.suggestItems(itemtype)]);
+ }
+ }, {
+ key: 'suggestGroups',
+ value: function suggestGroups() {
+ var _this2 = this;
+
+ return this.zabbix.getAllGroups().then(function (groups) {
+ _this2.metric.groupList = groups;
+ return groups;
+ });
+ }
+ }, {
+ key: 'suggestHosts',
+ value: function suggestHosts() {
+ var _this3 = this;
+
+ var groupFilter = this.replaceTemplateVars(this.target.group.filter);
+ return this.zabbix.getAllHosts(groupFilter).then(function (hosts) {
+ _this3.metric.hostList = hosts;
+ return hosts;
+ });
+ }
+ }, {
+ key: 'suggestApps',
+ value: function suggestApps() {
+ var _this4 = this;
+
+ var groupFilter = this.replaceTemplateVars(this.target.group.filter);
+ var hostFilter = this.replaceTemplateVars(this.target.host.filter);
+ return this.zabbix.getAllApps(groupFilter, hostFilter).then(function (apps) {
+ _this4.metric.appList = apps;
+ return apps;
+ });
+ }
+ }, {
+ key: 'suggestItems',
+ value: function suggestItems() {
+ var _this5 = this;
+
+ var itemtype = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'num';
+
+ var groupFilter = this.replaceTemplateVars(this.target.group.filter);
+ var hostFilter = this.replaceTemplateVars(this.target.host.filter);
+ var appFilter = this.replaceTemplateVars(this.target.application.filter);
+ var options = {
+ itemtype: itemtype,
+ showDisabledItems: this.target.options.showDisabledItems
+ };
+
+ return this.zabbix.getAllItems(groupFilter, hostFilter, appFilter, options).then(function (items) {
+ _this5.metric.itemList = items;
+ return items;
+ });
+ }
+ }, {
+ key: 'isRegex',
+ value: function isRegex(str) {
+ return utils.isRegex(str);
+ }
+ }, {
+ key: 'isVariable',
+ value: function isVariable(str) {
+ return utils.isTemplateVariable(str, this.templateSrv.variables);
+ }
+ }, {
+ key: 'onTargetBlur',
+ value: function onTargetBlur() {
+ var newTarget = _.cloneDeep(this.target);
+ if (!_.isEqual(this.oldTarget, this.target)) {
+ this.oldTarget = newTarget;
+ this.targetChanged();
+ }
+ }
+ }, {
+ key: 'onVariableChange',
+ value: function onVariableChange() {
+ if (this.isContainsVariables()) {
+ this.targetChanged();
+ }
+ }
+ }, {
+ key: 'isContainsVariables',
+ value: function isContainsVariables() {
+ var _this6 = this;
+
+ return _.some(['group', 'host', 'application'], function (field) {
+ if (_this6.target[field] && _this6.target[field].filter) {
+ return utils.isTemplateVariable(_this6.target[field].filter, _this6.templateSrv.variables);
+ } else {
+ return false;
+ }
+ });
+ }
+ }, {
+ key: 'parseTarget',
+ value: function parseTarget() {}
+ // Parse target
+
+
+ // Validate target and set validation info
+
+ }, {
+ key: 'validateTarget',
+ value: function validateTarget() {
+ // validate
+ }
+ }, {
+ key: 'targetChanged',
+ value: function targetChanged() {
+ this.initFilters();
+ this.parseTarget();
+ this.panelCtrl.refresh();
+ }
+ }, {
+ key: 'addFunction',
+ value: function addFunction(funcDef) {
+ var newFunc = metricFunctions.createFuncInstance(funcDef);
+ newFunc.added = true;
+ this.target.functions.push(newFunc);
+
+ this.moveAliasFuncLast();
+
+ if (newFunc.params.length && newFunc.added || newFunc.def.params.length === 0) {
+ this.targetChanged();
+ }
+ }
+ }, {
+ key: 'removeFunction',
+ value: function removeFunction(func) {
+ this.target.functions = _.without(this.target.functions, func);
+ this.targetChanged();
+ }
+ }, {
+ key: 'moveAliasFuncLast',
+ value: function moveAliasFuncLast() {
+ var aliasFunc = _.find(this.target.functions, function (func) {
+ return func.def.name === 'alias' || func.def.name === 'aliasByNode' || func.def.name === 'aliasByMetric';
+ });
+
+ if (aliasFunc) {
+ this.target.functions = _.without(this.target.functions, aliasFunc);
+ this.target.functions.push(aliasFunc);
+ }
+ }
+ }, {
+ key: 'toggleQueryOptions',
+ value: function toggleQueryOptions() {
+ this.showQueryOptions = !this.showQueryOptions;
+ }
+ }, {
+ key: 'onQueryOptionChange',
+ value: function onQueryOptionChange() {
+ this.queryOptionsText = this.renderQueryOptionsText();
+ this.onTargetBlur();
+ }
+ }, {
+ key: 'renderQueryOptionsText',
+ value: function renderQueryOptionsText() {
+ var optionsMap = {
+ showDisabledItems: "Show disabled items"
+ };
+ var options = [];
+ _.forOwn(this.target.options, function (value, key) {
+ if (value) {
+ if (value === true) {
+ // Show only option name (if enabled) for boolean options
+ options.push(optionsMap[key]);
+ } else {
+ // Show "option = value" for another options
+ options.push(optionsMap[key] + " = " + value);
+ }
+ }
+ });
+ return "Options: " + options.join(', ');
+ }
+ }, {
+ key: 'switchEditorMode',
+ value: function switchEditorMode(mode) {
+ this.target.mode = mode;
+ this.init();
+ }
+ }, {
+ key: 'updateITServiceList',
+ value: function updateITServiceList() {
+ var _this7 = this;
+
+ this.zabbix.getITService().then(function (iteservices) {
+ _this7.itserviceList = [];
+ _this7.itserviceList = _this7.itserviceList.concat(iteservices);
+ });
+ }
+ }, {
+ key: 'selectITService',
+ value: function selectITService() {
+ if (!_.isEqual(this.oldTarget, this.target) && _.isEmpty(this.target.errors)) {
+ this.oldTarget = angular.copy(this.target);
+ this.panelCtrl.refresh();
+ }
+ }
+ }]);
+
+ return ZabbixQueryController;
+ }(QueryCtrl));
+
+ _export('ZabbixQueryController', ZabbixQueryController);
+
+ // Set templateUrl as static property
+ ZabbixQueryController.templateUrl = 'datasource-zabbix/partials/query.editor.html';
+ }
+ };
+});
+//# sourceMappingURL=query.controller.js.map
diff --git a/dist/datasource-zabbix/query.controller.js.map b/dist/datasource-zabbix/query.controller.js.map
new file mode 100644
index 0000000..75433c9
--- /dev/null
+++ b/dist/datasource-zabbix/query.controller.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/query.controller.js"],"names":["getMetricNames","scope","metricList","_","uniq","map","metric","QueryCtrl","angular","utils","metricFunctions","migrations","ZabbixQueryController","$scope","$injector","$rootScope","$sce","templateSrv","zabbix","datasource","replaceTemplateVars","editorModes","value","text","mode","getGroupNames","partial","getHostNames","getApplicationNames","getItemNames","$on","onVariableChange","onTargetBlur","init","target","migrate","scopeDefaults","oldTarget","cloneDeep","queryOptionsText","renderQueryOptionsText","defaults","targetDefaults","group","filter","host","application","item","functions","options","showDisabledItems","func","createFuncInstance","def","params","downsampleFunctionList","name","initFilters","slaPropertyList","property","itserviceList","updateITServiceList","itemtype","Promise","all","suggestGroups","suggestHosts","suggestApps","suggestItems","getAllGroups","then","groupList","groups","groupFilter","getAllHosts","hostList","hosts","hostFilter","getAllApps","appList","apps","appFilter","getAllItems","itemList","items","str","isRegex","isTemplateVariable","variables","newTarget","isEqual","targetChanged","isContainsVariables","some","field","parseTarget","panelCtrl","refresh","funcDef","newFunc","added","push","moveAliasFuncLast","length","without","aliasFunc","find","showQueryOptions","optionsMap","forOwn","key","join","getITService","iteservices","concat","isEmpty","errors","copy","templateUrl"],"mappings":"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","file":"query.controller.js","sourcesContent":["import {QueryCtrl} from 'app/plugins/sdk';\nimport angular from 'angular';\nimport _ from 'lodash';\nimport * as utils from './utils';\nimport * as metricFunctions from './metricFunctions';\nimport * as migrations from './migrations';\n\nimport './add-metric-function.directive';\nimport './metric-function-editor.directive';\n\nimport './css/query-editor.css!';\n\nexport class ZabbixQueryController extends QueryCtrl {\n\n // ZabbixQueryCtrl constructor\n constructor($scope, $injector, $rootScope, $sce, templateSrv) {\n super($scope, $injector);\n this.zabbix = this.datasource.zabbix;\n\n // Use custom format for template variables\n this.replaceTemplateVars = this.datasource.replaceTemplateVars;\n this.templateSrv = templateSrv;\n\n this.editorModes = {\n 0: {value: 'num', text: 'Metrics', mode: 0},\n 1: {value: 'itservice', text: 'IT Services', mode: 1},\n 2: {value: 'text', text: 'Text', mode: 2}\n };\n\n // Map functions for bs-typeahead\n this.getGroupNames = _.partial(getMetricNames, this, 'groupList');\n this.getHostNames = _.partial(getMetricNames, this, 'hostList');\n this.getApplicationNames = _.partial(getMetricNames, this, 'appList');\n this.getItemNames = _.partial(getMetricNames, this, 'itemList');\n\n // Update metric suggestion when template variable was changed\n $rootScope.$on('template-variable-value-updated', () => this.onVariableChange());\n\n // Update metrics when item selected from dropdown\n $scope.$on('typeahead-updated', () => {\n this.onTargetBlur();\n });\n\n this.init = function() {\n var target = this.target;\n\n // Migrate old targets\n target = migrations.migrate(target);\n\n var scopeDefaults = {\n metric: {},\n oldTarget: _.cloneDeep(this.target),\n queryOptionsText: this.renderQueryOptionsText()\n };\n _.defaults(this, scopeDefaults);\n\n // Load default values\n var targetDefaults = {\n mode: 0,\n group: { filter: \"\" },\n host: { filter: \"\" },\n application: { filter: \"\" },\n item: { filter: \"\" },\n functions: [],\n options: {\n showDisabledItems: false\n }\n };\n _.defaults(target, targetDefaults);\n\n // Create function instances from saved JSON\n target.functions = _.map(target.functions, function(func) {\n return metricFunctions.createFuncInstance(func.def, func.params);\n });\n\n if (target.mode === 0 ||\n target.mode === 2) {\n\n this.downsampleFunctionList = [\n {name: \"avg\", value: \"avg\"},\n {name: \"min\", value: \"min\"},\n {name: \"max\", value: \"max\"}\n ];\n\n this.initFilters();\n }\n else if (target.mode === 1) {\n this.slaPropertyList = [\n {name: \"Status\", property: \"status\"},\n {name: \"SLA\", property: \"sla\"},\n {name: \"OK time\", property: \"okTime\"},\n {name: \"Problem time\", property: \"problemTime\"},\n {name: \"Down time\", property: \"downtimeTime\"}\n ];\n this.itserviceList = [{name: \"test\"}];\n this.updateITServiceList();\n }\n };\n\n this.init();\n }\n\n initFilters() {\n let itemtype = this.editorModes[this.target.mode].value;\n return Promise.all([\n this.suggestGroups(),\n this.suggestHosts(),\n this.suggestApps(),\n this.suggestItems(itemtype)\n ]);\n }\n\n suggestGroups() {\n return this.zabbix.getAllGroups()\n .then(groups => {\n this.metric.groupList = groups;\n return groups;\n });\n }\n\n suggestHosts() {\n let groupFilter = this.replaceTemplateVars(this.target.group.filter);\n return this.zabbix.getAllHosts(groupFilter)\n .then(hosts => {\n this.metric.hostList = hosts;\n return hosts;\n });\n }\n\n suggestApps() {\n let groupFilter = this.replaceTemplateVars(this.target.group.filter);\n let hostFilter = this.replaceTemplateVars(this.target.host.filter);\n return this.zabbix.getAllApps(groupFilter, hostFilter)\n .then(apps => {\n this.metric.appList = apps;\n return apps;\n });\n }\n\n suggestItems(itemtype = 'num') {\n let groupFilter = this.replaceTemplateVars(this.target.group.filter);\n let hostFilter = this.replaceTemplateVars(this.target.host.filter);\n let appFilter = this.replaceTemplateVars(this.target.application.filter);\n let options = {\n itemtype: itemtype,\n showDisabledItems: this.target.options.showDisabledItems\n };\n\n return this.zabbix\n .getAllItems(groupFilter, hostFilter, appFilter, options)\n .then(items => {\n this.metric.itemList = items;\n return items;\n });\n }\n\n isRegex(str) {\n return utils.isRegex(str);\n }\n\n isVariable(str) {\n return utils.isTemplateVariable(str, this.templateSrv.variables);\n }\n\n onTargetBlur() {\n var newTarget = _.cloneDeep(this.target);\n if (!_.isEqual(this.oldTarget, this.target)) {\n this.oldTarget = newTarget;\n this.targetChanged();\n }\n }\n\n onVariableChange() {\n if (this.isContainsVariables()) {\n this.targetChanged();\n }\n }\n\n /**\n * Check query for template variables\n */\n isContainsVariables() {\n return _.some(['group', 'host', 'application'], field => {\n if (this.target[field] && this.target[field].filter) {\n return utils.isTemplateVariable(this.target[field].filter, this.templateSrv.variables);\n } else {\n return false;\n }\n });\n }\n\n parseTarget() {\n // Parse target\n }\n\n // Validate target and set validation info\n validateTarget() {\n // validate\n }\n\n targetChanged() {\n this.initFilters();\n this.parseTarget();\n this.panelCtrl.refresh();\n }\n\n addFunction(funcDef) {\n var newFunc = metricFunctions.createFuncInstance(funcDef);\n newFunc.added = true;\n this.target.functions.push(newFunc);\n\n this.moveAliasFuncLast();\n\n if (newFunc.params.length && newFunc.added ||\n newFunc.def.params.length === 0) {\n this.targetChanged();\n }\n }\n\n removeFunction(func) {\n this.target.functions = _.without(this.target.functions, func);\n this.targetChanged();\n }\n\n moveAliasFuncLast() {\n var aliasFunc = _.find(this.target.functions, function(func) {\n return func.def.name === 'alias' ||\n func.def.name === 'aliasByNode' ||\n func.def.name === 'aliasByMetric';\n });\n\n if (aliasFunc) {\n this.target.functions = _.without(this.target.functions, aliasFunc);\n this.target.functions.push(aliasFunc);\n }\n }\n\n toggleQueryOptions() {\n this.showQueryOptions = !this.showQueryOptions;\n }\n\n onQueryOptionChange() {\n this.queryOptionsText = this.renderQueryOptionsText();\n this.onTargetBlur();\n }\n\n renderQueryOptionsText() {\n var optionsMap = {\n showDisabledItems: \"Show disabled items\"\n };\n var options = [];\n _.forOwn(this.target.options, (value, key) => {\n if (value) {\n if (value === true) {\n // Show only option name (if enabled) for boolean options\n options.push(optionsMap[key]);\n } else {\n // Show \"option = value\" for another options\n options.push(optionsMap[key] + \" = \" + value);\n }\n }\n });\n return \"Options: \" + options.join(', ');\n }\n\n /**\n * Switch query editor to specified mode.\n * Modes:\n * 0 - items\n * 1 - IT services\n * 2 - Text metrics\n */\n switchEditorMode(mode) {\n this.target.mode = mode;\n this.init();\n }\n\n /////////////////\n // IT Services //\n /////////////////\n\n /**\n * Update list of IT services\n */\n updateITServiceList() {\n this.zabbix.getITService().then((iteservices) => {\n this.itserviceList = [];\n this.itserviceList = this.itserviceList.concat(iteservices);\n });\n }\n\n /**\n * Call when IT service is selected.\n */\n selectITService() {\n if (!_.isEqual(this.oldTarget, this.target) && _.isEmpty(this.target.errors)) {\n this.oldTarget = angular.copy(this.target);\n this.panelCtrl.refresh();\n }\n }\n}\n\n// Set templateUrl as static property\nZabbixQueryController.templateUrl = 'datasource-zabbix/partials/query.editor.html';\n\n// Get list of metric names for bs-typeahead directive\nfunction getMetricNames(scope, metricList) {\n return _.uniq(_.map(scope.metric[metricList], 'name'));\n}\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/responseHandler.js b/dist/datasource-zabbix/responseHandler.js
new file mode 100644
index 0000000..7e6518a
--- /dev/null
+++ b/dist/datasource-zabbix/responseHandler.js
@@ -0,0 +1,113 @@
+'use strict';
+
+System.register(['lodash'], function (_export, _context) {
+ "use strict";
+
+ var _;
+
+ /**
+ * Convert Zabbix API history.get response to Grafana format
+ *
+ * @return {Array} Array of timeseries in Grafana format
+ * {
+ * target: "Metric name",
+ * datapoints: [[, ], ...]
+ * }
+ */
+ function convertHistory(history, items, addHostName, convertPointCallback) {
+ /**
+ * Response should be in the format:
+ * data: [
+ * {
+ * target: "Metric name",
+ * datapoints: [[, ], ...]
+ * }, ...
+ * ]
+ */
+
+ // Group history by itemid
+ var grouped_history = _.groupBy(history, 'itemid');
+ var hosts = _.uniqBy(_.flatten(_.map(items, 'hosts')), 'hostid'); //uniqBy is needed to deduplicate
+
+ return _.map(grouped_history, function (hist, itemid) {
+ var item = _.find(items, { 'itemid': itemid });
+ var alias = item.name;
+ if (_.keys(hosts).length > 1 && addHostName) {
+ //only when actual multi hosts selected
+ var host = _.find(hosts, { 'hostid': item.hostid });
+ alias = host.name + ": " + alias;
+ }
+ return {
+ target: alias,
+ datapoints: _.map(hist, convertPointCallback)
+ };
+ });
+ }
+
+ function handleHistory(history, items) {
+ var addHostName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
+
+ return convertHistory(history, items, addHostName, convertHistoryPoint);
+ }function handleTrends(history, items, valueType) {
+ var addHostName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
+
+ var convertPointCallback = _.partial(convertTrendPoint, valueType);
+ return convertHistory(history, items, addHostName, convertPointCallback);
+ }
+
+ function handleSLAResponse(itservice, slaProperty, slaObject) {
+ var targetSLA = slaObject[itservice.serviceid].sla[0];
+ if (slaProperty.property === 'status') {
+ var targetStatus = parseInt(slaObject[itservice.serviceid].status);
+ return {
+ target: itservice.name + ' ' + slaProperty.name,
+ datapoints: [[targetStatus, targetSLA.to * 1000]]
+ };
+ } else {
+ return {
+ target: itservice.name + ' ' + slaProperty.name,
+ datapoints: [[targetSLA[slaProperty.property], targetSLA.from * 1000], [targetSLA[slaProperty.property], targetSLA.to * 1000]]
+ };
+ }
+ }function convertHistoryPoint(point) {
+ // Value must be a number for properly work
+ return [Number(point.value), point.clock * 1000];
+ }
+
+ function convertTrendPoint(valueType, point) {
+ var value;
+ switch (valueType) {
+ case "min":
+ value = point.value_min;
+ break;
+ case "max":
+ value = point.value_max;
+ break;
+ case "avg":
+ value = point.value_avg;
+ break;
+ default:
+ value = point.value_avg;
+ }
+
+ return [Number(value), point.clock * 1000];
+ }return {
+ setters: [function (_lodash) {
+ _ = _lodash.default;
+ }],
+ execute: function () {
+ _export('default', {
+ handleHistory: handleHistory,
+ convertHistory: convertHistory,
+ handleTrends: handleTrends,
+ handleSLAResponse: handleSLAResponse
+ });
+
+ // Fix for backward compatibility with lodash 2.4
+ if (!_.uniqBy) {
+ _.uniqBy = _.uniq;
+ }
+ }
+ };
+});
+//# sourceMappingURL=responseHandler.js.map
diff --git a/dist/datasource-zabbix/responseHandler.js.map b/dist/datasource-zabbix/responseHandler.js.map
new file mode 100644
index 0000000..0106190
--- /dev/null
+++ b/dist/datasource-zabbix/responseHandler.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/responseHandler.js"],"names":["convertHistory","history","items","addHostName","convertPointCallback","grouped_history","_","groupBy","hosts","uniqBy","flatten","map","hist","itemid","item","find","alias","name","keys","length","host","hostid","target","datapoints","handleHistory","convertHistoryPoint","handleTrends","valueType","partial","convertTrendPoint","handleSLAResponse","itservice","slaProperty","slaObject","targetSLA","serviceid","sla","property","targetStatus","parseInt","status","to","from","point","Number","value","clock","value_min","value_max","value_avg","uniq"],"mappings":"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","file":"responseHandler.js","sourcesContent":["import _ from 'lodash';\n\n/**\n * Convert Zabbix API history.get response to Grafana format\n *\n * @return {Array} Array of timeseries in Grafana format\n * {\n * target: \"Metric name\",\n * datapoints: [[, ], ...]\n * }\n */\nfunction convertHistory(history, items, addHostName, convertPointCallback) {\n /**\n * Response should be in the format:\n * data: [\n * {\n * target: \"Metric name\",\n * datapoints: [[, ], ...]\n * }, ...\n * ]\n */\n\n // Group history by itemid\n var grouped_history = _.groupBy(history, 'itemid');\n var hosts = _.uniqBy(_.flatten(_.map(items, 'hosts')), 'hostid'); //uniqBy is needed to deduplicate\n\n return _.map(grouped_history, function(hist, itemid) {\n var item = _.find(items, {'itemid': itemid});\n var alias = item.name;\n if (_.keys(hosts).length > 1 && addHostName) { //only when actual multi hosts selected\n var host = _.find(hosts, {'hostid': item.hostid});\n alias = host.name + \": \" + alias;\n }\n return {\n target: alias,\n datapoints: _.map(hist, convertPointCallback)\n };\n });\n}\n\nfunction handleHistory(history, items, addHostName = true) {\n return convertHistory(history, items, addHostName, convertHistoryPoint);\n}\n\nfunction handleTrends(history, items, valueType, addHostName = true) {\n var convertPointCallback = _.partial(convertTrendPoint, valueType);\n return convertHistory(history, items, addHostName, convertPointCallback);\n}\n\nfunction handleSLAResponse(itservice, slaProperty, slaObject) {\n var targetSLA = slaObject[itservice.serviceid].sla[0];\n if (slaProperty.property === 'status') {\n var targetStatus = parseInt(slaObject[itservice.serviceid].status);\n return {\n target: itservice.name + ' ' + slaProperty.name,\n datapoints: [\n [targetStatus, targetSLA.to * 1000]\n ]\n };\n } else {\n return {\n target: itservice.name + ' ' + slaProperty.name,\n datapoints: [\n [targetSLA[slaProperty.property], targetSLA.from * 1000],\n [targetSLA[slaProperty.property], targetSLA.to * 1000]\n ]\n };\n }\n}\n\nfunction convertHistoryPoint(point) {\n // Value must be a number for properly work\n return [\n Number(point.value),\n point.clock * 1000\n ];\n}\n\nfunction convertTrendPoint(valueType, point) {\n var value;\n switch (valueType) {\n case \"min\":\n value = point.value_min;\n break;\n case \"max\":\n value = point.value_max;\n break;\n case \"avg\":\n value = point.value_avg;\n break;\n default:\n value = point.value_avg;\n }\n\n return [\n Number(value),\n point.clock * 1000\n ];\n}\n\nexport default {\n handleHistory: handleHistory,\n convertHistory: convertHistory,\n handleTrends: handleTrends,\n handleSLAResponse: handleSLAResponse\n};\n\n// Fix for backward compatibility with lodash 2.4\nif (!_.uniqBy) {_.uniqBy = _.uniq;}\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/specs/datasource_specs.js b/dist/datasource-zabbix/specs/datasource_specs.js
new file mode 100644
index 0000000..6b4dc45
--- /dev/null
+++ b/dist/datasource-zabbix/specs/datasource_specs.js
@@ -0,0 +1,230 @@
+import {Datasource} from "../module";
+import {zabbixTemplateFormat} from "../datasource";
+import Q from "q";
+import sinon from 'sinon';
+import _ from 'lodash';
+
+describe('ZabbixDatasource', () => {
+ let ctx = {};
+ let defined = sinon.match.defined;
+
+ beforeEach(() => {
+ ctx.instanceSettings = {
+ jsonData: {
+ username: 'zabbix',
+ password: 'zabbix',
+ trends: true,
+ trendsFrom: '7d'
+ }
+ };
+ ctx.templateSrv = {};
+ ctx.alertSrv = {};
+ ctx.zabbix = () => {};
+
+ ctx.ds = new Datasource(ctx.instanceSettings, ctx.templateSrv, ctx.alertSrv, ctx.zabbix);
+ });
+
+ describe('When querying data', () => {
+ beforeEach(() => {
+ ctx.ds.replaceTemplateVars = (str) => str;
+ });
+
+ ctx.options = {
+ targets: [
+ {
+ group: {filter: ""},
+ host: {filter: ""},
+ application: {filter: ""},
+ item: {filter: ""}
+ }
+ ],
+ range: {from: 'now-7d', to: 'now'}
+ };
+
+ it('should return an empty array when no targets are set', (done) => {
+ let options = {
+ targets: [],
+ range: {from: 'now-6h', to: 'now'}
+ };
+ ctx.ds.query(options).then(result => {
+ expect(result.data).to.have.length(0);
+ done();
+ });
+ });
+
+ it('should use trends if it enabled and time more than trendsFrom', (done) => {
+ let ranges = ['now-7d', 'now-168h', 'now-1M', 'now-1y'];
+
+ _.forEach(ranges, range => {
+ ctx.options.range.from = range;
+ ctx.ds.queryNumericData = sinon.spy();
+ ctx.ds.query(ctx.options);
+
+ // Check that useTrends options is true
+ expect(ctx.ds.queryNumericData)
+ .to.have.been.calledWith(defined, defined, defined, true);
+ });
+
+ done();
+ });
+
+ it('shouldnt use trends if it enabled and time less than trendsFrom', (done) => {
+ let ranges = ['now-6d', 'now-167h', 'now-1h', 'now-30m', 'now-30s'];
+
+ _.forEach(ranges, range => {
+ ctx.options.range.from = range;
+ ctx.ds.queryNumericData = sinon.spy();
+ ctx.ds.query(ctx.options);
+
+ // Check that useTrends options is false
+ expect(ctx.ds.queryNumericData)
+ .to.have.been.calledWith(defined, defined, defined, false);
+ });
+ done();
+ });
+
+ });
+
+ describe('When replacing template variables', () => {
+
+ function testReplacingVariable(target, varValue, expectedResult, done) {
+ ctx.ds.templateSrv.replace = () => {
+ return zabbixTemplateFormat(varValue);
+ };
+
+ let result = ctx.ds.replaceTemplateVars(target);
+ expect(result).to.equal(expectedResult);
+ done();
+ }
+
+ /*
+ * Alphanumerics, spaces, dots, dashes and underscores
+ * are allowed in Zabbix host name.
+ * 'AaBbCc0123 .-_'
+ */
+ it('should return properly escaped regex', (done) => {
+ let target = '$host';
+ let template_var_value = 'AaBbCc0123 .-_';
+ let expected_result = '/^AaBbCc0123 \\.-_$/';
+
+ testReplacingVariable(target, template_var_value, expected_result, done);
+ });
+
+ /*
+ * Single-value variable
+ * $host = backend01
+ * $host => /^backend01|backend01$/
+ */
+ it('should return proper regex for single value', (done) => {
+ let target = '$host';
+ let template_var_value = 'backend01';
+ let expected_result = '/^backend01$/';
+
+ testReplacingVariable(target, template_var_value, expected_result, done);
+ });
+
+ /*
+ * Multi-value variable
+ * $host = [backend01, backend02]
+ * $host => /^(backend01|backend01)$/
+ */
+ it('should return proper regex for multi-value', (done) => {
+ let target = '$host';
+ let template_var_value = ['backend01', 'backend02'];
+ let expected_result = '/^(backend01|backend02)$/';
+
+ testReplacingVariable(target, template_var_value, expected_result, done);
+ });
+ });
+
+ describe('When invoking metricFindQuery()', () => {
+ beforeEach(() => {
+ ctx.ds.replaceTemplateVars = (str) => str;
+ ctx.ds.zabbix = {
+ getGroups: () => Q.when([]),
+ getHosts: () => Q.when([]),
+ getApps: () => Q.when([]),
+ getItems: () => Q.when([])
+ };
+ });
+
+ it('should return groups', (done) => {
+ const tests = [
+ {query: '*', expect: '/.*/'},
+ {query: '', expect: ''},
+ {query: 'Backend', expect: 'Backend'},
+ {query: 'Back*', expect: 'Back*'}
+ ];
+
+ let getGroups = sinon.spy(ctx.ds.zabbix, 'getGroups');
+ for (const test of tests) {
+ ctx.ds.metricFindQuery(test.query);
+ expect(getGroups).to.have.been.calledWith(test.expect);
+ getGroups.reset();
+ }
+ done();
+ });
+
+ it('should return hosts', (done) => {
+ const tests = [
+ {query: '*.*', expect: '/.*/'},
+ {query: '.', expect: ''},
+ {query: 'Backend.*', expect: 'Backend'},
+ {query: 'Back*.', expect: 'Back*'}
+ ];
+
+ let getHosts = sinon.spy(ctx.ds.zabbix, 'getHosts');
+ for (const test of tests) {
+ ctx.ds.metricFindQuery(test.query);
+ expect(getHosts).to.have.been.calledWith(test.expect);
+ getHosts.reset();
+ }
+ done();
+ });
+
+ it('should return applications', (done) => {
+ const tests = [
+ {query: '*.*.*', expect: ['/.*/', '/.*/']},
+ {query: '.*.', expect: ['', '/.*/']},
+ {query: 'Backend.backend01.*', expect: ['Backend', 'backend01']},
+ {query: 'Back*.*.', expect: ['Back*', '/.*/']}
+ ];
+
+ let getApps = sinon.spy(ctx.ds.zabbix, 'getApps');
+ for (const test of tests) {
+ ctx.ds.metricFindQuery(test.query);
+ expect(getApps).to.have.been.calledWith(test.expect[0], test.expect[1]);
+ getApps.reset();
+ }
+ done();
+ });
+
+ it('should return items', (done) => {
+ const tests = [
+ {query: '*.*.*.*', expect: ['/.*/', '/.*/', '']},
+ {query: '.*.*.*', expect: ['', '/.*/', '']},
+ {query: 'Backend.backend01.*.*', expect: ['Backend', 'backend01', '']},
+ {query: 'Back*.*.cpu.*', expect: ['Back*', '/.*/', 'cpu']}
+ ];
+
+ let getItems = sinon.spy(ctx.ds.zabbix, 'getItems');
+ for (const test of tests) {
+ ctx.ds.metricFindQuery(test.query);
+ expect(getItems)
+ .to.have.been.calledWith(test.expect[0], test.expect[1], test.expect[2]);
+ getItems.reset();
+ }
+ done();
+ });
+
+ it('should invoke method with proper arguments', (done) => {
+ let query = '*.*';
+
+ let getHosts = sinon.spy(ctx.ds.zabbix, 'getHosts');
+ ctx.ds.metricFindQuery(query);
+ expect(getHosts).to.have.been.calledWith('/.*/');
+ done();
+ });
+ });
+
+});
diff --git a/dist/datasource-zabbix/specs/modules/datemath.js b/dist/datasource-zabbix/specs/modules/datemath.js
new file mode 100644
index 0000000..efbf0bf
--- /dev/null
+++ b/dist/datasource-zabbix/specs/modules/datemath.js
@@ -0,0 +1,111 @@
+import _ from 'lodash';
+import moment from 'moment';
+
+var units = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
+
+export function parse(text, roundUp) {
+ if (!text) { return undefined; }
+ if (moment.isMoment(text)) { return text; }
+ if (_.isDate(text)) { return moment(text); }
+
+ var time;
+ var mathString = '';
+ var index;
+ var parseString;
+
+ if (text.substring(0, 3) === 'now') {
+ time = moment();
+ mathString = text.substring('now'.length);
+ } else {
+ index = text.indexOf('||');
+ if (index === -1) {
+ parseString = text;
+ mathString = ''; // nothing else
+ } else {
+ parseString = text.substring(0, index);
+ mathString = text.substring(index + 2);
+ }
+ // We're going to just require ISO8601 timestamps, k?
+ time = moment(parseString, moment.ISO_8601);
+ }
+
+ if (!mathString.length) {
+ return time;
+ }
+
+ return parseDateMath(mathString, time, roundUp);
+}
+
+export function isValid(text) {
+ var date = parse(text);
+ if (!date) {
+ return false;
+ }
+
+ if (moment.isMoment(date)) {
+ return date.isValid();
+ }
+
+ return false;
+}
+
+export function parseDateMath(mathString, time, roundUp) {
+ var dateTime = time;
+ var i = 0;
+ var len = mathString.length;
+
+ while (i < len) {
+ var c = mathString.charAt(i++);
+ var type;
+ var num;
+ var unit;
+
+ if (c === '/') {
+ type = 0;
+ } else if (c === '+') {
+ type = 1;
+ } else if (c === '-') {
+ type = 2;
+ } else {
+ return undefined;
+ }
+
+ if (isNaN(mathString.charAt(i))) {
+ num = 1;
+ } else if (mathString.length === 2) {
+ num = mathString.charAt(i);
+ } else {
+ var numFrom = i;
+ while (!isNaN(mathString.charAt(i))) {
+ i++;
+ if (i > 10) { return undefined; }
+ }
+ num = parseInt(mathString.substring(numFrom, i), 10);
+ }
+
+ if (type === 0) {
+ // rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
+ if (num !== 1) {
+ return undefined;
+ }
+ }
+ unit = mathString.charAt(i++);
+
+ if (!_.includes(units, unit)) {
+ return undefined;
+ } else {
+ if (type === 0) {
+ if (roundUp) {
+ dateTime.endOf(unit);
+ } else {
+ dateTime.startOf(unit);
+ }
+ } else if (type === 1) {
+ dateTime.add(num, unit);
+ } else if (type === 2) {
+ dateTime.subtract(num, unit);
+ }
+ }
+ }
+ return dateTime;
+}
diff --git a/dist/datasource-zabbix/specs/test-main.js b/dist/datasource-zabbix/specs/test-main.js
new file mode 100644
index 0000000..cdaec55
--- /dev/null
+++ b/dist/datasource-zabbix/specs/test-main.js
@@ -0,0 +1,49 @@
+// JSHint options
+/* globals global: false */
+
+import prunk from 'prunk';
+import {jsdom} from 'jsdom';
+import chai from 'chai';
+// import sinon from 'sinon';
+import sinonChai from 'sinon-chai';
+import * as dateMath from './modules/datemath';
+
+// Mock angular module
+var angularMocks = {
+ module: function() {
+ return {
+ directive: function() {},
+ service: function() {},
+ factory: function() {}
+ };
+ }
+};
+
+var datemathMock = {
+ parse: dateMath.parse,
+ parseDateMath: dateMath.parseDateMath,
+ isValid: dateMath.isValid
+};
+
+// Mock Grafana modules that are not available outside of the core project
+// Required for loading module.js
+prunk.mock('./css/query-editor.css!', 'no css, dude.');
+prunk.mock('app/plugins/sdk', {
+ QueryCtrl: null
+});
+prunk.mock('app/core/utils/datemath', datemathMock);
+prunk.mock('angular', angularMocks);
+prunk.mock('jquery', 'module not found');
+
+// Setup jsdom
+// Required for loading angularjs
+global.document = jsdom('');
+global.window = global.document.parentWindow;
+global.navigator = window.navigator = {};
+global.Node = window.Node;
+
+// Setup Chai
+chai.should();
+chai.use(sinonChai);
+global.assert = chai.assert;
+global.expect = chai.expect;
diff --git a/dist/datasource-zabbix/utils.js b/dist/datasource-zabbix/utils.js
new file mode 100644
index 0000000..4db6fb0
--- /dev/null
+++ b/dist/datasource-zabbix/utils.js
@@ -0,0 +1,169 @@
+'use strict';
+
+System.register(['lodash', 'moment'], function (_export, _context) {
+ "use strict";
+
+ var _, moment, regexPattern;
+
+ /**
+ * Expand Zabbix item name
+ *
+ * @param {string} name item name, ie "CPU $2 time"
+ * @param {string} key item key, ie system.cpu.util[,system,avg1]
+ * @return {string} expanded name, ie "CPU system time"
+ */
+ function expandItemName(name, key) {
+
+ // extract params from key:
+ // "system.cpu.util[,system,avg1]" --> ["", "system", "avg1"]
+ var key_params = key.substring(key.indexOf('[') + 1, key.lastIndexOf(']')).split(',');
+
+ // replace item parameters
+ for (var i = key_params.length; i >= 1; i--) {
+ name = name.replace('$' + i, key_params[i - 1]);
+ }
+ return name;
+ }
+
+ // Pattern for testing regex
+
+ _export('expandItemName', expandItemName);
+
+ function isRegex(str) {
+ return regexPattern.test(str);
+ }
+
+ _export('isRegex', isRegex);
+
+ function isTemplateVariable(str, templateVariables) {
+ var variablePattern = /^\$\w+/;
+ if (variablePattern.test(str)) {
+ var variables = _.map(templateVariables, function (variable) {
+ return '$' + variable.name;
+ });
+ return _.includes(variables, str);
+ } else {
+ return false;
+ }
+ }
+
+ _export('isTemplateVariable', isTemplateVariable);
+
+ function buildRegex(str) {
+ var matches = str.match(regexPattern);
+ var pattern = matches[1];
+ var flags = matches[2] !== "" ? matches[2] : undefined;
+ return new RegExp(pattern, flags);
+ }
+
+ // Need for template variables replace
+ // From Grafana's templateSrv.js
+
+ _export('buildRegex', buildRegex);
+
+ function escapeRegex(value) {
+ return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&');
+ }
+
+ _export('escapeRegex', escapeRegex);
+
+ function parseInterval(interval) {
+ var intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)/g;
+ var momentInterval = intervalPattern.exec(interval);
+ return moment.duration(Number(momentInterval[1]), momentInterval[2]).valueOf();
+ }
+
+ _export('parseInterval', parseInterval);
+
+ function parseTimeShiftInterval(interval) {
+ var intervalPattern = /^([\+\-]*)([\d]+)(y|M|w|d|h|m|s)/g;
+ var momentInterval = intervalPattern.exec(interval);
+ var duration = 0;
+
+ if (momentInterval[1] === '+') {
+ duration = 0 - moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();
+ } else {
+ duration = moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();
+ }
+
+ return duration;
+ }
+
+ /**
+ * Format acknowledges.
+ *
+ * @param {array} acknowledges array of Zabbix acknowledge objects
+ * @return {string} HTML-formatted table
+ */
+
+ _export('parseTimeShiftInterval', parseTimeShiftInterval);
+
+ function formatAcknowledges(acknowledges) {
+ if (acknowledges.length) {
+ var formatted_acknowledges = ' Acknowledges:Time ' + 'User Comments ';
+ _.each(_.map(acknowledges, function (ack) {
+ var timestamp = moment.unix(ack.clock);
+ return '' + timestamp.format("DD MMM YYYY HH:mm:ss") + ' ' + ack.alias + ' (' + ack.name + ' ' + ack.surname + ')' + ' ' + ack.message + ' ';
+ }), function (ack) {
+ formatted_acknowledges = formatted_acknowledges.concat(ack);
+ });
+ formatted_acknowledges = formatted_acknowledges.concat('
');
+ return formatted_acknowledges;
+ } else {
+ return '';
+ }
+ }
+
+ _export('formatAcknowledges', formatAcknowledges);
+
+ function convertToZabbixAPIUrl(url) {
+ var zabbixAPIUrlPattern = /.*api_jsonrpc.php$/;
+ var trimSlashPattern = /(.*?)[\/]*$/;
+ if (url.match(zabbixAPIUrlPattern)) {
+ return url;
+ } else {
+ return url.replace(trimSlashPattern, "$1");
+ }
+ }
+
+ /**
+ * Wrap function to prevent multiple calls
+ * when waiting for result.
+ */
+
+ _export('convertToZabbixAPIUrl', convertToZabbixAPIUrl);
+
+ function callOnce(func, promiseKeeper) {
+ return function () {
+ if (!promiseKeeper) {
+ promiseKeeper = Promise.resolve(func.apply(this, arguments).then(function (result) {
+ promiseKeeper = null;
+ return result;
+ }));
+ }
+ return promiseKeeper;
+ };
+ }
+
+ // Fix for backward compatibility with lodash 2.4
+
+ _export('callOnce', callOnce);
+
+ return {
+ setters: [function (_lodash) {
+ _ = _lodash.default;
+ }, function (_moment) {
+ moment = _moment.default;
+ }],
+ execute: function () {
+ _export('regexPattern', regexPattern = /^\/(.*)\/([gmi]*)$/m);
+
+ _export('regexPattern', regexPattern);
+
+ if (!_.includes) {
+ _.includes = _.contains;
+ }
+ }
+ };
+});
+//# sourceMappingURL=utils.js.map
diff --git a/dist/datasource-zabbix/utils.js.map b/dist/datasource-zabbix/utils.js.map
new file mode 100644
index 0000000..bfec5a5
--- /dev/null
+++ b/dist/datasource-zabbix/utils.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/utils.js"],"names":["expandItemName","name","key","key_params","substring","indexOf","lastIndexOf","split","i","length","replace","isRegex","str","regexPattern","test","isTemplateVariable","templateVariables","variablePattern","variables","_","map","variable","includes","buildRegex","matches","match","pattern","flags","undefined","RegExp","escapeRegex","value","parseInterval","interval","intervalPattern","momentInterval","exec","moment","duration","Number","valueOf","parseTimeShiftInterval","formatAcknowledges","acknowledges","formatted_acknowledges","each","ack","timestamp","unix","clock","format","alias","surname","message","concat","convertToZabbixAPIUrl","url","zabbixAPIUrlPattern","trimSlashPattern","callOnce","func","promiseKeeper","Promise","resolve","apply","arguments","then","result","contains"],"mappings":"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","file":"utils.js","sourcesContent":["import _ from 'lodash';\nimport moment from 'moment';\n\n/**\n * Expand Zabbix item name\n *\n * @param {string} name item name, ie \"CPU $2 time\"\n * @param {string} key item key, ie system.cpu.util[,system,avg1]\n * @return {string} expanded name, ie \"CPU system time\"\n */\nexport function expandItemName(name, key) {\n\n // extract params from key:\n // \"system.cpu.util[,system,avg1]\" --> [\"\", \"system\", \"avg1\"]\n var key_params = key.substring(key.indexOf('[') + 1, key.lastIndexOf(']')).split(',');\n\n // replace item parameters\n for (var i = key_params.length; i >= 1; i--) {\n name = name.replace('$' + i, key_params[i - 1]);\n }\n return name;\n}\n\n// Pattern for testing regex\nexport var regexPattern = /^\\/(.*)\\/([gmi]*)$/m;\n\nexport function isRegex(str) {\n return regexPattern.test(str);\n}\n\nexport function isTemplateVariable(str, templateVariables) {\n var variablePattern = /^\\$\\w+/;\n if (variablePattern.test(str)) {\n var variables = _.map(templateVariables, variable => {\n return '$' + variable.name;\n });\n return _.includes(variables, str);\n } else {\n return false;\n }\n}\n\nexport function buildRegex(str) {\n var matches = str.match(regexPattern);\n var pattern = matches[1];\n var flags = matches[2] !== \"\" ? matches[2] : undefined;\n return new RegExp(pattern, flags);\n}\n\n// Need for template variables replace\n// From Grafana's templateSrv.js\nexport function escapeRegex(value) {\n return value.replace(/[\\\\^$*+?.()|[\\]{}\\/]/g, '\\\\$&');\n}\n\nexport function parseInterval(interval) {\n var intervalPattern = /(^[\\d]+)(y|M|w|d|h|m|s)/g;\n var momentInterval = intervalPattern.exec(interval);\n return moment.duration(Number(momentInterval[1]), momentInterval[2]).valueOf();\n}\n\nexport function parseTimeShiftInterval(interval) {\n let intervalPattern = /^([\\+\\-]*)([\\d]+)(y|M|w|d|h|m|s)/g;\n let momentInterval = intervalPattern.exec(interval);\n let duration = 0;\n\n if (momentInterval[1] === '+') {\n duration = 0 - moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();\n } else {\n duration = moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();\n }\n\n return duration;\n}\n\n/**\n * Format acknowledges.\n *\n * @param {array} acknowledges array of Zabbix acknowledge objects\n * @return {string} HTML-formatted table\n */\nexport function formatAcknowledges(acknowledges) {\n if (acknowledges.length) {\n var formatted_acknowledges = ' Acknowledges:Time '\n + 'User Comments ';\n _.each(_.map(acknowledges, function (ack) {\n var timestamp = moment.unix(ack.clock);\n return '' + timestamp.format(\"DD MMM YYYY HH:mm:ss\") + ' ' + ack.alias\n + ' (' + ack.name + ' ' + ack.surname + ')' + ' ' + ack.message + ' ';\n }), function (ack) {\n formatted_acknowledges = formatted_acknowledges.concat(ack);\n });\n formatted_acknowledges = formatted_acknowledges.concat('
');\n return formatted_acknowledges;\n } else {\n return '';\n }\n}\n\nexport function convertToZabbixAPIUrl(url) {\n var zabbixAPIUrlPattern = /.*api_jsonrpc.php$/;\n var trimSlashPattern = /(.*?)[\\/]*$/;\n if (url.match(zabbixAPIUrlPattern)) {\n return url;\n } else {\n return url.replace(trimSlashPattern, \"$1\");\n }\n}\n\n/**\n * Wrap function to prevent multiple calls\n * when waiting for result.\n */\nexport function callOnce(func, promiseKeeper) {\n return function() {\n if (!promiseKeeper) {\n promiseKeeper = Promise.resolve(\n func.apply(this, arguments)\n .then(result => {\n promiseKeeper = null;\n return result;\n })\n );\n }\n return promiseKeeper;\n };\n}\n\n// Fix for backward compatibility with lodash 2.4\nif (!_.includes) {\n _.includes = _.contains;\n}\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/zabbix.js b/dist/datasource-zabbix/zabbix.js
new file mode 100644
index 0000000..83e8875
--- /dev/null
+++ b/dist/datasource-zabbix/zabbix.js
@@ -0,0 +1,278 @@
+'use strict';
+
+System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './zabbixCachingProxy.service.js'], function (_export, _context) {
+ "use strict";
+
+ var angular, _, utils, _createClass;
+
+ function _toConsumableArray(arr) {
+ if (Array.isArray(arr)) {
+ for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
+ arr2[i] = arr[i];
+ }
+
+ return arr2;
+ } else {
+ return Array.from(arr);
+ }
+ }
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ // Use factory() instead service() for multiple data sources support.
+ // Each Zabbix data source instance should initialize its own API instance.
+
+ /** @ngInject */
+ function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy) {
+ var Zabbix = function () {
+ function Zabbix(url, username, password, basicAuth, withCredentials, cacheTTL) {
+ _classCallCheck(this, Zabbix);
+
+ // Initialize Zabbix API
+ var ZabbixAPI = zabbixAPIService;
+ this.zabbixAPI = new ZabbixAPI(url, username, password, basicAuth, withCredentials);
+
+ // Initialize caching proxy for requests
+ var cacheOptions = {
+ enabled: true,
+ ttl: cacheTTL
+ };
+ this.cachingProxy = new ZabbixCachingProxy(this.zabbixAPI, cacheOptions);
+
+ // Proxy methods
+ this.getHistory = this.cachingProxy.getHistory.bind(this.cachingProxy);
+
+ this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI);
+ this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI);
+ this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI);
+ this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI);
+ this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI);
+ this.getVersion = this.zabbixAPI.getVersion.bind(this.zabbixAPI);
+ this.login = this.zabbixAPI.login.bind(this.zabbixAPI);
+ }
+
+ _createClass(Zabbix, [{
+ key: 'getItemsFromTarget',
+ value: function getItemsFromTarget(target, options) {
+ var parts = ['group', 'host', 'application', 'item'];
+ var filters = _.map(parts, function (p) {
+ return target[p].filter;
+ });
+ return this.getItems.apply(this, _toConsumableArray(filters).concat([options]));
+ }
+ }, {
+ key: 'getAllGroups',
+ value: function getAllGroups() {
+ return this.cachingProxy.getGroups();
+ }
+ }, {
+ key: 'getGroups',
+ value: function getGroups(groupFilter) {
+ return this.getAllGroups().then(function (groups) {
+ return findByFilter(groups, groupFilter);
+ });
+ }
+ }, {
+ key: 'getAllHosts',
+ value: function getAllHosts(groupFilter) {
+ var _this = this;
+
+ return this.getGroups(groupFilter).then(function (groups) {
+ var groupids = _.map(groups, 'groupid');
+ return _this.cachingProxy.getHosts(groupids);
+ });
+ }
+ }, {
+ key: 'getHosts',
+ value: function getHosts(groupFilter, hostFilter) {
+ return this.getAllHosts(groupFilter).then(function (hosts) {
+ return findByFilter(hosts, hostFilter);
+ });
+ }
+ }, {
+ key: 'getAllApps',
+ value: function getAllApps(groupFilter, hostFilter) {
+ var _this2 = this;
+
+ return this.getHosts(groupFilter, hostFilter).then(function (hosts) {
+ var hostids = _.map(hosts, 'hostid');
+ return _this2.cachingProxy.getApps(hostids);
+ });
+ }
+ }, {
+ key: 'getApps',
+ value: function getApps(groupFilter, hostFilter, appFilter) {
+ var _this3 = this;
+
+ return this.getHosts(groupFilter, hostFilter).then(function (hosts) {
+ var hostids = _.map(hosts, 'hostid');
+ if (appFilter) {
+ return _this3.cachingProxy.getApps(hostids).then(function (apps) {
+ return filterByQuery(apps, appFilter);
+ });
+ } else {
+ return {
+ appFilterEmpty: true,
+ hostids: hostids
+ };
+ }
+ });
+ }
+ }, {
+ key: 'getAllItems',
+ value: function getAllItems(groupFilter, hostFilter, appFilter) {
+ var _this4 = this;
+
+ var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+
+ return this.getApps(groupFilter, hostFilter, appFilter).then(function (apps) {
+ if (apps.appFilterEmpty) {
+ return _this4.cachingProxy.getItems(apps.hostids, undefined, options.itemtype);
+ } else {
+ var appids = _.map(apps, 'applicationid');
+ return _this4.cachingProxy.getItems(undefined, appids, options.itemtype);
+ }
+ }).then(function (items) {
+ if (!options.showDisabledItems) {
+ items = _.filter(items, { 'status': '0' });
+ }
+ return items;
+ });
+ }
+ }, {
+ key: 'getItems',
+ value: function getItems(groupFilter, hostFilter, appFilter, itemFilter) {
+ var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
+
+ return this.getAllItems(groupFilter, hostFilter, appFilter, options).then(function (items) {
+ return filterByQuery(items, itemFilter);
+ });
+ }
+ }, {
+ key: 'getTriggers',
+ value: function getTriggers(groupFilter, hostFilter, appFilter, showTriggers) {
+ var _this5 = this;
+
+ var promises = [this.getGroups(groupFilter), this.getHosts(groupFilter, hostFilter), this.getApps(groupFilter, hostFilter, appFilter)];
+
+ return Promise.all(promises).then(function (results) {
+ var filteredGroups = results[0];
+ var filteredHosts = results[1];
+ var filteredApps = results[2];
+ var query = {};
+
+ if (appFilter) {
+ query.applicationids = _.flatten(_.map(filteredApps, 'applicationid'));
+ }
+ if (hostFilter) {
+ query.hostids = _.map(filteredHosts, 'hostid');
+ }
+ if (groupFilter) {
+ query.groupids = _.map(filteredGroups, 'groupid');
+ }
+
+ return query;
+ }).then(function (query) {
+ return _this5.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers);
+ });
+ }
+ }]);
+
+ return Zabbix;
+ }();
+
+ return Zabbix;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Find group, host, app or item by given name.
+ * @param list list of groups, apps or other
+ * @param name visible name
+ * @return array with finded element or undefined
+ */
+ function findByName(list, name) {
+ var finded = _.find(list, { 'name': name });
+ if (finded) {
+ return [finded];
+ } else {
+ return undefined;
+ }
+ }
+
+ /**
+ * Different hosts can contains applications and items with same name.
+ * For this reason use _.filter, which return all elements instead _.find,
+ * which return only first finded.
+ * @param {[type]} list list of elements
+ * @param {[type]} name app name
+ * @return {[type]} array with finded element or undefined
+ */
+ function filterByName(list, name) {
+ var finded = _.filter(list, { 'name': name });
+ if (finded) {
+ return finded;
+ } else {
+ return undefined;
+ }
+ }
+
+ function filterByRegex(list, regex) {
+ var filterPattern = utils.buildRegex(regex);
+ return _.filter(list, function (zbx_obj) {
+ return filterPattern.test(zbx_obj.name);
+ });
+ }
+
+ function findByFilter(list, filter) {
+ if (utils.isRegex(filter)) {
+ return filterByRegex(list, filter);
+ } else {
+ return findByName(list, filter);
+ }
+ }
+
+ function filterByQuery(list, filter) {
+ if (utils.isRegex(filter)) {
+ return filterByRegex(list, filter);
+ } else {
+ return filterByName(list, filter);
+ }
+ }
+ return {
+ setters: [function (_angular) {
+ angular = _angular.default;
+ }, function (_lodash) {
+ _ = _lodash.default;
+ }, function (_utils) {
+ utils = _utils;
+ }, function (_zabbixAPIServiceJs) {}, function (_zabbixCachingProxyServiceJs) {}],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ angular.module('grafana.services').factory('Zabbix', ZabbixFactory);
+ }
+ };
+});
+//# sourceMappingURL=zabbix.js.map
diff --git a/dist/datasource-zabbix/zabbix.js.map b/dist/datasource-zabbix/zabbix.js.map
new file mode 100644
index 0000000..8450b5d
--- /dev/null
+++ b/dist/datasource-zabbix/zabbix.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/zabbix.js"],"names":["ZabbixFactory","zabbixAPIService","ZabbixCachingProxy","Zabbix","url","username","password","basicAuth","withCredentials","cacheTTL","ZabbixAPI","zabbixAPI","cacheOptions","enabled","ttl","cachingProxy","getHistory","bind","getTrend","getEvents","getAcknowledges","getITService","getSLA","getVersion","login","target","options","parts","filters","_","map","p","filter","getItems","getGroups","groupFilter","getAllGroups","then","findByFilter","groups","groupids","getHosts","hostFilter","getAllHosts","hosts","hostids","getApps","appFilter","filterByQuery","apps","appFilterEmpty","undefined","itemtype","appids","showDisabledItems","items","itemFilter","getAllItems","showTriggers","promises","Promise","all","filteredGroups","results","filteredHosts","filteredApps","query","applicationids","flatten","getTriggers","findByName","list","name","finded","find","filterByName","filterByRegex","regex","filterPattern","utils","buildRegex","zbx_obj","test","isRegex","angular","module","factory"],"mappings":"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","file":"zabbix.js","sourcesContent":["import angular from 'angular';\nimport _ from 'lodash';\nimport * as utils from './utils';\nimport './zabbixAPI.service.js';\nimport './zabbixCachingProxy.service.js';\n\n// Use factory() instead service() for multiple data sources support.\n// Each Zabbix data source instance should initialize its own API instance.\n\n/** @ngInject */\nfunction ZabbixFactory(zabbixAPIService, ZabbixCachingProxy) {\n\n class Zabbix {\n constructor(url, username, password, basicAuth, withCredentials, cacheTTL) {\n\n // Initialize Zabbix API\n var ZabbixAPI = zabbixAPIService;\n this.zabbixAPI = new ZabbixAPI(url, username, password, basicAuth, withCredentials);\n\n // Initialize caching proxy for requests\n let cacheOptions = {\n enabled: true,\n ttl: cacheTTL\n };\n this.cachingProxy = new ZabbixCachingProxy(this.zabbixAPI, cacheOptions);\n\n // Proxy methods\n this.getHistory = this.cachingProxy.getHistory.bind(this.cachingProxy);\n\n this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI);\n this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI);\n this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI);\n this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI);\n this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI);\n this.getVersion = this.zabbixAPI.getVersion.bind(this.zabbixAPI);\n this.login = this.zabbixAPI.login.bind(this.zabbixAPI);\n }\n\n getItemsFromTarget(target, options) {\n let parts = ['group', 'host', 'application', 'item'];\n let filters = _.map(parts, p => target[p].filter);\n return this.getItems(...filters, options);\n }\n\n getAllGroups() {\n return this.cachingProxy.getGroups();\n }\n\n getGroups(groupFilter) {\n return this.getAllGroups()\n .then(groups => findByFilter(groups, groupFilter));\n }\n\n /**\n * Get list of host belonging to given groups.\n */\n getAllHosts(groupFilter) {\n return this.getGroups(groupFilter)\n .then(groups => {\n let groupids = _.map(groups, 'groupid');\n return this.cachingProxy.getHosts(groupids);\n });\n }\n\n getHosts(groupFilter, hostFilter) {\n return this.getAllHosts(groupFilter)\n .then(hosts => findByFilter(hosts, hostFilter));\n }\n\n /**\n * Get list of applications belonging to given groups and hosts.\n */\n getAllApps(groupFilter, hostFilter) {\n return this.getHosts(groupFilter, hostFilter)\n .then(hosts => {\n let hostids = _.map(hosts, 'hostid');\n return this.cachingProxy.getApps(hostids);\n });\n }\n\n getApps(groupFilter, hostFilter, appFilter) {\n return this.getHosts(groupFilter, hostFilter)\n .then(hosts => {\n let hostids = _.map(hosts, 'hostid');\n if (appFilter) {\n return this.cachingProxy.getApps(hostids)\n .then(apps => filterByQuery(apps, appFilter));\n } else {\n return {\n appFilterEmpty: true,\n hostids: hostids\n };\n }\n });\n }\n\n getAllItems(groupFilter, hostFilter, appFilter, options = {}) {\n return this.getApps(groupFilter, hostFilter, appFilter)\n .then(apps => {\n if (apps.appFilterEmpty) {\n return this.cachingProxy.getItems(apps.hostids, undefined, options.itemtype);\n } else {\n let appids = _.map(apps, 'applicationid');\n return this.cachingProxy.getItems(undefined, appids, options.itemtype);\n }\n })\n .then(items => {\n if (!options.showDisabledItems) {\n items = _.filter(items, {'status': '0'});\n }\n return items;\n });\n }\n\n getItems(groupFilter, hostFilter, appFilter, itemFilter, options = {}) {\n return this.getAllItems(groupFilter, hostFilter, appFilter, options)\n .then(items => filterByQuery(items, itemFilter));\n }\n\n /**\n * Build query - convert target filters to array of Zabbix items\n */\n getTriggers(groupFilter, hostFilter, appFilter, showTriggers) {\n let promises = [\n this.getGroups(groupFilter),\n this.getHosts(groupFilter, hostFilter),\n this.getApps(groupFilter, hostFilter, appFilter)\n ];\n\n return Promise.all(promises)\n .then(results => {\n let filteredGroups = results[0];\n let filteredHosts = results[1];\n let filteredApps = results[2];\n let query = {};\n\n if (appFilter) {\n query.applicationids = _.flatten(_.map(filteredApps, 'applicationid'));\n }\n if (hostFilter) {\n query.hostids = _.map(filteredHosts, 'hostid');\n }\n if (groupFilter) {\n query.groupids = _.map(filteredGroups, 'groupid');\n }\n\n return query;\n }).then(query => {\n return this.zabbixAPI\n .getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers);\n });\n }\n }\n\n return Zabbix;\n}\n\nangular\n .module('grafana.services')\n .factory('Zabbix', ZabbixFactory);\n\n///////////////////////////////////////////////////////////////////////////////\n\n/**\n * Find group, host, app or item by given name.\n * @param list list of groups, apps or other\n * @param name visible name\n * @return array with finded element or undefined\n */\nfunction findByName(list, name) {\n var finded = _.find(list, {'name': name});\n if (finded) {\n return [finded];\n } else {\n return undefined;\n }\n}\n\n/**\n * Different hosts can contains applications and items with same name.\n * For this reason use _.filter, which return all elements instead _.find,\n * which return only first finded.\n * @param {[type]} list list of elements\n * @param {[type]} name app name\n * @return {[type]} array with finded element or undefined\n */\nfunction filterByName(list, name) {\n var finded = _.filter(list, {'name': name});\n if (finded) {\n return finded;\n } else {\n return undefined;\n }\n}\n\nfunction filterByRegex(list, regex) {\n var filterPattern = utils.buildRegex(regex);\n return _.filter(list, function (zbx_obj) {\n return filterPattern.test(zbx_obj.name);\n });\n}\n\nfunction findByFilter(list, filter) {\n if (utils.isRegex(filter)) {\n return filterByRegex(list, filter);\n } else {\n return findByName(list, filter);\n }\n}\n\nfunction filterByQuery(list, filter) {\n if (utils.isRegex(filter)) {\n return filterByRegex(list, filter);\n } else {\n return filterByName(list, filter);\n }\n}\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/zabbixAPI.service.js b/dist/datasource-zabbix/zabbixAPI.service.js
new file mode 100644
index 0000000..83395c3
--- /dev/null
+++ b/dist/datasource-zabbix/zabbixAPI.service.js
@@ -0,0 +1,397 @@
+'use strict';
+
+System.register(['angular', 'lodash', './utils', './zabbixAPICore.service'], function (_export, _context) {
+ "use strict";
+
+ var angular, _, utils, _createClass;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ /** @ngInject */
+ function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
+ var ZabbixAPI = function () {
+ function ZabbixAPI(api_url, username, password, basicAuth, withCredentials) {
+ _classCallCheck(this, ZabbixAPI);
+
+ this.url = api_url;
+ this.username = username;
+ this.password = password;
+ this.auth = "";
+
+ this.requestOptions = {
+ basicAuth: basicAuth,
+ withCredentials: withCredentials
+ };
+
+ this.loginPromise = null;
+ this.loginErrorCount = 0;
+ this.maxLoginAttempts = 3;
+
+ this.alertSrv = alertSrv;
+ this.zabbixAPICore = zabbixAPICoreService;
+
+ this.getTrend = this.getTrend_ZBXNEXT1193;
+ //getTrend = getTrend_30;
+ }
+
+ //////////////////////////
+ // Core method wrappers //
+ //////////////////////////
+
+ _createClass(ZabbixAPI, [{
+ key: 'request',
+ value: function request(method, params) {
+ var _this = this;
+
+ return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth).catch(function (error) {
+ if (isNotAuthorized(error.data)) {
+ // Handle auth errors
+ _this.loginErrorCount++;
+ if (_this.loginErrorCount > _this.maxLoginAttempts) {
+ _this.loginErrorCount = 0;
+ return null;
+ } else {
+ return _this.loginOnce().then(function () {
+ return _this.request(method, params);
+ });
+ }
+ } else {
+ // Handle API errors
+ var message = error.data ? error.data : error.statusText;
+ _this.alertAPIError(message);
+ }
+ });
+ }
+ }, {
+ key: 'alertAPIError',
+ value: function alertAPIError(message) {
+ var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5000;
+
+ this.alertSrv.set("Zabbix API Error", message, 'error', timeout);
+ }
+ }, {
+ key: 'loginOnce',
+ value: function loginOnce() {
+ var _this2 = this;
+
+ if (!this.loginPromise) {
+ this.loginPromise = Promise.resolve(this.login().then(function (auth) {
+ _this2.auth = auth;
+ _this2.loginPromise = null;
+ return auth;
+ }));
+ }
+ return this.loginPromise;
+ }
+ }, {
+ key: 'login',
+ value: function login() {
+ return this.zabbixAPICore.login(this.url, this.username, this.password, this.requestOptions);
+ }
+ }, {
+ key: 'getVersion',
+ value: function getVersion() {
+ return this.zabbixAPICore.getVersion(this.url, this.requestOptions);
+ }
+ }, {
+ key: 'acknowledgeEvent',
+ value: function acknowledgeEvent(eventid, message) {
+ var params = {
+ eventids: eventid,
+ message: message
+ };
+
+ return this.request('event.acknowledge', params);
+ }
+ }, {
+ key: 'getGroups',
+ value: function getGroups() {
+ var params = {
+ output: ['name'],
+ sortfield: 'name',
+ real_hosts: true
+ };
+
+ return this.request('hostgroup.get', params);
+ }
+ }, {
+ key: 'getHosts',
+ value: function getHosts(groupids) {
+ var params = {
+ output: ['name', 'host'],
+ sortfield: 'name'
+ };
+ if (groupids) {
+ params.groupids = groupids;
+ }
+
+ return this.request('host.get', params);
+ }
+ }, {
+ key: 'getApps',
+ value: function getApps(hostids) {
+ var params = {
+ output: ['applicationid', 'name'],
+ hostids: hostids
+ };
+
+ return this.request('application.get', params);
+ }
+ }, {
+ key: 'getItems',
+ value: function getItems(hostids, appids, itemtype) {
+ var params = {
+ output: ['name', 'key_', 'value_type', 'hostid', 'status', 'state'],
+ sortfield: 'name',
+ webitems: true,
+ filter: {},
+ selectHosts: ['hostid', 'name']
+ };
+ if (hostids) {
+ params.hostids = hostids;
+ }
+ if (appids) {
+ params.applicationids = appids;
+ }
+ if (itemtype === 'num') {
+ // Return only numeric metrics
+ params.filter.value_type = [0, 3];
+ }
+ if (itemtype === 'text') {
+ // Return only text metrics
+ params.filter.value_type = [1, 2, 4];
+ }
+
+ return this.request('item.get', params).then(expandItems);
+
+ function expandItems(items) {
+ items.forEach(function (item) {
+ item.item = item.name;
+ item.name = utils.expandItemName(item.item, item.key_);
+ return item;
+ });
+ return items;
+ }
+ }
+ }, {
+ key: 'getLastValue',
+ value: function getLastValue(itemid) {
+ var params = {
+ output: ['lastvalue'],
+ itemids: itemid
+ };
+ return this.request('item.get', params).then(function (items) {
+ return items.length ? items[0].lastvalue : null;
+ });
+ }
+ }, {
+ key: 'getHistory',
+ value: function getHistory(items, timeFrom, timeTill) {
+ var _this3 = this;
+
+ // Group items by value type and perform request for each value type
+ var grouped_items = _.groupBy(items, 'value_type');
+ var promises = _.map(grouped_items, function (items, value_type) {
+ var itemids = _.map(items, 'itemid');
+ var params = {
+ output: 'extend',
+ history: value_type,
+ itemids: itemids,
+ sortfield: 'clock',
+ sortorder: 'ASC',
+ time_from: timeFrom
+ };
+
+ // Relative queries (e.g. last hour) don't include an end time
+ if (timeTill) {
+ params.time_till = timeTill;
+ }
+
+ return _this3.request('history.get', params);
+ });
+
+ return Promise.all(promises).then(_.flatten);
+ }
+ }, {
+ key: 'getTrend_ZBXNEXT1193',
+ value: function getTrend_ZBXNEXT1193(items, timeFrom, timeTill) {
+ var _this4 = this;
+
+ // Group items by value type and perform request for each value type
+ var grouped_items = _.groupBy(items, 'value_type');
+ var promises = _.map(grouped_items, function (items, value_type) {
+ var itemids = _.map(items, 'itemid');
+ var params = {
+ output: 'extend',
+ trend: value_type,
+ itemids: itemids,
+ sortfield: 'clock',
+ sortorder: 'ASC',
+ time_from: timeFrom
+ };
+
+ // Relative queries (e.g. last hour) don't include an end time
+ if (timeTill) {
+ params.time_till = timeTill;
+ }
+
+ return _this4.request('trend.get', params);
+ });
+
+ return Promise.all(promises).then(_.flatten);
+ }
+ }, {
+ key: 'getTrend_30',
+ value: function getTrend_30(items, time_from, time_till, value_type) {
+ var self = this;
+ var itemids = _.map(items, 'itemid');
+
+ var params = {
+ output: ["itemid", "clock", value_type],
+ itemids: itemids,
+ time_from: time_from
+ };
+
+ // Relative queries (e.g. last hour) don't include an end time
+ if (time_till) {
+ params.time_till = time_till;
+ }
+
+ return self.request('trend.get', params);
+ }
+ }, {
+ key: 'getITService',
+ value: function getITService(serviceids) {
+ var params = {
+ output: 'extend',
+ serviceids: serviceids
+ };
+ return this.request('service.get', params);
+ }
+ }, {
+ key: 'getSLA',
+ value: function getSLA(serviceids, timeFrom, timeTo) {
+ var params = {
+ serviceids: serviceids,
+ intervals: [{
+ from: timeFrom,
+ to: timeTo
+ }]
+ };
+ return this.request('service.getsla', params);
+ }
+ }, {
+ key: 'getTriggers',
+ value: function getTriggers(groupids, hostids, applicationids, showTriggers, timeFrom, timeTo) {
+ var params = {
+ output: 'extend',
+ groupids: groupids,
+ hostids: hostids,
+ applicationids: applicationids,
+ expandDescription: true,
+ expandData: true,
+ expandComment: true,
+ monitored: true,
+ skipDependent: true,
+ //only_true: true,
+ filter: {
+ value: 1
+ },
+ selectGroups: ['name'],
+ selectHosts: ['name', 'host'],
+ selectItems: ['name', 'key_', 'lastvalue'],
+ selectLastEvent: 'extend'
+ };
+
+ if (showTriggers) {
+ params.filter.value = showTriggers;
+ }
+
+ if (timeFrom || timeTo) {
+ params.lastChangeSince = timeFrom;
+ params.lastChangeTill = timeTo;
+ }
+
+ return this.request('trigger.get', params);
+ }
+ }, {
+ key: 'getEvents',
+ value: function getEvents(objectids, timeFrom, timeTo, showEvents) {
+ var params = {
+ output: 'extend',
+ time_from: timeFrom,
+ time_till: timeTo,
+ objectids: objectids,
+ select_acknowledges: 'extend',
+ selectHosts: 'extend',
+ value: showEvents
+ };
+
+ return this.request('event.get', params);
+ }
+ }, {
+ key: 'getAcknowledges',
+ value: function getAcknowledges(eventids) {
+ var params = {
+ output: 'extend',
+ eventids: eventids,
+ preservekeys: true,
+ select_acknowledges: 'extend',
+ sortfield: 'clock',
+ sortorder: 'DESC'
+ };
+
+ return this.request('event.get', params).then(function (events) {
+ return _.filter(events, function (event) {
+ return event.acknowledges.length;
+ });
+ });
+ }
+ }]);
+
+ return ZabbixAPI;
+ }();
+
+ return ZabbixAPI;
+ }
+
+ function isNotAuthorized(message) {
+ return message === "Session terminated, re-login, please." || message === "Not authorised." || message === "Not authorized.";
+ }
+
+ return {
+ setters: [function (_angular) {
+ angular = _angular.default;
+ }, function (_lodash) {
+ _ = _lodash.default;
+ }, function (_utils) {
+ utils = _utils;
+ }, function (_zabbixAPICoreService) {}],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ angular.module('grafana.services').factory('zabbixAPIService', ZabbixAPIServiceFactory);
+ }
+ };
+});
+//# sourceMappingURL=zabbixAPI.service.js.map
diff --git a/dist/datasource-zabbix/zabbixAPI.service.js.map b/dist/datasource-zabbix/zabbixAPI.service.js.map
new file mode 100644
index 0000000..5d8dfe9
--- /dev/null
+++ b/dist/datasource-zabbix/zabbixAPI.service.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/zabbixAPI.service.js"],"names":["ZabbixAPIServiceFactory","alertSrv","zabbixAPICoreService","ZabbixAPI","api_url","username","password","basicAuth","withCredentials","url","auth","requestOptions","loginPromise","loginErrorCount","maxLoginAttempts","zabbixAPICore","getTrend","getTrend_ZBXNEXT1193","method","params","request","catch","isNotAuthorized","error","data","loginOnce","then","message","statusText","alertAPIError","timeout","set","Promise","resolve","login","getVersion","eventid","eventids","output","sortfield","real_hosts","groupids","hostids","appids","itemtype","webitems","filter","selectHosts","applicationids","value_type","expandItems","items","forEach","item","name","utils","expandItemName","key_","itemid","itemids","length","lastvalue","timeFrom","timeTill","grouped_items","_","groupBy","promises","map","history","sortorder","time_from","time_till","all","flatten","trend","self","serviceids","timeTo","intervals","from","to","showTriggers","expandDescription","expandData","expandComment","monitored","skipDependent","value","selectGroups","selectItems","selectLastEvent","lastChangeSince","lastChangeTill","objectids","showEvents","select_acknowledges","preservekeys","events","event","acknowledges","angular","module","factory"],"mappings":"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","file":"zabbixAPI.service.js","sourcesContent":["import angular from 'angular';\nimport _ from 'lodash';\nimport * as utils from './utils';\nimport './zabbixAPICore.service';\n\n/** @ngInject */\nfunction ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {\n\n /**\n * Zabbix API Wrapper.\n * Creates Zabbix API instance with given parameters (url, credentials and other).\n * Wraps API calls and provides high-level methods.\n */\n class ZabbixAPI {\n\n constructor(api_url, username, password, basicAuth, withCredentials) {\n this.url = api_url;\n this.username = username;\n this.password = password;\n this.auth = \"\";\n\n this.requestOptions = {\n basicAuth: basicAuth,\n withCredentials: withCredentials\n };\n\n this.loginPromise = null;\n this.loginErrorCount = 0;\n this.maxLoginAttempts = 3;\n\n this.alertSrv = alertSrv;\n this.zabbixAPICore = zabbixAPICoreService;\n\n this.getTrend = this.getTrend_ZBXNEXT1193;\n //getTrend = getTrend_30;\n }\n\n //////////////////////////\n // Core method wrappers //\n //////////////////////////\n\n request(method, params) {\n return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth)\n .catch(error => {\n if (isNotAuthorized(error.data)) {\n // Handle auth errors\n this.loginErrorCount++;\n if (this.loginErrorCount > this.maxLoginAttempts) {\n this.loginErrorCount = 0;\n return null;\n } else {\n return this.loginOnce()\n .then(() => this.request(method, params));\n }\n } else {\n // Handle API errors\n let message = error.data ? error.data : error.statusText;\n this.alertAPIError(message);\n }\n });\n }\n\n alertAPIError(message, timeout = 5000) {\n this.alertSrv.set(\n \"Zabbix API Error\",\n message,\n 'error',\n timeout\n );\n }\n\n /**\n * When API unauthenticated or auth token expired each request produce login()\n * call. But auth token is common to all requests. This function wraps login() method\n * and call it once. If login() already called just wait for it (return its promise).\n * @return login promise\n */\n loginOnce() {\n if (!this.loginPromise) {\n this.loginPromise = Promise.resolve(\n this.login().then(auth => {\n this.auth = auth;\n this.loginPromise = null;\n return auth;\n })\n );\n }\n return this.loginPromise;\n }\n\n /**\n * Get authentication token.\n */\n login() {\n return this.zabbixAPICore.login(this.url, this.username, this.password, this.requestOptions);\n }\n\n /**\n * Get Zabbix API version\n */\n getVersion() {\n return this.zabbixAPICore.getVersion(this.url, this.requestOptions);\n }\n\n ////////////////////////////////\n // Zabbix API method wrappers //\n ////////////////////////////////\n\n acknowledgeEvent(eventid, message) {\n var params = {\n eventids: eventid,\n message: message\n };\n\n return this.request('event.acknowledge', params);\n }\n\n getGroups() {\n var params = {\n output: ['name'],\n sortfield: 'name',\n real_hosts: true\n };\n\n return this.request('hostgroup.get', params);\n }\n\n getHosts(groupids) {\n var params = {\n output: ['name', 'host'],\n sortfield: 'name'\n };\n if (groupids) {\n params.groupids = groupids;\n }\n\n return this.request('host.get', params);\n }\n\n getApps(hostids) {\n var params = {\n output: ['applicationid', 'name'],\n hostids: hostids\n };\n\n return this.request('application.get', params);\n }\n\n /**\n * Get Zabbix items\n * @param {[type]} hostids host ids\n * @param {[type]} appids application ids\n * @param {String} itemtype 'num' or 'text'\n * @return {[type]} array of items\n */\n getItems(hostids, appids, itemtype) {\n var params = {\n output: [\n 'name', 'key_',\n 'value_type',\n 'hostid',\n 'status',\n 'state'\n ],\n sortfield: 'name',\n webitems: true,\n filter: {},\n selectHosts: [\n 'hostid',\n 'name'\n ]\n };\n if (hostids) {\n params.hostids = hostids;\n }\n if (appids) {\n params.applicationids = appids;\n }\n if (itemtype === 'num') {\n // Return only numeric metrics\n params.filter.value_type = [0, 3];\n }\n if (itemtype === 'text') {\n // Return only text metrics\n params.filter.value_type = [1, 2, 4];\n }\n\n return this.request('item.get', params)\n .then(expandItems);\n\n function expandItems(items) {\n items.forEach(item => {\n item.item = item.name;\n item.name = utils.expandItemName(item.item, item.key_);\n return item;\n });\n return items;\n }\n }\n\n getLastValue(itemid) {\n var params = {\n output: ['lastvalue'],\n itemids: itemid\n };\n return this.request('item.get', params)\n .then(items => items.length ? items[0].lastvalue : null);\n }\n\n /**\n * Perform history query from Zabbix API\n *\n * @param {Array} items Array of Zabbix item objects\n * @param {Number} timeFrom Time in seconds\n * @param {Number} timeTill Time in seconds\n * @return {Array} Array of Zabbix history objects\n */\n getHistory(items, timeFrom, timeTill) {\n\n // Group items by value type and perform request for each value type\n let grouped_items = _.groupBy(items, 'value_type');\n let promises = _.map(grouped_items, (items, value_type) => {\n let itemids = _.map(items, 'itemid');\n let params = {\n output: 'extend',\n history: value_type,\n itemids: itemids,\n sortfield: 'clock',\n sortorder: 'ASC',\n time_from: timeFrom\n };\n\n // Relative queries (e.g. last hour) don't include an end time\n if (timeTill) {\n params.time_till = timeTill;\n }\n\n return this.request('history.get', params);\n });\n\n return Promise.all(promises).then(_.flatten);\n }\n\n /**\n * Perform trends query from Zabbix API\n * Use trends api extension from ZBXNEXT-1193 patch.\n *\n * @param {Array} items Array of Zabbix item objects\n * @param {Number} time_from Time in seconds\n * @param {Number} time_till Time in seconds\n * @return {Array} Array of Zabbix trend objects\n */\n getTrend_ZBXNEXT1193(items, timeFrom, timeTill) {\n\n // Group items by value type and perform request for each value type\n let grouped_items = _.groupBy(items, 'value_type');\n let promises = _.map(grouped_items, (items, value_type) => {\n let itemids = _.map(items, 'itemid');\n let params = {\n output: 'extend',\n trend: value_type,\n itemids: itemids,\n sortfield: 'clock',\n sortorder: 'ASC',\n time_from: timeFrom\n };\n\n // Relative queries (e.g. last hour) don't include an end time\n if (timeTill) {\n params.time_till = timeTill;\n }\n\n return this.request('trend.get', params);\n });\n\n return Promise.all(promises).then(_.flatten);\n }\n\n getTrend_30(items, time_from, time_till, value_type) {\n var self = this;\n var itemids = _.map(items, 'itemid');\n\n var params = {\n output: [\"itemid\",\n \"clock\",\n value_type\n ],\n itemids: itemids,\n time_from: time_from\n };\n\n // Relative queries (e.g. last hour) don't include an end time\n if (time_till) {\n params.time_till = time_till;\n }\n\n return self.request('trend.get', params);\n }\n\n getITService(serviceids) {\n var params = {\n output: 'extend',\n serviceids: serviceids\n };\n return this.request('service.get', params);\n }\n\n getSLA(serviceids, timeFrom, timeTo) {\n var params = {\n serviceids: serviceids,\n intervals: [{\n from: timeFrom,\n to: timeTo\n }]\n };\n return this.request('service.getsla', params);\n }\n\n getTriggers(groupids, hostids, applicationids, showTriggers, timeFrom, timeTo) {\n var params = {\n output: 'extend',\n groupids: groupids,\n hostids: hostids,\n applicationids: applicationids,\n expandDescription: true,\n expandData: true,\n expandComment: true,\n monitored: true,\n skipDependent: true,\n //only_true: true,\n filter: {\n value: 1\n },\n selectGroups: ['name'],\n selectHosts: ['name', 'host'],\n selectItems: ['name', 'key_', 'lastvalue'],\n selectLastEvent: 'extend'\n };\n\n if (showTriggers) {\n params.filter.value = showTriggers;\n }\n\n if (timeFrom || timeTo) {\n params.lastChangeSince = timeFrom;\n params.lastChangeTill = timeTo;\n }\n\n return this.request('trigger.get', params);\n }\n\n getEvents(objectids, timeFrom, timeTo, showEvents) {\n var params = {\n output: 'extend',\n time_from: timeFrom,\n time_till: timeTo,\n objectids: objectids,\n select_acknowledges: 'extend',\n selectHosts: 'extend',\n value: showEvents\n };\n\n return this.request('event.get', params);\n }\n\n getAcknowledges(eventids) {\n var params = {\n output: 'extend',\n eventids: eventids,\n preservekeys: true,\n select_acknowledges: 'extend',\n sortfield: 'clock',\n sortorder: 'DESC'\n };\n\n return this.request('event.get', params)\n .then(events => {\n return _.filter(events, (event) => event.acknowledges.length);\n });\n }\n\n }\n\n return ZabbixAPI;\n}\n\nfunction isNotAuthorized(message) {\n return (\n message === \"Session terminated, re-login, please.\" ||\n message === \"Not authorised.\" ||\n message === \"Not authorized.\"\n );\n}\n\nangular\n .module('grafana.services')\n .factory('zabbixAPIService', ZabbixAPIServiceFactory);\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/zabbixAPICore.service.js b/dist/datasource-zabbix/zabbixAPICore.service.js
new file mode 100644
index 0000000..1391f8c
--- /dev/null
+++ b/dist/datasource-zabbix/zabbixAPICore.service.js
@@ -0,0 +1,150 @@
+'use strict';
+
+System.register(['angular'], function (_export, _context) {
+ "use strict";
+
+ var angular, _createClass, ZabbixAPICoreService, ZabbixAPIError;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ return {
+ setters: [function (_angular) {
+ angular = _angular.default;
+ }],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ ZabbixAPICoreService = function () {
+
+ /** @ngInject */
+ function ZabbixAPICoreService(backendSrv) {
+ _classCallCheck(this, ZabbixAPICoreService);
+
+ this.backendSrv = backendSrv;
+ }
+
+ /**
+ * Request data from Zabbix API
+ * @return {object} response.result
+ */
+
+
+ _createClass(ZabbixAPICoreService, [{
+ key: 'request',
+ value: function request(api_url, method, params, options, auth) {
+ var requestData = {
+ jsonrpc: '2.0',
+ method: method,
+ params: params,
+ id: 1
+ };
+
+ if (auth === "") {
+ // Reject immediately if not authenticated
+ return Promise.reject(new ZabbixAPIError({ data: "Not authorised." }));
+ } else if (auth) {
+ // Set auth parameter only if it needed
+ requestData.auth = auth;
+ }
+
+ var requestOptions = {
+ method: 'POST',
+ url: api_url,
+ data: requestData,
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ };
+
+ // Set request options for basic auth
+ if (options.basicAuth || options.withCredentials) {
+ requestOptions.withCredentials = true;
+ }
+ if (options.basicAuth) {
+ requestOptions.headers.Authorization = options.basicAuth;
+ }
+
+ return this.datasourceRequest(requestOptions);
+ }
+ }, {
+ key: 'datasourceRequest',
+ value: function datasourceRequest(requestOptions) {
+ return this.backendSrv.datasourceRequest(requestOptions).then(function (response) {
+ if (!response.data) {
+ return Promise.reject(new ZabbixAPIError({ data: "General Error, no data" }));
+ } else if (response.data.error) {
+
+ // Handle Zabbix API errors
+ return Promise.reject(new ZabbixAPIError(response.data.error));
+ }
+
+ // Success
+ return response.data.result;
+ });
+ }
+ }, {
+ key: 'login',
+ value: function login(api_url, username, password, options) {
+ var params = {
+ user: username,
+ password: password
+ };
+ return this.request(api_url, 'user.login', params, options, null);
+ }
+ }, {
+ key: 'getVersion',
+ value: function getVersion(api_url, options) {
+ return this.request(api_url, 'apiinfo.version', [], options);
+ }
+ }]);
+
+ return ZabbixAPICoreService;
+ }();
+
+ _export('ZabbixAPIError', ZabbixAPIError = function () {
+ function ZabbixAPIError(error) {
+ _classCallCheck(this, ZabbixAPIError);
+
+ this.code = error.code;
+ this.name = error.data;
+ this.message = error.data;
+ this.data = error.data;
+ }
+
+ _createClass(ZabbixAPIError, [{
+ key: 'toString',
+ value: function toString() {
+ return this.name + ": " + this.message;
+ }
+ }]);
+
+ return ZabbixAPIError;
+ }());
+
+ _export('ZabbixAPIError', ZabbixAPIError);
+
+ angular.module('grafana.services').service('zabbixAPICoreService', ZabbixAPICoreService);
+ }
+ };
+});
+//# sourceMappingURL=zabbixAPICore.service.js.map
diff --git a/dist/datasource-zabbix/zabbixAPICore.service.js.map b/dist/datasource-zabbix/zabbixAPICore.service.js.map
new file mode 100644
index 0000000..042c8b7
--- /dev/null
+++ b/dist/datasource-zabbix/zabbixAPICore.service.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/zabbixAPICore.service.js"],"names":["angular","ZabbixAPICoreService","backendSrv","api_url","method","params","options","auth","requestData","jsonrpc","id","Promise","reject","ZabbixAPIError","data","requestOptions","url","headers","basicAuth","withCredentials","Authorization","datasourceRequest","then","response","error","result","username","password","user","request","code","name","message","module","service"],"mappings":";;;;;;;;;;;;;;;AAIOA,a;;;;;;;;;;;;;;;;;;;;;AAEDC,0B;;AAEJ;AACA,sCAAYC,UAAZ,EAAwB;AAAA;;AACtB,eAAKA,UAAL,GAAkBA,UAAlB;AACD;;AAED;;;;;;;;kCAIQC,O,EAASC,M,EAAQC,M,EAAQC,O,EAASC,I,EAAM;AAC9C,gBAAIC,cAAc;AAChBC,uBAAS,KADO;AAEhBL,sBAAQA,MAFQ;AAGhBC,sBAAQA,MAHQ;AAIhBK,kBAAI;AAJY,aAAlB;;AAOA,gBAAIH,SAAS,EAAb,EAAiB;AACf;AACA,qBAAOI,QAAQC,MAAR,CAAe,IAAIC,cAAJ,CAAmB,EAACC,MAAM,iBAAP,EAAnB,CAAf,CAAP;AACD,aAHD,MAGO,IAAIP,IAAJ,EAAU;AACf;AACAC,0BAAYD,IAAZ,GAAmBA,IAAnB;AACD;;AAED,gBAAIQ,iBAAiB;AACnBX,sBAAQ,MADW;AAEnBY,mBAAKb,OAFc;AAGnBW,oBAAMN,WAHa;AAInBS,uBAAS;AACP,gCAAgB;AADT;AAJU,aAArB;;AASA;AACA,gBAAIX,QAAQY,SAAR,IAAqBZ,QAAQa,eAAjC,EAAkD;AAChDJ,6BAAeI,eAAf,GAAiC,IAAjC;AACD;AACD,gBAAIb,QAAQY,SAAZ,EAAuB;AACrBH,6BAAeE,OAAf,CAAuBG,aAAvB,GAAuCd,QAAQY,SAA/C;AACD;;AAED,mBAAO,KAAKG,iBAAL,CAAuBN,cAAvB,CAAP;AACD;;;4CAEiBA,c,EAAgB;AAChC,mBAAO,KAAKb,UAAL,CAAgBmB,iBAAhB,CAAkCN,cAAlC,EACNO,IADM,CACD,oBAAY;AAChB,kBAAI,CAACC,SAAST,IAAd,EAAoB;AAClB,uBAAOH,QAAQC,MAAR,CAAe,IAAIC,cAAJ,CAAmB,EAACC,MAAM,wBAAP,EAAnB,CAAf,CAAP;AACD,eAFD,MAEO,IAAIS,SAAST,IAAT,CAAcU,KAAlB,EAAyB;;AAE9B;AACA,uBAAOb,QAAQC,MAAR,CAAe,IAAIC,cAAJ,CAAmBU,SAAST,IAAT,CAAcU,KAAjC,CAAf,CAAP;AACD;;AAED;AACA,qBAAOD,SAAST,IAAT,CAAcW,MAArB;AACD,aAZM,CAAP;AAaD;;;gCAMKtB,O,EAASuB,Q,EAAUC,Q,EAAUrB,O,EAAS;AAC1C,gBAAID,SAAS;AACXuB,oBAAMF,QADK;AAEXC,wBAAUA;AAFC,aAAb;AAIA,mBAAO,KAAKE,OAAL,CAAa1B,OAAb,EAAsB,YAAtB,EAAoCE,MAApC,EAA4CC,OAA5C,EAAqD,IAArD,CAAP;AACD;;;qCAMUH,O,EAASG,O,EAAS;AAC3B,mBAAO,KAAKuB,OAAL,CAAa1B,OAAb,EAAsB,iBAAtB,EAAyC,EAAzC,EAA6CG,OAA7C,CAAP;AACD;;;;;;gCAIUO,c;AACX,gCAAYW,KAAZ,EAAmB;AAAA;;AACjB,eAAKM,IAAL,GAAYN,MAAMM,IAAlB;AACA,eAAKC,IAAL,GAAYP,MAAMV,IAAlB;AACA,eAAKkB,OAAL,GAAeR,MAAMV,IAArB;AACA,eAAKA,IAAL,GAAYU,MAAMV,IAAlB;AACD;;;;qCAEU;AACT,mBAAO,KAAKiB,IAAL,GAAY,IAAZ,GAAmB,KAAKC,OAA/B;AACD;;;;;;;;AAGHhC,cACGiC,MADH,CACU,kBADV,EAEGC,OAFH,CAEW,sBAFX,EAEmCjC,oBAFnC","file":"zabbixAPICore.service.js","sourcesContent":["/**\n * General Zabbix API methods\n */\n\nimport angular from 'angular';\n\nclass ZabbixAPICoreService {\n\n /** @ngInject */\n constructor(backendSrv) {\n this.backendSrv = backendSrv;\n }\n\n /**\n * Request data from Zabbix API\n * @return {object} response.result\n */\n request(api_url, method, params, options, auth) {\n let requestData = {\n jsonrpc: '2.0',\n method: method,\n params: params,\n id: 1\n };\n\n if (auth === \"\") {\n // Reject immediately if not authenticated\n return Promise.reject(new ZabbixAPIError({data: \"Not authorised.\"}));\n } else if (auth) {\n // Set auth parameter only if it needed\n requestData.auth = auth;\n }\n\n let requestOptions = {\n method: 'POST',\n url: api_url,\n data: requestData,\n headers: {\n 'Content-Type': 'application/json'\n }\n };\n\n // Set request options for basic auth\n if (options.basicAuth || options.withCredentials) {\n requestOptions.withCredentials = true;\n }\n if (options.basicAuth) {\n requestOptions.headers.Authorization = options.basicAuth;\n }\n\n return this.datasourceRequest(requestOptions);\n }\n\n datasourceRequest(requestOptions) {\n return this.backendSrv.datasourceRequest(requestOptions)\n .then(response => {\n if (!response.data) {\n return Promise.reject(new ZabbixAPIError({data: \"General Error, no data\"}));\n } else if (response.data.error) {\n\n // Handle Zabbix API errors\n return Promise.reject(new ZabbixAPIError(response.data.error));\n }\n\n // Success\n return response.data.result;\n });\n }\n\n /**\n * Get authentication token.\n * @return {string} auth token\n */\n login(api_url, username, password, options) {\n let params = {\n user: username,\n password: password\n };\n return this.request(api_url, 'user.login', params, options, null);\n }\n\n /**\n * Get Zabbix API version\n * Matches the version of Zabbix starting from Zabbix 2.0.4\n */\n getVersion(api_url, options) {\n return this.request(api_url, 'apiinfo.version', [], options);\n }\n}\n\n// Define zabbix API exception type\nexport class ZabbixAPIError {\n constructor(error) {\n this.code = error.code;\n this.name = error.data;\n this.message = error.data;\n this.data = error.data;\n }\n\n toString() {\n return this.name + \": \" + this.message;\n }\n}\n\nangular\n .module('grafana.services')\n .service('zabbixAPICoreService', ZabbixAPICoreService);\n"]}
\ No newline at end of file
diff --git a/dist/datasource-zabbix/zabbixCachingProxy.service.js b/dist/datasource-zabbix/zabbixCachingProxy.service.js
new file mode 100644
index 0000000..3847c4c
--- /dev/null
+++ b/dist/datasource-zabbix/zabbixCachingProxy.service.js
@@ -0,0 +1,243 @@
+'use strict';
+
+System.register(['angular', 'lodash'], function (_export, _context) {
+ "use strict";
+
+ var angular, _, _createClass;
+
+ function _toConsumableArray(arr) {
+ if (Array.isArray(arr)) {
+ for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
+ arr2[i] = arr[i];
+ }
+
+ return arr2;
+ } else {
+ return Array.from(arr);
+ }
+ }
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ // Use factory() instead service() for multiple datasources support.
+ // Each datasource instance must initialize its own cache.
+
+ /** @ngInject */
+ function ZabbixCachingProxyFactory() {
+ var ZabbixCachingProxy = function () {
+ function ZabbixCachingProxy(zabbixAPI, cacheOptions) {
+ _classCallCheck(this, ZabbixCachingProxy);
+
+ this.zabbixAPI = zabbixAPI;
+ this.cacheEnabled = cacheOptions.enabled;
+ this.ttl = cacheOptions.ttl || 600000; // 10 minutes by default
+
+ // Internal objects for data storing
+ this.cache = {
+ groups: {},
+ hosts: {},
+ applications: {},
+ items: {},
+ history: {},
+ trends: {}
+ };
+
+ this.historyPromises = {};
+
+ // Don't run duplicated history requests
+ this.getHistory = callAPIRequestOnce(_.bind(this.zabbixAPI.getHistory, this.zabbixAPI), this.historyPromises, getHistoryRequestHash);
+
+ // Don't run duplicated requests
+ this.groupPromises = {};
+ this.getGroupsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getGroups, this.zabbixAPI), this.groupPromises, getRequestHash);
+
+ this.hostPromises = {};
+ this.getHostsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getHosts, this.zabbixAPI), this.hostPromises, getRequestHash);
+
+ this.appPromises = {};
+ this.getAppsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getApps, this.zabbixAPI), this.appPromises, getRequestHash);
+
+ this.itemPromises = {};
+ this.getItemsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getItems, this.zabbixAPI), this.itemPromises, getRequestHash);
+ }
+
+ _createClass(ZabbixCachingProxy, [{
+ key: 'isExpired',
+ value: function isExpired(cacheObject) {
+ if (cacheObject) {
+ var object_age = Date.now() - cacheObject.timestamp;
+ return !(cacheObject.timestamp && object_age < this.ttl);
+ } else {
+ return true;
+ }
+ }
+ }, {
+ key: 'proxyRequest',
+ value: function proxyRequest(request, params, cacheObject) {
+ var hash = getRequestHash(params);
+ if (this.cacheEnabled && !this.isExpired(cacheObject[hash])) {
+ return Promise.resolve(cacheObject[hash].value);
+ } else {
+ return request.apply(undefined, _toConsumableArray(params)).then(function (result) {
+ cacheObject[hash] = {
+ value: result,
+ timestamp: Date.now()
+ };
+ return result;
+ });
+ }
+ }
+ }, {
+ key: 'getGroups',
+ value: function getGroups() {
+ return this.proxyRequest(this.getGroupsOnce, [], this.cache.groups);
+ }
+ }, {
+ key: 'getHosts',
+ value: function getHosts(groupids) {
+ return this.proxyRequest(this.getHostsOnce, [groupids], this.cache.hosts);
+ }
+ }, {
+ key: 'getApps',
+ value: function getApps(hostids) {
+ return this.proxyRequest(this.getAppsOnce, [hostids], this.cache.applications);
+ }
+ }, {
+ key: 'getItems',
+ value: function getItems(hostids, appids, itemtype) {
+ var params = [hostids, appids, itemtype];
+ return this.proxyRequest(this.getItemsOnce, params, this.cache.items);
+ }
+ }, {
+ key: 'getHistoryFromCache',
+ value: function getHistoryFromCache(items, time_from, time_till) {
+ var historyStorage = this.cache.history;
+ var full_history;
+ var expired = _.filter(_.keyBy(items, 'itemid'), function (item, itemid) {
+ return !historyStorage[itemid];
+ });
+ if (expired.length) {
+ return this.zabbixAPI.getHistory(expired, time_from, time_till).then(function (history) {
+ var grouped_history = _.groupBy(history, 'itemid');
+ _.forEach(expired, function (item) {
+ var itemid = item.itemid;
+ historyStorage[itemid] = item;
+ historyStorage[itemid].time_from = time_from;
+ historyStorage[itemid].time_till = time_till;
+ historyStorage[itemid].history = grouped_history[itemid];
+ });
+ full_history = _.map(items, function (item) {
+ return historyStorage[item.itemid].history;
+ });
+ return _.flatten(full_history, true);
+ });
+ } else {
+ full_history = _.map(items, function (item) {
+ return historyStorage[item.itemid].history;
+ });
+ return Promise.resolve(_.flatten(full_history, true));
+ }
+ }
+ }, {
+ key: 'getHistoryFromAPI',
+ value: function getHistoryFromAPI(items, time_from, time_till) {
+ return this.zabbixAPI.getHistory(items, time_from, time_till);
+ }
+ }]);
+
+ return ZabbixCachingProxy;
+ }();
+
+ return ZabbixCachingProxy;
+ }
+
+ /**
+ * Wrap zabbix API request to prevent multiple calls
+ * with same params when waiting for result.
+ */
+ function callAPIRequestOnce(func, promiseKeeper, argsHashFunc) {
+ return function () {
+ var hash = argsHashFunc(arguments);
+ if (!promiseKeeper[hash]) {
+ promiseKeeper[hash] = Promise.resolve(func.apply(this, arguments).then(function (result) {
+ promiseKeeper[hash] = null;
+ return result;
+ }));
+ }
+ return promiseKeeper[hash];
+ };
+ }
+
+ function getRequestHash(args) {
+ var requestStamp = _.map(args, function (arg) {
+ if (arg === undefined) {
+ return 'undefined';
+ } else {
+ if (_.isArray(arg)) {
+ return arg.sort().toString();
+ } else {
+ return arg.toString();
+ }
+ }
+ }).join();
+ return requestStamp.getHash();
+ }
+
+ function getHistoryRequestHash(args) {
+ var itemids = _.map(args[0], 'itemid');
+ var stamp = itemids.join() + args[1] + args[2];
+ return stamp.getHash();
+ }
+
+ return {
+ setters: [function (_angular) {
+ angular = _angular.default;
+ }, function (_lodash) {
+ _ = _lodash.default;
+ }],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ angular.module('grafana.services').factory('ZabbixCachingProxy', ZabbixCachingProxyFactory);String.prototype.getHash = function () {
+ var hash = 0,
+ i,
+ chr,
+ len;
+ if (this.length !== 0) {
+ for (i = 0, len = this.length; i < len; i++) {
+ chr = this.charCodeAt(i);
+ hash = (hash << 5) - hash + chr;
+ hash |= 0; // Convert to 32bit integer
+ }
+ }
+ return hash;
+ };
+
+ // Fix for backward compatibility with lodash 2.4
+ if (!_.keyBy) {
+ _.keyBy = _.indexBy;
+ }
+ }
+ };
+});
+//# sourceMappingURL=zabbixCachingProxy.service.js.map
diff --git a/dist/datasource-zabbix/zabbixCachingProxy.service.js.map b/dist/datasource-zabbix/zabbixCachingProxy.service.js.map
new file mode 100644
index 0000000..e4ba4b1
--- /dev/null
+++ b/dist/datasource-zabbix/zabbixCachingProxy.service.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource-zabbix/zabbixCachingProxy.service.js"],"names":["ZabbixCachingProxyFactory","ZabbixCachingProxy","zabbixAPI","cacheOptions","cacheEnabled","enabled","ttl","cache","groups","hosts","applications","items","history","trends","historyPromises","getHistory","callAPIRequestOnce","_","bind","getHistoryRequestHash","groupPromises","getGroupsOnce","getGroups","getRequestHash","hostPromises","getHostsOnce","getHosts","appPromises","getAppsOnce","getApps","itemPromises","getItemsOnce","getItems","cacheObject","object_age","Date","now","timestamp","request","params","hash","isExpired","Promise","resolve","value","then","result","proxyRequest","groupids","hostids","appids","itemtype","time_from","time_till","historyStorage","full_history","expired","filter","keyBy","item","itemid","length","grouped_history","groupBy","forEach","map","flatten","func","promiseKeeper","argsHashFunc","arguments","apply","args","requestStamp","arg","undefined","isArray","sort","toString","join","getHash","itemids","stamp","angular","module","factory","String","prototype","i","chr","len","charCodeAt","indexBy"],"mappings":"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","file":"zabbixCachingProxy.service.js","sourcesContent":["import angular from 'angular';\nimport _ from 'lodash';\n\n// Use factory() instead service() for multiple datasources support.\n// Each datasource instance must initialize its own cache.\n\n/** @ngInject */\nfunction ZabbixCachingProxyFactory() {\n\n class ZabbixCachingProxy {\n constructor(zabbixAPI, cacheOptions) {\n this.zabbixAPI = zabbixAPI;\n this.cacheEnabled = cacheOptions.enabled;\n this.ttl = cacheOptions.ttl || 600000; // 10 minutes by default\n\n // Internal objects for data storing\n this.cache = {\n groups: {},\n hosts: {},\n applications: {},\n items: {},\n history: {},\n trends: {}\n };\n\n this.historyPromises = {};\n\n // Don't run duplicated history requests\n this.getHistory = callAPIRequestOnce(_.bind(this.zabbixAPI.getHistory, this.zabbixAPI),\n this.historyPromises, getHistoryRequestHash);\n\n // Don't run duplicated requests\n this.groupPromises = {};\n this.getGroupsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getGroups, this.zabbixAPI),\n this.groupPromises, getRequestHash);\n\n this.hostPromises = {};\n this.getHostsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getHosts, this.zabbixAPI),\n this.hostPromises, getRequestHash);\n\n this.appPromises = {};\n this.getAppsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getApps, this.zabbixAPI),\n this.appPromises, getRequestHash);\n\n this.itemPromises = {};\n this.getItemsOnce = callAPIRequestOnce(_.bind(this.zabbixAPI.getItems, this.zabbixAPI),\n this.itemPromises, getRequestHash);\n }\n\n isExpired(cacheObject) {\n if (cacheObject) {\n let object_age = Date.now() - cacheObject.timestamp;\n return !(cacheObject.timestamp && object_age < this.ttl);\n } else {\n return true;\n }\n }\n\n /**\n * Check that result is present in cache and up to date\n * or send request to API.\n */\n proxyRequest(request, params, cacheObject) {\n let hash = getRequestHash(params);\n if (this.cacheEnabled && !this.isExpired(cacheObject[hash])) {\n return Promise.resolve(cacheObject[hash].value);\n } else {\n return request(...params)\n .then(result => {\n cacheObject[hash] = {\n value: result,\n timestamp: Date.now()\n };\n return result;\n });\n }\n }\n\n getGroups() {\n return this.proxyRequest(this.getGroupsOnce, [], this.cache.groups);\n }\n\n getHosts(groupids) {\n return this.proxyRequest(this.getHostsOnce, [groupids], this.cache.hosts);\n }\n\n getApps(hostids) {\n return this.proxyRequest(this.getAppsOnce, [hostids], this.cache.applications);\n }\n\n getItems(hostids, appids, itemtype) {\n let params = [hostids, appids, itemtype];\n return this.proxyRequest(this.getItemsOnce, params, this.cache.items);\n }\n\n getHistoryFromCache(items, time_from, time_till) {\n var historyStorage = this.cache.history;\n var full_history;\n var expired = _.filter(_.keyBy(items, 'itemid'), (item, itemid) => {\n return !historyStorage[itemid];\n });\n if (expired.length) {\n return this.zabbixAPI.getHistory(expired, time_from, time_till).then(function(history) {\n var grouped_history = _.groupBy(history, 'itemid');\n _.forEach(expired, item => {\n var itemid = item.itemid;\n historyStorage[itemid] = item;\n historyStorage[itemid].time_from = time_from;\n historyStorage[itemid].time_till = time_till;\n historyStorage[itemid].history = grouped_history[itemid];\n });\n full_history = _.map(items, item => {\n return historyStorage[item.itemid].history;\n });\n return _.flatten(full_history, true);\n });\n } else {\n full_history = _.map(items, function(item) {\n return historyStorage[item.itemid].history;\n });\n return Promise.resolve(_.flatten(full_history, true));\n }\n }\n\n getHistoryFromAPI(items, time_from, time_till) {\n return this.zabbixAPI.getHistory(items, time_from, time_till);\n }\n }\n\n return ZabbixCachingProxy;\n}\n\nangular\n .module('grafana.services')\n .factory('ZabbixCachingProxy', ZabbixCachingProxyFactory);\n\n/**\n * Wrap zabbix API request to prevent multiple calls\n * with same params when waiting for result.\n */\nfunction callAPIRequestOnce(func, promiseKeeper, argsHashFunc) {\n return function() {\n var hash = argsHashFunc(arguments);\n if (!promiseKeeper[hash]) {\n promiseKeeper[hash] = Promise.resolve(\n func.apply(this, arguments)\n .then(result => {\n promiseKeeper[hash] = null;\n return result;\n })\n );\n }\n return promiseKeeper[hash];\n };\n}\n\nfunction getRequestHash(args) {\n var requestStamp = _.map(args, arg => {\n if (arg === undefined) {\n return 'undefined';\n } else {\n if (_.isArray(arg)) {\n return arg.sort().toString();\n } else {\n return arg.toString();\n }\n }\n }).join();\n return requestStamp.getHash();\n}\n\nfunction getHistoryRequestHash(args) {\n let itemids = _.map(args[0], 'itemid');\n let stamp = itemids.join() + args[1] + args[2];\n return stamp.getHash();\n}\n\nString.prototype.getHash = function() {\n var hash = 0, i, chr, len;\n if (this.length !== 0) {\n for (i = 0, len = this.length; i < len; i++) {\n chr = this.charCodeAt(i);\n hash = ((hash << 5) - hash) + chr;\n hash |= 0; // Convert to 32bit integer\n }\n }\n return hash;\n};\n\n// Fix for backward compatibility with lodash 2.4\nif (!_.keyBy) {_.keyBy = _.indexBy;}\n"]}
\ No newline at end of file
diff --git a/dist/img/screenshot-annotations.png b/dist/img/screenshot-annotations.png
new file mode 100644
index 0000000..8bedea3
Binary files /dev/null and b/dist/img/screenshot-annotations.png differ
diff --git a/dist/img/screenshot-dashboard01.png b/dist/img/screenshot-dashboard01.png
new file mode 100644
index 0000000..64ad1ac
Binary files /dev/null and b/dist/img/screenshot-dashboard01.png differ
diff --git a/dist/img/screenshot-metric_editor.png b/dist/img/screenshot-metric_editor.png
new file mode 100644
index 0000000..f28a372
Binary files /dev/null and b/dist/img/screenshot-metric_editor.png differ
diff --git a/dist/img/screenshot-showcase.png b/dist/img/screenshot-showcase.png
new file mode 100644
index 0000000..46f4b92
Binary files /dev/null and b/dist/img/screenshot-showcase.png differ
diff --git a/dist/img/screenshot-triggers.png b/dist/img/screenshot-triggers.png
new file mode 100644
index 0000000..002e518
Binary files /dev/null and b/dist/img/screenshot-triggers.png differ
diff --git a/dist/img/zabbix_app_logo.svg b/dist/img/zabbix_app_logo.svg
new file mode 100644
index 0000000..237247d
--- /dev/null
+++ b/dist/img/zabbix_app_logo.svg
@@ -0,0 +1,107 @@
+
+
+
+image/svg+xml
\ No newline at end of file
diff --git a/dist/module.js b/dist/module.js
new file mode 100644
index 0000000..ac2080f
--- /dev/null
+++ b/dist/module.js
@@ -0,0 +1,16 @@
+'use strict';
+
+System.register(['./components/config'], function (_export, _context) {
+ "use strict";
+
+ var ZabbixAppConfigCtrl;
+ return {
+ setters: [function (_componentsConfig) {
+ ZabbixAppConfigCtrl = _componentsConfig.ZabbixAppConfigCtrl;
+ }],
+ execute: function () {
+ _export('ConfigCtrl', ZabbixAppConfigCtrl);
+ }
+ };
+});
+//# sourceMappingURL=module.js.map
diff --git a/dist/module.js.map b/dist/module.js.map
new file mode 100644
index 0000000..aad765d
--- /dev/null
+++ b/dist/module.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../src/module.js"],"names":["ZabbixAppConfigCtrl"],"mappings":";;;;;;;;AAAQA,yB,qBAAAA,mB;;;4BAGNA,mB","file":"module.js","sourcesContent":["import {ZabbixAppConfigCtrl} from './components/config';\n\nexport {\n ZabbixAppConfigCtrl as ConfigCtrl\n};\n"]}
\ No newline at end of file
diff --git a/dist/panel-triggers/ack-tooltip.directive.js b/dist/panel-triggers/ack-tooltip.directive.js
new file mode 100644
index 0000000..614da93
--- /dev/null
+++ b/dist/panel-triggers/ack-tooltip.directive.js
@@ -0,0 +1,126 @@
+'use strict';
+
+System.register(['angular', 'jquery', 'tether-drop'], function (_export, _context) {
+ "use strict";
+
+ var angular, $, Drop;
+ return {
+ setters: [function (_angular) {
+ angular = _angular.default;
+ }, function (_jquery) {
+ $ = _jquery.default;
+ }, function (_tetherDrop) {
+ Drop = _tetherDrop.default;
+ }],
+ execute: function () {
+
+ /** @ngInject */
+ angular.module('grafana.directives').directive('ackTooltip', function ($sanitize, $compile) {
+ var buttonTemplate = ' ';
+
+ return {
+ scope: {
+ ack: "=",
+ trigger: "=",
+ onAck: "=",
+ context: "="
+ },
+ link: function link(scope, element) {
+ var acknowledges = scope.ack;
+ var $button = $(buttonTemplate);
+ $button.appendTo(element);
+
+ $button.click(function () {
+ var tooltip = '';
+
+ if (acknowledges && acknowledges.length) {
+ tooltip += '
' + 'Time ' + 'User ' + '' + ' ';
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = acknowledges[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var ack = _step.value;
+
+ tooltip += '' + ack.time + ' ' + '' + ack.user + ' ' + '' + ack.message + ' ';
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ tooltip += '
';
+ } else {
+ tooltip += 'Add acknowledge';
+ }
+
+ var addAckButtonTemplate = '
' + '' + ' ' + '
';
+ tooltip += addAckButtonTemplate;
+ tooltip += '
';
+
+ var 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() {
+ var inputTemplate = '' + ' ' + '' + 'Acknowledge ' + '' + 'Cancel' + '
';
+
+ var $input = $(inputTemplate);
+ var $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() {
+ var message = $('.ack-tooltip #ack-message')[0].value;
+ var onAck = scope.onAck.bind(scope.context);
+ onAck(scope.trigger, message).then(function () {
+ closeDrop();
+ });
+ }
+
+ function closeDrop() {
+ setTimeout(function () {
+ drop.destroy();
+ });
+ }
+ });
+
+ $compile(element.contents())(scope);
+ }
+ };
+ });
+ }
+ };
+});
+//# sourceMappingURL=ack-tooltip.directive.js.map
diff --git a/dist/panel-triggers/ack-tooltip.directive.js.map b/dist/panel-triggers/ack-tooltip.directive.js.map
new file mode 100644
index 0000000..0281afe
--- /dev/null
+++ b/dist/panel-triggers/ack-tooltip.directive.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/panel-triggers/ack-tooltip.directive.js"],"names":["angular","$","Drop","module","directive","$sanitize","$compile","buttonTemplate","scope","ack","trigger","onAck","context","link","element","acknowledges","$button","appendTo","click","tooltip","length","time","user","message","addAckButtonTemplate","drop","target","content","position","classes","openOn","hoverCloseDelay","tetherOptions","constraints","to","pin","attachment","open","on","closeDrop","onAddAckButtonClick","inputTemplate","$input","$addAckButton","replaceWith","onAckCancelButtonClick","onAckSendlButtonClick","value","bind","then","setTimeout","destroy","contents"],"mappings":"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","file":"ack-tooltip.directive.js","sourcesContent":["import angular from 'angular';\nimport $ from 'jquery';\nimport Drop from 'tether-drop';\n\n/** @ngInject */\nangular\n .module('grafana.directives')\n .directive('ackTooltip', function($sanitize, $compile) {\n let buttonTemplate = ' ';\n\n return {\n scope: {\n ack: \"=\",\n trigger: \"=\",\n onAck: \"=\",\n context: \"=\"\n },\n link: function(scope, element) {\n let acknowledges = scope.ack;\n let $button = $(buttonTemplate);\n $button.appendTo(element);\n\n $button.click(function() {\n let tooltip = '';\n\n if (acknowledges && acknowledges.length) {\n tooltip += '
' +\n 'Time ' +\n 'User ' +\n '' +\n ' ';\n for (let ack of acknowledges) {\n tooltip += '' + ack.time + ' ' +\n '' + ack.user + ' ' +\n '' + ack.message + ' ';\n }\n tooltip += '
';\n } else {\n tooltip += 'Add acknowledge';\n }\n\n let addAckButtonTemplate = '
' +\n '' +\n ' ' +\n '
';\n tooltip += addAckButtonTemplate;\n tooltip += '
';\n\n let drop = new Drop({\n target: element[0],\n content: tooltip,\n position: \"bottom left\",\n classes: 'drop-popover ack-tooltip',\n openOn: 'hover',\n hoverCloseDelay: 500,\n tetherOptions: {\n constraints: [{to: 'window', pin: true, attachment: \"both\"}]\n }\n });\n\n drop.open();\n drop.on('close', closeDrop);\n\n $('#add-acknowledge-btn').on('click', onAddAckButtonClick);\n\n function onAddAckButtonClick() {\n let inputTemplate = '' +\n ' ' +\n '' +\n 'Acknowledge ' +\n '' +\n 'Cancel' +\n '
';\n\n let $input = $(inputTemplate);\n let $addAckButton = $('.ack-tooltip .ack-add-button');\n $addAckButton.replaceWith($input);\n $('.ack-tooltip #cancel-ack-button').on('click', onAckCancelButtonClick);\n $('.ack-tooltip #send-ack-button').on('click', onAckSendlButtonClick);\n }\n\n function onAckCancelButtonClick() {\n $('.ack-tooltip .ack-input-group').replaceWith(addAckButtonTemplate);\n $('#add-acknowledge-btn').on('click', onAddAckButtonClick);\n }\n\n function onAckSendlButtonClick() {\n let message = $('.ack-tooltip #ack-message')[0].value;\n let onAck = scope.onAck.bind(scope.context);\n onAck(scope.trigger, message).then(() => {\n closeDrop();\n });\n }\n\n function closeDrop() {\n setTimeout(function() {\n drop.destroy();\n });\n }\n\n });\n\n $compile(element.contents())(scope);\n }\n };\n });\n"]}
\ No newline at end of file
diff --git a/dist/panel-triggers/css/panel_triggers.css b/dist/panel-triggers/css/panel_triggers.css
new file mode 100644
index 0000000..c705db7
--- /dev/null
+++ b/dist/panel-triggers/css/panel_triggers.css
@@ -0,0 +1,96 @@
+.triggers-panel-wrapper .panel-content {
+ padding: 0; }
+
+.triggers-panel-wrapper .panel-title-container {
+ padding-bottom: 4px; }
+
+.triggers-panel-scroll {
+ overflow: auto; }
+
+.triggers-panel-container {
+ padding-top: 2.2em;
+ position: relative; }
+
+.triggers-panel-footer {
+ text-align: center;
+ font-size: 90%;
+ line-height: 2px; }
+ .triggers-panel-footer ul {
+ position: relative;
+ display: inline-block;
+ margin-left: 0;
+ margin-bottom: 0; }
+ .triggers-panel-footer ul > li {
+ display: inline; }
+ .triggers-panel-footer ul > li > a {
+ float: left;
+ padding: 4px 12px;
+ text-decoration: none;
+ border-left-width: 0; }
+ .triggers-panel-footer ul > li > a:hover {
+ background-color: #333; }
+ .triggers-panel-footer ul > li > a.active {
+ font-weight: bold;
+ color: #33B5E5; }
+
+.triggers-panel-table {
+ width: 100%;
+ border-collapse: collapse; }
+ .triggers-panel-table th {
+ padding: 0; }
+ .triggers-panel-table th:first-child .triggers-panel-table-header-inner {
+ padding-left: 15px; }
+ .triggers-panel-table td {
+ padding: 0.45em 0 0.45em 1.1em;
+ border-bottom: 2px solid #141414;
+ border-right: 2px solid #141414; }
+ .triggers-panel-table td:first-child {
+ padding-left: 15px; }
+ .triggers-panel-table td:last-child {
+ border-right: none; }
+
+.triggers-panel-header-bg {
+ background: #242222;
+ border-top: 2px solid #141414;
+ border-bottom: 2px solid #141414;
+ height: 2.0em;
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0; }
+
+.triggers-panel-table-header-inner {
+ padding: 0.45em 0 0.45em 1.1em;
+ text-align: left;
+ color: #33B5E5;
+ position: absolute;
+ top: 0; }
+
+.triggers-panel-width-hack {
+ visibility: hidden;
+ height: 0px;
+ line-height: 0px; }
+
+.ack-tooltip .drop-content {
+ max-width: 70rem !important;
+ min-width: 30rem !important; }
+
+.ack-tooltip .ack-comments {
+ width: 60%; }
+
+.ack-tooltip .ack-add-button {
+ padding-top: 1rem; }
+
+.ack-tooltip table td, .ack-tooltip th {
+ padding-right: 1rem; }
+
+.ack-tooltip .ack-input-group {
+ padding-top: 1rem; }
+ .ack-tooltip .ack-input-group input {
+ border: 1px solid;
+ border-radius: 2px;
+ width: 50%; }
+ .ack-tooltip .ack-input-group button {
+ margin-left: 1rem; }
+
+/*# sourceMappingURL=panel_triggers.css.map */
\ No newline at end of file
diff --git a/dist/panel-triggers/css/panel_triggers.css.map b/dist/panel-triggers/css/panel_triggers.css.map
new file mode 100644
index 0000000..b4ec92b
--- /dev/null
+++ b/dist/panel-triggers/css/panel_triggers.css.map
@@ -0,0 +1,9 @@
+{
+ "version": 3,
+ "file": "panel_triggers.css",
+ "sources": [
+ "../../../src/panel-triggers/sass/panel_triggers.scss"
+ ],
+ "mappings": "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",
+ "names": []
+}
\ No newline at end of file
diff --git a/dist/panel-triggers/editor.html b/dist/panel-triggers/editor.html
new file mode 100644
index 0000000..ee1b24b
--- /dev/null
+++ b/dist/panel-triggers/editor.html
@@ -0,0 +1,256 @@
+
+
+
+
+
diff --git a/dist/panel-triggers/editor.js b/dist/panel-triggers/editor.js
new file mode 100644
index 0000000..ea74521
--- /dev/null
+++ b/dist/panel-triggers/editor.js
@@ -0,0 +1,225 @@
+'use strict';
+
+System.register(['lodash', '../datasource-zabbix/utils', '../datasource-zabbix/css/query-editor.css!'], function (_export, _context) {
+ "use strict";
+
+ var _, utils, _createClass, TriggerPanelEditorCtrl;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ // Get list of metric names for bs-typeahead directive
+ function getMetricNames(scope, metricList) {
+ return _.uniq(_.map(scope.metric[metricList], 'name'));
+ }
+
+ function triggerPanelEditor() {
+ return {
+ restrict: 'E',
+ scope: true,
+ templateUrl: 'public/plugins/alexanderzobnin-zabbix-app/panel-triggers/editor.html',
+ controller: TriggerPanelEditorCtrl
+ };
+ }
+
+ _export('triggerPanelEditor', triggerPanelEditor);
+
+ return {
+ setters: [function (_lodash) {
+ _ = _lodash.default;
+ }, function (_datasourceZabbixUtils) {
+ utils = _datasourceZabbixUtils;
+ }, function (_datasourceZabbixCssQueryEditorCss) {}],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ TriggerPanelEditorCtrl = function () {
+
+ /** @ngInject */
+ function TriggerPanelEditorCtrl($scope, $rootScope, uiSegmentSrv, datasourceSrv, templateSrv, popoverSrv) {
+ var _this = this;
+
+ _classCallCheck(this, TriggerPanelEditorCtrl);
+
+ $scope.editor = this;
+ this.panelCtrl = $scope.ctrl;
+ this.panel = this.panelCtrl.panel;
+
+ this.datasourceSrv = datasourceSrv;
+ this.templateSrv = templateSrv;
+ this.popoverSrv = popoverSrv;
+
+ // Map functions for bs-typeahead
+ this.getGroupNames = _.partial(getMetricNames, this, 'groupList');
+ this.getHostNames = _.partial(getMetricNames, this, 'hostList');
+ this.getApplicationNames = _.partial(getMetricNames, this, 'appList');
+
+ // Update metric suggestion when template variable was changed
+ $rootScope.$on('template-variable-value-updated', function () {
+ return _this.onVariableChange();
+ });
+
+ 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
+ var scopeDefaults = {
+ metric: {},
+ inputStyles: {},
+ oldTarget: _.cloneDeep(this.panel.triggers)
+ };
+ _.defaults(this, scopeDefaults);
+
+ // Set default datasource
+ this.datasources = _.map(this.getZabbixDataSources(), 'name');
+ if (!this.panel.datasource) {
+ this.panel.datasource = this.datasources[0];
+ }
+ // Load datasource
+ this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
+ _this.datasource = datasource;
+ _this.zabbix = datasource.zabbix;
+ _this.queryBuilder = datasource.queryBuilder;
+ _this.initFilters();
+ _this.panelCtrl.refresh();
+ });
+ }
+
+ _createClass(TriggerPanelEditorCtrl, [{
+ key: 'initFilters',
+ value: function initFilters() {
+ return Promise.all([this.suggestGroups(), this.suggestHosts(), this.suggestApps()]);
+ }
+ }, {
+ key: 'suggestGroups',
+ value: function suggestGroups() {
+ var _this2 = this;
+
+ return this.zabbix.getAllGroups().then(function (groups) {
+ _this2.metric.groupList = groups;
+ return groups;
+ });
+ }
+ }, {
+ key: 'suggestHosts',
+ value: function suggestHosts() {
+ var _this3 = this;
+
+ var groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);
+ return this.zabbix.getAllHosts(groupFilter).then(function (hosts) {
+ _this3.metric.hostList = hosts;
+ return hosts;
+ });
+ }
+ }, {
+ key: 'suggestApps',
+ value: function suggestApps() {
+ var _this4 = this;
+
+ var groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);
+ var hostFilter = this.datasource.replaceTemplateVars(this.panel.triggers.host.filter);
+ return this.zabbix.getAllApps(groupFilter, hostFilter).then(function (apps) {
+ _this4.metric.appList = apps;
+ return apps;
+ });
+ }
+ }, {
+ key: 'onVariableChange',
+ value: function onVariableChange() {
+ if (this.isContainsVariables()) {
+ this.targetChanged();
+ }
+ }
+ }, {
+ key: 'isContainsVariables',
+ value: function isContainsVariables() {
+ var _this5 = this;
+
+ return _.some(['group', 'host', 'application'], function (field) {
+ return utils.isTemplateVariable(_this5.panel.triggers[field].filter, _this5.templateSrv.variables);
+ });
+ }
+ }, {
+ key: 'targetChanged',
+ value: function targetChanged() {
+ this.initFilters();
+ this.panelCtrl.refresh();
+ }
+ }, {
+ key: 'parseTarget',
+ value: function parseTarget() {
+ this.initFilters();
+ var newTarget = _.cloneDeep(this.panel.triggers);
+ if (!_.isEqual(this.oldTarget, this.panel.triggers)) {
+ this.oldTarget = newTarget;
+ this.panelCtrl.refresh();
+ }
+ }
+ }, {
+ key: 'refreshTriggerSeverity',
+ value: function refreshTriggerSeverity() {
+ _.each(this.triggerList, function (trigger) {
+ trigger.color = this.panel.triggerSeverity[trigger.priority].color;
+ trigger.severity = this.panel.triggerSeverity[trigger.priority].severity;
+ });
+ this.panelCtrl.refresh();
+ }
+ }, {
+ key: 'datasourceChanged',
+ value: function datasourceChanged() {
+ this.panelCtrl.refresh();
+ }
+ }, {
+ key: 'changeTriggerSeverityColor',
+ value: function changeTriggerSeverityColor(trigger, color) {
+ this.panel.triggerSeverity[trigger.priority].color = color;
+ this.refreshTriggerSeverity();
+ }
+ }, {
+ key: 'isRegex',
+ value: function isRegex(str) {
+ return utils.isRegex(str);
+ }
+ }, {
+ key: 'isVariable',
+ value: function isVariable(str) {
+ return utils.isTemplateVariable(str, this.templateSrv.variables);
+ }
+ }, {
+ key: 'getZabbixDataSources',
+ value: function getZabbixDataSources() {
+ var ZABBIX_DS_ID = 'alexanderzobnin-zabbix-datasource';
+ return _.filter(this.datasourceSrv.getMetricSources(), function (datasource) {
+ return datasource.meta.id === ZABBIX_DS_ID && datasource.value;
+ });
+ }
+ }]);
+
+ return TriggerPanelEditorCtrl;
+ }();
+ }
+ };
+});
+//# sourceMappingURL=editor.js.map
diff --git a/dist/panel-triggers/editor.js.map b/dist/panel-triggers/editor.js.map
new file mode 100644
index 0000000..d016fb8
--- /dev/null
+++ b/dist/panel-triggers/editor.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/panel-triggers/editor.js"],"names":["getMetricNames","scope","metricList","_","uniq","map","metric","triggerPanelEditor","restrict","templateUrl","controller","TriggerPanelEditorCtrl","utils","$scope","$rootScope","uiSegmentSrv","datasourceSrv","templateSrv","popoverSrv","editor","panelCtrl","ctrl","panel","getGroupNames","partial","getHostNames","getApplicationNames","$on","onVariableChange","ackFilters","sortByFields","text","value","showEventsFields","scopeDefaults","inputStyles","oldTarget","cloneDeep","triggers","defaults","datasources","getZabbixDataSources","datasource","get","then","zabbix","queryBuilder","initFilters","refresh","Promise","all","suggestGroups","suggestHosts","suggestApps","getAllGroups","groupList","groups","groupFilter","replaceTemplateVars","group","filter","getAllHosts","hostList","hosts","hostFilter","host","getAllApps","appList","apps","isContainsVariables","targetChanged","some","isTemplateVariable","field","variables","newTarget","isEqual","each","triggerList","trigger","color","triggerSeverity","priority","severity","refreshTriggerSeverity","str","isRegex","ZABBIX_DS_ID","getMetricSources","meta","id"],"mappings":"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","file":"editor.js","sourcesContent":["/**\n * Grafana-Zabbix\n * Zabbix plugin for Grafana.\n * http://github.com/alexanderzobnin/grafana-zabbix\n *\n * Trigger panel.\n * This feature sponsored by CORE IT\n * http://www.coreit.fr\n *\n * Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com\n * Licensed under the Apache License, Version 2.0\n */\n\nimport _ from 'lodash';\nimport * as utils from '../datasource-zabbix/utils';\n\nimport '../datasource-zabbix/css/query-editor.css!';\n\nclass TriggerPanelEditorCtrl {\n\n /** @ngInject */\n constructor($scope, $rootScope, uiSegmentSrv, datasourceSrv, templateSrv, popoverSrv) {\n $scope.editor = this;\n this.panelCtrl = $scope.ctrl;\n this.panel = this.panelCtrl.panel;\n\n this.datasourceSrv = datasourceSrv;\n this.templateSrv = templateSrv;\n this.popoverSrv = popoverSrv;\n\n // Map functions for bs-typeahead\n this.getGroupNames = _.partial(getMetricNames, this, 'groupList');\n this.getHostNames = _.partial(getMetricNames, this, 'hostList');\n this.getApplicationNames = _.partial(getMetricNames, this, 'appList');\n\n // Update metric suggestion when template variable was changed\n $rootScope.$on('template-variable-value-updated', () => this.onVariableChange());\n\n this.ackFilters = [\n 'all triggers',\n 'unacknowledged',\n 'acknowledged'\n ];\n\n this.sortByFields = [\n { text: 'last change', value: 'lastchange' },\n { text: 'severity', value: 'priority' }\n ];\n\n this.showEventsFields = [\n { text: 'All', value: [0,1] },\n { text: 'OK', value: [0] },\n { text: 'Problems', value: 1 }\n ];\n\n // Load scope defaults\n var scopeDefaults = {\n metric: {},\n inputStyles: {},\n oldTarget: _.cloneDeep(this.panel.triggers)\n };\n _.defaults(this, scopeDefaults);\n\n // Set default datasource\n this.datasources = _.map(this.getZabbixDataSources(), 'name');\n if (!this.panel.datasource) {\n this.panel.datasource = this.datasources[0];\n }\n // Load datasource\n this.datasourceSrv.get(this.panel.datasource)\n .then(datasource => {\n this.datasource = datasource;\n this.zabbix = datasource.zabbix;\n this.queryBuilder = datasource.queryBuilder;\n this.initFilters();\n this.panelCtrl.refresh();\n });\n }\n\n initFilters() {\n return Promise.all([\n this.suggestGroups(),\n this.suggestHosts(),\n this.suggestApps()\n ]);\n }\n\n suggestGroups() {\n return this.zabbix.getAllGroups()\n .then(groups => {\n this.metric.groupList = groups;\n return groups;\n });\n }\n\n suggestHosts() {\n let groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);\n return this.zabbix.getAllHosts(groupFilter)\n .then(hosts => {\n this.metric.hostList = hosts;\n return hosts;\n });\n }\n\n suggestApps() {\n let groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);\n let hostFilter = this.datasource.replaceTemplateVars(this.panel.triggers.host.filter);\n return this.zabbix.getAllApps(groupFilter, hostFilter)\n .then(apps => {\n this.metric.appList = apps;\n return apps;\n });\n }\n\n onVariableChange() {\n if (this.isContainsVariables()) {\n this.targetChanged();\n }\n }\n\n /**\n * Check query for template variables\n */\n isContainsVariables() {\n return _.some(['group', 'host', 'application'], field => {\n return utils.isTemplateVariable(this.panel.triggers[field].filter, this.templateSrv.variables);\n });\n }\n\n targetChanged() {\n this.initFilters();\n this.panelCtrl.refresh();\n }\n\n parseTarget() {\n this.initFilters();\n var newTarget = _.cloneDeep(this.panel.triggers);\n if (!_.isEqual(this.oldTarget, this.panel.triggers)) {\n this.oldTarget = newTarget;\n this.panelCtrl.refresh();\n }\n }\n\n refreshTriggerSeverity() {\n _.each(this.triggerList, function(trigger) {\n trigger.color = this.panel.triggerSeverity[trigger.priority].color;\n trigger.severity = this.panel.triggerSeverity[trigger.priority].severity;\n });\n this.panelCtrl.refresh();\n }\n\n datasourceChanged() {\n this.panelCtrl.refresh();\n }\n\n changeTriggerSeverityColor(trigger, color) {\n this.panel.triggerSeverity[trigger.priority].color = color;\n this.refreshTriggerSeverity();\n }\n\n isRegex(str) {\n return utils.isRegex(str);\n }\n\n isVariable(str) {\n return utils.isTemplateVariable(str, this.templateSrv.variables);\n }\n\n getZabbixDataSources() {\n let ZABBIX_DS_ID = 'alexanderzobnin-zabbix-datasource';\n return _.filter(this.datasourceSrv.getMetricSources(), datasource => {\n return datasource.meta.id === ZABBIX_DS_ID && datasource.value;\n });\n }\n}\n\n// Get list of metric names for bs-typeahead directive\nfunction getMetricNames(scope, metricList) {\n return _.uniq(_.map(scope.metric[metricList], 'name'));\n}\n\nexport function triggerPanelEditor() {\n return {\n restrict: 'E',\n scope: true,\n templateUrl: 'public/plugins/alexanderzobnin-zabbix-app/panel-triggers/editor.html',\n controller: TriggerPanelEditorCtrl,\n };\n}\n"]}
\ No newline at end of file
diff --git a/dist/panel-triggers/module.html b/dist/panel-triggers/module.html
new file mode 100644
index 0000000..23c3ce0
--- /dev/null
+++ b/dist/panel-triggers/module.html
@@ -0,0 +1,124 @@
+
+
diff --git a/dist/panel-triggers/module.js b/dist/panel-triggers/module.js
new file mode 100644
index 0000000..3c764d3
--- /dev/null
+++ b/dist/panel-triggers/module.js
@@ -0,0 +1,321 @@
+'use strict';
+
+System.register(['lodash', '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;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function _possibleConstructorReturn(self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
+
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ }
+
+ function _inherits(subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ }
+
+ function filterTriggers(triggers, triggerFilter) {
+ if (utils.isRegex(triggerFilter)) {
+ return _.filter(triggers, function (trigger) {
+ return utils.buildRegex(triggerFilter).test(trigger.description);
+ });
+ } else {
+ return _.filter(triggers, function (trigger) {
+ return trigger.description === triggerFilter;
+ });
+ }
+ }
+
+ return {
+ setters: [function (_lodash) {
+ _ = _lodash.default;
+ }, function (_moment) {
+ moment = _moment.default;
+ }, function (_datasourceZabbixUtils) {
+ utils = _datasourceZabbixUtils;
+ }, function (_appPluginsSdk) {
+ MetricsPanelCtrl = _appPluginsSdk.MetricsPanelCtrl;
+ }, function (_editor) {
+ triggerPanelEditor = _editor.triggerPanelEditor;
+ }, function (_ackTooltipDirective) {}, function (_cssPanel_triggersCss) {}],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ defaultSeverity = [{ priority: 0, severity: 'Not classified', color: '#B7DBAB', show: true }, { priority: 1, severity: 'Information', color: '#82B5D8', show: true }, { priority: 2, severity: 'Warning', color: '#E5AC0E', show: true }, { priority: 3, severity: 'Average', color: '#C15C17', show: true }, { priority: 4, severity: 'High', color: '#BF1B00', show: true }, { priority: 5, severity: 'Disaster', color: '#890F02', show: true }];
+ panelDefaults = {
+ datasource: null,
+ triggers: {
+ group: { filter: "" },
+ host: { filter: "" },
+ application: { filter: "" },
+ trigger: { filter: "" }
+ },
+ hostField: true,
+ statusField: false,
+ severityField: false,
+ lastChangeField: true,
+ ageField: true,
+ infoField: true,
+ limit: 10,
+ showTriggers: 'all triggers',
+ 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)'
+ };
+ triggerStatusMap = {
+ '0': 'OK',
+ '1': 'Problem'
+ };
+ defaultTimeFormat = "DD MMM YYYY HH:mm:ss";
+
+ _export('PanelCtrl', _export('TriggerPanelCtrl', TriggerPanelCtrl = function (_MetricsPanelCtrl) {
+ _inherits(TriggerPanelCtrl, _MetricsPanelCtrl);
+
+ /** @ngInject */
+ function TriggerPanelCtrl($scope, $injector, $element, datasourceSrv, templateSrv, contextSrv) {
+ _classCallCheck(this, TriggerPanelCtrl);
+
+ var _this = _possibleConstructorReturn(this, (TriggerPanelCtrl.__proto__ || Object.getPrototypeOf(TriggerPanelCtrl)).call(this, $scope, $injector));
+
+ _this.datasourceSrv = datasourceSrv;
+ _this.templateSrv = templateSrv;
+ _this.contextSrv = contextSrv;
+ _this.triggerStatusMap = triggerStatusMap;
+ _this.defaultTimeFormat = defaultTimeFormat;
+
+ // 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();
+ return _this;
+ }
+
+ /**
+ * Override onInitMetricsPanelEditMode() method from MetricsPanelCtrl.
+ * We don't need metric editor from Metrics Panel.
+ */
+
+
+ _createClass(TriggerPanelCtrl, [{
+ key: 'onInitMetricsPanelEditMode',
+ value: function onInitMetricsPanelEditMode() {
+ 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;
+ }
+
+ this.refreshData();
+ }
+ }, {
+ key: 'refreshData',
+ value: function refreshData() {
+ // clear loading/error state
+ delete this.error;
+ this.loading = true;
+ this.setTimeQueryStart();
+
+ 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;
+
+ // 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);
+ 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;
+ });
+ });
+ });
+ }
+ }, {
+ key: 'switchComment',
+ value: function switchComment(trigger) {
+ trigger.showComment = !trigger.showComment;
+ }
+ }, {
+ 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 TriggerPanelCtrl;
+ }(MetricsPanelCtrl)));
+
+ TriggerPanelCtrl.templateUrl = 'panel-triggers/module.html';
+ _export('TriggerPanelCtrl', TriggerPanelCtrl);
+
+ _export('PanelCtrl', TriggerPanelCtrl);
+ }
+ };
+});
+//# sourceMappingURL=module.js.map
diff --git a/dist/panel-triggers/module.js.map b/dist/panel-triggers/module.js.map
new file mode 100644
index 0000000..75455e9
--- /dev/null
+++ b/dist/panel-triggers/module.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/panel-triggers/module.js"],"names":["filterTriggers","triggers","triggerFilter","utils","isRegex","_","filter","trigger","buildRegex","test","description","moment","MetricsPanelCtrl","triggerPanelEditor","defaultSeverity","priority","severity","color","show","panelDefaults","datasource","group","host","application","hostField","statusField","severityField","lastChangeField","ageField","infoField","limit","showTriggers","sortTriggersBy","text","value","showEvents","triggerSeverity","okEventColor","ackEventColor","triggerStatusMap","defaultTimeFormat","TriggerPanelCtrl","$scope","$injector","$element","datasourceSrv","templateSrv","contextSrv","defaults","panel","cloneDeep","triggerList","refreshData","addEditorTab","onMetricsPanelRefresh","otherPanelInFullscreenMode","error","loading","setTimeQueryStart","self","get","then","zabbix","groupFilter","replaceTemplateVars","hostFilter","appFilter","getTriggers","map","triggerObj","lastchangeUnix","Number","lastchange","timestamp","unix","customLastChangeFormat","format","lastChangeFormat","age","fromNow","hosts","length","name","hostTechName","eventids","lastEvent","eventid","getAcknowledges","each","event","find","events","acknowledges","ack","clock","time","user","alias","surname","markAckEvents","sortBy","reverse","slice","setTimeQueryEnd","showComment","message","grafana_user","ack_message","zabbixAPI","acknowledgeEvent","refresh","templateUrl"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0PA,WAASA,cAAT,CAAwBC,QAAxB,EAAkCC,aAAlC,EAAiD;AAC/C,QAAIC,MAAMC,OAAN,CAAcF,aAAd,CAAJ,EAAkC;AAChC,aAAOG,EAAEC,MAAF,CAASL,QAAT,EAAmB,UAASM,OAAT,EAAkB;AAC1C,eAAOJ,MAAMK,UAAN,CAAiBN,aAAjB,EAAgCO,IAAhC,CAAqCF,QAAQG,WAA7C,CAAP;AACD,OAFM,CAAP;AAGD,KAJD,MAIO;AACL,aAAOL,EAAEC,MAAF,CAASL,QAAT,EAAmB,UAASM,OAAT,EAAkB;AAC1C,eAAOA,QAAQG,WAAR,KAAwBR,aAA/B;AACD,OAFM,CAAP;AAGD;AACF;;;;AAvPMG,O;;AACAM,Y;;AACKR,W;;AACJS,sB,kBAAAA,gB;;AACAC,wB,WAAAA,kB;;;;;;;;;;;;;;;;;;;;;AAIJC,qB,GAAkB,CACpB,EAAEC,UAAU,CAAZ,EAAeC,UAAU,gBAAzB,EAA4CC,OAAO,SAAnD,EAA8DC,MAAM,IAApE,EADoB,EAEpB,EAAEH,UAAU,CAAZ,EAAeC,UAAU,aAAzB,EAA4CC,OAAO,SAAnD,EAA8DC,MAAM,IAApE,EAFoB,EAGpB,EAAEH,UAAU,CAAZ,EAAeC,UAAU,SAAzB,EAA4CC,OAAO,SAAnD,EAA8DC,MAAM,IAApE,EAHoB,EAIpB,EAAEH,UAAU,CAAZ,EAAeC,UAAU,SAAzB,EAA4CC,OAAO,SAAnD,EAA8DC,MAAM,IAApE,EAJoB,EAKpB,EAAEH,UAAU,CAAZ,EAAeC,UAAU,MAAzB,EAA4CC,OAAO,SAAnD,EAA8DC,MAAM,IAApE,EALoB,EAMpB,EAAEH,UAAU,CAAZ,EAAeC,UAAU,UAAzB,EAA4CC,OAAO,SAAnD,EAA8DC,MAAM,IAApE,EANoB,C;AASlBC,mB,GAAgB;AAClBC,oBAAY,IADM;AAElBnB,kBAAU;AACRoB,iBAAO,EAACf,QAAQ,EAAT,EADC;AAERgB,gBAAM,EAAChB,QAAQ,EAAT,EAFE;AAGRiB,uBAAa,EAACjB,QAAQ,EAAT,EAHL;AAIRC,mBAAS,EAACD,QAAQ,EAAT;AAJD,SAFQ;AAQlBkB,mBAAW,IARO;AASlBC,qBAAa,KATK;AAUlBC,uBAAe,KAVG;AAWlBC,yBAAiB,IAXC;AAYlBC,kBAAU,IAZQ;AAalBC,mBAAW,IAbO;AAclBC,eAAO,EAdW;AAelBC,sBAAc,cAfI;AAgBlBC,wBAAgB,EAAEC,MAAM,aAAR,EAAuBC,OAAO,YAA9B,EAhBE;AAiBlBC,oBAAY,EAAEF,MAAM,UAAR,EAAoBC,OAAO,GAA3B,EAjBM;AAkBlBE,yBAAiBtB,eAlBC;AAmBlBuB,sBAAc,yBAnBI;AAoBlBC,uBAAe;AApBG,O;AAuBhBC,sB,GAAmB;AACrB,aAAK,IADgB;AAErB,aAAK;AAFgB,O;AAKnBC,uB,GAAoB,sB;;uDAElBC,gB;;;AAEJ;AACA,kCAAYC,MAAZ,EAAoBC,SAApB,EAA+BC,QAA/B,EAAyCC,aAAzC,EAAwDC,WAAxD,EAAqEC,UAArE,EAAiF;AAAA;;AAAA,0IACzEL,MADyE,EACjEC,SADiE;;AAE/E,gBAAKE,aAAL,GAAqBA,aAArB;AACA,gBAAKC,WAAL,GAAmBA,WAAnB;AACA,gBAAKC,UAAL,GAAkBA,UAAlB;AACA,gBAAKR,gBAAL,GAAwBA,gBAAxB;AACA,gBAAKC,iBAAL,GAAyBA,iBAAzB;;AAEA;AACA;AACA;AACAnC,YAAE2C,QAAF,CAAW,MAAKC,KAAhB,EAAuB5C,EAAE6C,SAAF,CAAY/B,aAAZ,CAAvB;;AAEA,gBAAKgC,WAAL,GAAmB,EAAnB;AACA,gBAAKC,WAAL;AAd+E;AAehF;;AAED;;;;;;;;uDAI6B;AAC3B,iBAAKC,YAAL,CAAkB,SAAlB,EAA6BxC,kBAA7B,EAAiD,CAAjD;AACD;;;oCAES;AACR,iBAAKyC,qBAAL;AACD;;;kDAEuB;AACtB;AACA,gBAAI,KAAKC,0BAAL,EAAJ,EAAuC;AAAE;AAAS;;AAElD,iBAAKH,WAAL;AACD;;;wCAEa;AACZ;AACA,mBAAO,KAAKI,KAAZ;AACA,iBAAKC,OAAL,GAAe,IAAf;AACA,iBAAKC,iBAAL;;AAEA,gBAAIC,OAAO,IAAX;;AAEA;AACA,mBAAO,KAAKd,aAAL,CAAmBe,GAAnB,CAAuB,KAAKX,KAAL,CAAW7B,UAAlC,EACNyC,IADM,CACD,sBAAc;AAClB,kBAAIC,SAAS1C,WAAW0C,MAAxB;AACA,kBAAI3B,aAAawB,KAAKV,KAAL,CAAWd,UAAX,CAAsBD,KAAvC;AACA,kBAAIhC,gBAAgByD,KAAKV,KAAL,CAAWhD,QAA/B;;AAEA;AACA,kBAAI8D,cAAc3C,WAAW4C,mBAAX,CAA+B9D,cAAcmB,KAAd,CAAoBf,MAAnD,CAAlB;AACA,kBAAI2D,aAAa7C,WAAW4C,mBAAX,CAA+B9D,cAAcoB,IAAd,CAAmBhB,MAAlD,CAAjB;AACA,kBAAI4D,YAAY9C,WAAW4C,mBAAX,CAA+B9D,cAAcqB,WAAd,CAA0BjB,MAAzD,CAAhB;;AAEA,kBAAI6D,cAAcL,OAAOK,WAAP,CAAmBJ,WAAnB,EAAgCE,UAAhC,EAA4CC,SAA5C,EAAuD/B,UAAvD,CAAlB;AACA,qBAAOgC,YAAYN,IAAZ,CAAiB,oBAAY;AAClC,uBAAOxD,EAAE+D,GAAF,CAAMnE,QAAN,EAAgB,mBAAW;AAChC,sBAAIoE,aAAa9D,OAAjB;;AAEA;AACAA,0BAAQ+D,cAAR,GAAyBC,OAAOhE,QAAQiE,UAAf,CAAzB;AACA,sBAAIC,YAAY9D,OAAO+D,IAAP,CAAYnE,QAAQ+D,cAApB,CAAhB;AACA,sBAAIX,KAAKV,KAAL,CAAW0B,sBAAf,EAAuC;AACrC;AACAN,+BAAWG,UAAX,GAAwBC,UAAUG,MAAV,CAAiBjB,KAAKV,KAAL,CAAW4B,gBAA5B,CAAxB;AACD,mBAHD,MAGO;AACLR,+BAAWG,UAAX,GAAwBC,UAAUG,MAAV,CAAiBjB,KAAKnB,iBAAtB,CAAxB;AACD;AACD6B,6BAAWS,GAAX,GAAiBL,UAAUM,OAAV,CAAkB,IAAlB,CAAjB;;AAEA;AACA,sBAAIxE,QAAQyE,KAAR,CAAcC,MAAlB,EAA0B;AACxBZ,+BAAW/C,IAAX,GAAkBf,QAAQyE,KAAR,CAAc,CAAd,EAAiBE,IAAnC;AACAb,+BAAWc,YAAX,GAA0B5E,QAAQyE,KAAR,CAAc,CAAd,EAAiB1D,IAA3C;AACD;;AAED;AACA,sBAAIf,QAAQ2B,KAAR,KAAkB,GAAtB,EAA2B;AACzB;AACAmC,+BAAWpD,KAAX,GAAmB0C,KAAKV,KAAL,CAAWb,eAAX,CAA2B7B,QAAQQ,QAAnC,EAA6CE,KAAhE;AACD,mBAHD,MAGO;AACL;AACAoD,+BAAWpD,KAAX,GAAmB0C,KAAKV,KAAL,CAAWZ,YAA9B;AACD;;AAEDgC,6BAAWrD,QAAX,GAAsB2C,KAAKV,KAAL,CAAWb,eAAX,CAA2B7B,QAAQQ,QAAnC,EAA6CC,QAAnE;AACA,yBAAOqD,UAAP;AACD,iBA/BM,CAAP;AAgCD,eAjCM,EAkCNR,IAlCM,CAkCD,uBAAe;;AAEnB;AACA,oBAAIuB,WAAW/E,EAAE+D,GAAF,CAAMjB,WAAN,EAAmB,mBAAW;AAC3C,yBAAO5C,QAAQ8E,SAAR,CAAkBC,OAAzB;AACD,iBAFc,CAAf;;AAIA,uBAAOxB,OAAOyB,eAAP,CAAuBH,QAAvB,EACNvB,IADM,CACD,kBAAU;;AAEd;AACAxD,oBAAEmF,IAAF,CAAOrC,WAAP,EAAoB,mBAAW;AAC7B,wBAAIsC,QAAQpF,EAAEqF,IAAF,CAAOC,MAAP,EAAe,iBAAS;AAClC,6BAAOF,MAAMH,OAAN,KAAkB/E,QAAQ8E,SAAR,CAAkBC,OAA3C;AACD,qBAFW,CAAZ;;AAIA,wBAAIG,KAAJ,EAAW;AACTlF,8BAAQqF,YAAR,GAAuBvF,EAAE+D,GAAF,CAAMqB,MAAMG,YAAZ,EAA0B,eAAO;AACtD,4BAAInB,YAAY9D,OAAO+D,IAAP,CAAYmB,IAAIC,KAAhB,CAAhB;AACA,4BAAInC,KAAKV,KAAL,CAAW0B,sBAAf,EAAuC;AACrCkB,8BAAIE,IAAJ,GAAWtB,UAAUG,MAAV,CAAiBjB,KAAKV,KAAL,CAAW4B,gBAA5B,CAAX;AACD,yBAFD,MAEO;AACLgB,8BAAIE,IAAJ,GAAWtB,UAAUG,MAAV,CAAiBjB,KAAKnB,iBAAtB,CAAX;AACD;AACDqD,4BAAIG,IAAJ,GAAWH,IAAII,KAAJ,GAAY,IAAZ,GAAmBJ,IAAIX,IAAvB,GAA8B,GAA9B,GAAoCW,IAAIK,OAAxC,GAAkD,GAA7D;AACA,+BAAOL,GAAP;AACD,uBATsB,CAAvB;;AAWA;AACA,0BAAIlC,KAAKV,KAAL,CAAWkD,aAAX,IAA4B5F,QAAQqF,YAAR,CAAqBX,MAArD,EAA6D;AAC3D1E,gCAAQU,KAAR,GAAgB0C,KAAKV,KAAL,CAAWX,aAA3B;AACD;AACF;AACF,mBAtBD;;AAwBA;AACA,sBAAIpC,gBAAgByD,KAAKV,KAAL,CAAWhD,QAAX,CAAoBM,OAApB,CAA4BD,MAAhD;AACA,sBAAIJ,aAAJ,EAAmB;AACjBiD,kCAAcnD,eAAemD,WAAf,EAA4BjD,aAA5B,CAAd;AACD;;AAED;AACA,sBAAIyD,KAAKV,KAAL,CAAWlB,YAAX,KAA4B,gBAAhC,EAAkD;AAChDoB,kCAAc9C,EAAEC,MAAF,CAAS6C,WAAT,EAAsB,mBAAW;AAC7C,6BAAO,CAAC5C,QAAQqF,YAAhB;AACD,qBAFa,CAAd;AAGD,mBAJD,MAIO,IAAIjC,KAAKV,KAAL,CAAWlB,YAAX,KAA4B,cAAhC,EAAgD;AACrDoB,kCAAc9C,EAAEC,MAAF,CAAS6C,WAAT,EAAsB,cAAtB,CAAd;AACD,mBAFM,MAEA;AACLA,kCAAcA,WAAd;AACD;;AAED;AACAA,gCAAc9C,EAAEC,MAAF,CAAS6C,WAAT,EAAsB,mBAAW;AAC7C,2BAAOQ,KAAKV,KAAL,CAAWb,eAAX,CAA2B7B,QAAQQ,QAAnC,EAA6CG,IAApD;AACD,mBAFa,CAAd;;AAIA;AACA,sBAAIyC,KAAKV,KAAL,CAAWjB,cAAX,CAA0BE,KAA1B,KAAoC,UAAxC,EAAoD;AAClDiB,kCAAc9C,EAAE+F,MAAF,CAASjD,WAAT,EAAsB,UAAtB,EAAkCkD,OAAlC,EAAd;AACD,mBAFD,MAEO;AACLlD,kCAAc9C,EAAE+F,MAAF,CAASjD,WAAT,EAAsB,gBAAtB,EAAwCkD,OAAxC,EAAd;AACD;;AAED;AACA1C,uBAAKR,WAAL,GAAoBA,YAAYmD,KAAZ,CAAkB,CAAlB,EAAqB3C,KAAKV,KAAL,CAAWnB,KAAhC,CAApB;;AAEA;AACA6B,uBAAK4C,eAAL;AACA5C,uBAAKF,OAAL,GAAe,KAAf;AACD,iBA/DM,CAAP;AAgED,eAzGM,CAAP;AA0GD,aAtHM,CAAP;AAuHD;;;wCAEalD,O,EAAS;AACrBA,oBAAQiG,WAAR,GAAsB,CAACjG,QAAQiG,WAA/B;AACD;;;6CAEkBjG,O,EAASkG,O,EAAS;AAAA;;AACnC,gBAAInB,UAAU/E,QAAQ8E,SAAR,CAAkBC,OAAhC;AACA,gBAAIoB,eAAe,KAAK3D,UAAL,CAAgBiD,IAAhB,CAAqBd,IAAxC;AACA,gBAAIyB,cAAcD,eAAe,cAAf,GAAgCD,OAAlD;AACA,mBAAO,KAAK5D,aAAL,CAAmBe,GAAnB,CAAuB,KAAKX,KAAL,CAAW7B,UAAlC,EACNyC,IADM,CACD,sBAAc;AAClB,kBAAI+C,YAAYxF,WAAW0C,MAAX,CAAkB8C,SAAlC;AACA,qBAAOA,UAAUC,gBAAV,CAA2BvB,OAA3B,EAAoCqB,WAApC,EACN9C,IADM,CACD,YAAM;AACV,uBAAKiD,OAAL;AACD,eAHM,CAAP;AAID,aAPM,CAAP;AAQD;;;;QAzL4BlG,gB;;AA4L/B6B,uBAAiBsE,WAAjB,GAA+B,4BAA/B;kCAeEtE,gB;;2BACAA,gB","file":"module.js","sourcesContent":["/**\n * Grafana-Zabbix\n * Zabbix plugin for Grafana.\n * http://github.com/alexanderzobnin/grafana-zabbix\n *\n * Trigger panel.\n * This feature sponsored by CORE IT\n * http://www.coreit.fr\n *\n * Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com\n * Licensed under the Apache License, Version 2.0\n */\n\nimport _ from 'lodash';\nimport moment from 'moment';\nimport * as utils from '../datasource-zabbix/utils';\nimport {MetricsPanelCtrl} from 'app/plugins/sdk';\nimport {triggerPanelEditor} from './editor';\nimport './ack-tooltip.directive';\nimport './css/panel_triggers.css!';\n\nvar defaultSeverity = [\n { priority: 0, severity: 'Not classified', color: '#B7DBAB', show: true },\n { priority: 1, severity: 'Information', color: '#82B5D8', show: true },\n { priority: 2, severity: 'Warning', color: '#E5AC0E', show: true },\n { priority: 3, severity: 'Average', color: '#C15C17', show: true },\n { priority: 4, severity: 'High', color: '#BF1B00', show: true },\n { priority: 5, severity: 'Disaster', color: '#890F02', show: true }\n];\n\nvar panelDefaults = {\n datasource: null,\n triggers: {\n group: {filter: \"\"},\n host: {filter: \"\"},\n application: {filter: \"\"},\n trigger: {filter: \"\"}\n },\n hostField: true,\n statusField: false,\n severityField: false,\n lastChangeField: true,\n ageField: true,\n infoField: true,\n limit: 10,\n showTriggers: 'all triggers',\n sortTriggersBy: { text: 'last change', value: 'lastchange' },\n showEvents: { text: 'Problems', value: '1' },\n triggerSeverity: defaultSeverity,\n okEventColor: 'rgba(0, 245, 153, 0.45)',\n ackEventColor: 'rgba(0, 0, 0, 0)'\n};\n\nvar triggerStatusMap = {\n '0': 'OK',\n '1': 'Problem'\n};\n\nvar defaultTimeFormat = \"DD MMM YYYY HH:mm:ss\";\n\nclass TriggerPanelCtrl extends MetricsPanelCtrl {\n\n /** @ngInject */\n constructor($scope, $injector, $element, datasourceSrv, templateSrv, contextSrv) {\n super($scope, $injector);\n this.datasourceSrv = datasourceSrv;\n this.templateSrv = templateSrv;\n this.contextSrv = contextSrv;\n this.triggerStatusMap = triggerStatusMap;\n this.defaultTimeFormat = defaultTimeFormat;\n\n // Load panel defaults\n // _.cloneDeep() need for prevent changing shared defaultSeverity.\n // Load object \"by value\" istead \"by reference\".\n _.defaults(this.panel, _.cloneDeep(panelDefaults));\n\n this.triggerList = [];\n this.refreshData();\n }\n\n /**\n * Override onInitMetricsPanelEditMode() method from MetricsPanelCtrl.\n * We don't need metric editor from Metrics Panel.\n */\n onInitMetricsPanelEditMode() {\n this.addEditorTab('Options', triggerPanelEditor, 2);\n }\n\n refresh() {\n this.onMetricsPanelRefresh();\n }\n\n onMetricsPanelRefresh() {\n // ignore fetching data if another panel is in fullscreen\n if (this.otherPanelInFullscreenMode()) { return; }\n\n this.refreshData();\n }\n\n refreshData() {\n // clear loading/error state\n delete this.error;\n this.loading = true;\n this.setTimeQueryStart();\n\n var self = this;\n\n // Load datasource\n return this.datasourceSrv.get(this.panel.datasource)\n .then(datasource => {\n var zabbix = datasource.zabbix;\n var showEvents = self.panel.showEvents.value;\n var triggerFilter = self.panel.triggers;\n\n // Replace template variables\n var groupFilter = datasource.replaceTemplateVars(triggerFilter.group.filter);\n var hostFilter = datasource.replaceTemplateVars(triggerFilter.host.filter);\n var appFilter = datasource.replaceTemplateVars(triggerFilter.application.filter);\n\n var getTriggers = zabbix.getTriggers(groupFilter, hostFilter, appFilter, showEvents);\n return getTriggers.then(triggers => {\n return _.map(triggers, trigger => {\n let triggerObj = trigger;\n\n // Format last change and age\n trigger.lastchangeUnix = Number(trigger.lastchange);\n let timestamp = moment.unix(trigger.lastchangeUnix);\n if (self.panel.customLastChangeFormat) {\n // User defined format\n triggerObj.lastchange = timestamp.format(self.panel.lastChangeFormat);\n } else {\n triggerObj.lastchange = timestamp.format(self.defaultTimeFormat);\n }\n triggerObj.age = timestamp.fromNow(true);\n\n // Set host that the trigger belongs\n if (trigger.hosts.length) {\n triggerObj.host = trigger.hosts[0].name;\n triggerObj.hostTechName = trigger.hosts[0].host;\n }\n\n // Set color\n if (trigger.value === '1') {\n // Problem state\n triggerObj.color = self.panel.triggerSeverity[trigger.priority].color;\n } else {\n // OK state\n triggerObj.color = self.panel.okEventColor;\n }\n\n triggerObj.severity = self.panel.triggerSeverity[trigger.priority].severity;\n return triggerObj;\n });\n })\n .then(triggerList => {\n\n // Request acknowledges for trigger\n var eventids = _.map(triggerList, trigger => {\n return trigger.lastEvent.eventid;\n });\n\n return zabbix.getAcknowledges(eventids)\n .then(events => {\n\n // Map events to triggers\n _.each(triggerList, trigger => {\n var event = _.find(events, event => {\n return event.eventid === trigger.lastEvent.eventid;\n });\n\n if (event) {\n trigger.acknowledges = _.map(event.acknowledges, ack => {\n let timestamp = moment.unix(ack.clock);\n if (self.panel.customLastChangeFormat) {\n ack.time = timestamp.format(self.panel.lastChangeFormat);\n } else {\n ack.time = timestamp.format(self.defaultTimeFormat);\n }\n ack.user = ack.alias + ' (' + ack.name + ' ' + ack.surname + ')';\n return ack;\n });\n\n // Mark acknowledged triggers with different color\n if (self.panel.markAckEvents && trigger.acknowledges.length) {\n trigger.color = self.panel.ackEventColor;\n }\n }\n });\n\n // Filter triggers by description\n var triggerFilter = self.panel.triggers.trigger.filter;\n if (triggerFilter) {\n triggerList = filterTriggers(triggerList, triggerFilter);\n }\n\n // Filter acknowledged triggers\n if (self.panel.showTriggers === 'unacknowledged') {\n triggerList = _.filter(triggerList, trigger => {\n return !trigger.acknowledges;\n });\n } else if (self.panel.showTriggers === 'acknowledged') {\n triggerList = _.filter(triggerList, 'acknowledges');\n } else {\n triggerList = triggerList;\n }\n\n // Filter triggers by severity\n triggerList = _.filter(triggerList, trigger => {\n return self.panel.triggerSeverity[trigger.priority].show;\n });\n\n // Sort triggers\n if (self.panel.sortTriggersBy.value === 'priority') {\n triggerList = _.sortBy(triggerList, 'priority').reverse();\n } else {\n triggerList = _.sortBy(triggerList, 'lastchangeUnix').reverse();\n }\n\n // Limit triggers number\n self.triggerList = triggerList.slice(0, self.panel.limit);\n\n // Notify panel that request is finished\n self.setTimeQueryEnd();\n self.loading = false;\n });\n });\n });\n }\n\n switchComment(trigger) {\n trigger.showComment = !trigger.showComment;\n }\n\n acknowledgeTrigger(trigger, message) {\n let eventid = trigger.lastEvent.eventid;\n let grafana_user = this.contextSrv.user.name;\n let ack_message = grafana_user + ' (Grafana): ' + message;\n return this.datasourceSrv.get(this.panel.datasource)\n .then(datasource => {\n let zabbixAPI = datasource.zabbix.zabbixAPI;\n return zabbixAPI.acknowledgeEvent(eventid, ack_message)\n .then(() => {\n this.refresh();\n });\n });\n }\n}\n\nTriggerPanelCtrl.templateUrl = 'panel-triggers/module.html';\n\nfunction filterTriggers(triggers, triggerFilter) {\n if (utils.isRegex(triggerFilter)) {\n return _.filter(triggers, function(trigger) {\n return utils.buildRegex(triggerFilter).test(trigger.description);\n });\n } else {\n return _.filter(triggers, function(trigger) {\n return trigger.description === triggerFilter;\n });\n }\n}\n\nexport {\n TriggerPanelCtrl,\n TriggerPanelCtrl as PanelCtrl\n};\n"]}
\ No newline at end of file
diff --git a/dist/panel-triggers/plugin.json b/dist/panel-triggers/plugin.json
new file mode 100644
index 0000000..d4c3ef8
--- /dev/null
+++ b/dist/panel-triggers/plugin.json
@@ -0,0 +1,12 @@
+{
+ "type": "panel",
+ "name": "Zabbix Triggers",
+ "id": "alexanderzobnin-zabbix-triggers-panel",
+
+ "info": {
+ "author": {
+ "name": "Alexander Zobnin",
+ "url": "https://github.com/alexanderzobnin/grafana-zabbix"
+ }
+ }
+}
diff --git a/dist/plugin.json b/dist/plugin.json
new file mode 100644
index 0000000..0db8b1f
--- /dev/null
+++ b/dist/plugin.json
@@ -0,0 +1,65 @@
+{
+ "type": "app",
+ "name": "Zabbix",
+ "id": "alexanderzobnin-zabbix-app",
+
+ "css": {
+ "dark": "css/dark.css",
+ "light": "css/light.css"
+ },
+
+ "info": {
+ "description": "Zabbix plugin for Grafana",
+ "author": {
+ "name": "Alexander Zobnin",
+ "url": "https://github.com/alexanderzobnin"
+ },
+ "keywords": ["zabbix"],
+ "logos": {
+ "small": "img/zabbix_app_logo.svg",
+ "large": "img/zabbix_app_logo.svg"
+ },
+ "links": [
+ {"name": "GitHub", "url": "https://github.com/alexanderzobnin/grafana-zabbix"},
+ {"name": "Docs", "url": "http://docs.grafana-zabbix.org"},
+ {"name": "License", "url": "https://github.com/alexanderzobnin/grafana-zabbix/blob/master/LICENSE.md"}
+ ],
+ "screenshots": [
+ {"name": "Showcase", "path": "img/screenshot-showcase.png"},
+ {"name": "Dashboard", "path": "img/screenshot-dashboard01.png"},
+ {"name": "Annotations", "path": "img/screenshot-annotations.png"},
+ {"name": "Metric Editor", "path": "img/screenshot-metric_editor.png"},
+ {"name": "Triggers", "path": "img/screenshot-triggers.png"}
+ ],
+ "version": "3.2.0",
+ "updated": "2016-12-20"
+ },
+
+ "includes": [
+ {
+ "type": "datasource",
+ "name": "Zabbix Datasource"
+ },
+ {
+ "type": "panel",
+ "name": "Triggers Panel"
+ },
+ {
+ "type": "dashboard",
+ "name": "Zabbix Server Dashboard",
+ "path": "dashboards/zabbix_server_dashboard.json",
+ "addToNav": true
+ },
+ {
+ "type": "dashboard",
+ "name": "Template Linux Server",
+ "path": "dashboards/template_linux_server.json",
+ "addToNav": true
+ }
+ ],
+
+ "dependencies": {
+ "grafanaVersion": "3.x.x",
+ "plugins": []
+ }
+}
diff --git a/dist/test/components/config.js b/dist/test/components/config.js
new file mode 100644
index 0000000..ad0987c
--- /dev/null
+++ b/dist/test/components/config.js
@@ -0,0 +1,13 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var ZabbixAppConfigCtrl = exports.ZabbixAppConfigCtrl = function ZabbixAppConfigCtrl() {
+ _classCallCheck(this, ZabbixAppConfigCtrl);
+};
+
+ZabbixAppConfigCtrl.templateUrl = 'components/config.html';
diff --git a/dist/test/datasource-zabbix/add-metric-function.directive.js b/dist/test/datasource-zabbix/add-metric-function.directive.js
new file mode 100644
index 0000000..26b55cc
--- /dev/null
+++ b/dist/test/datasource-zabbix/add-metric-function.directive.js
@@ -0,0 +1,116 @@
+'use strict';
+
+var _angular = require('angular');
+
+var _angular2 = _interopRequireDefault(_angular);
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _jquery = require('jquery');
+
+var _jquery2 = _interopRequireDefault(_jquery);
+
+var _metricFunctions = require('./metricFunctions');
+
+var metricFunctions = _interopRequireWildcard(_metricFunctions);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/** @ngInject */
+_angular2.default.module('grafana.directives').directive('addMetricFunction', function ($compile) {
+ var inputTemplate = ' ';
+
+ var buttonTemplate = '' + ' ';
+
+ return {
+ link: function link($scope, elem) {
+ var categories = metricFunctions.getCategories();
+ var allFunctions = getAllFunctionNames(categories);
+
+ $scope.functionMenu = createFunctionDropDownMenu(categories);
+
+ var $input = (0, _jquery2.default)(inputTemplate);
+ var $button = (0, _jquery2.default)(buttonTemplate);
+ $input.appendTo(elem);
+ $button.appendTo(elem);
+
+ $input.attr('data-provide', 'typeahead');
+ $input.typeahead({
+ source: allFunctions,
+ minLength: 1,
+ items: 10,
+ updater: function updater(value) {
+ var funcDef = metricFunctions.getFuncDef(value);
+ if (!funcDef) {
+ // try find close match
+ value = value.toLowerCase();
+ funcDef = _lodash2.default.find(allFunctions, function (funcName) {
+ return funcName.toLowerCase().indexOf(value) === 0;
+ });
+
+ if (!funcDef) {
+ return;
+ }
+ }
+
+ $scope.$apply(function () {
+ $scope.addFunction(funcDef);
+ });
+
+ $input.trigger('blur');
+ return '';
+ }
+ });
+
+ $button.click(function () {
+ $button.hide();
+ $input.show();
+ $input.focus();
+ });
+
+ $input.keyup(function () {
+ elem.toggleClass('open', $input.val() === '');
+ });
+
+ $input.blur(function () {
+ // clicking the function dropdown menu wont
+ // work if you remove class at once
+ setTimeout(function () {
+ $input.val('');
+ $input.hide();
+ $button.show();
+ elem.removeClass('open');
+ }, 200);
+ });
+
+ $compile(elem.contents())($scope);
+ }
+ };
+});
+
+function getAllFunctionNames(categories) {
+ return _lodash2.default.reduce(categories, function (list, category) {
+ _lodash2.default.each(category, function (func) {
+ list.push(func.name);
+ });
+ return list;
+ }, []);
+}
+
+function createFunctionDropDownMenu(categories) {
+ return _lodash2.default.map(categories, function (list, category) {
+ return {
+ text: category,
+ submenu: _lodash2.default.map(list, function (value) {
+ return {
+ text: value.name,
+ click: "ctrl.addFunction('" + value.name + "')"
+ };
+ })
+ };
+ });
+}
diff --git a/dist/test/datasource-zabbix/dataProcessor.js b/dist/test/datasource-zabbix/dataProcessor.js
new file mode 100644
index 0000000..2ce1585
--- /dev/null
+++ b/dist/test/datasource-zabbix/dataProcessor.js
@@ -0,0 +1,330 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _utils = require('./utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Downsample datapoints series
+ */
+function downsampleSeries(datapoints, time_to, ms_interval, func) {
+ var downsampledSeries = [];
+ var timeWindow = {
+ from: time_to * 1000 - ms_interval,
+ to: time_to * 1000
+ };
+
+ var points_sum = 0;
+ var points_num = 0;
+ var value_avg = 0;
+ var frame = [];
+
+ for (var i = datapoints.length - 1; i >= 0; i -= 1) {
+ if (timeWindow.from < datapoints[i][1] && datapoints[i][1] <= timeWindow.to) {
+ points_sum += datapoints[i][0];
+ points_num++;
+ frame.push(datapoints[i][0]);
+ } else {
+ value_avg = points_num ? points_sum / points_num : 0;
+
+ if (func === "max") {
+ downsampledSeries.push([_lodash2.default.max(frame), timeWindow.to]);
+ } else if (func === "min") {
+ downsampledSeries.push([_lodash2.default.min(frame), timeWindow.to]);
+ }
+
+ // avg by default
+ else {
+ downsampledSeries.push([value_avg, timeWindow.to]);
+ }
+
+ // Shift time window
+ timeWindow.to = timeWindow.from;
+ timeWindow.from -= ms_interval;
+
+ points_sum = 0;
+ points_num = 0;
+ frame = [];
+
+ // Process point again
+ i++;
+ }
+ }
+ return downsampledSeries.reverse();
+}
+
+/**
+ * Group points by given time interval
+ * datapoints: [[, ], ...]
+ */
+function groupBy(interval, groupByCallback, datapoints) {
+ var ms_interval = utils.parseInterval(interval);
+
+ // Calculate frame timestamps
+ var frames = _lodash2.default.groupBy(datapoints, function (point) {
+ // Calculate time for group of points
+ return Math.floor(point[1] / ms_interval) * ms_interval;
+ });
+
+ // frame: { '': [[, ], ...] }
+ // return [{ '': }, { '': }, ...]
+ var grouped = _lodash2.default.mapValues(frames, function (frame) {
+ var points = _lodash2.default.map(frame, function (point) {
+ return point[0];
+ });
+ return groupByCallback(points);
+ });
+
+ // Convert points to Grafana format
+ return sortByTime(_lodash2.default.map(grouped, function (value, timestamp) {
+ return [Number(value), Number(timestamp)];
+ }));
+}
+
+function sumSeries(timeseries) {
+
+ // Calculate new points for interpolation
+ var new_timestamps = _lodash2.default.uniq(_lodash2.default.map(_lodash2.default.flatten(timeseries, true), function (point) {
+ return point[1];
+ }));
+ new_timestamps = _lodash2.default.sortBy(new_timestamps);
+
+ var interpolated_timeseries = _lodash2.default.map(timeseries, function (series) {
+ var timestamps = _lodash2.default.map(series, function (point) {
+ return point[1];
+ });
+ var new_points = _lodash2.default.map(_lodash2.default.difference(new_timestamps, timestamps), function (timestamp) {
+ return [null, timestamp];
+ });
+ var new_series = series.concat(new_points);
+ return sortByTime(new_series);
+ });
+
+ _lodash2.default.each(interpolated_timeseries, interpolateSeries);
+
+ var new_timeseries = [];
+ var sum;
+ for (var i = new_timestamps.length - 1; i >= 0; i--) {
+ sum = 0;
+ for (var j = interpolated_timeseries.length - 1; j >= 0; j--) {
+ sum += interpolated_timeseries[j][i][0];
+ }
+ new_timeseries.push([sum, new_timestamps[i]]);
+ }
+
+ return sortByTime(new_timeseries);
+}
+
+function limit(order, n, orderByFunc, timeseries) {
+ var orderByCallback = aggregationFunctions[orderByFunc];
+ var sortByIteratee = function sortByIteratee(ts) {
+ var values = _lodash2.default.map(ts.datapoints, function (point) {
+ return point[0];
+ });
+ return orderByCallback(values);
+ };
+ var sortedTimeseries = _lodash2.default.sortBy(timeseries, sortByIteratee);
+ if (order === 'bottom') {
+ return sortedTimeseries.slice(0, n);
+ } else {
+ return sortedTimeseries.slice(-n);
+ }
+}
+
+function AVERAGE(values) {
+ var sum = 0;
+ _lodash2.default.each(values, function (value) {
+ sum += value;
+ });
+ return sum / values.length;
+}
+
+function MIN(values) {
+ return _lodash2.default.min(values);
+}
+
+function MAX(values) {
+ return _lodash2.default.max(values);
+}
+
+function MEDIAN(values) {
+ var sorted = _lodash2.default.sortBy(values);
+ return sorted[Math.floor(sorted.length / 2)];
+}
+
+function setAlias(alias, timeseries) {
+ timeseries.target = alias;
+ return timeseries;
+}
+
+function setAliasByRegex(alias, timeseries) {
+ timeseries.target = extractText(timeseries.target, alias);
+ return timeseries;
+}
+
+function extractText(str, pattern) {
+ var extractPattern = new RegExp(pattern);
+ var extractedValue = extractPattern.exec(str);
+ extractedValue = extractedValue[0];
+ return extractedValue;
+}
+
+function scale(factor, datapoints) {
+ return _lodash2.default.map(datapoints, function (point) {
+ return [point[0] * factor, point[1]];
+ });
+}
+
+function delta(datapoints) {
+ var newSeries = [];
+ var deltaValue = void 0;
+ for (var i = 1; i < datapoints.length; i++) {
+ deltaValue = datapoints[i][0] - datapoints[i - 1][0];
+ newSeries.push([deltaValue, datapoints[i][1]]);
+ }
+ return newSeries;
+}
+
+function groupByWrapper(interval, groupFunc, datapoints) {
+ var groupByCallback = aggregationFunctions[groupFunc];
+ return groupBy(interval, groupByCallback, datapoints);
+}
+
+function aggregateByWrapper(interval, aggregateFunc, datapoints) {
+ // Flatten all points in frame and then just use groupBy()
+ var flattenedPoints = _lodash2.default.flatten(datapoints, true);
+ var groupByCallback = aggregationFunctions[aggregateFunc];
+ return groupBy(interval, groupByCallback, flattenedPoints);
+}
+
+function aggregateWrapper(groupByCallback, interval, datapoints) {
+ var flattenedPoints = _lodash2.default.flatten(datapoints, true);
+ return groupBy(interval, groupByCallback, flattenedPoints);
+}
+
+function sortByTime(series) {
+ return _lodash2.default.sortBy(series, function (point) {
+ return point[1];
+ });
+}
+
+/**
+ * Interpolate series with gaps
+ */
+function interpolateSeries(series) {
+ var left, right;
+
+ // Interpolate series
+ for (var i = series.length - 1; i >= 0; i--) {
+ if (!series[i][0]) {
+ left = findNearestLeft(series, series[i]);
+ right = findNearestRight(series, series[i]);
+ if (!left) {
+ left = right;
+ }
+ if (!right) {
+ right = left;
+ }
+ series[i][0] = linearInterpolation(series[i][1], left, right);
+ }
+ }
+ return series;
+}
+
+function linearInterpolation(timestamp, left, right) {
+ if (left[1] === right[1]) {
+ return (left[0] + right[0]) / 2;
+ } else {
+ return left[0] + (right[0] - left[0]) / (right[1] - left[1]) * (timestamp - left[1]);
+ }
+}
+
+function findNearestRight(series, point) {
+ var point_index = _lodash2.default.indexOf(series, point);
+ var nearestRight;
+ for (var i = point_index; i < series.length; i++) {
+ if (series[i][0] !== null) {
+ return series[i];
+ }
+ }
+ return nearestRight;
+}
+
+function findNearestLeft(series, point) {
+ var point_index = _lodash2.default.indexOf(series, point);
+ var nearestLeft;
+ for (var i = point_index; i > 0; i--) {
+ if (series[i][0] !== null) {
+ return series[i];
+ }
+ }
+ return nearestLeft;
+}
+
+function timeShift(interval, range) {
+ var shift = utils.parseTimeShiftInterval(interval) / 1000;
+ return range.map(function (time) {
+ return time - shift;
+ });
+}
+
+function unShiftTimeSeries(interval, datapoints) {
+ var unshift = utils.parseTimeShiftInterval(interval);
+ return datapoints.map(function (dp) {
+ return [dp[0], dp[1] + unshift];
+ });
+}
+
+var metricFunctions = {
+ groupBy: groupByWrapper,
+ scale: scale,
+ delta: delta,
+ aggregateBy: aggregateByWrapper,
+ average: _lodash2.default.partial(aggregateWrapper, AVERAGE),
+ min: _lodash2.default.partial(aggregateWrapper, MIN),
+ max: _lodash2.default.partial(aggregateWrapper, MAX),
+ median: _lodash2.default.partial(aggregateWrapper, MEDIAN),
+ sumSeries: sumSeries,
+ top: _lodash2.default.partial(limit, 'top'),
+ bottom: _lodash2.default.partial(limit, 'bottom'),
+ timeShift: timeShift,
+ setAlias: setAlias,
+ setAliasByRegex: setAliasByRegex
+};
+
+var aggregationFunctions = {
+ avg: AVERAGE,
+ min: MIN,
+ max: MAX,
+ median: MEDIAN
+};
+
+exports.default = {
+ downsampleSeries: downsampleSeries,
+ groupBy: groupBy,
+ AVERAGE: AVERAGE,
+ MIN: MIN,
+ MAX: MAX,
+ MEDIAN: MEDIAN,
+ unShiftTimeSeries: unShiftTimeSeries,
+
+ get aggregationFunctions() {
+ return aggregationFunctions;
+ },
+
+ get metricFunctions() {
+ return metricFunctions;
+ }
+};
diff --git a/dist/test/datasource-zabbix/datasource.js b/dist/test/datasource-zabbix/datasource.js
new file mode 100644
index 0000000..2ecc64a
--- /dev/null
+++ b/dist/test/datasource-zabbix/datasource.js
@@ -0,0 +1,582 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.zabbixTemplateFormat = exports.ZabbixAPIDatasource = undefined;
+
+var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); //import angular from 'angular';
+
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _datemath = require('app/core/utils/datemath');
+
+var dateMath = _interopRequireWildcard(_datemath);
+
+var _utils = require('./utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+var _migrations = require('./migrations');
+
+var migrations = _interopRequireWildcard(_migrations);
+
+var _metricFunctions = require('./metricFunctions');
+
+var metricFunctions = _interopRequireWildcard(_metricFunctions);
+
+var _dataProcessor = require('./dataProcessor');
+
+var _dataProcessor2 = _interopRequireDefault(_dataProcessor);
+
+var _responseHandler = require('./responseHandler');
+
+var _responseHandler2 = _interopRequireDefault(_responseHandler);
+
+require('./zabbix.js');
+
+var _zabbixAPICoreService = require('./zabbixAPICore.service.js');
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var ZabbixAPIDatasource = function () {
+
+ /** @ngInject */
+ function ZabbixAPIDatasource(instanceSettings, templateSrv, alertSrv, Zabbix) {
+ _classCallCheck(this, ZabbixAPIDatasource);
+
+ this.templateSrv = templateSrv;
+ this.alertSrv = alertSrv;
+
+ // General data source settings
+ this.name = instanceSettings.name;
+ this.url = instanceSettings.url;
+ this.basicAuth = instanceSettings.basicAuth;
+ this.withCredentials = instanceSettings.withCredentials;
+
+ // Zabbix API credentials
+ this.username = instanceSettings.jsonData.username;
+ this.password = instanceSettings.jsonData.password;
+
+ // Use trends instead history since specified time
+ this.trends = instanceSettings.jsonData.trends;
+ this.trendsFrom = instanceSettings.jsonData.trendsFrom || '7d';
+
+ // Set cache update interval
+ var ttl = instanceSettings.jsonData.cacheTTL || '1h';
+ this.cacheTTL = utils.parseInterval(ttl);
+
+ this.zabbix = new Zabbix(this.url, this.username, this.password, this.basicAuth, this.withCredentials, this.cacheTTL);
+
+ // Use custom format for template variables
+ this.replaceTemplateVars = _lodash2.default.partial(replaceTemplateVars, this.templateSrv);
+ }
+
+ ////////////////////////
+ // Datasource methods //
+ ////////////////////////
+
+ /**
+ * Query panel data. Calls for each panel in dashboard.
+ * @param {Object} options Contains time range, targets and other info.
+ * @return {Object} Grafana metrics object with timeseries data for each target.
+ */
+
+
+ _createClass(ZabbixAPIDatasource, [{
+ key: 'query',
+ value: function query(options) {
+ var _this = this;
+
+ var timeFrom = Math.ceil(dateMath.parse(options.range.from) / 1000);
+ var timeTo = Math.ceil(dateMath.parse(options.range.to) / 1000);
+
+ var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000);
+ var useTrends = timeFrom <= useTrendsFrom && this.trends;
+
+ // Create request for each target
+ var promises = _lodash2.default.map(options.targets, function (target) {
+ // Prevent changes of original object
+ target = _lodash2.default.cloneDeep(target);
+ _this.replaceTargetVariables(target, options);
+
+ // Apply Time-related functions (timeShift(), etc)
+ var timeFunctions = bindFunctionDefs(target.functions, 'Time');
+ if (timeFunctions.length) {
+ var _sequence = sequence(timeFunctions)([timeFrom, timeTo]),
+ _sequence2 = _slicedToArray(_sequence, 2),
+ time_from = _sequence2[0],
+ time_to = _sequence2[1];
+
+ timeFrom = time_from;
+ timeTo = time_to;
+ }
+
+ // Metrics or Text query mode
+ if (target.mode !== 1) {
+ // Migrate old targets
+ target = migrations.migrate(target);
+
+ // Don't request undefined and hidden targets
+ if (target.hide || !target.group || !target.host || !target.item) {
+ return [];
+ }
+
+ if (!target.mode || target.mode === 0) {
+ return _this.queryNumericData(target, timeFrom, timeTo, useTrends);
+ } else if (target.mode === 2) {
+ return _this.queryTextData(target, timeFrom, timeTo);
+ }
+ }
+
+ // IT services mode
+ else if (target.mode === 1) {
+ // Don't show undefined and hidden targets
+ if (target.hide || !target.itservice || !target.slaProperty) {
+ return [];
+ }
+
+ return _this.zabbix.getSLA(target.itservice.serviceid, timeFrom, timeTo).then(function (slaObject) {
+ return _responseHandler2.default.handleSLAResponse(target.itservice, target.slaProperty, slaObject);
+ });
+ }
+ });
+
+ // Data for panel (all targets)
+ return Promise.all(_lodash2.default.flatten(promises)).then(_lodash2.default.flatten).then(function (timeseries_data) {
+ return downsampleSeries(timeseries_data, options);
+ }).then(function (data) {
+ return { data: data };
+ });
+ }
+ }, {
+ key: 'queryNumericData',
+ value: function queryNumericData(target, timeFrom, timeTo, useTrends) {
+ var _this2 = this;
+
+ var options = {
+ itemtype: 'num'
+ };
+ return this.zabbix.getItemsFromTarget(target, options).then(function (items) {
+ var getHistoryPromise = void 0;
+
+ if (useTrends) {
+ (function () {
+ var valueType = _this2.getTrendValueType(target);
+ getHistoryPromise = _this2.zabbix.getTrend(items, timeFrom, timeTo).then(function (history) {
+ return _responseHandler2.default.handleTrends(history, items, valueType);
+ });
+ })();
+ } else {
+ // Use history
+ getHistoryPromise = _this2.zabbix.getHistory(items, timeFrom, timeTo).then(function (history) {
+ return _responseHandler2.default.handleHistory(history, items);
+ });
+ }
+
+ return getHistoryPromise.then(function (timeseries_data) {
+ return _this2.applyDataProcessingFunctions(timeseries_data, target);
+ });
+ });
+ }
+ }, {
+ key: 'getTrendValueType',
+ value: function getTrendValueType(target) {
+ // Find trendValue() function and get specified trend value
+ var trendFunctions = _lodash2.default.map(metricFunctions.getCategories()['Trends'], 'name');
+ var trendValueFunc = _lodash2.default.find(target.functions, function (func) {
+ return _lodash2.default.includes(trendFunctions, func.def.name);
+ });
+ return trendValueFunc ? trendValueFunc.params[0] : "avg";
+ }
+ }, {
+ key: 'applyDataProcessingFunctions',
+ value: function applyDataProcessingFunctions(timeseries_data, target) {
+ var transformFunctions = bindFunctionDefs(target.functions, 'Transform');
+ var aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate');
+ var filterFunctions = bindFunctionDefs(target.functions, 'Filter');
+ var aliasFunctions = bindFunctionDefs(target.functions, 'Alias');
+
+ // Apply transformation functions
+ timeseries_data = _lodash2.default.map(timeseries_data, function (timeseries) {
+ timeseries.datapoints = sequence(transformFunctions)(timeseries.datapoints);
+ return timeseries;
+ });
+
+ // Apply filter functions
+ if (filterFunctions.length) {
+ timeseries_data = sequence(filterFunctions)(timeseries_data);
+ }
+
+ // Apply aggregations
+ if (aggregationFunctions.length) {
+ (function () {
+ var dp = _lodash2.default.map(timeseries_data, 'datapoints');
+ dp = sequence(aggregationFunctions)(dp);
+
+ var aggFuncNames = _lodash2.default.map(metricFunctions.getCategories()['Aggregate'], 'name');
+ var lastAgg = _lodash2.default.findLast(target.functions, function (func) {
+ return _lodash2.default.includes(aggFuncNames, func.def.name);
+ });
+
+ timeseries_data = [{
+ target: lastAgg.text,
+ datapoints: dp
+ }];
+ })();
+ }
+
+ // Apply alias functions
+ _lodash2.default.forEach(timeseries_data, sequence(aliasFunctions));
+
+ // Apply Time-related functions (timeShift(), etc)
+ // Find timeShift() function and get specified trend value
+ this.applyTimeShiftFunction(timeseries_data, target);
+
+ return timeseries_data;
+ }
+ }, {
+ key: 'applyTimeShiftFunction',
+ value: function applyTimeShiftFunction(timeseries_data, target) {
+ // Find timeShift() function and get specified interval
+ var timeShiftFunc = _lodash2.default.find(target.functions, function (func) {
+ return func.def.name === 'timeShift';
+ });
+ if (timeShiftFunc) {
+ (function () {
+ var shift = timeShiftFunc.params[0];
+ _lodash2.default.forEach(timeseries_data, function (series) {
+ series.datapoints = _dataProcessor2.default.unShiftTimeSeries(shift, series.datapoints);
+ });
+ })();
+ }
+ }
+ }, {
+ key: 'queryTextData',
+ value: function queryTextData(target, timeFrom, timeTo) {
+ var _this3 = this;
+
+ var options = {
+ itemtype: 'text'
+ };
+ return this.zabbix.getItemsFromTarget(target, options).then(function (items) {
+ if (items.length) {
+ return _this3.zabbix.getHistory(items, timeFrom, timeTo).then(function (history) {
+ return _responseHandler2.default.convertHistory(history, items, false, function (point) {
+ var value = point.value;
+
+ // Regex-based extractor
+ if (target.textFilter) {
+ value = extractText(point.value, target.textFilter, target.useCaptureGroups);
+ }
+
+ return [value, point.clock * 1000];
+ });
+ });
+ } else {
+ return Promise.resolve([]);
+ }
+ });
+ }
+
+ /**
+ * Test connection to Zabbix API
+ * @return {object} Connection status and Zabbix API version
+ */
+
+ }, {
+ key: 'testDatasource',
+ value: function testDatasource() {
+ var _this4 = this;
+
+ var zabbixVersion = void 0;
+ return this.zabbix.getVersion().then(function (version) {
+ zabbixVersion = version;
+ return _this4.zabbix.login();
+ }).then(function () {
+ return {
+ status: "success",
+ title: "Success",
+ message: "Zabbix API version: " + zabbixVersion
+ };
+ }).catch(function (error) {
+ if (error instanceof _zabbixAPICoreService.ZabbixAPIError) {
+ return {
+ status: "error",
+ title: error.message,
+ message: error.data
+ };
+ } else {
+ return {
+ status: "error",
+ title: "Connection failed",
+ message: "Could not connect to given url"
+ };
+ }
+ });
+ }
+
+ ////////////////
+ // Templating //
+ ////////////////
+
+ /**
+ * Find metrics from templated request.
+ *
+ * @param {string} query Query from Templating
+ * @return {string} Metric name - group, host, app or item or list
+ * of metrics in "{metric1,metcic2,...,metricN}" format.
+ */
+
+ }, {
+ key: 'metricFindQuery',
+ value: function metricFindQuery(query) {
+ var _this5 = this;
+
+ var result = void 0;
+ var parts = [];
+
+ // Split query. Query structure: group.host.app.item
+ _lodash2.default.each(query.split('.'), function (part) {
+ part = _this5.replaceTemplateVars(part, {});
+
+ // Replace wildcard to regex
+ if (part === '*') {
+ part = '/.*/';
+ }
+ parts.push(part);
+ });
+ var template = _lodash2.default.zipObject(['group', 'host', 'app', 'item'], parts);
+
+ // Get items
+ if (parts.length === 4) {
+ // Search for all items, even it's not belong to any application
+ if (template.app === '/.*/') {
+ template.app = '';
+ }
+ result = this.zabbix.getItems(template.group, template.host, template.app, template.item);
+ } else if (parts.length === 3) {
+ // Get applications
+ result = this.zabbix.getApps(template.group, template.host, template.app);
+ } else if (parts.length === 2) {
+ // Get hosts
+ result = this.zabbix.getHosts(template.group, template.host);
+ } else if (parts.length === 1) {
+ // Get groups
+ result = this.zabbix.getGroups(template.group);
+ } else {
+ result = Promise.resolve([]);
+ }
+
+ return result.then(function (metrics) {
+ return metrics.map(formatMetric);
+ });
+ }
+
+ /////////////////
+ // Annotations //
+ /////////////////
+
+ }, {
+ key: 'annotationQuery',
+ value: function annotationQuery(options) {
+ var _this6 = this;
+
+ var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000);
+ var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000);
+ var annotation = options.annotation;
+ var showOkEvents = annotation.showOkEvents ? [0, 1] : 1;
+
+ // Show all triggers
+ var showTriggers = [0, 1];
+
+ var getTriggers = this.zabbix.getTriggers(this.replaceTemplateVars(annotation.group, {}), this.replaceTemplateVars(annotation.host, {}), this.replaceTemplateVars(annotation.application, {}), showTriggers);
+
+ return getTriggers.then(function (triggers) {
+
+ // Filter triggers by description
+ if (utils.isRegex(annotation.trigger)) {
+ triggers = _lodash2.default.filter(triggers, function (trigger) {
+ return utils.buildRegex(annotation.trigger).test(trigger.description);
+ });
+ } else if (annotation.trigger) {
+ triggers = _lodash2.default.filter(triggers, function (trigger) {
+ return trigger.description === annotation.trigger;
+ });
+ }
+
+ // Remove events below the chose severity
+ triggers = _lodash2.default.filter(triggers, function (trigger) {
+ return Number(trigger.priority) >= Number(annotation.minseverity);
+ });
+
+ var objectids = _lodash2.default.map(triggers, 'triggerid');
+ return _this6.zabbix.getEvents(objectids, timeFrom, timeTo, showOkEvents).then(function (events) {
+ var indexedTriggers = _lodash2.default.keyBy(triggers, 'triggerid');
+
+ // Hide acknowledged events if option enabled
+ if (annotation.hideAcknowledged) {
+ events = _lodash2.default.filter(events, function (event) {
+ return !event.acknowledges.length;
+ });
+ }
+
+ return _lodash2.default.map(events, function (event) {
+ var tags = void 0;
+ if (annotation.showHostname) {
+ tags = _lodash2.default.map(event.hosts, 'name');
+ }
+
+ // Show event type (OK or Problem)
+ var title = Number(event.value) ? 'Problem' : 'OK';
+
+ var formatted_acknowledges = utils.formatAcknowledges(event.acknowledges);
+ return {
+ annotation: annotation,
+ time: event.clock * 1000,
+ title: title,
+ tags: tags,
+ text: indexedTriggers[event.objectid].description + formatted_acknowledges
+ };
+ });
+ });
+ });
+ }
+
+ // Replace template variables
+
+ }, {
+ key: 'replaceTargetVariables',
+ value: function replaceTargetVariables(target, options) {
+ var _this7 = this;
+
+ var parts = ['group', 'host', 'application', 'item'];
+ parts.forEach(function (p) {
+ if (target[p] && target[p].filter) {
+ target[p].filter = _this7.replaceTemplateVars(target[p].filter, options.scopedVars);
+ }
+ });
+ target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars);
+
+ _lodash2.default.forEach(target.functions, function (func) {
+ func.params = func.params.map(function (param) {
+ if (typeof param === 'number') {
+ return +_this7.templateSrv.replace(param.toString(), options.scopedVars);
+ } else {
+ return _this7.templateSrv.replace(param, options.scopedVars);
+ }
+ });
+ });
+ }
+ }]);
+
+ return ZabbixAPIDatasource;
+}();
+
+function bindFunctionDefs(functionDefs, category) {
+ var aggregationFunctions = _lodash2.default.map(metricFunctions.getCategories()[category], 'name');
+ var aggFuncDefs = _lodash2.default.filter(functionDefs, function (func) {
+ return _lodash2.default.includes(aggregationFunctions, func.def.name);
+ });
+
+ return _lodash2.default.map(aggFuncDefs, function (func) {
+ var funcInstance = metricFunctions.createFuncInstance(func.def, func.params);
+ return funcInstance.bindFunction(_dataProcessor2.default.metricFunctions);
+ });
+}
+
+function downsampleSeries(timeseries_data, options) {
+ return _lodash2.default.map(timeseries_data, function (timeseries) {
+ if (timeseries.datapoints.length > options.maxDataPoints) {
+ timeseries.datapoints = _dataProcessor2.default.groupBy(options.interval, _dataProcessor2.default.AVERAGE, timeseries.datapoints);
+ }
+ return timeseries;
+ });
+}
+
+function formatMetric(metricObj) {
+ return {
+ text: metricObj.name,
+ expandable: false
+ };
+}
+
+/**
+ * Custom formatter for template variables.
+ * Default Grafana "regex" formatter returns
+ * value1|value2
+ * This formatter returns
+ * (value1|value2)
+ * This format needed for using in complex regex with
+ * template variables, for example
+ * /CPU $cpu_item.*time/ where $cpu_item is system,user,iowait
+ */
+function zabbixTemplateFormat(value) {
+ if (typeof value === 'string') {
+ return utils.escapeRegex(value);
+ }
+
+ var escapedValues = _lodash2.default.map(value, utils.escapeRegex);
+ return '(' + escapedValues.join('|') + ')';
+}
+
+/**
+ * If template variables are used in request, replace it using regex format
+ * and wrap with '/' for proper multi-value work. Example:
+ * $variable selected as a, b, c
+ * We use filter $variable
+ * $variable -> a|b|c -> /a|b|c/
+ * /$variable/ -> /a|b|c/ -> /a|b|c/
+ */
+function replaceTemplateVars(templateSrv, target, scopedVars) {
+ var replacedTarget = templateSrv.replace(target, scopedVars, zabbixTemplateFormat);
+ if (target !== replacedTarget && !utils.isRegex(replacedTarget)) {
+ replacedTarget = '/^' + replacedTarget + '$/';
+ }
+ return replacedTarget;
+}
+
+function extractText(str, pattern, useCaptureGroups) {
+ var extractPattern = new RegExp(pattern);
+ var extractedValue = extractPattern.exec(str);
+ if (extractedValue) {
+ if (useCaptureGroups) {
+ extractedValue = extractedValue[1];
+ } else {
+ extractedValue = extractedValue[0];
+ }
+ }
+ return extractedValue;
+}
+
+// Apply function one by one:
+// sequence([a(), b(), c()]) = c(b(a()));
+function sequence(funcsArray) {
+ return function (result) {
+ for (var i = 0; i < funcsArray.length; i++) {
+ result = funcsArray[i].call(this, result);
+ }
+ return result;
+ };
+}
+
+exports.ZabbixAPIDatasource = ZabbixAPIDatasource;
+exports.zabbixTemplateFormat = zabbixTemplateFormat;
+
+// Fix for backward compatibility with lodash 2.4
+
+if (!_lodash2.default.includes) {
+ _lodash2.default.includes = _lodash2.default.contains;
+}
+if (!_lodash2.default.keyBy) {
+ _lodash2.default.keyBy = _lodash2.default.indexBy;
+}
diff --git a/dist/test/datasource-zabbix/metric-function-editor.directive.js b/dist/test/datasource-zabbix/metric-function-editor.directive.js
new file mode 100644
index 0000000..02135e9
--- /dev/null
+++ b/dist/test/datasource-zabbix/metric-function-editor.directive.js
@@ -0,0 +1,246 @@
+'use strict';
+
+var _angular = require('angular');
+
+var _angular2 = _interopRequireDefault(_angular);
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _jquery = require('jquery');
+
+var _jquery2 = _interopRequireDefault(_jquery);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/** @ngInject */
+_angular2.default.module('grafana.directives').directive('metricFunctionEditor', function ($compile, templateSrv) {
+
+ var funcSpanTemplate = '{{func.def.name}} ( ';
+ var paramTemplate = ' ';
+
+ var funcControlsTemplate = '' + ' ' + ' ' + ' ' + ' ' + '
';
+
+ return {
+ restrict: 'A',
+ link: function postLink($scope, elem) {
+ var $funcLink = (0, _jquery2.default)(funcSpanTemplate);
+ var $funcControls = (0, _jquery2.default)(funcControlsTemplate);
+ var ctrl = $scope.ctrl;
+ var func = $scope.func;
+ var funcDef = func.def;
+ var scheduledRelink = false;
+ var paramCountAtLink = 0;
+
+ function clickFuncParam(paramIndex) {
+ /*jshint validthis:true */
+
+ var $link = (0, _jquery2.default)(this);
+ var $input = $link.next();
+
+ $input.val(func.params[paramIndex]);
+ $input.css('width', $link.width() + 16 + 'px');
+
+ $link.hide();
+ $input.show();
+ $input.focus();
+ $input.select();
+
+ var typeahead = $input.data('typeahead');
+ if (typeahead) {
+ $input.val('');
+ typeahead.lookup();
+ }
+ }
+
+ function scheduledRelinkIfNeeded() {
+ if (paramCountAtLink === func.params.length) {
+ return;
+ }
+
+ if (!scheduledRelink) {
+ scheduledRelink = true;
+ setTimeout(function () {
+ relink();
+ scheduledRelink = false;
+ }, 200);
+ }
+ }
+
+ function inputBlur(paramIndex) {
+ /*jshint validthis:true */
+ var $input = (0, _jquery2.default)(this);
+ var $link = $input.prev();
+ var newValue = $input.val();
+
+ if (newValue !== '' || func.def.params[paramIndex].optional) {
+ $link.html(templateSrv.highlightVariablesAsHtml(newValue));
+
+ func.updateParam($input.val(), paramIndex);
+ scheduledRelinkIfNeeded();
+
+ $scope.$apply(function () {
+ ctrl.targetChanged();
+ });
+
+ $input.hide();
+ $link.show();
+ }
+ }
+
+ function inputKeyPress(paramIndex, e) {
+ /*jshint validthis:true */
+ if (e.which === 13) {
+ inputBlur.call(this, paramIndex);
+ }
+ }
+
+ function inputKeyDown() {
+ /*jshint validthis:true */
+ this.style.width = (3 + this.value.length) * 8 + 'px';
+ }
+
+ function addTypeahead($input, paramIndex) {
+ $input.attr('data-provide', 'typeahead');
+
+ var options = funcDef.params[paramIndex].options;
+ if (funcDef.params[paramIndex].type === 'int' || funcDef.params[paramIndex].type === 'float') {
+ options = _lodash2.default.map(options, function (val) {
+ return val.toString();
+ });
+ }
+
+ $input.typeahead({
+ source: options,
+ minLength: 0,
+ items: 20,
+ updater: function updater(value) {
+ setTimeout(function () {
+ inputBlur.call($input[0], paramIndex);
+ }, 0);
+ return value;
+ }
+ });
+
+ var typeahead = $input.data('typeahead');
+ typeahead.lookup = function () {
+ this.query = this.$element.val() || '';
+ return this.process(this.source);
+ };
+ }
+
+ function toggleFuncControls() {
+ var targetDiv = elem.closest('.tight-form');
+
+ if (elem.hasClass('show-function-controls')) {
+ elem.removeClass('show-function-controls');
+ targetDiv.removeClass('has-open-function');
+ $funcControls.hide();
+ return;
+ }
+
+ elem.addClass('show-function-controls');
+ targetDiv.addClass('has-open-function');
+
+ $funcControls.show();
+ }
+
+ function addElementsAndCompile() {
+ $funcControls.appendTo(elem);
+ $funcLink.appendTo(elem);
+
+ _lodash2.default.each(funcDef.params, function (param, index) {
+ if (param.optional && func.params.length <= index) {
+ return;
+ }
+
+ if (index > 0) {
+ (0, _jquery2.default)(', ').appendTo(elem);
+ }
+
+ var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);
+ var $paramLink = (0, _jquery2.default)('' + paramValue + ' ');
+ var $input = (0, _jquery2.default)(paramTemplate);
+
+ paramCountAtLink++;
+
+ $paramLink.appendTo(elem);
+ $input.appendTo(elem);
+
+ $input.blur(_lodash2.default.partial(inputBlur, index));
+ $input.keyup(inputKeyDown);
+ $input.keypress(_lodash2.default.partial(inputKeyPress, index));
+ $paramLink.click(_lodash2.default.partial(clickFuncParam, index));
+
+ if (funcDef.params[index].options) {
+ addTypeahead($input, index);
+ }
+ });
+
+ (0, _jquery2.default)(') ').appendTo(elem);
+
+ $compile(elem.contents())($scope);
+ }
+
+ function ifJustAddedFocusFistParam() {
+ if ($scope.func.added) {
+ $scope.func.added = false;
+ setTimeout(function () {
+ elem.find('.graphite-func-param-link').first().click();
+ }, 10);
+ }
+ }
+
+ function registerFuncControlsToggle() {
+ $funcLink.click(toggleFuncControls);
+ }
+
+ function registerFuncControlsActions() {
+ $funcControls.click(function (e) {
+ var $target = (0, _jquery2.default)(e.target);
+ if ($target.hasClass('fa-remove')) {
+ toggleFuncControls();
+ $scope.$apply(function () {
+ ctrl.removeFunction($scope.func);
+ });
+ return;
+ }
+
+ if ($target.hasClass('fa-arrow-left')) {
+ $scope.$apply(function () {
+ _lodash2.default.move($scope.target.functions, $scope.$index, $scope.$index - 1);
+ ctrl.targetChanged();
+ });
+ return;
+ }
+
+ if ($target.hasClass('fa-arrow-right')) {
+ $scope.$apply(function () {
+ _lodash2.default.move($scope.target.functions, $scope.$index, $scope.$index + 1);
+ ctrl.targetChanged();
+ });
+ return;
+ }
+
+ if ($target.hasClass('fa-question-circle')) {
+ var docSite = "http://docs.grafana-zabbix.org/reference/functions/";
+ window.open(docSite + '#' + funcDef.name.toLowerCase(), '_blank');
+ return;
+ }
+ });
+ }
+
+ function relink() {
+ elem.children().remove();
+
+ addElementsAndCompile();
+ ifJustAddedFocusFistParam();
+ registerFuncControlsToggle();
+ registerFuncControlsActions();
+ }
+
+ relink();
+ }
+ };
+});
diff --git a/dist/test/datasource-zabbix/metricFunctions.js b/dist/test/datasource-zabbix/metricFunctions.js
new file mode 100644
index 0000000..1a54a57
--- /dev/null
+++ b/dist/test/datasource-zabbix/metricFunctions.js
@@ -0,0 +1,292 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+exports.createFuncInstance = createFuncInstance;
+exports.getFuncDef = getFuncDef;
+exports.getCategories = getCategories;
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _jquery = require('jquery');
+
+var _jquery2 = _interopRequireDefault(_jquery);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var index = [];
+var categories = {
+ Transform: [],
+ Aggregate: [],
+ Filter: [],
+ Trends: [],
+ Time: [],
+ Alias: []
+};
+
+function addFuncDef(funcDef) {
+ funcDef.params = funcDef.params || [];
+ funcDef.defaultParams = funcDef.defaultParams || [];
+
+ if (funcDef.category) {
+ categories[funcDef.category].push(funcDef);
+ }
+ index[funcDef.name] = funcDef;
+ index[funcDef.shortName || funcDef.name] = funcDef;
+}
+
+// Transform
+
+addFuncDef({
+ name: 'groupBy',
+ category: 'Transform',
+ params: [{ name: 'interval', type: 'string' }, { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
+ defaultParams: ['1m', 'avg']
+});
+
+addFuncDef({
+ name: 'scale',
+ category: 'Transform',
+ params: [{ name: 'factor', type: 'float', options: [100, 0.01, 10, -1] }],
+ defaultParams: [100]
+});
+
+addFuncDef({
+ name: 'delta',
+ category: 'Transform',
+ params: [],
+ defaultParams: []
+});
+
+// Aggregate
+
+addFuncDef({
+ name: 'sumSeries',
+ category: 'Aggregate',
+ params: [],
+ defaultParams: []
+});
+
+addFuncDef({
+ name: 'median',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }],
+ defaultParams: ['1m']
+});
+
+addFuncDef({
+ name: 'average',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }],
+ defaultParams: ['1m']
+});
+
+addFuncDef({
+ name: 'min',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }],
+ defaultParams: ['1m']
+});
+
+addFuncDef({
+ name: 'max',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }],
+ defaultParams: ['1m']
+});
+
+addFuncDef({
+ name: 'aggregateBy',
+ category: 'Aggregate',
+ params: [{ name: 'interval', type: 'string' }, { name: 'function', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
+ defaultParams: ['1m', 'avg']
+});
+
+// Filter
+
+addFuncDef({
+ name: 'top',
+ category: 'Filter',
+ params: [{ name: 'number', type: 'int' }, { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
+ defaultParams: [5, 'avg']
+});
+
+addFuncDef({
+ name: 'bottom',
+ category: 'Filter',
+ params: [{ name: 'number', type: 'int' }, { name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }],
+ defaultParams: [5, 'avg']
+});
+
+// Trends
+
+addFuncDef({
+ name: 'trendValue',
+ category: 'Trends',
+ params: [{ name: 'type', type: 'string', options: ['avg', 'min', 'max'] }],
+ defaultParams: ['avg']
+});
+
+// Time
+
+addFuncDef({
+ name: 'timeShift',
+ category: 'Time',
+ params: [{ name: 'interval', type: 'string', options: ['24h', '7d', '1M', '+24h', '-24h'] }],
+ defaultParams: ['24h']
+});
+
+//Alias
+
+addFuncDef({
+ name: 'setAlias',
+ category: 'Alias',
+ params: [{ name: 'alias', type: 'string' }],
+ defaultParams: []
+});
+
+addFuncDef({
+ name: 'setAliasByRegex',
+ category: 'Alias',
+ params: [{ name: 'aliasByRegex', type: 'string' }],
+ defaultParams: []
+});
+
+_lodash2.default.each(categories, function (funcList, catName) {
+ categories[catName] = _lodash2.default.sortBy(funcList, 'name');
+});
+
+var FuncInstance = function () {
+ function FuncInstance(funcDef, params) {
+ _classCallCheck(this, FuncInstance);
+
+ this.def = funcDef;
+
+ if (params) {
+ this.params = params;
+ } else {
+ // Create with default params
+ this.params = [];
+ this.params = funcDef.defaultParams.slice(0);
+ }
+
+ this.updateText();
+ }
+
+ _createClass(FuncInstance, [{
+ key: 'bindFunction',
+ value: function bindFunction(metricFunctions) {
+ var func = metricFunctions[this.def.name];
+ if (func) {
+
+ // Bind function arguments
+ var bindedFunc = func;
+ var param;
+ for (var i = 0; i < this.params.length; i++) {
+ param = this.params[i];
+
+ // Convert numeric params
+ if (this.def.params[i].type === 'int' || this.def.params[i].type === 'float') {
+ param = Number(param);
+ }
+ bindedFunc = _lodash2.default.partial(bindedFunc, param);
+ }
+ return bindedFunc;
+ } else {
+ throw { message: 'Method not found ' + this.def.name };
+ }
+ }
+ }, {
+ key: 'render',
+ value: function render(metricExp) {
+ var str = this.def.name + '(';
+ var parameters = _lodash2.default.map(this.params, function (value, index) {
+
+ var paramType = this.def.params[index].type;
+ if (paramType === 'int' || paramType === 'float' || paramType === 'value_or_series' || paramType === 'boolean') {
+ return value;
+ } else if (paramType === 'int_or_interval' && _jquery2.default.isNumeric(value)) {
+ return value;
+ }
+
+ return "'" + value + "'";
+ }, this);
+
+ if (metricExp) {
+ parameters.unshift(metricExp);
+ }
+
+ return str + parameters.join(', ') + ')';
+ }
+ }, {
+ key: '_hasMultipleParamsInString',
+ value: function _hasMultipleParamsInString(strValue, index) {
+ if (strValue.indexOf(',') === -1) {
+ return false;
+ }
+
+ return this.def.params[index + 1] && this.def.params[index + 1].optional;
+ }
+ }, {
+ key: 'updateParam',
+ value: function updateParam(strValue, index) {
+ // handle optional parameters
+ // if string contains ',' and next param is optional, split and update both
+ if (this._hasMultipleParamsInString(strValue, index)) {
+ _lodash2.default.each(strValue.split(','), function (partVal, idx) {
+ this.updateParam(partVal.trim(), idx);
+ }, this);
+ return;
+ }
+
+ if (strValue === '' && this.def.params[index].optional) {
+ this.params.splice(index, 1);
+ } else {
+ this.params[index] = strValue;
+ }
+
+ this.updateText();
+ }
+ }, {
+ key: 'updateText',
+ value: function updateText() {
+ if (this.params.length === 0) {
+ this.text = this.def.name + '()';
+ return;
+ }
+
+ var text = this.def.name + '(';
+ text += this.params.join(', ');
+ text += ')';
+ this.text = text;
+ }
+ }]);
+
+ return FuncInstance;
+}();
+
+function createFuncInstance(funcDef, params) {
+ if (_lodash2.default.isString(funcDef)) {
+ if (!index[funcDef]) {
+ throw { message: 'Method not found ' + name };
+ }
+ funcDef = index[funcDef];
+ }
+ return new FuncInstance(funcDef, params);
+}
+
+function getFuncDef(name) {
+ return index[name];
+}
+
+function getCategories() {
+ return categories;
+}
diff --git a/dist/test/datasource-zabbix/migrations.js b/dist/test/datasource-zabbix/migrations.js
new file mode 100644
index 0000000..dc422c0
--- /dev/null
+++ b/dist/test/datasource-zabbix/migrations.js
@@ -0,0 +1,48 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.isGrafana2target = isGrafana2target;
+exports.migrateFrom2To3version = migrateFrom2To3version;
+exports.migrate = migrate;
+/**
+ * Query format migration.
+ * This module can detect query format version and make migration.
+ */
+
+function isGrafana2target(target) {
+ if (!target.mode || target.mode === 0 || target.mode === 2) {
+ if ((target.hostFilter || target.itemFilter || target.downsampleFunction || target.host && target.host.host) && target.item.filter === undefined && target.host.filter === undefined) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
+function migrateFrom2To3version(target) {
+ target.group.filter = target.group.name === "*" ? "/.*/" : target.group.name;
+ target.host.filter = target.host.name === "*" ? convertToRegex(target.hostFilter) : target.host.name;
+ target.application.filter = target.application.name === "*" ? "" : target.application.name;
+ target.item.filter = target.item.name === "All" ? convertToRegex(target.itemFilter) : target.item.name;
+ return target;
+}
+
+function migrate(target) {
+ if (isGrafana2target(target)) {
+ return migrateFrom2To3version(target);
+ } else {
+ return target;
+ }
+}
+
+function convertToRegex(str) {
+ if (str) {
+ return '/' + str + '/';
+ } else {
+ return '/.*/';
+ }
+}
diff --git a/dist/test/datasource-zabbix/module.js b/dist/test/datasource-zabbix/module.js
new file mode 100644
index 0000000..10f88d0
--- /dev/null
+++ b/dist/test/datasource-zabbix/module.js
@@ -0,0 +1,36 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.AnnotationsQueryCtrl = exports.QueryOptionsCtrl = exports.QueryCtrl = exports.ConfigCtrl = exports.Datasource = undefined;
+
+var _datasource = require('./datasource');
+
+var _query = require('./query.controller');
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var ZabbixConfigController = function ZabbixConfigController() {
+ _classCallCheck(this, ZabbixConfigController);
+};
+
+ZabbixConfigController.templateUrl = 'datasource-zabbix/partials/config.html';
+
+var ZabbixQueryOptionsController = function ZabbixQueryOptionsController() {
+ _classCallCheck(this, ZabbixQueryOptionsController);
+};
+
+ZabbixQueryOptionsController.templateUrl = 'datasource-zabbix/partials/query.options.html';
+
+var ZabbixAnnotationsQueryController = function ZabbixAnnotationsQueryController() {
+ _classCallCheck(this, ZabbixAnnotationsQueryController);
+};
+
+ZabbixAnnotationsQueryController.templateUrl = 'datasource-zabbix/partials/annotations.editor.html';
+
+exports.Datasource = _datasource.ZabbixAPIDatasource;
+exports.ConfigCtrl = ZabbixConfigController;
+exports.QueryCtrl = _query.ZabbixQueryController;
+exports.QueryOptionsCtrl = ZabbixQueryOptionsController;
+exports.AnnotationsQueryCtrl = ZabbixAnnotationsQueryController;
diff --git a/dist/test/datasource-zabbix/query.controller.js b/dist/test/datasource-zabbix/query.controller.js
new file mode 100644
index 0000000..24542f5
--- /dev/null
+++ b/dist/test/datasource-zabbix/query.controller.js
@@ -0,0 +1,378 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.ZabbixQueryController = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _sdk = require('app/plugins/sdk');
+
+var _angular = require('angular');
+
+var _angular2 = _interopRequireDefault(_angular);
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _utils = require('./utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+var _metricFunctions = require('./metricFunctions');
+
+var metricFunctions = _interopRequireWildcard(_metricFunctions);
+
+var _migrations = require('./migrations');
+
+var migrations = _interopRequireWildcard(_migrations);
+
+require('./add-metric-function.directive');
+
+require('./metric-function-editor.directive');
+
+require('./css/query-editor.css!');
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var ZabbixQueryController = exports.ZabbixQueryController = function (_QueryCtrl) {
+ _inherits(ZabbixQueryController, _QueryCtrl);
+
+ // ZabbixQueryCtrl constructor
+ function ZabbixQueryController($scope, $injector, $rootScope, $sce, templateSrv) {
+ _classCallCheck(this, ZabbixQueryController);
+
+ var _this = _possibleConstructorReturn(this, (ZabbixQueryController.__proto__ || Object.getPrototypeOf(ZabbixQueryController)).call(this, $scope, $injector));
+
+ _this.zabbix = _this.datasource.zabbix;
+
+ // Use custom format for template variables
+ _this.replaceTemplateVars = _this.datasource.replaceTemplateVars;
+ _this.templateSrv = templateSrv;
+
+ _this.editorModes = {
+ 0: { value: 'num', text: 'Metrics', mode: 0 },
+ 1: { value: 'itservice', text: 'IT Services', mode: 1 },
+ 2: { value: 'text', text: 'Text', mode: 2 }
+ };
+
+ // Map functions for bs-typeahead
+ _this.getGroupNames = _lodash2.default.partial(getMetricNames, _this, 'groupList');
+ _this.getHostNames = _lodash2.default.partial(getMetricNames, _this, 'hostList');
+ _this.getApplicationNames = _lodash2.default.partial(getMetricNames, _this, 'appList');
+ _this.getItemNames = _lodash2.default.partial(getMetricNames, _this, 'itemList');
+
+ // Update metric suggestion when template variable was changed
+ $rootScope.$on('template-variable-value-updated', function () {
+ return _this.onVariableChange();
+ });
+
+ // Update metrics when item selected from dropdown
+ $scope.$on('typeahead-updated', function () {
+ _this.onTargetBlur();
+ });
+
+ _this.init = function () {
+ var target = this.target;
+
+ // Migrate old targets
+ target = migrations.migrate(target);
+
+ var scopeDefaults = {
+ metric: {},
+ oldTarget: _lodash2.default.cloneDeep(this.target),
+ queryOptionsText: this.renderQueryOptionsText()
+ };
+ _lodash2.default.defaults(this, scopeDefaults);
+
+ // Load default values
+ var targetDefaults = {
+ mode: 0,
+ group: { filter: "" },
+ host: { filter: "" },
+ application: { filter: "" },
+ item: { filter: "" },
+ functions: [],
+ options: {
+ showDisabledItems: false
+ }
+ };
+ _lodash2.default.defaults(target, targetDefaults);
+
+ // Create function instances from saved JSON
+ target.functions = _lodash2.default.map(target.functions, function (func) {
+ return metricFunctions.createFuncInstance(func.def, func.params);
+ });
+
+ if (target.mode === 0 || target.mode === 2) {
+
+ this.downsampleFunctionList = [{ name: "avg", value: "avg" }, { name: "min", value: "min" }, { name: "max", value: "max" }];
+
+ this.initFilters();
+ } else if (target.mode === 1) {
+ this.slaPropertyList = [{ name: "Status", property: "status" }, { name: "SLA", property: "sla" }, { name: "OK time", property: "okTime" }, { name: "Problem time", property: "problemTime" }, { name: "Down time", property: "downtimeTime" }];
+ this.itserviceList = [{ name: "test" }];
+ this.updateITServiceList();
+ }
+ };
+
+ _this.init();
+ return _this;
+ }
+
+ _createClass(ZabbixQueryController, [{
+ key: 'initFilters',
+ value: function initFilters() {
+ var itemtype = this.editorModes[this.target.mode].value;
+ return Promise.all([this.suggestGroups(), this.suggestHosts(), this.suggestApps(), this.suggestItems(itemtype)]);
+ }
+ }, {
+ key: 'suggestGroups',
+ value: function suggestGroups() {
+ var _this2 = this;
+
+ return this.zabbix.getAllGroups().then(function (groups) {
+ _this2.metric.groupList = groups;
+ return groups;
+ });
+ }
+ }, {
+ key: 'suggestHosts',
+ value: function suggestHosts() {
+ var _this3 = this;
+
+ var groupFilter = this.replaceTemplateVars(this.target.group.filter);
+ return this.zabbix.getAllHosts(groupFilter).then(function (hosts) {
+ _this3.metric.hostList = hosts;
+ return hosts;
+ });
+ }
+ }, {
+ key: 'suggestApps',
+ value: function suggestApps() {
+ var _this4 = this;
+
+ var groupFilter = this.replaceTemplateVars(this.target.group.filter);
+ var hostFilter = this.replaceTemplateVars(this.target.host.filter);
+ return this.zabbix.getAllApps(groupFilter, hostFilter).then(function (apps) {
+ _this4.metric.appList = apps;
+ return apps;
+ });
+ }
+ }, {
+ key: 'suggestItems',
+ value: function suggestItems() {
+ var _this5 = this;
+
+ var itemtype = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'num';
+
+ var groupFilter = this.replaceTemplateVars(this.target.group.filter);
+ var hostFilter = this.replaceTemplateVars(this.target.host.filter);
+ var appFilter = this.replaceTemplateVars(this.target.application.filter);
+ var options = {
+ itemtype: itemtype,
+ showDisabledItems: this.target.options.showDisabledItems
+ };
+
+ return this.zabbix.getAllItems(groupFilter, hostFilter, appFilter, options).then(function (items) {
+ _this5.metric.itemList = items;
+ return items;
+ });
+ }
+ }, {
+ key: 'isRegex',
+ value: function isRegex(str) {
+ return utils.isRegex(str);
+ }
+ }, {
+ key: 'isVariable',
+ value: function isVariable(str) {
+ return utils.isTemplateVariable(str, this.templateSrv.variables);
+ }
+ }, {
+ key: 'onTargetBlur',
+ value: function onTargetBlur() {
+ var newTarget = _lodash2.default.cloneDeep(this.target);
+ if (!_lodash2.default.isEqual(this.oldTarget, this.target)) {
+ this.oldTarget = newTarget;
+ this.targetChanged();
+ }
+ }
+ }, {
+ key: 'onVariableChange',
+ value: function onVariableChange() {
+ if (this.isContainsVariables()) {
+ this.targetChanged();
+ }
+ }
+
+ /**
+ * Check query for template variables
+ */
+
+ }, {
+ key: 'isContainsVariables',
+ value: function isContainsVariables() {
+ var _this6 = this;
+
+ return _lodash2.default.some(['group', 'host', 'application'], function (field) {
+ if (_this6.target[field] && _this6.target[field].filter) {
+ return utils.isTemplateVariable(_this6.target[field].filter, _this6.templateSrv.variables);
+ } else {
+ return false;
+ }
+ });
+ }
+ }, {
+ key: 'parseTarget',
+ value: function parseTarget() {}
+ // Parse target
+
+
+ // Validate target and set validation info
+
+ }, {
+ key: 'validateTarget',
+ value: function validateTarget() {
+ // validate
+ }
+ }, {
+ key: 'targetChanged',
+ value: function targetChanged() {
+ this.initFilters();
+ this.parseTarget();
+ this.panelCtrl.refresh();
+ }
+ }, {
+ key: 'addFunction',
+ value: function addFunction(funcDef) {
+ var newFunc = metricFunctions.createFuncInstance(funcDef);
+ newFunc.added = true;
+ this.target.functions.push(newFunc);
+
+ this.moveAliasFuncLast();
+
+ if (newFunc.params.length && newFunc.added || newFunc.def.params.length === 0) {
+ this.targetChanged();
+ }
+ }
+ }, {
+ key: 'removeFunction',
+ value: function removeFunction(func) {
+ this.target.functions = _lodash2.default.without(this.target.functions, func);
+ this.targetChanged();
+ }
+ }, {
+ key: 'moveAliasFuncLast',
+ value: function moveAliasFuncLast() {
+ var aliasFunc = _lodash2.default.find(this.target.functions, function (func) {
+ return func.def.name === 'alias' || func.def.name === 'aliasByNode' || func.def.name === 'aliasByMetric';
+ });
+
+ if (aliasFunc) {
+ this.target.functions = _lodash2.default.without(this.target.functions, aliasFunc);
+ this.target.functions.push(aliasFunc);
+ }
+ }
+ }, {
+ key: 'toggleQueryOptions',
+ value: function toggleQueryOptions() {
+ this.showQueryOptions = !this.showQueryOptions;
+ }
+ }, {
+ key: 'onQueryOptionChange',
+ value: function onQueryOptionChange() {
+ this.queryOptionsText = this.renderQueryOptionsText();
+ this.onTargetBlur();
+ }
+ }, {
+ key: 'renderQueryOptionsText',
+ value: function renderQueryOptionsText() {
+ var optionsMap = {
+ showDisabledItems: "Show disabled items"
+ };
+ var options = [];
+ _lodash2.default.forOwn(this.target.options, function (value, key) {
+ if (value) {
+ if (value === true) {
+ // Show only option name (if enabled) for boolean options
+ options.push(optionsMap[key]);
+ } else {
+ // Show "option = value" for another options
+ options.push(optionsMap[key] + " = " + value);
+ }
+ }
+ });
+ return "Options: " + options.join(', ');
+ }
+
+ /**
+ * Switch query editor to specified mode.
+ * Modes:
+ * 0 - items
+ * 1 - IT services
+ * 2 - Text metrics
+ */
+
+ }, {
+ key: 'switchEditorMode',
+ value: function switchEditorMode(mode) {
+ this.target.mode = mode;
+ this.init();
+ }
+
+ /////////////////
+ // IT Services //
+ /////////////////
+
+ /**
+ * Update list of IT services
+ */
+
+ }, {
+ key: 'updateITServiceList',
+ value: function updateITServiceList() {
+ var _this7 = this;
+
+ this.zabbix.getITService().then(function (iteservices) {
+ _this7.itserviceList = [];
+ _this7.itserviceList = _this7.itserviceList.concat(iteservices);
+ });
+ }
+
+ /**
+ * Call when IT service is selected.
+ */
+
+ }, {
+ key: 'selectITService',
+ value: function selectITService() {
+ if (!_lodash2.default.isEqual(this.oldTarget, this.target) && _lodash2.default.isEmpty(this.target.errors)) {
+ this.oldTarget = _angular2.default.copy(this.target);
+ this.panelCtrl.refresh();
+ }
+ }
+ }]);
+
+ return ZabbixQueryController;
+}(_sdk.QueryCtrl);
+
+// Set templateUrl as static property
+
+
+ZabbixQueryController.templateUrl = 'datasource-zabbix/partials/query.editor.html';
+
+// Get list of metric names for bs-typeahead directive
+function getMetricNames(scope, metricList) {
+ return _lodash2.default.uniq(_lodash2.default.map(scope.metric[metricList], 'name'));
+}
diff --git a/dist/test/datasource-zabbix/responseHandler.js b/dist/test/datasource-zabbix/responseHandler.js
new file mode 100644
index 0000000..8bad6f4
--- /dev/null
+++ b/dist/test/datasource-zabbix/responseHandler.js
@@ -0,0 +1,116 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Convert Zabbix API history.get response to Grafana format
+ *
+ * @return {Array} Array of timeseries in Grafana format
+ * {
+ * target: "Metric name",
+ * datapoints: [[, ], ...]
+ * }
+ */
+function convertHistory(history, items, addHostName, convertPointCallback) {
+ /**
+ * Response should be in the format:
+ * data: [
+ * {
+ * target: "Metric name",
+ * datapoints: [[, ], ...]
+ * }, ...
+ * ]
+ */
+
+ // Group history by itemid
+ var grouped_history = _lodash2.default.groupBy(history, 'itemid');
+ var hosts = _lodash2.default.uniqBy(_lodash2.default.flatten(_lodash2.default.map(items, 'hosts')), 'hostid'); //uniqBy is needed to deduplicate
+
+ return _lodash2.default.map(grouped_history, function (hist, itemid) {
+ var item = _lodash2.default.find(items, { 'itemid': itemid });
+ var alias = item.name;
+ if (_lodash2.default.keys(hosts).length > 1 && addHostName) {
+ //only when actual multi hosts selected
+ var host = _lodash2.default.find(hosts, { 'hostid': item.hostid });
+ alias = host.name + ": " + alias;
+ }
+ return {
+ target: alias,
+ datapoints: _lodash2.default.map(hist, convertPointCallback)
+ };
+ });
+}
+
+function handleHistory(history, items) {
+ var addHostName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
+
+ return convertHistory(history, items, addHostName, convertHistoryPoint);
+}
+
+function handleTrends(history, items, valueType) {
+ var addHostName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
+
+ var convertPointCallback = _lodash2.default.partial(convertTrendPoint, valueType);
+ return convertHistory(history, items, addHostName, convertPointCallback);
+}
+
+function handleSLAResponse(itservice, slaProperty, slaObject) {
+ var targetSLA = slaObject[itservice.serviceid].sla[0];
+ if (slaProperty.property === 'status') {
+ var targetStatus = parseInt(slaObject[itservice.serviceid].status);
+ return {
+ target: itservice.name + ' ' + slaProperty.name,
+ datapoints: [[targetStatus, targetSLA.to * 1000]]
+ };
+ } else {
+ return {
+ target: itservice.name + ' ' + slaProperty.name,
+ datapoints: [[targetSLA[slaProperty.property], targetSLA.from * 1000], [targetSLA[slaProperty.property], targetSLA.to * 1000]]
+ };
+ }
+}
+
+function convertHistoryPoint(point) {
+ // Value must be a number for properly work
+ return [Number(point.value), point.clock * 1000];
+}
+
+function convertTrendPoint(valueType, point) {
+ var value;
+ switch (valueType) {
+ case "min":
+ value = point.value_min;
+ break;
+ case "max":
+ value = point.value_max;
+ break;
+ case "avg":
+ value = point.value_avg;
+ break;
+ default:
+ value = point.value_avg;
+ }
+
+ return [Number(value), point.clock * 1000];
+}
+
+exports.default = {
+ handleHistory: handleHistory,
+ convertHistory: convertHistory,
+ handleTrends: handleTrends,
+ handleSLAResponse: handleSLAResponse
+};
+
+// Fix for backward compatibility with lodash 2.4
+
+if (!_lodash2.default.uniqBy) {
+ _lodash2.default.uniqBy = _lodash2.default.uniq;
+}
diff --git a/dist/test/datasource-zabbix/specs/datasource_specs.js b/dist/test/datasource-zabbix/specs/datasource_specs.js
new file mode 100644
index 0000000..f34a105
--- /dev/null
+++ b/dist/test/datasource-zabbix/specs/datasource_specs.js
@@ -0,0 +1,317 @@
+"use strict";
+
+var _module = require("../module");
+
+var _datasource = require("../datasource");
+
+var _q = require("q");
+
+var _q2 = _interopRequireDefault(_q);
+
+var _sinon = require("sinon");
+
+var _sinon2 = _interopRequireDefault(_sinon);
+
+var _lodash = require("lodash");
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+describe('ZabbixDatasource', function () {
+ var ctx = {};
+ var defined = _sinon2.default.match.defined;
+
+ beforeEach(function () {
+ ctx.instanceSettings = {
+ jsonData: {
+ username: 'zabbix',
+ password: 'zabbix',
+ trends: true,
+ trendsFrom: '7d'
+ }
+ };
+ ctx.templateSrv = {};
+ ctx.alertSrv = {};
+ ctx.zabbix = function () {};
+
+ ctx.ds = new _module.Datasource(ctx.instanceSettings, ctx.templateSrv, ctx.alertSrv, ctx.zabbix);
+ });
+
+ describe('When querying data', function () {
+ beforeEach(function () {
+ ctx.ds.replaceTemplateVars = function (str) {
+ return str;
+ };
+ });
+
+ ctx.options = {
+ targets: [{
+ group: { filter: "" },
+ host: { filter: "" },
+ application: { filter: "" },
+ item: { filter: "" }
+ }],
+ range: { from: 'now-7d', to: 'now' }
+ };
+
+ it('should return an empty array when no targets are set', function (done) {
+ var options = {
+ targets: [],
+ range: { from: 'now-6h', to: 'now' }
+ };
+ ctx.ds.query(options).then(function (result) {
+ expect(result.data).to.have.length(0);
+ done();
+ });
+ });
+
+ it('should use trends if it enabled and time more than trendsFrom', function (done) {
+ var ranges = ['now-7d', 'now-168h', 'now-1M', 'now-1y'];
+
+ _lodash2.default.forEach(ranges, function (range) {
+ ctx.options.range.from = range;
+ ctx.ds.queryNumericData = _sinon2.default.spy();
+ ctx.ds.query(ctx.options);
+
+ // Check that useTrends options is true
+ expect(ctx.ds.queryNumericData).to.have.been.calledWith(defined, defined, defined, true);
+ });
+
+ done();
+ });
+
+ it('shouldnt use trends if it enabled and time less than trendsFrom', function (done) {
+ var ranges = ['now-6d', 'now-167h', 'now-1h', 'now-30m', 'now-30s'];
+
+ _lodash2.default.forEach(ranges, function (range) {
+ ctx.options.range.from = range;
+ ctx.ds.queryNumericData = _sinon2.default.spy();
+ ctx.ds.query(ctx.options);
+
+ // Check that useTrends options is false
+ expect(ctx.ds.queryNumericData).to.have.been.calledWith(defined, defined, defined, false);
+ });
+ done();
+ });
+ });
+
+ describe('When replacing template variables', function () {
+
+ function testReplacingVariable(target, varValue, expectedResult, done) {
+ ctx.ds.templateSrv.replace = function () {
+ return (0, _datasource.zabbixTemplateFormat)(varValue);
+ };
+
+ var result = ctx.ds.replaceTemplateVars(target);
+ expect(result).to.equal(expectedResult);
+ done();
+ }
+
+ /*
+ * Alphanumerics, spaces, dots, dashes and underscores
+ * are allowed in Zabbix host name.
+ * 'AaBbCc0123 .-_'
+ */
+ it('should return properly escaped regex', function (done) {
+ var target = '$host';
+ var template_var_value = 'AaBbCc0123 .-_';
+ var expected_result = '/^AaBbCc0123 \\.-_$/';
+
+ testReplacingVariable(target, template_var_value, expected_result, done);
+ });
+
+ /*
+ * Single-value variable
+ * $host = backend01
+ * $host => /^backend01|backend01$/
+ */
+ it('should return proper regex for single value', function (done) {
+ var target = '$host';
+ var template_var_value = 'backend01';
+ var expected_result = '/^backend01$/';
+
+ testReplacingVariable(target, template_var_value, expected_result, done);
+ });
+
+ /*
+ * Multi-value variable
+ * $host = [backend01, backend02]
+ * $host => /^(backend01|backend01)$/
+ */
+ it('should return proper regex for multi-value', function (done) {
+ var target = '$host';
+ var template_var_value = ['backend01', 'backend02'];
+ var expected_result = '/^(backend01|backend02)$/';
+
+ testReplacingVariable(target, template_var_value, expected_result, done);
+ });
+ });
+
+ describe('When invoking metricFindQuery()', function () {
+ beforeEach(function () {
+ ctx.ds.replaceTemplateVars = function (str) {
+ return str;
+ };
+ ctx.ds.zabbix = {
+ getGroups: function getGroups() {
+ return _q2.default.when([]);
+ },
+ getHosts: function getHosts() {
+ return _q2.default.when([]);
+ },
+ getApps: function getApps() {
+ return _q2.default.when([]);
+ },
+ getItems: function getItems() {
+ return _q2.default.when([]);
+ }
+ };
+ });
+
+ it('should return groups', function (done) {
+ var tests = [{ query: '*', expect: '/.*/' }, { query: '', expect: '' }, { query: 'Backend', expect: 'Backend' }, { query: 'Back*', expect: 'Back*' }];
+
+ var getGroups = _sinon2.default.spy(ctx.ds.zabbix, 'getGroups');
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = tests[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var test = _step.value;
+
+ ctx.ds.metricFindQuery(test.query);
+ expect(getGroups).to.have.been.calledWith(test.expect);
+ getGroups.reset();
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ done();
+ });
+
+ it('should return hosts', function (done) {
+ var tests = [{ query: '*.*', expect: '/.*/' }, { query: '.', expect: '' }, { query: 'Backend.*', expect: 'Backend' }, { query: 'Back*.', expect: 'Back*' }];
+
+ var getHosts = _sinon2.default.spy(ctx.ds.zabbix, 'getHosts');
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = tests[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var test = _step2.value;
+
+ ctx.ds.metricFindQuery(test.query);
+ expect(getHosts).to.have.been.calledWith(test.expect);
+ getHosts.reset();
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ done();
+ });
+
+ it('should return applications', function (done) {
+ var tests = [{ query: '*.*.*', expect: ['/.*/', '/.*/'] }, { query: '.*.', expect: ['', '/.*/'] }, { query: 'Backend.backend01.*', expect: ['Backend', 'backend01'] }, { query: 'Back*.*.', expect: ['Back*', '/.*/'] }];
+
+ var getApps = _sinon2.default.spy(ctx.ds.zabbix, 'getApps');
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = tests[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var test = _step3.value;
+
+ ctx.ds.metricFindQuery(test.query);
+ expect(getApps).to.have.been.calledWith(test.expect[0], test.expect[1]);
+ getApps.reset();
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ done();
+ });
+
+ it('should return items', function (done) {
+ var tests = [{ query: '*.*.*.*', expect: ['/.*/', '/.*/', ''] }, { query: '.*.*.*', expect: ['', '/.*/', ''] }, { query: 'Backend.backend01.*.*', expect: ['Backend', 'backend01', ''] }, { query: 'Back*.*.cpu.*', expect: ['Back*', '/.*/', 'cpu'] }];
+
+ var getItems = _sinon2.default.spy(ctx.ds.zabbix, 'getItems');
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = tests[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var test = _step4.value;
+
+ ctx.ds.metricFindQuery(test.query);
+ expect(getItems).to.have.been.calledWith(test.expect[0], test.expect[1], test.expect[2]);
+ getItems.reset();
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4.return) {
+ _iterator4.return();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ done();
+ });
+
+ it('should invoke method with proper arguments', function (done) {
+ var query = '*.*';
+
+ var getHosts = _sinon2.default.spy(ctx.ds.zabbix, 'getHosts');
+ ctx.ds.metricFindQuery(query);
+ expect(getHosts).to.have.been.calledWith('/.*/');
+ done();
+ });
+ });
+});
diff --git a/dist/test/datasource-zabbix/specs/modules/datemath.js b/dist/test/datasource-zabbix/specs/modules/datemath.js
new file mode 100644
index 0000000..063ad04
--- /dev/null
+++ b/dist/test/datasource-zabbix/specs/modules/datemath.js
@@ -0,0 +1,135 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.parse = parse;
+exports.isValid = isValid;
+exports.parseDateMath = parseDateMath;
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _moment = require('moment');
+
+var _moment2 = _interopRequireDefault(_moment);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var units = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
+
+function parse(text, roundUp) {
+ if (!text) {
+ return undefined;
+ }
+ if (_moment2.default.isMoment(text)) {
+ return text;
+ }
+ if (_lodash2.default.isDate(text)) {
+ return (0, _moment2.default)(text);
+ }
+
+ var time;
+ var mathString = '';
+ var index;
+ var parseString;
+
+ if (text.substring(0, 3) === 'now') {
+ time = (0, _moment2.default)();
+ mathString = text.substring('now'.length);
+ } else {
+ index = text.indexOf('||');
+ if (index === -1) {
+ parseString = text;
+ mathString = ''; // nothing else
+ } else {
+ parseString = text.substring(0, index);
+ mathString = text.substring(index + 2);
+ }
+ // We're going to just require ISO8601 timestamps, k?
+ time = (0, _moment2.default)(parseString, _moment2.default.ISO_8601);
+ }
+
+ if (!mathString.length) {
+ return time;
+ }
+
+ return parseDateMath(mathString, time, roundUp);
+}
+
+function isValid(text) {
+ var date = parse(text);
+ if (!date) {
+ return false;
+ }
+
+ if (_moment2.default.isMoment(date)) {
+ return date.isValid();
+ }
+
+ return false;
+}
+
+function parseDateMath(mathString, time, roundUp) {
+ var dateTime = time;
+ var i = 0;
+ var len = mathString.length;
+
+ while (i < len) {
+ var c = mathString.charAt(i++);
+ var type;
+ var num;
+ var unit;
+
+ if (c === '/') {
+ type = 0;
+ } else if (c === '+') {
+ type = 1;
+ } else if (c === '-') {
+ type = 2;
+ } else {
+ return undefined;
+ }
+
+ if (isNaN(mathString.charAt(i))) {
+ num = 1;
+ } else if (mathString.length === 2) {
+ num = mathString.charAt(i);
+ } else {
+ var numFrom = i;
+ while (!isNaN(mathString.charAt(i))) {
+ i++;
+ if (i > 10) {
+ return undefined;
+ }
+ }
+ num = parseInt(mathString.substring(numFrom, i), 10);
+ }
+
+ if (type === 0) {
+ // rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
+ if (num !== 1) {
+ return undefined;
+ }
+ }
+ unit = mathString.charAt(i++);
+
+ if (!_lodash2.default.includes(units, unit)) {
+ return undefined;
+ } else {
+ if (type === 0) {
+ if (roundUp) {
+ dateTime.endOf(unit);
+ } else {
+ dateTime.startOf(unit);
+ }
+ } else if (type === 1) {
+ dateTime.add(num, unit);
+ } else if (type === 2) {
+ dateTime.subtract(num, unit);
+ }
+ }
+ }
+ return dateTime;
+}
diff --git a/dist/test/datasource-zabbix/specs/test-main.js b/dist/test/datasource-zabbix/specs/test-main.js
new file mode 100644
index 0000000..a80d33a
--- /dev/null
+++ b/dist/test/datasource-zabbix/specs/test-main.js
@@ -0,0 +1,66 @@
+'use strict';
+
+var _prunk = require('prunk');
+
+var _prunk2 = _interopRequireDefault(_prunk);
+
+var _jsdom = require('jsdom');
+
+var _chai = require('chai');
+
+var _chai2 = _interopRequireDefault(_chai);
+
+var _sinonChai = require('sinon-chai');
+
+var _sinonChai2 = _interopRequireDefault(_sinonChai);
+
+var _datemath = require('./modules/datemath');
+
+var dateMath = _interopRequireWildcard(_datemath);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+// Mock angular module
+
+// import sinon from 'sinon';
+var angularMocks = {
+ module: function module() {
+ return {
+ directive: function directive() {},
+ service: function service() {},
+ factory: function factory() {}
+ };
+ }
+}; // JSHint options
+/* globals global: false */
+
+var datemathMock = {
+ parse: dateMath.parse,
+ parseDateMath: dateMath.parseDateMath,
+ isValid: dateMath.isValid
+};
+
+// Mock Grafana modules that are not available outside of the core project
+// Required for loading module.js
+_prunk2.default.mock('./css/query-editor.css!', 'no css, dude.');
+_prunk2.default.mock('app/plugins/sdk', {
+ QueryCtrl: null
+});
+_prunk2.default.mock('app/core/utils/datemath', datemathMock);
+_prunk2.default.mock('angular', angularMocks);
+_prunk2.default.mock('jquery', 'module not found');
+
+// Setup jsdom
+// Required for loading angularjs
+global.document = (0, _jsdom.jsdom)('');
+global.window = global.document.parentWindow;
+global.navigator = window.navigator = {};
+global.Node = window.Node;
+
+// Setup Chai
+_chai2.default.should();
+_chai2.default.use(_sinonChai2.default);
+global.assert = _chai2.default.assert;
+global.expect = _chai2.default.expect;
diff --git a/dist/test/datasource-zabbix/utils.js b/dist/test/datasource-zabbix/utils.js
new file mode 100644
index 0000000..36eceb9
--- /dev/null
+++ b/dist/test/datasource-zabbix/utils.js
@@ -0,0 +1,151 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.regexPattern = undefined;
+exports.expandItemName = expandItemName;
+exports.isRegex = isRegex;
+exports.isTemplateVariable = isTemplateVariable;
+exports.buildRegex = buildRegex;
+exports.escapeRegex = escapeRegex;
+exports.parseInterval = parseInterval;
+exports.parseTimeShiftInterval = parseTimeShiftInterval;
+exports.formatAcknowledges = formatAcknowledges;
+exports.convertToZabbixAPIUrl = convertToZabbixAPIUrl;
+exports.callOnce = callOnce;
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _moment = require('moment');
+
+var _moment2 = _interopRequireDefault(_moment);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Expand Zabbix item name
+ *
+ * @param {string} name item name, ie "CPU $2 time"
+ * @param {string} key item key, ie system.cpu.util[,system,avg1]
+ * @return {string} expanded name, ie "CPU system time"
+ */
+function expandItemName(name, key) {
+
+ // extract params from key:
+ // "system.cpu.util[,system,avg1]" --> ["", "system", "avg1"]
+ var key_params = key.substring(key.indexOf('[') + 1, key.lastIndexOf(']')).split(',');
+
+ // replace item parameters
+ for (var i = key_params.length; i >= 1; i--) {
+ name = name.replace('$' + i, key_params[i - 1]);
+ }
+ return name;
+}
+
+// Pattern for testing regex
+var regexPattern = exports.regexPattern = /^\/(.*)\/([gmi]*)$/m;
+
+function isRegex(str) {
+ return regexPattern.test(str);
+}
+
+function isTemplateVariable(str, templateVariables) {
+ var variablePattern = /^\$\w+/;
+ if (variablePattern.test(str)) {
+ var variables = _lodash2.default.map(templateVariables, function (variable) {
+ return '$' + variable.name;
+ });
+ return _lodash2.default.includes(variables, str);
+ } else {
+ return false;
+ }
+}
+
+function buildRegex(str) {
+ var matches = str.match(regexPattern);
+ var pattern = matches[1];
+ var flags = matches[2] !== "" ? matches[2] : undefined;
+ return new RegExp(pattern, flags);
+}
+
+// Need for template variables replace
+// From Grafana's templateSrv.js
+function escapeRegex(value) {
+ return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&');
+}
+
+function parseInterval(interval) {
+ var intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)/g;
+ var momentInterval = intervalPattern.exec(interval);
+ return _moment2.default.duration(Number(momentInterval[1]), momentInterval[2]).valueOf();
+}
+
+function parseTimeShiftInterval(interval) {
+ var intervalPattern = /^([\+\-]*)([\d]+)(y|M|w|d|h|m|s)/g;
+ var momentInterval = intervalPattern.exec(interval);
+ var duration = 0;
+
+ if (momentInterval[1] === '+') {
+ duration = 0 - _moment2.default.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();
+ } else {
+ duration = _moment2.default.duration(Number(momentInterval[2]), momentInterval[3]).valueOf();
+ }
+
+ return duration;
+}
+
+/**
+ * Format acknowledges.
+ *
+ * @param {array} acknowledges array of Zabbix acknowledge objects
+ * @return {string} HTML-formatted table
+ */
+function formatAcknowledges(acknowledges) {
+ if (acknowledges.length) {
+ var formatted_acknowledges = ' Acknowledges:Time ' + 'User Comments ';
+ _lodash2.default.each(_lodash2.default.map(acknowledges, function (ack) {
+ var timestamp = _moment2.default.unix(ack.clock);
+ return '' + timestamp.format("DD MMM YYYY HH:mm:ss") + ' ' + ack.alias + ' (' + ack.name + ' ' + ack.surname + ')' + ' ' + ack.message + ' ';
+ }), function (ack) {
+ formatted_acknowledges = formatted_acknowledges.concat(ack);
+ });
+ formatted_acknowledges = formatted_acknowledges.concat('
');
+ return formatted_acknowledges;
+ } else {
+ return '';
+ }
+}
+
+function convertToZabbixAPIUrl(url) {
+ var zabbixAPIUrlPattern = /.*api_jsonrpc.php$/;
+ var trimSlashPattern = /(.*?)[\/]*$/;
+ if (url.match(zabbixAPIUrlPattern)) {
+ return url;
+ } else {
+ return url.replace(trimSlashPattern, "$1");
+ }
+}
+
+/**
+ * Wrap function to prevent multiple calls
+ * when waiting for result.
+ */
+function callOnce(func, promiseKeeper) {
+ return function () {
+ if (!promiseKeeper) {
+ promiseKeeper = Promise.resolve(func.apply(this, arguments).then(function (result) {
+ promiseKeeper = null;
+ return result;
+ }));
+ }
+ return promiseKeeper;
+ };
+}
+
+// Fix for backward compatibility with lodash 2.4
+if (!_lodash2.default.includes) {
+ _lodash2.default.includes = _lodash2.default.contains;
+}
diff --git a/dist/test/datasource-zabbix/zabbix.js b/dist/test/datasource-zabbix/zabbix.js
new file mode 100644
index 0000000..627d107
--- /dev/null
+++ b/dist/test/datasource-zabbix/zabbix.js
@@ -0,0 +1,266 @@
+'use strict';
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _angular = require('angular');
+
+var _angular2 = _interopRequireDefault(_angular);
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _utils = require('./utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+require('./zabbixAPI.service.js');
+
+require('./zabbixCachingProxy.service.js');
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+// Use factory() instead service() for multiple data sources support.
+// Each Zabbix data source instance should initialize its own API instance.
+
+/** @ngInject */
+function ZabbixFactory(zabbixAPIService, ZabbixCachingProxy) {
+ var Zabbix = function () {
+ function Zabbix(url, username, password, basicAuth, withCredentials, cacheTTL) {
+ _classCallCheck(this, Zabbix);
+
+ // Initialize Zabbix API
+ var ZabbixAPI = zabbixAPIService;
+ this.zabbixAPI = new ZabbixAPI(url, username, password, basicAuth, withCredentials);
+
+ // Initialize caching proxy for requests
+ var cacheOptions = {
+ enabled: true,
+ ttl: cacheTTL
+ };
+ this.cachingProxy = new ZabbixCachingProxy(this.zabbixAPI, cacheOptions);
+
+ // Proxy methods
+ this.getHistory = this.cachingProxy.getHistory.bind(this.cachingProxy);
+
+ this.getTrend = this.zabbixAPI.getTrend.bind(this.zabbixAPI);
+ this.getEvents = this.zabbixAPI.getEvents.bind(this.zabbixAPI);
+ this.getAcknowledges = this.zabbixAPI.getAcknowledges.bind(this.zabbixAPI);
+ this.getITService = this.zabbixAPI.getITService.bind(this.zabbixAPI);
+ this.getSLA = this.zabbixAPI.getSLA.bind(this.zabbixAPI);
+ this.getVersion = this.zabbixAPI.getVersion.bind(this.zabbixAPI);
+ this.login = this.zabbixAPI.login.bind(this.zabbixAPI);
+ }
+
+ _createClass(Zabbix, [{
+ key: 'getItemsFromTarget',
+ value: function getItemsFromTarget(target, options) {
+ var parts = ['group', 'host', 'application', 'item'];
+ var filters = _lodash2.default.map(parts, function (p) {
+ return target[p].filter;
+ });
+ return this.getItems.apply(this, _toConsumableArray(filters).concat([options]));
+ }
+ }, {
+ key: 'getAllGroups',
+ value: function getAllGroups() {
+ return this.cachingProxy.getGroups();
+ }
+ }, {
+ key: 'getGroups',
+ value: function getGroups(groupFilter) {
+ return this.getAllGroups().then(function (groups) {
+ return findByFilter(groups, groupFilter);
+ });
+ }
+
+ /**
+ * Get list of host belonging to given groups.
+ */
+
+ }, {
+ key: 'getAllHosts',
+ value: function getAllHosts(groupFilter) {
+ var _this = this;
+
+ return this.getGroups(groupFilter).then(function (groups) {
+ var groupids = _lodash2.default.map(groups, 'groupid');
+ return _this.cachingProxy.getHosts(groupids);
+ });
+ }
+ }, {
+ key: 'getHosts',
+ value: function getHosts(groupFilter, hostFilter) {
+ return this.getAllHosts(groupFilter).then(function (hosts) {
+ return findByFilter(hosts, hostFilter);
+ });
+ }
+
+ /**
+ * Get list of applications belonging to given groups and hosts.
+ */
+
+ }, {
+ key: 'getAllApps',
+ value: function getAllApps(groupFilter, hostFilter) {
+ var _this2 = this;
+
+ return this.getHosts(groupFilter, hostFilter).then(function (hosts) {
+ var hostids = _lodash2.default.map(hosts, 'hostid');
+ return _this2.cachingProxy.getApps(hostids);
+ });
+ }
+ }, {
+ key: 'getApps',
+ value: function getApps(groupFilter, hostFilter, appFilter) {
+ var _this3 = this;
+
+ return this.getHosts(groupFilter, hostFilter).then(function (hosts) {
+ var hostids = _lodash2.default.map(hosts, 'hostid');
+ if (appFilter) {
+ return _this3.cachingProxy.getApps(hostids).then(function (apps) {
+ return filterByQuery(apps, appFilter);
+ });
+ } else {
+ return {
+ appFilterEmpty: true,
+ hostids: hostids
+ };
+ }
+ });
+ }
+ }, {
+ key: 'getAllItems',
+ value: function getAllItems(groupFilter, hostFilter, appFilter) {
+ var _this4 = this;
+
+ var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+
+ return this.getApps(groupFilter, hostFilter, appFilter).then(function (apps) {
+ if (apps.appFilterEmpty) {
+ return _this4.cachingProxy.getItems(apps.hostids, undefined, options.itemtype);
+ } else {
+ var appids = _lodash2.default.map(apps, 'applicationid');
+ return _this4.cachingProxy.getItems(undefined, appids, options.itemtype);
+ }
+ }).then(function (items) {
+ if (!options.showDisabledItems) {
+ items = _lodash2.default.filter(items, { 'status': '0' });
+ }
+ return items;
+ });
+ }
+ }, {
+ key: 'getItems',
+ value: function getItems(groupFilter, hostFilter, appFilter, itemFilter) {
+ var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
+
+ return this.getAllItems(groupFilter, hostFilter, appFilter, options).then(function (items) {
+ return filterByQuery(items, itemFilter);
+ });
+ }
+
+ /**
+ * Build query - convert target filters to array of Zabbix items
+ */
+
+ }, {
+ key: 'getTriggers',
+ value: function getTriggers(groupFilter, hostFilter, appFilter, showTriggers) {
+ var _this5 = this;
+
+ var promises = [this.getGroups(groupFilter), this.getHosts(groupFilter, hostFilter), this.getApps(groupFilter, hostFilter, appFilter)];
+
+ return Promise.all(promises).then(function (results) {
+ var filteredGroups = results[0];
+ var filteredHosts = results[1];
+ var filteredApps = results[2];
+ var query = {};
+
+ if (appFilter) {
+ query.applicationids = _lodash2.default.flatten(_lodash2.default.map(filteredApps, 'applicationid'));
+ }
+ if (hostFilter) {
+ query.hostids = _lodash2.default.map(filteredHosts, 'hostid');
+ }
+ if (groupFilter) {
+ query.groupids = _lodash2.default.map(filteredGroups, 'groupid');
+ }
+
+ return query;
+ }).then(function (query) {
+ return _this5.zabbixAPI.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers);
+ });
+ }
+ }]);
+
+ return Zabbix;
+ }();
+
+ return Zabbix;
+}
+
+_angular2.default.module('grafana.services').factory('Zabbix', ZabbixFactory);
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Find group, host, app or item by given name.
+ * @param list list of groups, apps or other
+ * @param name visible name
+ * @return array with finded element or undefined
+ */
+function findByName(list, name) {
+ var finded = _lodash2.default.find(list, { 'name': name });
+ if (finded) {
+ return [finded];
+ } else {
+ return undefined;
+ }
+}
+
+/**
+ * Different hosts can contains applications and items with same name.
+ * For this reason use _.filter, which return all elements instead _.find,
+ * which return only first finded.
+ * @param {[type]} list list of elements
+ * @param {[type]} name app name
+ * @return {[type]} array with finded element or undefined
+ */
+function filterByName(list, name) {
+ var finded = _lodash2.default.filter(list, { 'name': name });
+ if (finded) {
+ return finded;
+ } else {
+ return undefined;
+ }
+}
+
+function filterByRegex(list, regex) {
+ var filterPattern = utils.buildRegex(regex);
+ return _lodash2.default.filter(list, function (zbx_obj) {
+ return filterPattern.test(zbx_obj.name);
+ });
+}
+
+function findByFilter(list, filter) {
+ if (utils.isRegex(filter)) {
+ return filterByRegex(list, filter);
+ } else {
+ return findByName(list, filter);
+ }
+}
+
+function filterByQuery(list, filter) {
+ if (utils.isRegex(filter)) {
+ return filterByRegex(list, filter);
+ } else {
+ return filterByName(list, filter);
+ }
+}
diff --git a/dist/test/datasource-zabbix/zabbixAPI.service.js b/dist/test/datasource-zabbix/zabbixAPI.service.js
new file mode 100644
index 0000000..cd82a13
--- /dev/null
+++ b/dist/test/datasource-zabbix/zabbixAPI.service.js
@@ -0,0 +1,436 @@
+'use strict';
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _angular = require('angular');
+
+var _angular2 = _interopRequireDefault(_angular);
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _utils = require('./utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+require('./zabbixAPICore.service');
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+/** @ngInject */
+function ZabbixAPIServiceFactory(alertSrv, zabbixAPICoreService) {
+
+ /**
+ * Zabbix API Wrapper.
+ * Creates Zabbix API instance with given parameters (url, credentials and other).
+ * Wraps API calls and provides high-level methods.
+ */
+ var ZabbixAPI = function () {
+ function ZabbixAPI(api_url, username, password, basicAuth, withCredentials) {
+ _classCallCheck(this, ZabbixAPI);
+
+ this.url = api_url;
+ this.username = username;
+ this.password = password;
+ this.auth = "";
+
+ this.requestOptions = {
+ basicAuth: basicAuth,
+ withCredentials: withCredentials
+ };
+
+ this.loginPromise = null;
+ this.loginErrorCount = 0;
+ this.maxLoginAttempts = 3;
+
+ this.alertSrv = alertSrv;
+ this.zabbixAPICore = zabbixAPICoreService;
+
+ this.getTrend = this.getTrend_ZBXNEXT1193;
+ //getTrend = getTrend_30;
+ }
+
+ //////////////////////////
+ // Core method wrappers //
+ //////////////////////////
+
+ _createClass(ZabbixAPI, [{
+ key: 'request',
+ value: function request(method, params) {
+ var _this = this;
+
+ return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth).catch(function (error) {
+ if (isNotAuthorized(error.data)) {
+ // Handle auth errors
+ _this.loginErrorCount++;
+ if (_this.loginErrorCount > _this.maxLoginAttempts) {
+ _this.loginErrorCount = 0;
+ return null;
+ } else {
+ return _this.loginOnce().then(function () {
+ return _this.request(method, params);
+ });
+ }
+ } else {
+ // Handle API errors
+ var message = error.data ? error.data : error.statusText;
+ _this.alertAPIError(message);
+ }
+ });
+ }
+ }, {
+ key: 'alertAPIError',
+ value: function alertAPIError(message) {
+ var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5000;
+
+ this.alertSrv.set("Zabbix API Error", message, 'error', timeout);
+ }
+
+ /**
+ * When API unauthenticated or auth token expired each request produce login()
+ * call. But auth token is common to all requests. This function wraps login() method
+ * and call it once. If login() already called just wait for it (return its promise).
+ * @return login promise
+ */
+
+ }, {
+ key: 'loginOnce',
+ value: function loginOnce() {
+ var _this2 = this;
+
+ if (!this.loginPromise) {
+ this.loginPromise = Promise.resolve(this.login().then(function (auth) {
+ _this2.auth = auth;
+ _this2.loginPromise = null;
+ return auth;
+ }));
+ }
+ return this.loginPromise;
+ }
+
+ /**
+ * Get authentication token.
+ */
+
+ }, {
+ key: 'login',
+ value: function login() {
+ return this.zabbixAPICore.login(this.url, this.username, this.password, this.requestOptions);
+ }
+
+ /**
+ * Get Zabbix API version
+ */
+
+ }, {
+ key: 'getVersion',
+ value: function getVersion() {
+ return this.zabbixAPICore.getVersion(this.url, this.requestOptions);
+ }
+
+ ////////////////////////////////
+ // Zabbix API method wrappers //
+ ////////////////////////////////
+
+ }, {
+ key: 'acknowledgeEvent',
+ value: function acknowledgeEvent(eventid, message) {
+ var params = {
+ eventids: eventid,
+ message: message
+ };
+
+ return this.request('event.acknowledge', params);
+ }
+ }, {
+ key: 'getGroups',
+ value: function getGroups() {
+ var params = {
+ output: ['name'],
+ sortfield: 'name',
+ real_hosts: true
+ };
+
+ return this.request('hostgroup.get', params);
+ }
+ }, {
+ key: 'getHosts',
+ value: function getHosts(groupids) {
+ var params = {
+ output: ['name', 'host'],
+ sortfield: 'name'
+ };
+ if (groupids) {
+ params.groupids = groupids;
+ }
+
+ return this.request('host.get', params);
+ }
+ }, {
+ key: 'getApps',
+ value: function getApps(hostids) {
+ var params = {
+ output: ['applicationid', 'name'],
+ hostids: hostids
+ };
+
+ return this.request('application.get', params);
+ }
+
+ /**
+ * Get Zabbix items
+ * @param {[type]} hostids host ids
+ * @param {[type]} appids application ids
+ * @param {String} itemtype 'num' or 'text'
+ * @return {[type]} array of items
+ */
+
+ }, {
+ key: 'getItems',
+ value: function getItems(hostids, appids, itemtype) {
+ var params = {
+ output: ['name', 'key_', 'value_type', 'hostid', 'status', 'state'],
+ sortfield: 'name',
+ webitems: true,
+ filter: {},
+ selectHosts: ['hostid', 'name']
+ };
+ if (hostids) {
+ params.hostids = hostids;
+ }
+ if (appids) {
+ params.applicationids = appids;
+ }
+ if (itemtype === 'num') {
+ // Return only numeric metrics
+ params.filter.value_type = [0, 3];
+ }
+ if (itemtype === 'text') {
+ // Return only text metrics
+ params.filter.value_type = [1, 2, 4];
+ }
+
+ return this.request('item.get', params).then(expandItems);
+
+ function expandItems(items) {
+ items.forEach(function (item) {
+ item.item = item.name;
+ item.name = utils.expandItemName(item.item, item.key_);
+ return item;
+ });
+ return items;
+ }
+ }
+ }, {
+ key: 'getLastValue',
+ value: function getLastValue(itemid) {
+ var params = {
+ output: ['lastvalue'],
+ itemids: itemid
+ };
+ return this.request('item.get', params).then(function (items) {
+ return items.length ? items[0].lastvalue : null;
+ });
+ }
+
+ /**
+ * Perform history query from Zabbix API
+ *
+ * @param {Array} items Array of Zabbix item objects
+ * @param {Number} timeFrom Time in seconds
+ * @param {Number} timeTill Time in seconds
+ * @return {Array} Array of Zabbix history objects
+ */
+
+ }, {
+ key: 'getHistory',
+ value: function getHistory(items, timeFrom, timeTill) {
+ var _this3 = this;
+
+ // Group items by value type and perform request for each value type
+ var grouped_items = _lodash2.default.groupBy(items, 'value_type');
+ var promises = _lodash2.default.map(grouped_items, function (items, value_type) {
+ var itemids = _lodash2.default.map(items, 'itemid');
+ var params = {
+ output: 'extend',
+ history: value_type,
+ itemids: itemids,
+ sortfield: 'clock',
+ sortorder: 'ASC',
+ time_from: timeFrom
+ };
+
+ // Relative queries (e.g. last hour) don't include an end time
+ if (timeTill) {
+ params.time_till = timeTill;
+ }
+
+ return _this3.request('history.get', params);
+ });
+
+ return Promise.all(promises).then(_lodash2.default.flatten);
+ }
+
+ /**
+ * Perform trends query from Zabbix API
+ * Use trends api extension from ZBXNEXT-1193 patch.
+ *
+ * @param {Array} items Array of Zabbix item objects
+ * @param {Number} time_from Time in seconds
+ * @param {Number} time_till Time in seconds
+ * @return {Array} Array of Zabbix trend objects
+ */
+
+ }, {
+ key: 'getTrend_ZBXNEXT1193',
+ value: function getTrend_ZBXNEXT1193(items, timeFrom, timeTill) {
+ var _this4 = this;
+
+ // Group items by value type and perform request for each value type
+ var grouped_items = _lodash2.default.groupBy(items, 'value_type');
+ var promises = _lodash2.default.map(grouped_items, function (items, value_type) {
+ var itemids = _lodash2.default.map(items, 'itemid');
+ var params = {
+ output: 'extend',
+ trend: value_type,
+ itemids: itemids,
+ sortfield: 'clock',
+ sortorder: 'ASC',
+ time_from: timeFrom
+ };
+
+ // Relative queries (e.g. last hour) don't include an end time
+ if (timeTill) {
+ params.time_till = timeTill;
+ }
+
+ return _this4.request('trend.get', params);
+ });
+
+ return Promise.all(promises).then(_lodash2.default.flatten);
+ }
+ }, {
+ key: 'getTrend_30',
+ value: function getTrend_30(items, time_from, time_till, value_type) {
+ var self = this;
+ var itemids = _lodash2.default.map(items, 'itemid');
+
+ var params = {
+ output: ["itemid", "clock", value_type],
+ itemids: itemids,
+ time_from: time_from
+ };
+
+ // Relative queries (e.g. last hour) don't include an end time
+ if (time_till) {
+ params.time_till = time_till;
+ }
+
+ return self.request('trend.get', params);
+ }
+ }, {
+ key: 'getITService',
+ value: function getITService(serviceids) {
+ var params = {
+ output: 'extend',
+ serviceids: serviceids
+ };
+ return this.request('service.get', params);
+ }
+ }, {
+ key: 'getSLA',
+ value: function getSLA(serviceids, timeFrom, timeTo) {
+ var params = {
+ serviceids: serviceids,
+ intervals: [{
+ from: timeFrom,
+ to: timeTo
+ }]
+ };
+ return this.request('service.getsla', params);
+ }
+ }, {
+ key: 'getTriggers',
+ value: function getTriggers(groupids, hostids, applicationids, showTriggers, timeFrom, timeTo) {
+ var params = {
+ output: 'extend',
+ groupids: groupids,
+ hostids: hostids,
+ applicationids: applicationids,
+ expandDescription: true,
+ expandData: true,
+ expandComment: true,
+ monitored: true,
+ skipDependent: true,
+ //only_true: true,
+ filter: {
+ value: 1
+ },
+ selectGroups: ['name'],
+ selectHosts: ['name', 'host'],
+ selectItems: ['name', 'key_', 'lastvalue'],
+ selectLastEvent: 'extend'
+ };
+
+ if (showTriggers) {
+ params.filter.value = showTriggers;
+ }
+
+ if (timeFrom || timeTo) {
+ params.lastChangeSince = timeFrom;
+ params.lastChangeTill = timeTo;
+ }
+
+ return this.request('trigger.get', params);
+ }
+ }, {
+ key: 'getEvents',
+ value: function getEvents(objectids, timeFrom, timeTo, showEvents) {
+ var params = {
+ output: 'extend',
+ time_from: timeFrom,
+ time_till: timeTo,
+ objectids: objectids,
+ select_acknowledges: 'extend',
+ selectHosts: 'extend',
+ value: showEvents
+ };
+
+ return this.request('event.get', params);
+ }
+ }, {
+ key: 'getAcknowledges',
+ value: function getAcknowledges(eventids) {
+ var params = {
+ output: 'extend',
+ eventids: eventids,
+ preservekeys: true,
+ select_acknowledges: 'extend',
+ sortfield: 'clock',
+ sortorder: 'DESC'
+ };
+
+ return this.request('event.get', params).then(function (events) {
+ return _lodash2.default.filter(events, function (event) {
+ return event.acknowledges.length;
+ });
+ });
+ }
+ }]);
+
+ return ZabbixAPI;
+ }();
+
+ return ZabbixAPI;
+}
+
+function isNotAuthorized(message) {
+ return message === "Session terminated, re-login, please." || message === "Not authorised." || message === "Not authorized.";
+}
+
+_angular2.default.module('grafana.services').factory('zabbixAPIService', ZabbixAPIServiceFactory);
diff --git a/dist/test/datasource-zabbix/zabbixAPICore.service.js b/dist/test/datasource-zabbix/zabbixAPICore.service.js
new file mode 100644
index 0000000..075f149
--- /dev/null
+++ b/dist/test/datasource-zabbix/zabbixAPICore.service.js
@@ -0,0 +1,142 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.ZabbixAPIError = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * General Zabbix API methods
+ */
+
+var _angular = require('angular');
+
+var _angular2 = _interopRequireDefault(_angular);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var ZabbixAPICoreService = function () {
+
+ /** @ngInject */
+ function ZabbixAPICoreService(backendSrv) {
+ _classCallCheck(this, ZabbixAPICoreService);
+
+ this.backendSrv = backendSrv;
+ }
+
+ /**
+ * Request data from Zabbix API
+ * @return {object} response.result
+ */
+
+
+ _createClass(ZabbixAPICoreService, [{
+ key: 'request',
+ value: function request(api_url, method, params, options, auth) {
+ var requestData = {
+ jsonrpc: '2.0',
+ method: method,
+ params: params,
+ id: 1
+ };
+
+ if (auth === "") {
+ // Reject immediately if not authenticated
+ return Promise.reject(new ZabbixAPIError({ data: "Not authorised." }));
+ } else if (auth) {
+ // Set auth parameter only if it needed
+ requestData.auth = auth;
+ }
+
+ var requestOptions = {
+ method: 'POST',
+ url: api_url,
+ data: requestData,
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ };
+
+ // Set request options for basic auth
+ if (options.basicAuth || options.withCredentials) {
+ requestOptions.withCredentials = true;
+ }
+ if (options.basicAuth) {
+ requestOptions.headers.Authorization = options.basicAuth;
+ }
+
+ return this.datasourceRequest(requestOptions);
+ }
+ }, {
+ key: 'datasourceRequest',
+ value: function datasourceRequest(requestOptions) {
+ return this.backendSrv.datasourceRequest(requestOptions).then(function (response) {
+ if (!response.data) {
+ return Promise.reject(new ZabbixAPIError({ data: "General Error, no data" }));
+ } else if (response.data.error) {
+
+ // Handle Zabbix API errors
+ return Promise.reject(new ZabbixAPIError(response.data.error));
+ }
+
+ // Success
+ return response.data.result;
+ });
+ }
+
+ /**
+ * Get authentication token.
+ * @return {string} auth token
+ */
+
+ }, {
+ key: 'login',
+ value: function login(api_url, username, password, options) {
+ var params = {
+ user: username,
+ password: password
+ };
+ return this.request(api_url, 'user.login', params, options, null);
+ }
+
+ /**
+ * Get Zabbix API version
+ * Matches the version of Zabbix starting from Zabbix 2.0.4
+ */
+
+ }, {
+ key: 'getVersion',
+ value: function getVersion(api_url, options) {
+ return this.request(api_url, 'apiinfo.version', [], options);
+ }
+ }]);
+
+ return ZabbixAPICoreService;
+}();
+
+// Define zabbix API exception type
+
+
+var ZabbixAPIError = exports.ZabbixAPIError = function () {
+ function ZabbixAPIError(error) {
+ _classCallCheck(this, ZabbixAPIError);
+
+ this.code = error.code;
+ this.name = error.data;
+ this.message = error.data;
+ this.data = error.data;
+ }
+
+ _createClass(ZabbixAPIError, [{
+ key: 'toString',
+ value: function toString() {
+ return this.name + ": " + this.message;
+ }
+ }]);
+
+ return ZabbixAPIError;
+}();
+
+_angular2.default.module('grafana.services').service('zabbixAPICoreService', ZabbixAPICoreService);
diff --git a/dist/test/datasource-zabbix/zabbixCachingProxy.service.js b/dist/test/datasource-zabbix/zabbixCachingProxy.service.js
new file mode 100644
index 0000000..a378045
--- /dev/null
+++ b/dist/test/datasource-zabbix/zabbixCachingProxy.service.js
@@ -0,0 +1,215 @@
+'use strict';
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _angular = require('angular');
+
+var _angular2 = _interopRequireDefault(_angular);
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+// Use factory() instead service() for multiple datasources support.
+// Each datasource instance must initialize its own cache.
+
+/** @ngInject */
+function ZabbixCachingProxyFactory() {
+ var ZabbixCachingProxy = function () {
+ function ZabbixCachingProxy(zabbixAPI, cacheOptions) {
+ _classCallCheck(this, ZabbixCachingProxy);
+
+ this.zabbixAPI = zabbixAPI;
+ this.cacheEnabled = cacheOptions.enabled;
+ this.ttl = cacheOptions.ttl || 600000; // 10 minutes by default
+
+ // Internal objects for data storing
+ this.cache = {
+ groups: {},
+ hosts: {},
+ applications: {},
+ items: {},
+ history: {},
+ trends: {}
+ };
+
+ this.historyPromises = {};
+
+ // Don't run duplicated history requests
+ this.getHistory = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getHistory, this.zabbixAPI), this.historyPromises, getHistoryRequestHash);
+
+ // Don't run duplicated requests
+ this.groupPromises = {};
+ this.getGroupsOnce = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getGroups, this.zabbixAPI), this.groupPromises, getRequestHash);
+
+ this.hostPromises = {};
+ this.getHostsOnce = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getHosts, this.zabbixAPI), this.hostPromises, getRequestHash);
+
+ this.appPromises = {};
+ this.getAppsOnce = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getApps, this.zabbixAPI), this.appPromises, getRequestHash);
+
+ this.itemPromises = {};
+ this.getItemsOnce = callAPIRequestOnce(_lodash2.default.bind(this.zabbixAPI.getItems, this.zabbixAPI), this.itemPromises, getRequestHash);
+ }
+
+ _createClass(ZabbixCachingProxy, [{
+ key: 'isExpired',
+ value: function isExpired(cacheObject) {
+ if (cacheObject) {
+ var object_age = Date.now() - cacheObject.timestamp;
+ return !(cacheObject.timestamp && object_age < this.ttl);
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Check that result is present in cache and up to date
+ * or send request to API.
+ */
+
+ }, {
+ key: 'proxyRequest',
+ value: function proxyRequest(request, params, cacheObject) {
+ var hash = getRequestHash(params);
+ if (this.cacheEnabled && !this.isExpired(cacheObject[hash])) {
+ return Promise.resolve(cacheObject[hash].value);
+ } else {
+ return request.apply(undefined, _toConsumableArray(params)).then(function (result) {
+ cacheObject[hash] = {
+ value: result,
+ timestamp: Date.now()
+ };
+ return result;
+ });
+ }
+ }
+ }, {
+ key: 'getGroups',
+ value: function getGroups() {
+ return this.proxyRequest(this.getGroupsOnce, [], this.cache.groups);
+ }
+ }, {
+ key: 'getHosts',
+ value: function getHosts(groupids) {
+ return this.proxyRequest(this.getHostsOnce, [groupids], this.cache.hosts);
+ }
+ }, {
+ key: 'getApps',
+ value: function getApps(hostids) {
+ return this.proxyRequest(this.getAppsOnce, [hostids], this.cache.applications);
+ }
+ }, {
+ key: 'getItems',
+ value: function getItems(hostids, appids, itemtype) {
+ var params = [hostids, appids, itemtype];
+ return this.proxyRequest(this.getItemsOnce, params, this.cache.items);
+ }
+ }, {
+ key: 'getHistoryFromCache',
+ value: function getHistoryFromCache(items, time_from, time_till) {
+ var historyStorage = this.cache.history;
+ var full_history;
+ var expired = _lodash2.default.filter(_lodash2.default.keyBy(items, 'itemid'), function (item, itemid) {
+ return !historyStorage[itemid];
+ });
+ if (expired.length) {
+ return this.zabbixAPI.getHistory(expired, time_from, time_till).then(function (history) {
+ var grouped_history = _lodash2.default.groupBy(history, 'itemid');
+ _lodash2.default.forEach(expired, function (item) {
+ var itemid = item.itemid;
+ historyStorage[itemid] = item;
+ historyStorage[itemid].time_from = time_from;
+ historyStorage[itemid].time_till = time_till;
+ historyStorage[itemid].history = grouped_history[itemid];
+ });
+ full_history = _lodash2.default.map(items, function (item) {
+ return historyStorage[item.itemid].history;
+ });
+ return _lodash2.default.flatten(full_history, true);
+ });
+ } else {
+ full_history = _lodash2.default.map(items, function (item) {
+ return historyStorage[item.itemid].history;
+ });
+ return Promise.resolve(_lodash2.default.flatten(full_history, true));
+ }
+ }
+ }, {
+ key: 'getHistoryFromAPI',
+ value: function getHistoryFromAPI(items, time_from, time_till) {
+ return this.zabbixAPI.getHistory(items, time_from, time_till);
+ }
+ }]);
+
+ return ZabbixCachingProxy;
+ }();
+
+ return ZabbixCachingProxy;
+}
+
+_angular2.default.module('grafana.services').factory('ZabbixCachingProxy', ZabbixCachingProxyFactory);
+
+/**
+ * Wrap zabbix API request to prevent multiple calls
+ * with same params when waiting for result.
+ */
+function callAPIRequestOnce(func, promiseKeeper, argsHashFunc) {
+ return function () {
+ var hash = argsHashFunc(arguments);
+ if (!promiseKeeper[hash]) {
+ promiseKeeper[hash] = Promise.resolve(func.apply(this, arguments).then(function (result) {
+ promiseKeeper[hash] = null;
+ return result;
+ }));
+ }
+ return promiseKeeper[hash];
+ };
+}
+
+function getRequestHash(args) {
+ var requestStamp = _lodash2.default.map(args, function (arg) {
+ if (arg === undefined) {
+ return 'undefined';
+ } else {
+ if (_lodash2.default.isArray(arg)) {
+ return arg.sort().toString();
+ } else {
+ return arg.toString();
+ }
+ }
+ }).join();
+ return requestStamp.getHash();
+}
+
+function getHistoryRequestHash(args) {
+ var itemids = _lodash2.default.map(args[0], 'itemid');
+ var stamp = itemids.join() + args[1] + args[2];
+ return stamp.getHash();
+}
+
+String.prototype.getHash = function () {
+ var hash = 0,
+ i,
+ chr,
+ len;
+ if (this.length !== 0) {
+ for (i = 0, len = this.length; i < len; i++) {
+ chr = this.charCodeAt(i);
+ hash = (hash << 5) - hash + chr;
+ hash |= 0; // Convert to 32bit integer
+ }
+ }
+ return hash;
+};
+
+// Fix for backward compatibility with lodash 2.4
+if (!_lodash2.default.keyBy) {
+ _lodash2.default.keyBy = _lodash2.default.indexBy;
+}
diff --git a/dist/test/module.js b/dist/test/module.js
new file mode 100644
index 0000000..ac26ed7
--- /dev/null
+++ b/dist/test/module.js
@@ -0,0 +1,10 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.ConfigCtrl = undefined;
+
+var _config = require('./components/config');
+
+exports.ConfigCtrl = _config.ZabbixAppConfigCtrl;
diff --git a/dist/test/panel-triggers/ack-tooltip.directive.js b/dist/test/panel-triggers/ack-tooltip.directive.js
new file mode 100644
index 0000000..e74683e
--- /dev/null
+++ b/dist/test/panel-triggers/ack-tooltip.directive.js
@@ -0,0 +1,122 @@
+'use strict';
+
+var _angular = require('angular');
+
+var _angular2 = _interopRequireDefault(_angular);
+
+var _jquery = require('jquery');
+
+var _jquery2 = _interopRequireDefault(_jquery);
+
+var _tetherDrop = require('tether-drop');
+
+var _tetherDrop2 = _interopRequireDefault(_tetherDrop);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/** @ngInject */
+_angular2.default.module('grafana.directives').directive('ackTooltip', function ($sanitize, $compile) {
+ var buttonTemplate = ' ';
+
+ return {
+ scope: {
+ ack: "=",
+ trigger: "=",
+ onAck: "=",
+ context: "="
+ },
+ link: function link(scope, element) {
+ var acknowledges = scope.ack;
+ var $button = (0, _jquery2.default)(buttonTemplate);
+ $button.appendTo(element);
+
+ $button.click(function () {
+ var tooltip = '';
+
+ if (acknowledges && acknowledges.length) {
+ tooltip += '
' + 'Time ' + 'User ' + '' + ' ';
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = acknowledges[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var ack = _step.value;
+
+ tooltip += '' + ack.time + ' ' + '' + ack.user + ' ' + '' + ack.message + ' ';
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ tooltip += '
';
+ } else {
+ tooltip += 'Add acknowledge';
+ }
+
+ var addAckButtonTemplate = '
' + '' + ' ' + '
';
+ tooltip += addAckButtonTemplate;
+ tooltip += '
';
+
+ var drop = new _tetherDrop2.default({
+ 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);
+
+ (0, _jquery2.default)('#add-acknowledge-btn').on('click', onAddAckButtonClick);
+
+ function onAddAckButtonClick() {
+ var inputTemplate = '' + ' ' + '' + 'Acknowledge ' + '' + 'Cancel' + '
';
+
+ var $input = (0, _jquery2.default)(inputTemplate);
+ var $addAckButton = (0, _jquery2.default)('.ack-tooltip .ack-add-button');
+ $addAckButton.replaceWith($input);
+ (0, _jquery2.default)('.ack-tooltip #cancel-ack-button').on('click', onAckCancelButtonClick);
+ (0, _jquery2.default)('.ack-tooltip #send-ack-button').on('click', onAckSendlButtonClick);
+ }
+
+ function onAckCancelButtonClick() {
+ (0, _jquery2.default)('.ack-tooltip .ack-input-group').replaceWith(addAckButtonTemplate);
+ (0, _jquery2.default)('#add-acknowledge-btn').on('click', onAddAckButtonClick);
+ }
+
+ function onAckSendlButtonClick() {
+ var message = (0, _jquery2.default)('.ack-tooltip #ack-message')[0].value;
+ var onAck = scope.onAck.bind(scope.context);
+ onAck(scope.trigger, message).then(function () {
+ closeDrop();
+ });
+ }
+
+ function closeDrop() {
+ setTimeout(function () {
+ drop.destroy();
+ });
+ }
+ });
+
+ $compile(element.contents())(scope);
+ }
+ };
+});
diff --git a/dist/test/panel-triggers/editor.js b/dist/test/panel-triggers/editor.js
new file mode 100644
index 0000000..ceb50a8
--- /dev/null
+++ b/dist/test/panel-triggers/editor.js
@@ -0,0 +1,225 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * Grafana-Zabbix
+ * Zabbix plugin for Grafana.
+ * http://github.com/alexanderzobnin/grafana-zabbix
+ *
+ * Trigger panel.
+ * This feature sponsored by CORE IT
+ * http://www.coreit.fr
+ *
+ * Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com
+ * Licensed under the Apache License, Version 2.0
+ */
+
+exports.triggerPanelEditor = triggerPanelEditor;
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _utils = require('../datasource-zabbix/utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+require('../datasource-zabbix/css/query-editor.css!');
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var TriggerPanelEditorCtrl = function () {
+
+ /** @ngInject */
+ function TriggerPanelEditorCtrl($scope, $rootScope, uiSegmentSrv, datasourceSrv, templateSrv, popoverSrv) {
+ var _this = this;
+
+ _classCallCheck(this, TriggerPanelEditorCtrl);
+
+ $scope.editor = this;
+ this.panelCtrl = $scope.ctrl;
+ this.panel = this.panelCtrl.panel;
+
+ this.datasourceSrv = datasourceSrv;
+ this.templateSrv = templateSrv;
+ this.popoverSrv = popoverSrv;
+
+ // Map functions for bs-typeahead
+ this.getGroupNames = _lodash2.default.partial(getMetricNames, this, 'groupList');
+ this.getHostNames = _lodash2.default.partial(getMetricNames, this, 'hostList');
+ this.getApplicationNames = _lodash2.default.partial(getMetricNames, this, 'appList');
+
+ // Update metric suggestion when template variable was changed
+ $rootScope.$on('template-variable-value-updated', function () {
+ return _this.onVariableChange();
+ });
+
+ 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
+ var scopeDefaults = {
+ metric: {},
+ inputStyles: {},
+ oldTarget: _lodash2.default.cloneDeep(this.panel.triggers)
+ };
+ _lodash2.default.defaults(this, scopeDefaults);
+
+ // Set default datasource
+ this.datasources = _lodash2.default.map(this.getZabbixDataSources(), 'name');
+ if (!this.panel.datasource) {
+ this.panel.datasource = this.datasources[0];
+ }
+ // Load datasource
+ this.datasourceSrv.get(this.panel.datasource).then(function (datasource) {
+ _this.datasource = datasource;
+ _this.zabbix = datasource.zabbix;
+ _this.queryBuilder = datasource.queryBuilder;
+ _this.initFilters();
+ _this.panelCtrl.refresh();
+ });
+ }
+
+ _createClass(TriggerPanelEditorCtrl, [{
+ key: 'initFilters',
+ value: function initFilters() {
+ return Promise.all([this.suggestGroups(), this.suggestHosts(), this.suggestApps()]);
+ }
+ }, {
+ key: 'suggestGroups',
+ value: function suggestGroups() {
+ var _this2 = this;
+
+ return this.zabbix.getAllGroups().then(function (groups) {
+ _this2.metric.groupList = groups;
+ return groups;
+ });
+ }
+ }, {
+ key: 'suggestHosts',
+ value: function suggestHosts() {
+ var _this3 = this;
+
+ var groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);
+ return this.zabbix.getAllHosts(groupFilter).then(function (hosts) {
+ _this3.metric.hostList = hosts;
+ return hosts;
+ });
+ }
+ }, {
+ key: 'suggestApps',
+ value: function suggestApps() {
+ var _this4 = this;
+
+ var groupFilter = this.datasource.replaceTemplateVars(this.panel.triggers.group.filter);
+ var hostFilter = this.datasource.replaceTemplateVars(this.panel.triggers.host.filter);
+ return this.zabbix.getAllApps(groupFilter, hostFilter).then(function (apps) {
+ _this4.metric.appList = apps;
+ return apps;
+ });
+ }
+ }, {
+ key: 'onVariableChange',
+ value: function onVariableChange() {
+ if (this.isContainsVariables()) {
+ this.targetChanged();
+ }
+ }
+
+ /**
+ * Check query for template variables
+ */
+
+ }, {
+ key: 'isContainsVariables',
+ value: function isContainsVariables() {
+ var _this5 = this;
+
+ return _lodash2.default.some(['group', 'host', 'application'], function (field) {
+ return utils.isTemplateVariable(_this5.panel.triggers[field].filter, _this5.templateSrv.variables);
+ });
+ }
+ }, {
+ key: 'targetChanged',
+ value: function targetChanged() {
+ this.initFilters();
+ this.panelCtrl.refresh();
+ }
+ }, {
+ key: 'parseTarget',
+ value: function parseTarget() {
+ this.initFilters();
+ var newTarget = _lodash2.default.cloneDeep(this.panel.triggers);
+ if (!_lodash2.default.isEqual(this.oldTarget, this.panel.triggers)) {
+ this.oldTarget = newTarget;
+ this.panelCtrl.refresh();
+ }
+ }
+ }, {
+ key: 'refreshTriggerSeverity',
+ value: function refreshTriggerSeverity() {
+ _lodash2.default.each(this.triggerList, function (trigger) {
+ trigger.color = this.panel.triggerSeverity[trigger.priority].color;
+ trigger.severity = this.panel.triggerSeverity[trigger.priority].severity;
+ });
+ this.panelCtrl.refresh();
+ }
+ }, {
+ key: 'datasourceChanged',
+ value: function datasourceChanged() {
+ this.panelCtrl.refresh();
+ }
+ }, {
+ key: 'changeTriggerSeverityColor',
+ value: function changeTriggerSeverityColor(trigger, color) {
+ this.panel.triggerSeverity[trigger.priority].color = color;
+ this.refreshTriggerSeverity();
+ }
+ }, {
+ key: 'isRegex',
+ value: function isRegex(str) {
+ return utils.isRegex(str);
+ }
+ }, {
+ key: 'isVariable',
+ value: function isVariable(str) {
+ return utils.isTemplateVariable(str, this.templateSrv.variables);
+ }
+ }, {
+ key: 'getZabbixDataSources',
+ value: function getZabbixDataSources() {
+ var ZABBIX_DS_ID = 'alexanderzobnin-zabbix-datasource';
+ return _lodash2.default.filter(this.datasourceSrv.getMetricSources(), function (datasource) {
+ return datasource.meta.id === ZABBIX_DS_ID && datasource.value;
+ });
+ }
+ }]);
+
+ return TriggerPanelEditorCtrl;
+}();
+
+// Get list of metric names for bs-typeahead directive
+
+
+function getMetricNames(scope, metricList) {
+ return _lodash2.default.uniq(_lodash2.default.map(scope.metric[metricList], 'name'));
+}
+
+function triggerPanelEditor() {
+ return {
+ restrict: 'E',
+ scope: true,
+ templateUrl: 'public/plugins/alexanderzobnin-zabbix-app/panel-triggers/editor.html',
+ controller: TriggerPanelEditorCtrl
+ };
+}
diff --git a/dist/test/panel-triggers/module.js b/dist/test/panel-triggers/module.js
new file mode 100644
index 0000000..c1542a4
--- /dev/null
+++ b/dist/test/panel-triggers/module.js
@@ -0,0 +1,302 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PanelCtrl = exports.TriggerPanelCtrl = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _moment = require('moment');
+
+var _moment2 = _interopRequireDefault(_moment);
+
+var _utils = require('../datasource-zabbix/utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+var _sdk = require('app/plugins/sdk');
+
+var _editor = require('./editor');
+
+require('./ack-tooltip.directive');
+
+require('./css/panel_triggers.css!');
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+ * Grafana-Zabbix
+ * Zabbix plugin for Grafana.
+ * http://github.com/alexanderzobnin/grafana-zabbix
+ *
+ * Trigger panel.
+ * This feature sponsored by CORE IT
+ * http://www.coreit.fr
+ *
+ * Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com
+ * Licensed under the Apache License, Version 2.0
+ */
+
+var defaultSeverity = [{ priority: 0, severity: 'Not classified', color: '#B7DBAB', show: true }, { priority: 1, severity: 'Information', color: '#82B5D8', show: true }, { priority: 2, severity: 'Warning', color: '#E5AC0E', show: true }, { priority: 3, severity: 'Average', color: '#C15C17', show: true }, { priority: 4, severity: 'High', color: '#BF1B00', show: true }, { priority: 5, severity: 'Disaster', color: '#890F02', show: true }];
+
+var panelDefaults = {
+ datasource: null,
+ triggers: {
+ group: { filter: "" },
+ host: { filter: "" },
+ application: { filter: "" },
+ trigger: { filter: "" }
+ },
+ hostField: true,
+ statusField: false,
+ severityField: false,
+ lastChangeField: true,
+ ageField: true,
+ infoField: true,
+ limit: 10,
+ showTriggers: 'all triggers',
+ 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)'
+};
+
+var triggerStatusMap = {
+ '0': 'OK',
+ '1': 'Problem'
+};
+
+var defaultTimeFormat = "DD MMM YYYY HH:mm:ss";
+
+var TriggerPanelCtrl = function (_MetricsPanelCtrl) {
+ _inherits(TriggerPanelCtrl, _MetricsPanelCtrl);
+
+ /** @ngInject */
+ function TriggerPanelCtrl($scope, $injector, $element, datasourceSrv, templateSrv, contextSrv) {
+ _classCallCheck(this, TriggerPanelCtrl);
+
+ var _this = _possibleConstructorReturn(this, (TriggerPanelCtrl.__proto__ || Object.getPrototypeOf(TriggerPanelCtrl)).call(this, $scope, $injector));
+
+ _this.datasourceSrv = datasourceSrv;
+ _this.templateSrv = templateSrv;
+ _this.contextSrv = contextSrv;
+ _this.triggerStatusMap = triggerStatusMap;
+ _this.defaultTimeFormat = defaultTimeFormat;
+
+ // 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();
+ return _this;
+ }
+
+ /**
+ * Override onInitMetricsPanelEditMode() method from MetricsPanelCtrl.
+ * We don't need metric editor from Metrics Panel.
+ */
+
+
+ _createClass(TriggerPanelCtrl, [{
+ key: 'onInitMetricsPanelEditMode',
+ value: function onInitMetricsPanelEditMode() {
+ 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;
+ }
+
+ this.refreshData();
+ }
+ }, {
+ key: 'refreshData',
+ value: function refreshData() {
+ // clear loading/error state
+ delete this.error;
+ this.loading = true;
+ this.setTimeQueryStart();
+
+ 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;
+
+ // 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);
+ 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;
+ });
+ });
+ });
+ }
+ }, {
+ key: 'switchComment',
+ value: function switchComment(trigger) {
+ trigger.showComment = !trigger.showComment;
+ }
+ }, {
+ 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 TriggerPanelCtrl;
+}(_sdk.MetricsPanelCtrl);
+
+TriggerPanelCtrl.templateUrl = 'panel-triggers/module.html';
+
+function filterTriggers(triggers, triggerFilter) {
+ if (utils.isRegex(triggerFilter)) {
+ return _lodash2.default.filter(triggers, function (trigger) {
+ return utils.buildRegex(triggerFilter).test(trigger.description);
+ });
+ } else {
+ return _lodash2.default.filter(triggers, function (trigger) {
+ return trigger.description === triggerFilter;
+ });
+ }
+}
+
+exports.TriggerPanelCtrl = TriggerPanelCtrl;
+exports.PanelCtrl = TriggerPanelCtrl;