Бунин Олег Александрович
2018-04-19 17:40:08 +03:00
parent f0a5e7de8d
commit e78387fcb0
72 changed files with 4110 additions and 4005 deletions

2
.gitignore vendored
View File

@@ -3,6 +3,8 @@
.idea/ .idea/
.vscode .vscode
grafana-zabbix.iml
package-lock.json
*.bat *.bat

44
dist/README.md vendored
View File

@@ -1,22 +1,22 @@
# Zabbix plugin for Grafana # Zabbix plugin for Grafana
[![GitHub version](https://badge.fury.io/gh/alexanderzobnin%2Fgrafana-zabbix.svg)](https://github.com/alexanderzobnin/grafana-zabbix/releases) [![GitHub version](https://badge.fury.io/gh/alexanderzobnin%2Fgrafana-zabbix.svg)](https://github.com/alexanderzobnin/grafana-zabbix/releases)
[![Change Log](https://img.shields.io/badge/change-log-blue.svg?style=flat)](https://github.com/alexanderzobnin/grafana-zabbix/blob/master/CHANGELOG.md) [![Change Log](https://img.shields.io/badge/change-log-blue.svg?style=flat)](https://github.com/alexanderzobnin/grafana-zabbix/blob/master/CHANGELOG.md)
[![Docs](https://img.shields.io/badge/docs-latest-red.svg?style=flat)](http://docs.grafana-zabbix.org) [![Docs](https://img.shields.io/badge/docs-latest-red.svg?style=flat)](http://docs.grafana-zabbix.org)
Visualize your Zabbix metrics with the leading open source software for time series analytics. Visualize your Zabbix metrics with the leading open source software for time series analytics.
### Live Demo ### Live Demo
See all features overview and dashboards examples at Grafana-Zabbix [Live demo](http://play.grafana-zabbix.org) site. See all features overview and dashboards examples at Grafana-Zabbix [Live demo](http://play.grafana-zabbix.org) site.
### Features ### Features
- Select multiple metrics [by using Regex](http://docs.grafana-zabbix.org/guides/gettingstarted/#multiple-items-on-one-graph) - Select multiple metrics [by using Regex](http://docs.grafana-zabbix.org/guides/gettingstarted/#multiple-items-on-one-graph)
- Create interactive and reusable dashboards with [template variables](http://docs.grafana-zabbix.org/guides/templating/) - Create interactive and reusable dashboards with [template variables](http://docs.grafana-zabbix.org/guides/templating/)
- Show events on graphs with [Annotations](http://docs.grafana.org/reference/annotations/) - Show events on graphs with [Annotations](http://docs.grafana.org/reference/annotations/)
- Display active problems with Triggers panel - Display active problems with Triggers panel
- Transform and shape your data with [metric processing functions](http://docs.grafana-zabbix.org/reference/functions/) (Avg, Median, Min, Max, Multiply, Summarize, Time shift, Alias) - Transform and shape your data with [metric processing functions](http://docs.grafana-zabbix.org/reference/functions/) (Avg, Median, Min, Max, Multiply, Summarize, Time shift, Alias)
- Find problems faster with [Alerting](http://docs.grafana-zabbix.org/reference/alerting/) feature - Find problems faster with [Alerting](http://docs.grafana-zabbix.org/reference/alerting/) feature
- Mix metrics from multiple data sources in the same dashboard or even graph - Mix metrics from multiple data sources in the same dashboard or even graph
- Discover and share [dashboards](https://grafana.com/dashboards) in the official library - Discover and share [dashboards](https://grafana.com/dashboards) in the official library

View File

@@ -1 +1 @@
<h3 class="page-heading">Zabbix Plugin Config</h3> <h3 class="page-heading">Zabbix Plugin Config</h3>

View File

@@ -1 +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"]} {"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 {\r\n constructor() { }\r\n}\r\nZabbixAppConfigCtrl.templateUrl = 'components/config.html';\r\n"]}

View File

@@ -9,6 +9,6 @@
"../../src/sass/_panel-triggers.scss", "../../src/sass/_panel-triggers.scss",
"../../src/sass/_query_editor.scss" "../../src/sass/_query_editor.scss"
], ],
"mappings": "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", "names": [],
"names": [] "mappings": "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"
} }

View File

@@ -9,6 +9,6 @@
"../../src/sass/_panel-triggers.scss", "../../src/sass/_panel-triggers.scss",
"../../src/sass/_query_editor.scss" "../../src/sass/_query_editor.scss"
], ],
"mappings": "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", "names": [],
"names": [] "mappings": "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"
} }

View File

@@ -1,447 +1,447 @@
{ {
"__inputs": [ "__inputs": [
{ {
"name": "DS_NAME", "name": "DS_NAME",
"type": "datasource", "type": "datasource",
"pluginId": "alexanderzobnin-zabbix-datasource" "pluginId": "alexanderzobnin-zabbix-datasource"
} }
], ],
"title": "Zabbix Template Linux Server", "title": "Zabbix Template Linux Server",
"revision": 1, "revision": 1,
"annotations": { "annotations": {
"list": [] "list": []
}, },
"editable": true, "editable": true,
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"hideControls": false, "hideControls": false,
"id": null, "id": null,
"links": [], "links": [],
"rows": [ "rows": [
{ {
"collapse": false, "collapse": false,
"height": "250px", "height": "250px",
"panels": [ "panels": [
{ {
"aliasColors": { "aliasColors": {
"CPU iowait time": "#B7DBAB", "CPU iowait time": "#B7DBAB",
"CPU system time": "#BF1B00", "CPU system time": "#BF1B00",
"CPU user time": "#EAB839" "CPU user time": "#EAB839"
}, },
"bars": false, "bars": false,
"dashLength": 10, "dashLength": 10,
"dashes": false, "dashes": false,
"datasource": "${DS_NAME}", "datasource": "${DS_NAME}",
"editable": true, "editable": true,
"error": false, "error": false,
"fill": 3, "fill": 3,
"grid": {}, "grid": {},
"id": 1, "id": 1,
"legend": { "legend": {
"avg": false, "avg": false,
"current": false, "current": false,
"max": false, "max": false,
"min": false, "min": false,
"show": true, "show": true,
"total": false, "total": false,
"values": false "values": false
}, },
"lines": true, "lines": true,
"linewidth": 1, "linewidth": 1,
"links": [], "links": [],
"nullPointMode": "connected", "nullPointMode": "connected",
"percentage": false, "percentage": false,
"pointradius": 2, "pointradius": 2,
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"seriesOverrides": [], "seriesOverrides": [],
"spaceLength": 10, "spaceLength": 10,
"span": 6, "span": 6,
"stack": true, "stack": true,
"steppedLine": false, "steppedLine": false,
"targets": [ "targets": [
{ {
"application": { "application": {
"filter": "CPU" "filter": "CPU"
}, },
"countTriggers": true, "countTriggers": true,
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
}, },
"host": { "host": {
"filter": "$host" "filter": "$host"
}, },
"item": { "item": {
"filter": "/CPU/" "filter": "/CPU/"
}, },
"minSeverity": 3, "minSeverity": 3,
"mode": 0, "mode": 0,
"options": { "options": {
"showDisabledItems": false "showDisabledItems": false
}, },
"refId": "A" "refId": "A"
} }
], ],
"thresholds": [], "thresholds": [],
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "CPU", "title": "CPU",
"tooltip": { "tooltip": {
"msResolution": false, "msResolution": false,
"shared": true, "shared": true,
"sort": 0, "sort": 0,
"value_type": "individual" "value_type": "individual"
}, },
"type": "graph", "type": "graph",
"xaxis": { "xaxis": {
"buckets": null, "buckets": null,
"mode": "time", "mode": "time",
"name": null, "name": null,
"show": true, "show": true,
"values": [] "values": []
}, },
"yaxes": [ "yaxes": [
{ {
"format": "percent", "format": "percent",
"logBase": 1, "logBase": 1,
"max": 100, "max": 100,
"min": 0, "min": 0,
"show": true "show": true
}, },
{ {
"format": "short", "format": "short",
"logBase": 1, "logBase": 1,
"max": null, "max": null,
"min": null, "min": null,
"show": true "show": true
} }
] ]
}, },
{ {
"aliasColors": { "aliasColors": {
"Processor load (1 min average per core)": "#1F78C1" "Processor load (1 min average per core)": "#1F78C1"
}, },
"bars": false, "bars": false,
"dashLength": 10, "dashLength": 10,
"dashes": false, "dashes": false,
"datasource": "${DS_NAME}", "datasource": "${DS_NAME}",
"editable": true, "editable": true,
"error": false, "error": false,
"fill": 1, "fill": 1,
"grid": {}, "grid": {},
"id": 2, "id": 2,
"legend": { "legend": {
"avg": false, "avg": false,
"current": false, "current": false,
"max": false, "max": false,
"min": false, "min": false,
"show": true, "show": true,
"total": false, "total": false,
"values": false "values": false
}, },
"lines": true, "lines": true,
"linewidth": 2, "linewidth": 2,
"links": [], "links": [],
"nullPointMode": "connected", "nullPointMode": "connected",
"percentage": false, "percentage": false,
"pointradius": 5, "pointradius": 5,
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"seriesOverrides": [], "seriesOverrides": [],
"spaceLength": 10, "spaceLength": 10,
"span": 6, "span": 6,
"stack": false, "stack": false,
"steppedLine": false, "steppedLine": false,
"targets": [ "targets": [
{ {
"application": { "application": {
"filter": "CPU" "filter": "CPU"
}, },
"countTriggers": true, "countTriggers": true,
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
}, },
"host": { "host": {
"filter": "$host" "filter": "$host"
}, },
"item": { "item": {
"filter": "Processor load (15 min average per core)" "filter": "Processor load (15 min average per core)"
}, },
"minSeverity": 3, "minSeverity": 3,
"mode": 0, "mode": 0,
"options": { "options": {
"showDisabledItems": false "showDisabledItems": false
}, },
"refId": "A" "refId": "A"
} }
], ],
"thresholds": [], "thresholds": [],
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "System load", "title": "System load",
"tooltip": { "tooltip": {
"msResolution": false, "msResolution": false,
"shared": true, "shared": true,
"sort": 0, "sort": 0,
"value_type": "cumulative" "value_type": "cumulative"
}, },
"type": "graph", "type": "graph",
"xaxis": { "xaxis": {
"buckets": null, "buckets": null,
"mode": "time", "mode": "time",
"name": null, "name": null,
"show": true, "show": true,
"values": [] "values": []
}, },
"yaxes": [ "yaxes": [
{ {
"format": "short", "format": "short",
"logBase": 1, "logBase": 1,
"max": null, "max": null,
"min": 0, "min": 0,
"show": true "show": true
}, },
{ {
"format": "short", "format": "short",
"logBase": 1, "logBase": 1,
"max": null, "max": null,
"min": null, "min": null,
"show": true "show": true
} }
] ]
} }
], ],
"repeat": null, "repeat": null,
"repeatIteration": null, "repeatIteration": null,
"repeatRowId": null, "repeatRowId": null,
"showTitle": true, "showTitle": true,
"title": "CPU", "title": "CPU",
"titleSize": "h6" "titleSize": "h6"
}, },
{ {
"collapse": false, "collapse": false,
"height": "250px", "height": "250px",
"panels": [ "panels": [
{ {
"aliasColors": {}, "aliasColors": {},
"bars": false, "bars": false,
"dashLength": 10, "dashLength": 10,
"dashes": false, "dashes": false,
"datasource": "${DS_NAME}", "datasource": "${DS_NAME}",
"editable": true, "editable": true,
"error": false, "error": false,
"fill": 3, "fill": 3,
"grid": {}, "grid": {},
"id": 3, "id": 3,
"legend": { "legend": {
"alignAsTable": false, "alignAsTable": false,
"avg": false, "avg": false,
"current": false, "current": false,
"max": false, "max": false,
"min": false, "min": false,
"rightSide": false, "rightSide": false,
"show": true, "show": true,
"total": false, "total": false,
"values": false "values": false
}, },
"lines": true, "lines": true,
"linewidth": 2, "linewidth": 2,
"links": [], "links": [],
"minSpan": 4, "minSpan": 4,
"nullPointMode": "connected", "nullPointMode": "connected",
"percentage": false, "percentage": false,
"pointradius": 5, "pointradius": 5,
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"repeat": "netif", "repeat": "netif",
"seriesOverrides": [ "seriesOverrides": [
{ {
"alias": "/Incoming/", "alias": "/Incoming/",
"transform": "negative-Y" "transform": "negative-Y"
} }
], ],
"spaceLength": 10, "spaceLength": 10,
"span": 12, "span": 12,
"stack": false, "stack": false,
"steppedLine": false, "steppedLine": false,
"targets": [ "targets": [
{ {
"application": { "application": {
"filter": "" "filter": ""
}, },
"countTriggers": true, "countTriggers": true,
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
}, },
"host": { "host": {
"filter": "$host" "filter": "$host"
}, },
"item": { "item": {
"filter": "/$netif/" "filter": "/$netif/"
}, },
"minSeverity": 3, "minSeverity": 3,
"mode": 0, "mode": 0,
"options": { "options": {
"showDisabledItems": false "showDisabledItems": false
}, },
"refId": "A" "refId": "A"
} }
], ],
"thresholds": [], "thresholds": [],
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "Network traffic on $netif", "title": "Network traffic on $netif",
"tooltip": { "tooltip": {
"msResolution": false, "msResolution": false,
"shared": true, "shared": true,
"sort": 0, "sort": 0,
"value_type": "cumulative" "value_type": "cumulative"
}, },
"type": "graph", "type": "graph",
"xaxis": { "xaxis": {
"buckets": null, "buckets": null,
"mode": "time", "mode": "time",
"name": null, "name": null,
"show": true, "show": true,
"values": [] "values": []
}, },
"yaxes": [ "yaxes": [
{ {
"format": "bps", "format": "bps",
"logBase": 1, "logBase": 1,
"max": null, "max": null,
"min": null, "min": null,
"show": true "show": true
}, },
{ {
"format": "short", "format": "short",
"logBase": 1, "logBase": 1,
"max": null, "max": null,
"min": null, "min": null,
"show": true "show": true
} }
] ]
} }
], ],
"repeat": null, "repeat": null,
"repeatIteration": null, "repeatIteration": null,
"repeatRowId": null, "repeatRowId": null,
"showTitle": true, "showTitle": true,
"title": "Network", "title": "Network",
"titleSize": "h6" "titleSize": "h6"
} }
], ],
"schemaVersion": 14, "schemaVersion": 14,
"style": "dark", "style": "dark",
"tags": [ "tags": [
"zabbix", "zabbix",
"example" "example"
], ],
"templating": { "templating": {
"list": [ "list": [
{ {
"allFormat": "regex values", "allFormat": "regex values",
"allValue": null, "allValue": null,
"current": {}, "current": {},
"datasource": "${DS_NAME}", "datasource": "${DS_NAME}",
"hide": 0, "hide": 0,
"includeAll": false, "includeAll": false,
"label": "Group", "label": "Group",
"multi": false, "multi": false,
"multiFormat": "glob", "multiFormat": "glob",
"name": "group", "name": "group",
"options": [], "options": [],
"query": "*", "query": "*",
"refresh": 1, "refresh": 1,
"refresh_on_load": false, "refresh_on_load": false,
"regex": "", "regex": "",
"sort": 0, "sort": 0,
"tagValuesQuery": "", "tagValuesQuery": "",
"tags": [], "tags": [],
"tagsQuery": "", "tagsQuery": "",
"type": "query", "type": "query",
"useTags": false "useTags": false
}, },
{ {
"allFormat": "glob", "allFormat": "glob",
"allValue": null, "allValue": null,
"current": {}, "current": {},
"datasource": "${DS_NAME}", "datasource": "${DS_NAME}",
"hide": 0, "hide": 0,
"includeAll": false, "includeAll": false,
"label": "Host", "label": "Host",
"multi": false, "multi": false,
"multiFormat": "glob", "multiFormat": "glob",
"name": "host", "name": "host",
"options": [], "options": [],
"query": "$group.*", "query": "$group.*",
"refresh": 1, "refresh": 1,
"refresh_on_load": false, "refresh_on_load": false,
"regex": "", "regex": "",
"sort": 0, "sort": 0,
"tagValuesQuery": "", "tagValuesQuery": "",
"tags": [], "tags": [],
"tagsQuery": "", "tagsQuery": "",
"type": "query", "type": "query",
"useTags": false "useTags": false
}, },
{ {
"allFormat": "regex values", "allFormat": "regex values",
"allValue": null, "allValue": null,
"current": {}, "current": {},
"datasource": "${DS_NAME}", "datasource": "${DS_NAME}",
"hide": 0, "hide": 0,
"hideLabel": false, "hideLabel": false,
"includeAll": true, "includeAll": true,
"label": "Network interface", "label": "Network interface",
"multi": true, "multi": true,
"multiFormat": "regex values", "multiFormat": "regex values",
"name": "netif", "name": "netif",
"options": [], "options": [],
"query": "*.$host.Network interfaces.*", "query": "*.$host.Network interfaces.*",
"refresh": 1, "refresh": 1,
"refresh_on_load": false, "refresh_on_load": false,
"regex": "/(?:Incoming|Outgoing) network traffic on (.*)/", "regex": "/(?:Incoming|Outgoing) network traffic on (.*)/",
"sort": 0, "sort": 0,
"tagValuesQuery": "", "tagValuesQuery": "",
"tags": [], "tags": [],
"tagsQuery": "", "tagsQuery": "",
"type": "query", "type": "query",
"useTags": false "useTags": false
} }
] ]
}, },
"time": { "time": {
"from": "now-3h", "from": "now-3h",
"to": "now" "to": "now"
}, },
"timepicker": { "timepicker": {
"now": true, "now": true,
"refresh_intervals": [ "refresh_intervals": [
"30s", "30s",
"1m", "1m",
"5m", "5m",
"15m", "15m",
"30m", "30m",
"1h", "1h",
"3h", "3h",
"2h", "2h",
"1d" "1d"
], ],
"time_options": [ "time_options": [
"5m", "5m",
"15m", "15m",
"1h", "1h",
"6h", "6h",
"12h", "12h",
"24h", "24h",
"2d", "2d",
"7d", "7d",
"30d" "30d"
] ]
}, },
"timezone": "browser" "timezone": "browser"
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,370 +1,370 @@
{ {
"__inputs": [ "__inputs": [
{ {
"name": "DS_NAME", "name": "DS_NAME",
"type": "datasource", "type": "datasource",
"pluginId": "alexanderzobnin-zabbix-datasource" "pluginId": "alexanderzobnin-zabbix-datasource"
} }
], ],
"title": "Zabbix System Status", "title": "Zabbix System Status",
"revision": "1.0", "revision": "1.0",
"annotations": { "annotations": {
"list": [] "list": []
}, },
"editable": true, "editable": true,
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"hideControls": false, "hideControls": false,
"id": null, "id": null,
"links": [], "links": [],
"rows": [ "rows": [
{ {
"collapse": false, "collapse": false,
"height": 250, "height": 250,
"panels": [ "panels": [
{ {
"columns": [], "columns": [],
"datasource": "${DS_NAME}", "datasource": "${DS_NAME}",
"fontSize": "100%", "fontSize": "100%",
"id": 9, "id": 9,
"links": [], "links": [],
"pageSize": null, "pageSize": null,
"scroll": true, "scroll": true,
"showHeader": true, "showHeader": true,
"sort": { "sort": {
"col": 0, "col": 0,
"desc": true "desc": true
}, },
"span": 12, "span": 12,
"styles": [ "styles": [
{ {
"alias": "Time", "alias": "Time",
"dateFormat": "YYYY-MM-DD HH:mm:ss", "dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "Time", "pattern": "Time",
"type": "date" "type": "date"
}, },
{ {
"alias": "", "alias": "",
"colorMode": "cell", "colorMode": "cell",
"colors": [ "colors": [
"rgba(45, 172, 121, 0.97)", "rgba(45, 172, 121, 0.97)",
"rgba(45, 172, 121, 0.97)", "rgba(45, 172, 121, 0.97)",
"#58140c" "#58140c"
], ],
"dateFormat": "YYYY-MM-DD HH:mm:ss", "dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0, "decimals": 0,
"pattern": "Disaster", "pattern": "Disaster",
"thresholds": [ "thresholds": [
"0", "0",
"1" "1"
], ],
"type": "number", "type": "number",
"unit": "none" "unit": "none"
}, },
{ {
"alias": "", "alias": "",
"colorMode": "cell", "colorMode": "cell",
"colors": [ "colors": [
"#99440a", "#99440a",
"rgba(45, 172, 121, 0.97)", "rgba(45, 172, 121, 0.97)",
"#99440a" "#99440a"
], ],
"dateFormat": "YYYY-MM-DD HH:mm:ss", "dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0, "decimals": 0,
"pattern": "High", "pattern": "High",
"thresholds": [ "thresholds": [
"0", "0",
"1" "1"
], ],
"type": "number", "type": "number",
"unit": "short" "unit": "short"
}, },
{ {
"alias": "", "alias": "",
"colorMode": "cell", "colorMode": "cell",
"colors": [ "colors": [
"rgba(50, 172, 45, 0.97)", "rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)", "rgba(45, 172, 121, 0.97)",
"#c15c17" "#c15c17"
], ],
"dateFormat": "YYYY-MM-DD HH:mm:ss", "dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0, "decimals": 0,
"pattern": "Average", "pattern": "Average",
"thresholds": [ "thresholds": [
"0", "0",
"1" "1"
], ],
"type": "number", "type": "number",
"unit": "short" "unit": "short"
}, },
{ {
"alias": "", "alias": "",
"colorMode": "cell", "colorMode": "cell",
"colors": [ "colors": [
"rgba(50, 172, 45, 0.97)", "rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)", "rgba(45, 172, 121, 0.97)",
"#cca300" "#cca300"
], ],
"dateFormat": "YYYY-MM-DD HH:mm:ss", "dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0, "decimals": 0,
"pattern": "Warning", "pattern": "Warning",
"thresholds": [ "thresholds": [
"0", "0",
"1" "1"
], ],
"type": "number", "type": "number",
"unit": "short" "unit": "short"
}, },
{ {
"alias": "", "alias": "",
"colorMode": "cell", "colorMode": "cell",
"colors": [ "colors": [
"rgba(50, 172, 45, 0.97)", "rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)", "rgba(45, 172, 121, 0.97)",
"#64b0c8" "#64b0c8"
], ],
"dateFormat": "YYYY-MM-DD HH:mm:ss", "dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0, "decimals": 0,
"pattern": "Information", "pattern": "Information",
"thresholds": [ "thresholds": [
"0", "0",
"1" "1"
], ],
"type": "number", "type": "number",
"unit": "short" "unit": "short"
}, },
{ {
"alias": "", "alias": "",
"colorMode": "cell", "colorMode": "cell",
"colors": [ "colors": [
"rgba(50, 172, 45, 0.97)", "rgba(50, 172, 45, 0.97)",
"rgba(45, 172, 121, 0.97)", "rgba(45, 172, 121, 0.97)",
"rgb(176, 176, 176)" "rgb(176, 176, 176)"
], ],
"dateFormat": "YYYY-MM-DD HH:mm:ss", "dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0, "decimals": 0,
"pattern": "Not classified", "pattern": "Not classified",
"thresholds": [ "thresholds": [
"0", "0",
"1" "1"
], ],
"type": "number", "type": "number",
"unit": "short" "unit": "short"
}, },
{ {
"alias": "", "alias": "",
"colorMode": null, "colorMode": null,
"colors": [ "colors": [
"rgba(245, 54, 54, 0.9)", "rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)", "rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)" "rgba(50, 172, 45, 0.97)"
], ],
"decimals": 0, "decimals": 0,
"pattern": "/.*/", "pattern": "/.*/",
"thresholds": [], "thresholds": [],
"type": "number", "type": "number",
"unit": "none" "unit": "none"
} }
], ],
"targets": [ "targets": [
{ {
"application": { "application": {
"filter": "" "filter": ""
}, },
"functions": [], "functions": [],
"group": { "group": {
"filter": "/.*/" "filter": "/.*/"
}, },
"host": { "host": {
"filter": "/.*/" "filter": "/.*/"
}, },
"item": { "item": {
"filter": "" "filter": ""
}, },
"mode": 4, "mode": 4,
"triggers": { "triggers": {
"count": false, "count": false,
"minSeverity": 0, "minSeverity": 0,
"acknowledged": 2 "acknowledged": 2
}, },
"refId": "A", "refId": "A",
"target": "" "target": ""
} }
], ],
"title": "System status", "title": "System status",
"transform": "table", "transform": "table",
"type": "table" "type": "table"
} }
], ],
"repeat": null, "repeat": null,
"repeatIteration": null, "repeatIteration": null,
"repeatRowId": null, "repeatRowId": null,
"showTitle": false, "showTitle": false,
"title": "Dashboard Row", "title": "Dashboard Row",
"titleSize": "h6" "titleSize": "h6"
}, },
{ {
"collapse": false, "collapse": false,
"height": "150px", "height": "150px",
"panels": [ "panels": [
{ {
"cacheTimeout": null, "cacheTimeout": null,
"colorBackground": true, "colorBackground": true,
"colorValue": false, "colorValue": false,
"colors": [ "colors": [
"rgba(50, 172, 45, 0.97)", "rgba(50, 172, 45, 0.97)",
"rgba(16, 154, 113, 0.97)", "rgba(16, 154, 113, 0.97)",
"#890f02" "#890f02"
], ],
"datasource": "${DS_NAME}", "datasource": "${DS_NAME}",
"format": "none", "format": "none",
"gauge": { "gauge": {
"maxValue": 100, "maxValue": 100,
"minValue": 0, "minValue": 0,
"show": false, "show": false,
"thresholdLabels": false, "thresholdLabels": false,
"thresholdMarkers": true "thresholdMarkers": true
}, },
"id": 1, "id": 1,
"interval": null, "interval": null,
"links": [], "links": [],
"mappingType": 1, "mappingType": 1,
"mappingTypes": [ "mappingTypes": [
{ {
"name": "value to text", "name": "value to text",
"value": 1 "value": 1
}, },
{ {
"name": "range to text", "name": "range to text",
"value": 2 "value": 2
} }
], ],
"maxDataPoints": 100, "maxDataPoints": 100,
"minSpan": 2, "minSpan": 2,
"nullPointMode": "connected", "nullPointMode": "connected",
"nullText": null, "nullText": null,
"postfix": "", "postfix": "",
"postfixFontSize": "50%", "postfixFontSize": "50%",
"prefix": "", "prefix": "",
"prefixFontSize": "50%", "prefixFontSize": "50%",
"rangeMaps": [ "rangeMaps": [
{ {
"from": "null", "from": "null",
"text": "N/A", "text": "N/A",
"to": "null" "to": "null"
} }
], ],
"repeat": "group", "repeat": "group",
"span": 2, "span": 2,
"sparkline": { "sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)", "fillColor": "rgba(31, 118, 189, 0.18)",
"full": false, "full": false,
"lineColor": "rgb(31, 120, 193)", "lineColor": "rgb(31, 120, 193)",
"show": false "show": false
}, },
"tableColumn": "", "tableColumn": "",
"targets": [ "targets": [
{ {
"application": { "application": {
"filter": "" "filter": ""
}, },
"functions": [], "functions": [],
"group": { "group": {
"filter": "$group" "filter": "$group"
}, },
"host": { "host": {
"filter": "/.*/" "filter": "/.*/"
}, },
"item": { "item": {
"filter": "" "filter": ""
}, },
"mode": 4, "mode": 4,
"triggers": { "triggers": {
"count": true, "count": true,
"minSeverity": 3, "minSeverity": 3,
"acknowledged": 2 "acknowledged": 2
}, },
"refId": "A", "refId": "A",
"target": "" "target": ""
} }
], ],
"thresholds": "0,1", "thresholds": "0,1",
"title": "$group", "title": "$group",
"type": "singlestat", "type": "singlestat",
"valueFontSize": "120%", "valueFontSize": "120%",
"valueMaps": [ "valueMaps": [
{ {
"op": "=", "op": "=",
"text": "N/A", "text": "N/A",
"value": "null" "value": "null"
} }
], ],
"valueName": "avg" "valueName": "avg"
} }
], ],
"repeat": null, "repeat": null,
"repeatIteration": null, "repeatIteration": null,
"repeatRowId": null, "repeatRowId": null,
"showTitle": false, "showTitle": false,
"title": "Dashboard Row", "title": "Dashboard Row",
"titleSize": "h6" "titleSize": "h6"
} }
], ],
"schemaVersion": 14, "schemaVersion": 14,
"style": "dark", "style": "dark",
"tags": [], "tags": [],
"templating": { "templating": {
"list": [ "list": [
{ {
"allValue": null, "allValue": null,
"current": {}, "current": {},
"datasource": "${DS_NAME}", "datasource": "${DS_NAME}",
"hide": 0, "hide": 0,
"includeAll": true, "includeAll": true,
"label": null, "label": null,
"multi": true, "multi": true,
"name": "group", "name": "group",
"options": [], "options": [],
"query": "*", "query": "*",
"refresh": 1, "refresh": 1,
"regex": "", "regex": "",
"sort": 0, "sort": 0,
"tagValuesQuery": "", "tagValuesQuery": "",
"tags": [], "tags": [],
"tagsQuery": "", "tagsQuery": "",
"type": "query", "type": "query",
"useTags": false "useTags": false
} }
] ]
}, },
"time": { "time": {
"from": "now-6h", "from": "now-6h",
"to": "now" "to": "now"
}, },
"timepicker": { "timepicker": {
"refresh_intervals": [ "refresh_intervals": [
"5s", "5s",
"10s", "10s",
"30s", "30s",
"1m", "1m",
"5m", "5m",
"15m", "15m",
"30m", "30m",
"1h", "1h",
"2h", "2h",
"1d" "1d"
], ],
"time_options": [ "time_options": [
"5m", "5m",
"15m", "15m",
"1h", "1h",
"6h", "6h",
"12h", "12h",
"24h", "24h",
"2d", "2d",
"7d", "7d",
"30d" "30d"
] ]
}, },
"timezone": "" "timezone": ""
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,70 +1,70 @@
import _ from 'lodash'; import _ from 'lodash';
import ts from '../timeseries'; import ts from '../timeseries';
let datapoints = [[10.7104, 1498409636085], [10.578, 1498409651011], [10.5985, 1498409666628], [10.6877, 1498409681525], [10.5495, 1498409696586], [10.5981, 1498409711009], [10.5076, 1498409726949], [11.4807, 1498409741853], [11.6165, 1498409756165], [11.8575, 1498409771018], [11.9936, 1498409786056], [10.7566, 1498409801942], [10.7484, 1498409816010], [10.6038, 1498409831018], [10.2932, 1498409846010], [10.4912, 1498409861946], [10.4151, 1498409876871], [10.2401, 1498409891710], [10.4921, 1498409906143], [10.4413, 1498409921477], [10.6318, 1498409936147], [10.5277, 1498409951915], [10.6333, 1498409966052], [10.6417, 1498409981944], [10.4505, 1498409996867], [10.5812, 1498410011770], [10.4934, 1498410026573], [10.5731, 1498410041317], [10.5, 1498410056213], [10.6505, 1498410071013], [9.4035, 1498410086387]]; let datapoints = [[10.7104, 1498409636085], [10.578, 1498409651011], [10.5985, 1498409666628], [10.6877, 1498409681525], [10.5495, 1498409696586], [10.5981, 1498409711009], [10.5076, 1498409726949], [11.4807, 1498409741853], [11.6165, 1498409756165], [11.8575, 1498409771018], [11.9936, 1498409786056], [10.7566, 1498409801942], [10.7484, 1498409816010], [10.6038, 1498409831018], [10.2932, 1498409846010], [10.4912, 1498409861946], [10.4151, 1498409876871], [10.2401, 1498409891710], [10.4921, 1498409906143], [10.4413, 1498409921477], [10.6318, 1498409936147], [10.5277, 1498409951915], [10.6333, 1498409966052], [10.6417, 1498409981944], [10.4505, 1498409996867], [10.5812, 1498410011770], [10.4934, 1498410026573], [10.5731, 1498410041317], [10.5, 1498410056213], [10.6505, 1498410071013], [9.4035, 1498410086387]];
let series_set = [ let series_set = [
[[1.0247, 1498409631773], [0.9988, 1498409646697], [0.9817, 1498409661239], [0.9569, 1498409676045], [1.0331, 1498409691922], [1.0755, 1498409706546], [1.1862, 1498409721525], [1.2984, 1498409736175], [1.2389, 1498409751817], [1.1452, 1498409766783], [1.102, 1498409781699], [0.9647, 1498409796664], [1.0063, 1498409811627], [1.0318, 1498409826887], [1.065, 1498409841645], [1.0907, 1498409856647], [1.0229, 1498409871521], [1.0654, 1498409886031], [1.0568, 1498409901544], [1.0818, 1498409916194], [1.1335, 1498409931672], [1.057, 1498409946673], [1.0243, 1498409961669], [1.0329, 1498409976637], [1.1428, 1498409991563], [1.2198, 1498410006441], [1.2192, 1498410021230], [1.2615, 1498410036027], [1.1765, 1498410051907], [1.2352, 1498410066109], [1.0557, 1498410081043]], [[1.0247, 1498409631773], [0.9988, 1498409646697], [0.9817, 1498409661239], [0.9569, 1498409676045], [1.0331, 1498409691922], [1.0755, 1498409706546], [1.1862, 1498409721525], [1.2984, 1498409736175], [1.2389, 1498409751817], [1.1452, 1498409766783], [1.102, 1498409781699], [0.9647, 1498409796664], [1.0063, 1498409811627], [1.0318, 1498409826887], [1.065, 1498409841645], [1.0907, 1498409856647], [1.0229, 1498409871521], [1.0654, 1498409886031], [1.0568, 1498409901544], [1.0818, 1498409916194], [1.1335, 1498409931672], [1.057, 1498409946673], [1.0243, 1498409961669], [1.0329, 1498409976637], [1.1428, 1498409991563], [1.2198, 1498410006441], [1.2192, 1498410021230], [1.2615, 1498410036027], [1.1765, 1498410051907], [1.2352, 1498410066109], [1.0557, 1498410081043]],
[[10.7104, 1498409636085], [10.578, 1498409651011], [10.5985, 1498409666628], [10.6877, 1498409681525], [10.5495, 1498409696586], [10.5981, 1498409711009], [10.5076, 1498409726949], [11.4807, 1498409741853], [11.6165, 1498409756165], [11.8575, 1498409771018], [11.9936, 1498409786056], [10.7566, 1498409801942], [10.7484, 1498409816010], [10.6038, 1498409831018], [10.2932, 1498409846010], [10.4912, 1498409861946], [10.4151, 1498409876871], [10.2401, 1498409891710], [10.4921, 1498409906143], [10.4413, 1498409921477], [10.6318, 1498409936147], [10.5277, 1498409951915], [10.6333, 1498409966052], [10.6417, 1498409981944], [10.4505, 1498409996867], [10.5812, 1498410011770], [10.4934, 1498410026573], [10.5731, 1498410041317], [10.5, 1498410056213], [10.6505, 1498410071013], [9.4035, 1498410086387]] [[10.7104, 1498409636085], [10.578, 1498409651011], [10.5985, 1498409666628], [10.6877, 1498409681525], [10.5495, 1498409696586], [10.5981, 1498409711009], [10.5076, 1498409726949], [11.4807, 1498409741853], [11.6165, 1498409756165], [11.8575, 1498409771018], [11.9936, 1498409786056], [10.7566, 1498409801942], [10.7484, 1498409816010], [10.6038, 1498409831018], [10.2932, 1498409846010], [10.4912, 1498409861946], [10.4151, 1498409876871], [10.2401, 1498409891710], [10.4921, 1498409906143], [10.4413, 1498409921477], [10.6318, 1498409936147], [10.5277, 1498409951915], [10.6333, 1498409966052], [10.6417, 1498409981944], [10.4505, 1498409996867], [10.5812, 1498410011770], [10.4934, 1498410026573], [10.5731, 1498410041317], [10.5, 1498410056213], [10.6505, 1498410071013], [9.4035, 1498410086387]]
]; ];
let growing_series = [[10755200, 1498332216642], [10761200, 1498332276802], [10767200, 1498332336367], [10773200, 1498332396584], [10779200, 1498332456880], [10785200, 1498332516479], [10791200, 1498332576610], [10797200, 1498332636353], [10803200, 1498332696513], [10809200, 1498332756884], [10815200, 1498332816890], [10821200, 1498332876305], [10827200, 1498332936384], [10833200, 1498332996659], [10839200, 1498333056965], [10845200, 1498333116748], [10851200, 1498333176687], [10857200, 1498333236646], [10863200, 1498333297034], [10869200, 1498333356358], [10875200, 1498333416445], [4800, 1498333536686], [17900, 1498333667962], [24000, 1498333729157], [29500, 1498333783662], [34800, 1498333836813], [40700, 1498333896403], [46800, 1498333956953], [52800, 1498334016976], [6000, 1498334136593], [12000, 1498334196567]]; let growing_series = [[10755200, 1498332216642], [10761200, 1498332276802], [10767200, 1498332336367], [10773200, 1498332396584], [10779200, 1498332456880], [10785200, 1498332516479], [10791200, 1498332576610], [10797200, 1498332636353], [10803200, 1498332696513], [10809200, 1498332756884], [10815200, 1498332816890], [10821200, 1498332876305], [10827200, 1498332936384], [10833200, 1498332996659], [10839200, 1498333056965], [10845200, 1498333116748], [10851200, 1498333176687], [10857200, 1498333236646], [10863200, 1498333297034], [10869200, 1498333356358], [10875200, 1498333416445], [4800, 1498333536686], [17900, 1498333667962], [24000, 1498333729157], [29500, 1498333783662], [34800, 1498333836813], [40700, 1498333896403], [46800, 1498333956953], [52800, 1498334016976], [6000, 1498334136593], [12000, 1498334196567]];
module.exports = [ module.exports = [
{ {
name: 'groupBy', name: 'groupBy',
tests: { tests: {
'groupBy(AVERAGE)': () => { 'groupBy(AVERAGE)': () => {
ts.groupBy(datapoints, '5m', ts.AVERAGE); ts.groupBy(datapoints, '5m', ts.AVERAGE);
}, },
'groupBy(MAX)': () => { 'groupBy(MAX)': () => {
ts.groupBy(datapoints, '5m', ts.COUNT); ts.groupBy(datapoints, '5m', ts.COUNT);
} }
} }
}, },
{ {
name: 'sumSeries', name: 'sumSeries',
tests: { tests: {
'sumSeries()': () => { 'sumSeries()': () => {
ts.sumSeries(series_set); ts.sumSeries(series_set);
}, },
'groupBy(MAX)->sumSeries()': () => { 'groupBy(MAX)->sumSeries()': () => {
let prepeared_series = _.map(series_set, datapoints => ts.groupBy(datapoints, '5m', ts.MAX)); let prepeared_series = _.map(series_set, datapoints => ts.groupBy(datapoints, '5m', ts.MAX));
ts.sumSeries(prepeared_series); ts.sumSeries(prepeared_series);
} }
} }
}, },
{ {
name: 'delta vs rate', name: 'delta vs rate',
tests: { tests: {
'delta()': () => { 'delta()': () => {
ts.delta(growing_series); ts.delta(growing_series);
}, },
'rate()': () => { 'rate()': () => {
ts.rate(growing_series); ts.rate(growing_series);
} }
} }
}, },
{ {
name: 'scale', name: 'scale',
tests: { tests: {
'scale()': () => { 'scale()': () => {
ts.scale(datapoints, 42); ts.scale(datapoints, 42);
}, },
'scale_perf()': () => { 'scale_perf()': () => {
ts.scale_perf(datapoints, 42); ts.scale_perf(datapoints, 42);
} }
} }
}, },
{ {
name: 'groupBy vs groupBy_perf', name: 'groupBy vs groupBy_perf',
tests: { tests: {
'groupBy()': () => { 'groupBy()': () => {
ts.groupBy(datapoints, '5m', ts.AVERAGE); ts.groupBy(datapoints, '5m', ts.AVERAGE);
}, },
'groupBy_perf()': () => { 'groupBy_perf()': () => {
ts.groupBy_perf(datapoints, '5m', ts.AVERAGE); ts.groupBy_perf(datapoints, '5m', ts.AVERAGE);
} }
} }
} }
]; ];

View File

@@ -1 +1 @@
{"version":3,"sources":["../../src/datasource-zabbix/config.controller.js"],"names":["_","SUPPORTED_SQL_DS","defaultConfig","dbConnection","enable","ZabbixDSConfigController","$scope","$injector","datasourceSrv","defaults","current","jsonData","sqlDataSources","getSupportedSQLDataSources","datasources","getAll","filter","includes","ds","type","templateUrl"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;;;;;;;;;;;;;;;;;;;;AAEDC,sB,GAAmB,CAAC,OAAD,EAAU,UAAV,C;AAEnBC,mB,GAAgB;AACpBC,sBAAc;AACZC,kBAAQ;AADI;AADM,O;;0CAMTC,wB;AACX;AACA,0CAAYC,MAAZ,EAAoBC,SAApB,EAA+BC,aAA/B,EAA8C;AAAA;;AAC5C,eAAKA,aAAL,GAAqBA,aAArB;;AAEAR,YAAES,QAAF,CAAW,KAAKC,OAAL,CAAaC,QAAxB,EAAkCT,aAAlC;AACA,eAAKU,cAAL,GAAsB,KAAKC,0BAAL,EAAtB;AACD;;;;uDAE4B;AAC3B,gBAAIC,cAAc,KAAKN,aAAL,CAAmBO,MAAnB,EAAlB;AACA,mBAAOf,EAAEgB,MAAF,CAASF,WAAT,EAAsB,cAAM;AACjC,qBAAOd,EAAEiB,QAAF,CAAWhB,gBAAX,EAA6BiB,GAAGC,IAAhC,CAAP;AACD,aAFM,CAAP;AAGD;;;;;;;;AAGHd,+BAAyBe,WAAzB,GAAuC,wCAAvC","file":"config.controller.js","sourcesContent":["import _ from 'lodash';\n\nconst SUPPORTED_SQL_DS = ['mysql', 'postgres'];\n\nconst defaultConfig = {\n dbConnection: {\n enable: false,\n }\n};\n\nexport class ZabbixDSConfigController {\n /** @ngInject */\n constructor($scope, $injector, datasourceSrv) {\n this.datasourceSrv = datasourceSrv;\n\n _.defaults(this.current.jsonData, defaultConfig);\n this.sqlDataSources = this.getSupportedSQLDataSources();\n }\n\n getSupportedSQLDataSources() {\n let datasources = this.datasourceSrv.getAll();\n return _.filter(datasources, ds => {\n return _.includes(SUPPORTED_SQL_DS, ds.type);\n });\n }\n}\n\nZabbixDSConfigController.templateUrl = 'datasource-zabbix/partials/config.html';\n"]} {"version":3,"sources":["../../src/datasource-zabbix/config.controller.js"],"names":["_","SUPPORTED_SQL_DS","defaultConfig","dbConnection","enable","ZabbixDSConfigController","$scope","$injector","datasourceSrv","defaults","current","jsonData","sqlDataSources","getSupportedSQLDataSources","datasources","getAll","filter","includes","ds","type","templateUrl"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;;;;;;;;;;;;;;;;;;;;AAEDC,sB,GAAmB,CAAC,OAAD,EAAU,UAAV,C;AAEnBC,mB,GAAgB;AACpBC,sBAAc;AACZC,kBAAQ;AADI;AADM,O;;0CAMTC,wB;AACX;AACA,0CAAYC,MAAZ,EAAoBC,SAApB,EAA+BC,aAA/B,EAA8C;AAAA;;AAC5C,eAAKA,aAAL,GAAqBA,aAArB;;AAEAR,YAAES,QAAF,CAAW,KAAKC,OAAL,CAAaC,QAAxB,EAAkCT,aAAlC;AACA,eAAKU,cAAL,GAAsB,KAAKC,0BAAL,EAAtB;AACD;;;;uDAE4B;AAC3B,gBAAIC,cAAc,KAAKN,aAAL,CAAmBO,MAAnB,EAAlB;AACA,mBAAOf,EAAEgB,MAAF,CAASF,WAAT,EAAsB,cAAM;AACjC,qBAAOd,EAAEiB,QAAF,CAAWhB,gBAAX,EAA6BiB,GAAGC,IAAhC,CAAP;AACD,aAFM,CAAP;AAGD;;;;;;;;AAGHd,+BAAyBe,WAAzB,GAAuC,wCAAvC","file":"config.controller.js","sourcesContent":["import _ from 'lodash';\r\n\r\nconst SUPPORTED_SQL_DS = ['mysql', 'postgres'];\r\n\r\nconst defaultConfig = {\r\n dbConnection: {\r\n enable: false,\r\n }\r\n};\r\n\r\nexport class ZabbixDSConfigController {\r\n /** @ngInject */\r\n constructor($scope, $injector, datasourceSrv) {\r\n this.datasourceSrv = datasourceSrv;\r\n\r\n _.defaults(this.current.jsonData, defaultConfig);\r\n this.sqlDataSources = this.getSupportedSQLDataSources();\r\n }\r\n\r\n getSupportedSQLDataSources() {\r\n let datasources = this.datasourceSrv.getAll();\r\n return _.filter(datasources, ds => {\r\n return _.includes(SUPPORTED_SQL_DS, ds.type);\r\n });\r\n }\r\n}\r\n\r\nZabbixDSConfigController.templateUrl = 'datasource-zabbix/partials/config.html';\r\n"]}

View File

@@ -1 +1 @@
{"version":3,"sources":["../../src/datasource-zabbix/constants.js"],"names":["MODE_METRICS","MODE_ITSERVICE","MODE_TEXT","MODE_ITEMID","MODE_TRIGGERS","SEV_NOT_CLASSIFIED","SEV_INFORMATION","SEV_WARNING","SEV_AVERAGE","SEV_HIGH","SEV_DISASTER","SHOW_ALL_TRIGGERS","SHOW_ALL_EVENTS","SHOW_OK_EVENTS","DATAPOINT_VALUE","DATAPOINT_TS","TRIGGER_SEVERITY","val","text"],"mappings":";;;;;;;;;8BACaA,Y,GAAe,C;;;;gCACfC,c,GAAiB,C;;;;2BACjBC,S,GAAY,C;;;;6BACZC,W,GAAc,C;;;;+BACdC,a,GAAgB,C;;;;oCAGhBC,kB,GAAqB,C;;;;iCACrBC,e,GAAkB,C;;;;6BAClBC,W,GAAc,C;;;;6BACdC,W,GAAc,C;;;;0BACdC,Q,GAAW,C;;;;8BACXC,Y,GAAe,C;;;;mCAEfC,iB,GAAoB,CAAC,CAAD,EAAI,CAAJ,C;;;;iCACpBC,e,GAAkB,CAAC,CAAD,EAAI,CAAJ,C;;;;gCAClBC,c,GAAiB,C;;;;iCAGjBC,e,GAAkB,C;;;;8BAClBC,Y,GAAe,C;;;;kCAEfC,gB,GAAmB,CAC9B,EAACC,KAAK,CAAN,EAASC,MAAM,gBAAf,EAD8B,EAE9B,EAACD,KAAK,CAAN,EAASC,MAAM,aAAf,EAF8B,EAG9B,EAACD,KAAK,CAAN,EAASC,MAAM,SAAf,EAH8B,EAI9B,EAACD,KAAK,CAAN,EAASC,MAAM,SAAf,EAJ8B,EAK9B,EAACD,KAAK,CAAN,EAASC,MAAM,MAAf,EAL8B,EAM9B,EAACD,KAAK,CAAN,EAASC,MAAM,UAAf,EAN8B,C","file":"constants.js","sourcesContent":["// Editor modes\nexport const MODE_METRICS = 0;\nexport const MODE_ITSERVICE = 1;\nexport const MODE_TEXT = 2;\nexport const MODE_ITEMID = 3;\nexport const MODE_TRIGGERS = 4;\n\n// Triggers severity\nexport const SEV_NOT_CLASSIFIED = 0;\nexport const SEV_INFORMATION = 1;\nexport const SEV_WARNING = 2;\nexport const SEV_AVERAGE = 3;\nexport const SEV_HIGH = 4;\nexport const SEV_DISASTER = 5;\n\nexport const SHOW_ALL_TRIGGERS = [0, 1];\nexport const SHOW_ALL_EVENTS = [0, 1];\nexport const SHOW_OK_EVENTS = 1;\n\n// Data point\nexport const DATAPOINT_VALUE = 0;\nexport const DATAPOINT_TS = 1;\n\nexport const TRIGGER_SEVERITY = [\n {val: 0, text: 'Not classified'},\n {val: 1, text: 'Information'},\n {val: 2, text: 'Warning'},\n {val: 3, text: 'Average'},\n {val: 4, text: 'High'},\n {val: 5, text: 'Disaster'}\n];\n"]} {"version":3,"sources":["../../src/datasource-zabbix/constants.js"],"names":["MODE_METRICS","MODE_ITSERVICE","MODE_TEXT","MODE_ITEMID","MODE_TRIGGERS","SEV_NOT_CLASSIFIED","SEV_INFORMATION","SEV_WARNING","SEV_AVERAGE","SEV_HIGH","SEV_DISASTER","SHOW_ALL_TRIGGERS","SHOW_ALL_EVENTS","SHOW_OK_EVENTS","DATAPOINT_VALUE","DATAPOINT_TS","TRIGGER_SEVERITY","val","text"],"mappings":";;;;;;;;;8BACaA,Y,GAAe,C;;;;gCACfC,c,GAAiB,C;;;;2BACjBC,S,GAAY,C;;;;6BACZC,W,GAAc,C;;;;+BACdC,a,GAAgB,C;;;;oCAGhBC,kB,GAAqB,C;;;;iCACrBC,e,GAAkB,C;;;;6BAClBC,W,GAAc,C;;;;6BACdC,W,GAAc,C;;;;0BACdC,Q,GAAW,C;;;;8BACXC,Y,GAAe,C;;;;mCAEfC,iB,GAAoB,CAAC,CAAD,EAAI,CAAJ,C;;;;iCACpBC,e,GAAkB,CAAC,CAAD,EAAI,CAAJ,C;;;;gCAClBC,c,GAAiB,C;;;;iCAGjBC,e,GAAkB,C;;;;8BAClBC,Y,GAAe,C;;;;kCAEfC,gB,GAAmB,CAC9B,EAACC,KAAK,CAAN,EAASC,MAAM,gBAAf,EAD8B,EAE9B,EAACD,KAAK,CAAN,EAASC,MAAM,aAAf,EAF8B,EAG9B,EAACD,KAAK,CAAN,EAASC,MAAM,SAAf,EAH8B,EAI9B,EAACD,KAAK,CAAN,EAASC,MAAM,SAAf,EAJ8B,EAK9B,EAACD,KAAK,CAAN,EAASC,MAAM,MAAf,EAL8B,EAM9B,EAACD,KAAK,CAAN,EAASC,MAAM,UAAf,EAN8B,C","file":"constants.js","sourcesContent":["// Editor modes\r\nexport const MODE_METRICS = 0;\r\nexport const MODE_ITSERVICE = 1;\r\nexport const MODE_TEXT = 2;\r\nexport const MODE_ITEMID = 3;\r\nexport const MODE_TRIGGERS = 4;\r\n\r\n// Triggers severity\r\nexport const SEV_NOT_CLASSIFIED = 0;\r\nexport const SEV_INFORMATION = 1;\r\nexport const SEV_WARNING = 2;\r\nexport const SEV_AVERAGE = 3;\r\nexport const SEV_HIGH = 4;\r\nexport const SEV_DISASTER = 5;\r\n\r\nexport const SHOW_ALL_TRIGGERS = [0, 1];\r\nexport const SHOW_ALL_EVENTS = [0, 1];\r\nexport const SHOW_OK_EVENTS = 1;\r\n\r\n// Data point\r\nexport const DATAPOINT_VALUE = 0;\r\nexport const DATAPOINT_TS = 1;\r\n\r\nexport const TRIGGER_SEVERITY = [\r\n {val: 0, text: 'Not classified'},\r\n {val: 1, text: 'Information'},\r\n {val: 2, text: 'Warning'},\r\n {val: 3, text: 'Average'},\r\n {val: 4, text: 'High'},\r\n {val: 5, text: 'Disaster'}\r\n];\r\n"]}

View File

@@ -21,6 +21,24 @@ System.register(['lodash', './utils', './timeseries'], function (_export, _conte
} }
} }
function removeAboveValue(n, datapoints) {
return _.map(datapoints, function (point) {
return [point[0] > n ? null : point[0], point[1]];
});
}
function removeBelowValue(n, datapoints) {
return _.map(datapoints, function (point) {
return [point[0] < n ? null : point[0], point[1]];
});
}
function transformNull(n, datapoints) {
return _.map(datapoints, function (point) {
return [point[0] !== null ? point[0] : n, point[1]];
});
}
function sortSeries(direction, timeseries) { function sortSeries(direction, timeseries) {
return _.orderBy(timeseries, [function (ts) { return _.orderBy(timeseries, [function (ts) {
return ts.target.toLowerCase(); return ts.target.toLowerCase();
@@ -142,6 +160,7 @@ System.register(['lodash', './utils', './timeseries'], function (_export, _conte
rate: rate, rate: rate,
movingAverage: simpleMovingAverage, movingAverage: simpleMovingAverage,
exponentialMovingAverage: expMovingAverage, exponentialMovingAverage: expMovingAverage,
transformNull: transformNull,
aggregateBy: aggregateByWrapper, aggregateBy: aggregateByWrapper,
// Predefined aggs // Predefined aggs
percentil: percentil, percentil: percentil,
@@ -152,6 +171,8 @@ System.register(['lodash', './utils', './timeseries'], function (_export, _conte
sum: _.partial(aggregateWrapper, SUM), sum: _.partial(aggregateWrapper, SUM),
count: _.partial(aggregateWrapper, COUNT), count: _.partial(aggregateWrapper, COUNT),
sumSeries: sumSeries, sumSeries: sumSeries,
removeAboveValue: removeAboveValue,
removeBelowValue: removeBelowValue,
top: _.partial(limit, 'top'), top: _.partial(limit, 'top'),
bottom: _.partial(limit, 'bottom'), bottom: _.partial(limit, 'bottom'),
sortSeries: sortSeries, sortSeries: sortSeries,

File diff suppressed because one or more lines are too long

View File

@@ -52,15 +52,15 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
}; };
} }
/** /**
* Custom formatter for template variables. * Custom formatter for template variables.
* Default Grafana "regex" formatter returns * Default Grafana "regex" formatter returns
* value1|value2 * value1|value2
* This formatter returns * This formatter returns
* (value1|value2) * (value1|value2)
* This format needed for using in complex regex with * This format needed for using in complex regex with
* template variables, for example * template variables, for example
* /CPU $cpu_item.*time/ where $cpu_item is system,user,iowait * /CPU $cpu_item.*time/ where $cpu_item is system,user,iowait
*/ */
function zabbixTemplateFormat(value) { function zabbixTemplateFormat(value) {
if (typeof value === 'string') { if (typeof value === 'string') {
@@ -78,13 +78,13 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
return value.join(','); return value.join(',');
} }
/** /**
* If template variables are used in request, replace it using regex format * If template variables are used in request, replace it using regex format
* and wrap with '/' for proper multi-value work. Example: * and wrap with '/' for proper multi-value work. Example:
* $variable selected as a, b, c * $variable selected as a, b, c
* We use filter $variable * We use filter $variable
* $variable -> a|b|c -> /a|b|c/ * $variable -> a|b|c -> /a|b|c/
* /$variable/ -> /a|b|c/ -> /a|b|c/ * /$variable/ -> /a|b|c/ -> /a|b|c/
*/ */
function replaceTemplateVars(templateSrv, target, scopedVars) { function replaceTemplateVars(templateSrv, target, scopedVars) {
var replacedTarget = templateSrv.replace(target, scopedVars, zabbixTemplateFormat); var replacedTarget = templateSrv.replace(target, scopedVars, zabbixTemplateFormat);
@@ -265,10 +265,10 @@ System.register(['lodash', 'app/core/utils/datemath', './utils', './migrations',
// Datasource methods // // Datasource methods //
//////////////////////// ////////////////////////
/** /**
* Query panel data. Calls for each panel in dashboard. * Query panel data. Calls for each panel in dashboard.
* @param {Object} options Contains time range, targets and other info. * @param {Object} options Contains time range, targets and other info.
* @return {Object} Grafana metrics object with timeseries data for each target. * @return {Object} Grafana metrics object with timeseries data for each target.
*/ */

File diff suppressed because one or more lines are too long

View File

@@ -1,107 +1,107 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0" version="1.0"
id="Layer_1" id="Layer_1"
x="0px" x="0px"
y="0px" y="0px"
width="100px" width="100px"
height="100px" height="100px"
viewBox="692 0 100 100" viewBox="692 0 100 100"
style="enable-background:new 692 0 100 100;" style="enable-background:new 692 0 100 100;"
xml:space="preserve" xml:space="preserve"
inkscape:version="0.91 r" inkscape:version="0.91 r"
sodipodi:docname="zabbix_app_logo.svg" sodipodi:docname="zabbix_app_logo.svg"
enable-background="new"><metadata enable-background="new"><metadata
id="metadata13"><rdf:RDF><cc:Work id="metadata13"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs11"><linearGradient id="defs11"><linearGradient
id="SVGID_1_" id="SVGID_1_"
gradientUnits="userSpaceOnUse" gradientUnits="userSpaceOnUse"
x1="2.6005001" x1="2.6005001"
y1="65.475197" y1="65.475197"
x2="94.377701" x2="94.377701"
y2="30.245199"><stop y2="30.245199"><stop
id="stop34" id="stop34"
style="stop-color:#58595B" style="stop-color:#58595B"
offset="0.2583" /><stop offset="0.2583" /><stop
id="stop32" id="stop32"
style="stop-color:#646C70" style="stop-color:#646C70"
offset="0.2917" /><stop offset="0.2917" /><stop
id="stop30" id="stop30"
style="stop-color:#6C8087" style="stop-color:#6C8087"
offset="0.3398" /><stop offset="0.3398" /><stop
id="stop28" id="stop28"
style="stop-color:#6D8F9B" style="stop-color:#6D8F9B"
offset="0.3927" /><stop offset="0.3927" /><stop
id="stop26" id="stop26"
style="stop-color:#689BAA" style="stop-color:#689BAA"
offset="0.4499" /><stop offset="0.4499" /><stop
id="stop24" id="stop24"
style="stop-color:#5FA3B5" style="stop-color:#5FA3B5"
offset="0.5128" /><stop offset="0.5128" /><stop
id="stop22" id="stop22"
style="stop-color:#53A8BD" style="stop-color:#53A8BD"
offset="0.5837" /><stop offset="0.5837" /><stop
id="stop20" id="stop20"
style="stop-color:#47ABC2" style="stop-color:#47ABC2"
offset="0.6674" /><stop offset="0.6674" /><stop
id="stop18" id="stop18"
style="stop-color:#3FAEC5" style="stop-color:#3FAEC5"
offset="0.7759" /><stop offset="0.7759" /><stop
id="stop16" id="stop16"
style="stop-color:#3CAFC7" style="stop-color:#3CAFC7"
offset="1" /><stop offset="1" /><stop
id="stop14" id="stop14"
style="stop-color:#3BB0C9" style="stop-color:#3BB0C9"
offset="1" /></linearGradient></defs><sodipodi:namedview offset="1" /></linearGradient></defs><sodipodi:namedview
pagecolor="#ffffff" pagecolor="#ffffff"
bordercolor="#666666" bordercolor="#666666"
borderopacity="1" borderopacity="1"
objecttolerance="10" objecttolerance="10"
gridtolerance="10" gridtolerance="10"
guidetolerance="10" guidetolerance="10"
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:window-width="1615" inkscape:window-width="1615"
inkscape:window-height="1026" inkscape:window-height="1026"
id="namedview9" id="namedview9"
showgrid="false" showgrid="false"
inkscape:zoom="4.285" inkscape:zoom="4.285"
inkscape:cx="50.424685" inkscape:cx="50.424685"
inkscape:cy="23.581186" inkscape:cy="23.581186"
inkscape:window-x="65" inkscape:window-x="65"
inkscape:window-y="24" inkscape:window-y="24"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="g5194" /><style inkscape:current-layer="g5194" /><style
type="text/css" type="text/css"
id="style3"> id="style3">
.st0{fill:#787878;} .st0{fill:#787878;}
</style><g </style><g
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="g5194" id="g5194"
inkscape:label="Zabbix BG Original" inkscape:label="Zabbix BG Original"
style="display:inline"><rect style="display:inline"><rect
style="fill:#d40000;fill-opacity:1" style="fill:#d40000;fill-opacity:1"
id="rect5196" id="rect5196"
width="100" width="100"
height="100" height="100"
x="692" x="692"
y="0" /></g><g y="0" /></g><g
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer6" id="layer6"
inkscape:label="Zabbix Original Z" inkscape:label="Zabbix Original Z"
style="display:inline"><path style="display:inline"><path
d="m 715.54426,16.689227 52.91147,0 0,6.87033 -42.58255,52.167008 43.62047,0 0,7.584207 -54.9873,0 0,-6.871516 42.58255,-52.166552 -41.54464,0 0,-7.583477 z" d="m 715.54426,16.689227 52.91147,0 0,6.87033 -42.58255,52.167008 43.62047,0 0,7.584207 -54.9873,0 0,-6.871516 42.58255,-52.166552 -41.54464,0 0,-7.583477 z"
style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4169-6" id="path4169-6"
inkscape:connector-curvature="0" /></g></svg> inkscape:connector-curvature="0" /></g></svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

File diff suppressed because one or more lines are too long

View File

@@ -125,6 +125,13 @@ System.register(['lodash', 'jquery'], function (_export, _context) {
defaultParams: [0.2] defaultParams: [0.2]
}); });
addFuncDef({
name: 'transformNull',
category: 'Transform',
params: [{ name: 'number', type: 'float' }],
defaultParams: [0]
});
// Aggregate // Aggregate
addFuncDef({ addFuncDef({
@@ -192,6 +199,20 @@ System.register(['lodash', 'jquery'], function (_export, _context) {
// Filter // Filter
addFuncDef({
name: 'removeAboveValue',
category: 'Filter',
params: [{ name: 'number', type: 'float' }],
defaultParams: [0]
});
addFuncDef({
name: 'removeBelowValue',
category: 'Filter',
params: [{ name: 'number', type: 'float' }],
defaultParams: [0]
});
addFuncDef({ addFuncDef({
name: 'top', name: 'top',
category: 'Filter', category: 'Filter',

File diff suppressed because one or more lines are too long

View File

@@ -3,9 +3,9 @@
System.register([], function (_export, _context) { System.register([], function (_export, _context) {
"use strict"; "use strict";
/** /**
* Query format migration. * Query format migration.
* This module can detect query format version and make migration. * This module can detect query format version and make migration.
*/ */
function isGrafana2target(target) { function isGrafana2target(target) {

View File

@@ -1 +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","resultFormat","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;AAC9BA,WAAOe,YAAP,GAAsBf,OAAOe,YAAP,IAAuB,aAA7C;AACA,QAAIhB,iBAAiBC,MAAjB,CAAJ,EAA8B;AAC5B,aAAOS,uBAAuBT,MAAvB,CAAP;AACD,KAFD,MAEO;AACL,aAAOA,MAAP;AACD;AACF;;qBAPec,O;;AAShB,WAASF,cAAT,CAAwBI,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 target.resultFormat = target.resultFormat || 'time_series';\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"]} {"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","resultFormat","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;AAC9BA,WAAOe,YAAP,GAAsBf,OAAOe,YAAP,IAAuB,aAA7C;AACA,QAAIhB,iBAAiBC,MAAjB,CAAJ,EAA8B;AAC5B,aAAOS,uBAAuBT,MAAvB,CAAP;AACD,KAFD,MAEO;AACL,aAAOA,MAAP;AACD;AACF;;qBAPec,O;;AAShB,WAASF,cAAT,CAAwBI,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":["/**\r\n * Query format migration.\r\n * This module can detect query format version and make migration.\r\n */\r\n\r\nexport function isGrafana2target(target) {\r\n if (!target.mode || target.mode === 0 || target.mode === 2) {\r\n if ((target.hostFilter || target.itemFilter || target.downsampleFunction ||\r\n (target.host && target.host.host)) &&\r\n (target.item.filter === undefined && target.host.filter === undefined)) {\r\n return true;\r\n } else {\r\n return false;\r\n }\r\n } else {\r\n return false;\r\n }\r\n}\r\n\r\nexport function migrateFrom2To3version(target) {\r\n target.group.filter = target.group.name === \"*\" ? \"/.*/\" : target.group.name;\r\n target.host.filter = target.host.name === \"*\" ? convertToRegex(target.hostFilter) : target.host.name;\r\n target.application.filter = target.application.name === \"*\" ? \"\" : target.application.name;\r\n target.item.filter = target.item.name === \"All\" ? convertToRegex(target.itemFilter) : target.item.name;\r\n return target;\r\n}\r\n\r\nexport function migrate(target) {\r\n target.resultFormat = target.resultFormat || 'time_series';\r\n if (isGrafana2target(target)) {\r\n return migrateFrom2To3version(target);\r\n } else {\r\n return target;\r\n }\r\n}\r\n\r\nfunction convertToRegex(str) {\r\n if (str) {\r\n return '/' + str + '/';\r\n } else {\r\n return '/.*/';\r\n }\r\n}\r\n"]}

View File

@@ -1 +1 @@
{"version":3,"sources":["../../src/datasource-zabbix/module.js"],"names":["loadPluginCss","ZabbixAPIDatasource","ZabbixQueryController","ZabbixDSConfigController","dark","light","ZabbixQueryOptionsController","templateUrl","ZabbixAnnotationsQueryController"],"mappings":";;;;;;;;;;;;;;;AAAQA,mB,kBAAAA,a;;AACAC,yB,eAAAA,mB;;AACAC,2B,oBAAAA,qB;;AACAC,8B,qBAAAA,wB;;;;AAERH,oBAAc;AACZI,cAAM,gEADM;AAEZC,eAAO;AAFK,OAAd;;kCAKMC,4B;;;;AACNA,mCAA6BC,WAA7B,GAA2C,+CAA3C;;sCAEMC,gC;;;;AACNA,uCAAiCD,WAAjC,GAA+C,oDAA/C;;4BAGEN,mB;;4BACAE,wB;;2BACAD,qB;;kCACAI,4B;;sCACAE,gC","file":"module.js","sourcesContent":["import {loadPluginCss} from 'app/plugins/sdk';\nimport {ZabbixAPIDatasource} from './datasource';\nimport {ZabbixQueryController} from './query.controller';\nimport {ZabbixDSConfigController} from './config.controller';\n\nloadPluginCss({\n dark: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.dark.css',\n light: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.light.css'\n});\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 ZabbixDSConfigController as ConfigCtrl,\n ZabbixQueryController as QueryCtrl,\n ZabbixQueryOptionsController as QueryOptionsCtrl,\n ZabbixAnnotationsQueryController as AnnotationsQueryCtrl\n};\n"]} {"version":3,"sources":["../../src/datasource-zabbix/module.js"],"names":["loadPluginCss","ZabbixAPIDatasource","ZabbixQueryController","ZabbixDSConfigController","dark","light","ZabbixQueryOptionsController","templateUrl","ZabbixAnnotationsQueryController"],"mappings":";;;;;;;;;;;;;;;AAAQA,mB,kBAAAA,a;;AACAC,yB,eAAAA,mB;;AACAC,2B,oBAAAA,qB;;AACAC,8B,qBAAAA,wB;;;;AAERH,oBAAc;AACZI,cAAM,gEADM;AAEZC,eAAO;AAFK,OAAd;;kCAKMC,4B;;;;AACNA,mCAA6BC,WAA7B,GAA2C,+CAA3C;;sCAEMC,gC;;;;AACNA,uCAAiCD,WAAjC,GAA+C,oDAA/C;;4BAGEN,mB;;4BACAE,wB;;2BACAD,qB;;kCACAI,4B;;sCACAE,gC","file":"module.js","sourcesContent":["import {loadPluginCss} from 'app/plugins/sdk';\r\nimport {ZabbixAPIDatasource} from './datasource';\r\nimport {ZabbixQueryController} from './query.controller';\r\nimport {ZabbixDSConfigController} from './config.controller';\r\n\r\nloadPluginCss({\r\n dark: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.dark.css',\r\n light: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.light.css'\r\n});\r\n\r\nclass ZabbixQueryOptionsController {}\r\nZabbixQueryOptionsController.templateUrl = 'datasource-zabbix/partials/query.options.html';\r\n\r\nclass ZabbixAnnotationsQueryController {}\r\nZabbixAnnotationsQueryController.templateUrl = 'datasource-zabbix/partials/annotations.editor.html';\r\n\r\nexport {\r\n ZabbixAPIDatasource as Datasource,\r\n ZabbixDSConfigController as ConfigCtrl,\r\n ZabbixQueryController as QueryCtrl,\r\n ZabbixQueryOptionsController as QueryOptionsCtrl,\r\n ZabbixAnnotationsQueryController as AnnotationsQueryCtrl\r\n};\r\n"]}

View File

@@ -1,65 +1,65 @@
<div class="gf-form-group"> <div class="gf-form-group">
<h6>Filter Triggers</h6> <h6>Filter Triggers</h6>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-10">Group</span> <span class="gf-form-label width-10">Group</span>
<input type="text" <input type="text"
class="gf-form-input max-width-16" class="gf-form-input max-width-16"
ng-model="ctrl.annotation.group"> ng-model="ctrl.annotation.group">
</input> </input>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-10">Host</span> <span class="gf-form-label width-10">Host</span>
<input type="text" <input type="text"
class="gf-form-input max-width-16" class="gf-form-input max-width-16"
ng-model="ctrl.annotation.host"> ng-model="ctrl.annotation.host">
</input> </input>
</div> </div>
</div> </div>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-10">Application</span> <span class="gf-form-label width-10">Application</span>
<input type="text" <input type="text"
class="gf-form-input max-width-16" class="gf-form-input max-width-16"
ng-model="ctrl.annotation.application"> ng-model="ctrl.annotation.application">
</input> </input>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-10">Trigger</span> <span class="gf-form-label width-10">Trigger</span>
<input type="text" <input type="text"
class="gf-form-input max-width-16" class="gf-form-input max-width-16"
ng-model="ctrl.annotation.trigger"> ng-model="ctrl.annotation.trigger">
</input> </input>
</div> </div>
</div> </div>
</div> </div>
<div class="gf-form-group"> <div class="gf-form-group">
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-10">Minimum severity</span> <span class="gf-form-label width-10">Minimum severity</span>
<div class="gf-form-select-wrapper"> <div class="gf-form-select-wrapper">
<select class="gf-form-input gf-size-auto" <select class="gf-form-input gf-size-auto"
ng-init='ctrl.annotation.minseverity = ctrl.annotation.minseverity || 0' ng-init='ctrl.annotation.minseverity = ctrl.annotation.minseverity || 0'
ng-model='ctrl.annotation.minseverity' ng-model='ctrl.annotation.minseverity'
ng-options="v as k for (k, v) in { ng-options="v as k for (k, v) in {
'Not classified': 0, 'Not classified': 0,
'Information': 1, 'Information': 1,
'Warning': 2, 'Warning': 2,
'Average': 3, 'Average': 3,
'High': 4, 'High': 4,
'Disaster': 5 'Disaster': 5
}" }"
ng-change="render()"> ng-change="render()">
</select> </select>
</div> </div>
</div> </div>
</div> </div>
<div class="gf-form-group"> <div class="gf-form-group">
<h6>Options</h6> <h6>Options</h6>
<div class="gf-form"> <div class="gf-form">
<editor-checkbox text="Show OK events" model="ctrl.annotation.showOkEvents"></editor-checkbox> <editor-checkbox text="Show OK events" model="ctrl.annotation.showOkEvents"></editor-checkbox>
<editor-checkbox text="Hide acknowledged events" model="ctrl.annotation.hideAcknowledged"></editor-checkbox> <editor-checkbox text="Hide acknowledged events" model="ctrl.annotation.hideAcknowledged"></editor-checkbox>
<editor-checkbox text="Show hostname" model="ctrl.annotation.showHostname"></editor-checkbox> <editor-checkbox text="Show hostname" model="ctrl.annotation.showHostname"></editor-checkbox>
</div> </div>
</div> </div>

View File

@@ -1,136 +1,136 @@
<datasource-http-settings current="ctrl.current"> <datasource-http-settings current="ctrl.current">
</datasource-http-settings> </datasource-http-settings>
<div class="gf-form-group"> <div class="gf-form-group">
<h3 class="page-heading">Zabbix API details</h3> <h3 class="page-heading">Zabbix API details</h3>
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-7"> <span class="gf-form-label width-7">
Username Username
</span> </span>
<input class="gf-form-input max-width-21" <input class="gf-form-input max-width-21"
type="text" type="text"
ng-model='ctrl.current.jsonData.username' ng-model='ctrl.current.jsonData.username'
placeholder="user" placeholder="user"
required> required>
</input> </input>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-7"> <span class="gf-form-label width-7">
Password Password
</span> </span>
<input class="gf-form-input max-width-21" <input class="gf-form-input max-width-21"
type="password" type="password"
ng-model='ctrl.current.jsonData.password' ng-model='ctrl.current.jsonData.password'
placeholder="password"> placeholder="password">
</input> </input>
</div> </div>
<gf-form-switch class="gf-form" label-class="width-7" <gf-form-switch class="gf-form" label-class="width-7"
label="Trends" label="Trends"
checked="ctrl.current.jsonData.trends" checked="ctrl.current.jsonData.trends"
switch-class="max-width-5"> switch-class="max-width-5">
</gf-form-switch> </gf-form-switch>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form" ng-if="ctrl.current.jsonData.trends"> <div class="gf-form" ng-if="ctrl.current.jsonData.trends">
<span class="gf-form-label width-7"> <span class="gf-form-label width-7">
After After
<info-popover mode="right-normal"> <info-popover mode="right-normal">
Time after which trends will be used. Time after which trends will be used.
Best practice is to set this value to your history storage period (7d, 30d, etc). Best practice is to set this value to your history storage period (7d, 30d, etc).
</info-popover> </info-popover>
</span> </span>
<input class="gf-form-input max-width-5" <input class="gf-form-input max-width-5"
type="text" type="text"
ng-model='ctrl.current.jsonData.trendsFrom' ng-model='ctrl.current.jsonData.trendsFrom'
placeholder="7d"> placeholder="7d">
</input> </input>
</div> </div>
<div class="gf-form" ng-if="ctrl.current.jsonData.trends"> <div class="gf-form" ng-if="ctrl.current.jsonData.trends">
<span class="gf-form-label width-7"> <span class="gf-form-label width-7">
Range Range
<info-popover mode="right-normal"> <info-popover mode="right-normal">
Time range width after which trends will be used instead of history. Time range width after which trends will be used instead of history.
It's better to set this value in range of 4 to 7 days to prevent loading large amount of history data. It's better to set this value in range of 4 to 7 days to prevent loading large amount of history data.
</info-popover> </info-popover>
</span> </span>
<input class="gf-form-input max-width-5" type="text" ng-model='ctrl.current.jsonData.trendsRange' placeholder="4d"> <input class="gf-form-input max-width-5" type="text" ng-model='ctrl.current.jsonData.trendsRange' placeholder="4d">
</input> </input>
</div> </div>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-12"> <span class="gf-form-label width-12">
Cache TTL Cache TTL
<info-popover mode="right-normal"> <info-popover mode="right-normal">
Zabbix data source caches metric names in memory. Specify how often data will be updated. Zabbix data source caches metric names in memory. Specify how often data will be updated.
</info-popover> </info-popover>
</span> </span>
<input class="gf-form-input max-width-5" <input class="gf-form-input max-width-5"
type="text" type="text"
ng-model='ctrl.current.jsonData.cacheTTL' ng-model='ctrl.current.jsonData.cacheTTL'
placeholder="1h"> placeholder="1h">
</input> </input>
</div> </div>
</div> </div>
<div class="gf-form-group"> <div class="gf-form-group">
<h3 class="page-heading">Direct DB Connection</h3> <h3 class="page-heading">Direct DB Connection</h3>
<gf-form-switch class="gf-form" label-class="width-12" <gf-form-switch class="gf-form" label-class="width-12"
label="Enable" label="Enable"
checked="ctrl.current.jsonData.dbConnection.enable"> checked="ctrl.current.jsonData.dbConnection.enable">
</gf-form-switch> </gf-form-switch>
<div ng-if="ctrl.current.jsonData.dbConnection.enable"> <div ng-if="ctrl.current.jsonData.dbConnection.enable">
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<span class="gf-form-label width-12"> <span class="gf-form-label width-12">
SQL Data Source SQL Data Source
<info-popover mode="right-normal"> <info-popover mode="right-normal">
Select SQL Data Source for Zabbix database. Select SQL Data Source for Zabbix database.
In order to use this feature you should <a href="/datasources/new" target="_blank">create</a> and In order to use this feature you should <a href="/datasources/new" target="_blank">create</a> and
configure it first. Zabbix plugin uses this data source for querying history data directly from database. configure it first. Zabbix plugin uses this data source for querying history data directly from database.
This way usually faster than pulling data from Zabbix API, especially on the wide time ranges, and reduces This way usually faster than pulling data from Zabbix API, especially on the wide time ranges, and reduces
amount of data transfered. amount of data transfered.
</info-popover> </info-popover>
</span> </span>
<div class="gf-form-select-wrapper max-width-16"> <div class="gf-form-select-wrapper max-width-16">
<select class="gf-form-input" ng-model="ctrl.current.jsonData.dbConnection.datasourceId" <select class="gf-form-input" ng-model="ctrl.current.jsonData.dbConnection.datasourceId"
ng-options="ds.id as ds.name for ds in ctrl.sqlDataSources"> ng-options="ds.id as ds.name for ds in ctrl.sqlDataSources">
</select> </select>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="gf-form-group"> <div class="gf-form-group">
<h3 class="page-heading">Alerting</h3> <h3 class="page-heading">Alerting</h3>
<gf-form-switch class="gf-form" label-class="width-12" <gf-form-switch class="gf-form" label-class="width-12"
label="Enable alerting" label="Enable alerting"
checked="ctrl.current.jsonData.alerting"> checked="ctrl.current.jsonData.alerting">
</gf-form-switch> </gf-form-switch>
<div ng-if="ctrl.current.jsonData.alerting"> <div ng-if="ctrl.current.jsonData.alerting">
<gf-form-switch class="gf-form" label-class="width-12" <gf-form-switch class="gf-form" label-class="width-12"
label="Add thresholds" label="Add thresholds"
checked="ctrl.current.jsonData.addThresholds"> checked="ctrl.current.jsonData.addThresholds">
</gf-form-switch> </gf-form-switch>
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<span class="gf-form-label width-12">Min severity</span> <span class="gf-form-label width-12">Min severity</span>
<div class="gf-form-select-wrapper max-width-16"> <div class="gf-form-select-wrapper max-width-16">
<select class="gf-form-input" ng-model="ctrl.current.jsonData.alertingMinSeverity" <select class="gf-form-input" ng-model="ctrl.current.jsonData.alertingMinSeverity"
ng-options="s.val as s.text for s in [ ng-options="s.val as s.text for s in [
{val: 0, text: 'Not classified'}, {val: 1, text:'Information'}, {val: 0, text: 'Not classified'}, {val: 1, text:'Information'},
{val: 2, text: 'Warning'}, {val: 3, text: 'Average'}, {val: 2, text: 'Warning'}, {val: 3, text: 'Average'},
{val: 4, text: 'High'}, {val: 5, text: 'Disaster'}]"> {val: 4, text: 'High'}, {val: 5, text: 'Disaster'}]">
</select> </select>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="gf-form-group"> <div class="gf-form-group">
<h3 class="page-heading">Other</h3> <h3 class="page-heading">Other</h3>
<gf-form-switch class="gf-form" label-class="width-20" <gf-form-switch class="gf-form" label-class="width-20"
label="Disable acknowledges for read-only users" label="Disable acknowledges for read-only users"
checked="ctrl.current.jsonData.disableReadOnlyUsersAck"> checked="ctrl.current.jsonData.disableReadOnlyUsersAck">
</gf-form-switch> </gf-form-switch>
</div> </div>

View File

@@ -1,235 +1,235 @@
<query-editor-row query-ctrl="ctrl" can-collapse="false"> <query-editor-row query-ctrl="ctrl" can-collapse="false">
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label width-7">Query Mode</label> <label class="gf-form-label width-7">Query Mode</label>
<div class="gf-form-select-wrapper max-width-20"> <div class="gf-form-select-wrapper max-width-20">
<select class="gf-form-input" <select class="gf-form-input"
ng-change="ctrl.switchEditorMode(ctrl.target.mode)" ng-change="ctrl.switchEditorMode(ctrl.target.mode)"
ng-model="ctrl.target.mode" ng-model="ctrl.target.mode"
ng-options="m.mode as m.text for m in ctrl.editorModes"> ng-options="m.mode as m.text for m in ctrl.editorModes">
</select> </select>
</div> </div>
</div> </div>
<div class="gf-form" ng-show="ctrl.target.mode == editorMode.TEXT"> <div class="gf-form" ng-show="ctrl.target.mode == editorMode.TEXT">
<label class="gf-form-label query-keyword width-8">Format As</label> <label class="gf-form-label query-keyword width-8">Format As</label>
<div class="gf-form-select-wrapper"> <div class="gf-form-select-wrapper">
<select class="gf-form-input gf-size-auto" ng-model="ctrl.target.resultFormat" ng-options="f.value as f.text for f in ctrl.resultFormats" ng-change="ctrl.refresh()"></select> <select class="gf-form-input gf-size-auto" ng-model="ctrl.target.resultFormat" ng-options="f.value as f.text for f in ctrl.resultFormats" ng-change="ctrl.refresh()"></select>
</div> </div>
</div> </div>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div> <div class="gf-form-label gf-form-label--grow"></div>
</div> </div>
</div> </div>
<!-- IT Service editor --> <!-- IT Service editor -->
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.ITSERVICE"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.ITSERVICE">
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">IT Service</label> <label class="gf-form-label query-keyword width-7">IT Service</label>
<input type="text" <input type="text"
ng-model="ctrl.target.itServiceFilter" ng-model="ctrl.target.itServiceFilter"
bs-typeahead="ctrl.getITServices" bs-typeahead="ctrl.getITServices"
ng-blur="ctrl.onTargetBlur()" ng-blur="ctrl.onTargetBlur()"
data-min-length=0 data-min-length=0
data-items=100 data-items=100
class="gf-form-input" class="gf-form-input"
ng-class="{ ng-class="{
'zbx-variable': ctrl.isVariable(ctrl.target.itServiceFilter), 'zbx-variable': ctrl.isVariable(ctrl.target.itServiceFilter),
'zbx-regex': ctrl.isRegex(ctrl.target.itServiceFilter) 'zbx-regex': ctrl.isRegex(ctrl.target.itServiceFilter)
}"> }">
</input> </input>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword">Property</label> <label class="gf-form-label query-keyword">Property</label>
<div class="gf-form-select-wrapper"> <div class="gf-form-select-wrapper">
<select class="gf-form-input" <select class="gf-form-input"
ng-change="ctrl.onTargetBlur()" ng-change="ctrl.onTargetBlur()"
ng-model="ctrl.target.slaProperty" ng-model="ctrl.target.slaProperty"
ng-options="slaProperty.name for slaProperty in ctrl.slaPropertyList track by slaProperty.name"> ng-options="slaProperty.name for slaProperty in ctrl.slaPropertyList track by slaProperty.name">
</select> </select>
</div> </div>
</div> </div>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div> <div class="gf-form-label gf-form-label--grow"></div>
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT || ctrl.target.mode == editorMode.TRIGGERS"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT || ctrl.target.mode == editorMode.TRIGGERS">
<!-- Select Group --> <!-- Select Group -->
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Group</label> <label class="gf-form-label query-keyword width-7">Group</label>
<input type="text" <input type="text"
ng-model="ctrl.target.group.filter" ng-model="ctrl.target.group.filter"
bs-typeahead="ctrl.getGroupNames" bs-typeahead="ctrl.getGroupNames"
ng-blur="ctrl.onTargetBlur()" ng-blur="ctrl.onTargetBlur()"
data-min-length=0 data-min-length=0
data-items=100 data-items=100
class="gf-form-input" class="gf-form-input"
ng-class="{ ng-class="{
'zbx-variable': ctrl.isVariable(ctrl.target.group.filter), 'zbx-variable': ctrl.isVariable(ctrl.target.group.filter),
'zbx-regex': ctrl.isRegex(ctrl.target.group.filter) 'zbx-regex': ctrl.isRegex(ctrl.target.group.filter)
}"></input> }"></input>
</div> </div>
<!-- Select Host --> <!-- Select Host -->
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword width-8">Host</label> <label class="gf-form-label query-keyword width-8">Host</label>
<input type="text" <input type="text"
ng-model="ctrl.target.host.filter" ng-model="ctrl.target.host.filter"
bs-typeahead="ctrl.getHostNames" bs-typeahead="ctrl.getHostNames"
ng-blur="ctrl.onTargetBlur()" ng-blur="ctrl.onTargetBlur()"
data-min-length=0 data-min-length=0
data-items=100 data-items=100
class="gf-form-input" class="gf-form-input"
ng-class="{ ng-class="{
'zbx-variable': ctrl.isVariable(ctrl.target.host.filter), 'zbx-variable': ctrl.isVariable(ctrl.target.host.filter),
'zbx-regex': ctrl.isRegex(ctrl.target.host.filter) 'zbx-regex': ctrl.isRegex(ctrl.target.host.filter)
}"> }">
</div> </div>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div> <div class="gf-form-label gf-form-label--grow"></div>
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT || ctrl.target.mode == editorMode.TRIGGERS"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT || ctrl.target.mode == editorMode.TRIGGERS">
<!-- Select Application --> <!-- Select Application -->
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Application</label> <label class="gf-form-label query-keyword width-7">Application</label>
<input type="text" <input type="text"
ng-model="ctrl.target.application.filter" ng-model="ctrl.target.application.filter"
bs-typeahead="ctrl.getApplicationNames" bs-typeahead="ctrl.getApplicationNames"
ng-blur="ctrl.onTargetBlur()" ng-blur="ctrl.onTargetBlur()"
data-min-length=0 data-min-length=0
data-items=100 data-items=100
class="gf-form-input" class="gf-form-input"
ng-class="{ ng-class="{
'zbx-variable': ctrl.isVariable(ctrl.target.application.filter), 'zbx-variable': ctrl.isVariable(ctrl.target.application.filter),
'zbx-regex': ctrl.isRegex(ctrl.target.application.filter) 'zbx-regex': ctrl.isRegex(ctrl.target.application.filter)
}"> }">
</div> </div>
<!-- Select Item --> <!-- Select Item -->
<div class="gf-form" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT"> <div class="gf-form" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.TEXT">
<label class="gf-form-label query-keyword width-8">Item</label> <label class="gf-form-label query-keyword width-8">Item</label>
<input type="text" <input type="text"
ng-model="ctrl.target.item.filter" ng-model="ctrl.target.item.filter"
bs-typeahead="ctrl.getItemNames" bs-typeahead="ctrl.getItemNames"
ng-blur="ctrl.onTargetBlur()" ng-blur="ctrl.onTargetBlur()"
data-min-length=0 data-min-length=0
data-items=100 data-items=100
class="gf-form-input" class="gf-form-input"
ng-class="{ ng-class="{
'zbx-variable': ctrl.isVariable(ctrl.target.item.filter), 'zbx-variable': ctrl.isVariable(ctrl.target.item.filter),
'zbx-regex': ctrl.isRegex(ctrl.target.item.filter) 'zbx-regex': ctrl.isRegex(ctrl.target.item.filter)
}"> }">
</div> </div>
<div class="gf-form max-width-23" ng-show="ctrl.target.mode == editorMode.TRIGGERS"> <div class="gf-form max-width-23" ng-show="ctrl.target.mode == editorMode.TRIGGERS">
<label class="gf-form-label query-keyword width-8">Min Severity</label> <label class="gf-form-label query-keyword width-8">Min Severity</label>
<div class="gf-form-select-wrapper width-16"> <div class="gf-form-select-wrapper width-16">
<select class="gf-form-input" <select class="gf-form-input"
ng-change="ctrl.onTargetBlur()" ng-change="ctrl.onTargetBlur()"
ng-model="ctrl.target.triggers.minSeverity" ng-model="ctrl.target.triggers.minSeverity"
ng-options="s.val as s.text for s in ctrl.triggerSeverity"> ng-options="s.val as s.text for s in ctrl.triggerSeverity">
</select> </select>
</div> </div>
</div> </div>
<div class="gf-form max-width-20" ng-show="ctrl.target.mode == editorMode.TRIGGERS"> <div class="gf-form max-width-20" ng-show="ctrl.target.mode == editorMode.TRIGGERS">
<label class="gf-form-label query-keyword width-8">Acknowledged</label> <label class="gf-form-label query-keyword width-8">Acknowledged</label>
<div class="gf-form-select-wrapper width-12"> <div class="gf-form-select-wrapper width-12">
<select class="gf-form-input" <select class="gf-form-input"
ng-change="ctrl.onTargetBlur()" ng-change="ctrl.onTargetBlur()"
ng-model="ctrl.target.triggers.acknowledged" ng-model="ctrl.target.triggers.acknowledged"
ng-options="a.value as a.text for a in ctrl.ackFilters"> ng-options="a.value as a.text for a in ctrl.ackFilters">
</select> </select>
</div> </div>
</div> </div>
<gf-form-switch class="gf-form" label="Count" ng-show="ctrl.target.mode == editorMode.TRIGGERS" <gf-form-switch class="gf-form" label="Count" ng-show="ctrl.target.mode == editorMode.TRIGGERS"
checked="ctrl.target.triggers.count" on-change="ctrl.onTargetBlur()"> checked="ctrl.target.triggers.count" on-change="ctrl.onTargetBlur()">
</gf-form-switch> </gf-form-switch>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<label class="gf-form-label gf-form-label--grow"> <label class="gf-form-label gf-form-label--grow">
<a ng-click="ctrl.toggleQueryOptions()" ng-hide="ctrl.target.mode == editorMode.TRIGGERS"> <a ng-click="ctrl.toggleQueryOptions()" ng-hide="ctrl.target.mode == editorMode.TRIGGERS">
<i class="fa fa-caret-down" ng-show="ctrl.showQueryOptions"></i> <i class="fa fa-caret-down" ng-show="ctrl.showQueryOptions"></i>
<i class="fa fa-caret-right" ng-hide="ctrl.showQueryOptions"></i> <i class="fa fa-caret-right" ng-hide="ctrl.showQueryOptions"></i>
{{ctrl.queryOptionsText}} {{ctrl.queryOptionsText}}
</a> </a>
</label> </label>
</div> </div>
</div> </div>
<!-- Query options --> <!-- Query options -->
<div class="gf-form-group" ng-if="ctrl.showQueryOptions"> <div class="gf-form-group" ng-if="ctrl.showQueryOptions">
<div class="gf-form offset-width-7" ng-hide="ctrl.target.mode == editorMode.TRIGGERS"> <div class="gf-form offset-width-7" ng-hide="ctrl.target.mode == editorMode.TRIGGERS">
<gf-form-switch class="gf-form" label-class="width-10" <gf-form-switch class="gf-form" label-class="width-10"
label="Show disabled items" label="Show disabled items"
checked="ctrl.target.options.showDisabledItems" checked="ctrl.target.options.showDisabledItems"
on-change="ctrl.onQueryOptionChange()"> on-change="ctrl.onQueryOptionChange()">
</gf-form-switch> </gf-form-switch>
</div> </div>
<div class="gf-form offset-width-7" ng-show="ctrl.target.mode === editorMode.TEXT && ctrl.target.resultFormat === 'table'"> <div class="gf-form offset-width-7" ng-show="ctrl.target.mode === editorMode.TEXT && ctrl.target.resultFormat === 'table'">
<gf-form-switch class="gf-form" label-class="width-10" <gf-form-switch class="gf-form" label-class="width-10"
label="Skip empty values" label="Skip empty values"
checked="ctrl.target.options.skipEmptyValues" checked="ctrl.target.options.skipEmptyValues"
on-change="ctrl.onQueryOptionChange()"> on-change="ctrl.onQueryOptionChange()">
</gf-form-switch> </gf-form-switch>
</div> </div>
</div> </div>
<!-- Item IDs editor mode --> <!-- Item IDs editor mode -->
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.ITEMID"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.ITEMID">
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Item IDs</label> <label class="gf-form-label query-keyword width-7">Item IDs</label>
<input type="text" <input type="text"
ng-model="ctrl.target.itemids" ng-model="ctrl.target.itemids"
bs-typeahead="ctrl.getVariables" bs-typeahead="ctrl.getVariables"
ng-blur="ctrl.onTargetBlur()" ng-blur="ctrl.onTargetBlur()"
data-min-length=0 data-min-length=0
data-items=100 data-items=100
class="gf-form-input" class="gf-form-input"
ng-class="{ ng-class="{
'zbx-variable': ctrl.isVariable(ctrl.target.itServiceFilter), 'zbx-variable': ctrl.isVariable(ctrl.target.itServiceFilter),
'zbx-regex': ctrl.isRegex(ctrl.target.itServiceFilter) 'zbx-regex': ctrl.isRegex(ctrl.target.itServiceFilter)
}"> }">
</input> </input>
</div> </div>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div> <div class="gf-form-label gf-form-label--grow"></div>
</div> </div>
</div> </div>
<!-- Metric processing functions --> <!-- Metric processing functions -->
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.ITEMID"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.METRICS || ctrl.target.mode == editorMode.ITEMID">
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword width-7">Functions</label> <label class="gf-form-label query-keyword width-7">Functions</label>
<div ng-repeat="func in ctrl.target.functions" class="gf-form-label query-part" metric-function-editor></div> <div ng-repeat="func in ctrl.target.functions" class="gf-form-label query-part" metric-function-editor></div>
</div> </div>
<div class="gf-form dropdown" add-metric-function> <div class="gf-form dropdown" add-metric-function>
</div> </div>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div> <div class="gf-form-label gf-form-label--grow"></div>
</div> </div>
</div> </div>
<!-- Text mode options --> <!-- Text mode options -->
<div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.TEXT"> <div class="gf-form-inline" ng-show="ctrl.target.mode == editorMode.TEXT">
<!-- Text metric regex --> <!-- Text metric regex -->
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Text filter</label> <label class="gf-form-label query-keyword width-7">Text filter</label>
<input type="text" <input type="text"
class="gf-form-input" class="gf-form-input"
ng-model="ctrl.target.textFilter" ng-model="ctrl.target.textFilter"
spellcheck='false' spellcheck='false'
placeholder="Text filter (regex)" placeholder="Text filter (regex)"
ng-blur="ctrl.onTargetBlur()"> ng-blur="ctrl.onTargetBlur()">
</div> </div>
<gf-form-switch class="gf-form" label="Use capture groups" checked="ctrl.target.useCaptureGroups" on-change="ctrl.onTargetBlur()"> <gf-form-switch class="gf-form" label="Use capture groups" checked="ctrl.target.useCaptureGroups" on-change="ctrl.onTargetBlur()">
</gf-form-switch> </gf-form-switch>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div> <div class="gf-form-label gf-form-label--grow"></div>
</div> </div>
</div> </div>
</query-editor-row> </query-editor-row>

View File

@@ -1,88 +1,88 @@
<section class="grafana-metric-options gf-form-group"> <section class="grafana-metric-options gf-form-group">
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form max-width-15"> <div class="gf-form max-width-15">
<span class="gf-form-label">Max data points</span> <span class="gf-form-label">Max data points</span>
<input type="text" <input type="text"
class="gf-form-input" class="gf-form-input"
ng-model="ctrl.panelCtrl.panel.maxDataPoints" ng-model="ctrl.panelCtrl.panel.maxDataPoints"
bs-tooltip="'Override max data points, automatically set to graph width in pixels.'" bs-tooltip="'Override max data points, automatically set to graph width in pixels.'"
data-placement="right" data-placement="right"
ng-model-onblur ng-change="ctrl.panelCtrl.refresh()" ng-model-onblur ng-change="ctrl.panelCtrl.refresh()"
spellcheck='false' spellcheck='false'
placeholder="auto"> placeholder="auto">
</input> </input>
</div> </div>
</div> </div>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-10"> <span class="gf-form-label width-10">
<i class="fa fa-info-circle"></i> <i class="fa fa-info-circle"></i>
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom"> <a ng-click="ctrl.panelCtrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
Max data points Max data points
</a> </a>
</span> </span>
<span class="gf-form-label width-10"> <span class="gf-form-label width-10">
<i class="fa fa-info-circle"></i> <i class="fa fa-info-circle"></i>
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom"> <a ng-click="ctrl.panelCtrl.toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
IT services IT services
</a> </a>
</span> </span>
<span class="gf-form-label width-12"> <span class="gf-form-label width-12">
<i class="fa fa-info-circle"></i> <i class="fa fa-info-circle"></i>
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom"> <a ng-click="ctrl.panelCtrl.toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
IT service property IT service property
</a> </a>
</span> </span>
<span class="gf-form-label width-8"> <span class="gf-form-label width-8">
<i class="fa fa-info-circle"></i> <i class="fa fa-info-circle"></i>
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom"> <a ng-click="ctrl.panelCtrl.toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
Text filter Text filter
</a> </a>
</span> </span>
</div> </div>
</div> </div>
</section> </section>
<div class="editor-row"> <div class="editor-row">
<div class="pull-left"> <div class="pull-left">
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 1"> <div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
<h5>Max data points</h5> <h5>Max data points</h5>
<ul> <ul>
<li>Grafana-Zabbix plugin uses maxDataPoints parameter to consolidate the real number of values down to this <li>Grafana-Zabbix plugin uses maxDataPoints parameter to consolidate the real number of values down to this
number number
</li> </li>
<li>If there are more real values, then by default they will be consolidated using averages</li> <li>If there are more real values, then by default they will be consolidated using averages</li>
<li>This could hide real peaks and max values in your series</li> <li>This could hide real peaks and max values in your series</li>
<li>Point consolidation will effect series legend values (min,max,total,current)</li> <li>Point consolidation will effect series legend values (min,max,total,current)</li>
<li>If you override maxDataPoint and set a high value performance can be severely effected</li> <li>If you override maxDataPoint and set a high value performance can be severely effected</li>
</ul> </ul>
</div> </div>
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 2"> <div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 2">
<h5>IT services</h5> <h5>IT services</h5>
<ul> <ul>
<li>Select "IT services" in targets menu to activate IT services mode.</li> <li>Select "IT services" in targets menu to activate IT services mode.</li>
</ul> </ul>
</div> </div>
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 3"> <div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 3">
<h5>IT service property</h5> <h5>IT service property</h5>
<ul> <ul>
<li>Zabbix returns the following availability information about IT service</li> <li>Zabbix returns the following availability information about IT service</li>
<li>Status - current status of the IT service</li> <li>Status - current status of the IT service</li>
<li>SLA - SLA for the given time interval</li> <li>SLA - SLA for the given time interval</li>
<li>OK time - time the service was in OK state, in seconds</li> <li>OK time - time the service was in OK state, in seconds</li>
<li>Problem time - time the service was in problem state, in seconds</li> <li>Problem time - time the service was in problem state, in seconds</li>
<li>Down time - time the service was in scheduled downtime, in seconds</li> <li>Down time - time the service was in scheduled downtime, in seconds</li>
</ul> </ul>
</div> </div>
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 4"> <div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 4">
<h5>Text filter</h5> <h5>Text filter</h5>
<ul> <ul>
<li>Use regex to extract a part of the returned value.</li> <li>Use regex to extract a part of the returned value.</li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,36 +1,36 @@
{ {
"type": "datasource", "type": "datasource",
"name": "Zabbix", "name": "Zabbix",
"id": "alexanderzobnin-zabbix-datasource", "id": "alexanderzobnin-zabbix-datasource",
"includes": [ "includes": [
{ {
"type": "dashboard", "type": "dashboard",
"name": "Zabbix System Status", "name": "Zabbix System Status",
"path": "../dashboards/zabbix_system_status.json" "path": "../dashboards/zabbix_system_status.json"
}, },
{ {
"type": "dashboard", "type": "dashboard",
"name": "Zabbix Template Linux Server", "name": "Zabbix Template Linux Server",
"path": "../dashboards/template_linux_server.json" "path": "../dashboards/template_linux_server.json"
} }
], ],
"metrics": true, "metrics": true,
"annotations": true, "annotations": true,
"queryOptions": { "queryOptions": {
"maxDataPoints": true "maxDataPoints": true
}, },
"info": { "info": {
"author": { "author": {
"name": "Alexander Zobnin", "name": "Alexander Zobnin",
"url": "https://github.com/alexanderzobnin/grafana-zabbix" "url": "https://github.com/alexanderzobnin/grafana-zabbix"
}, },
"logos": { "logos": {
"small": "img/zabbix_app_logo.svg", "small": "img/zabbix_app_logo.svg",
"large": "img/zabbix_app_logo.svg" "large": "img/zabbix_app_logo.svg"
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,31 +1,31 @@
#### Max data points #### Max data points
Override max data points, automatically set to graph width in pixels. 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 affect series legend values (min,max,total,current). Override max data points, automatically set to graph width in pixels. 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 affect series legend values (min,max,total,current).
#### Query Mode #### Query Mode
##### Merics ##### Merics
Data from numeric items. Data from numeric items.
##### Text ##### Text
Data from items with `Character`, `Text` or `Log` type. Data from items with `Character`, `Text` or `Log` type.
##### IT Services ##### IT Services
Time series representation of IT Services data Time series representation of IT Services data
###### IT service property ###### IT service property
Zabbix returns the following availability information about IT service: Zabbix returns the following availability information about IT service:
- Status - current status of the IT service - Status - current status of the IT service
- SLA - SLA for the given time interval - SLA - SLA for the given time interval
- OK time - time the service was in OK state, in seconds - OK time - time the service was in OK state, in seconds
- Problem time - time the service was in problem 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 - Down time - time the service was in scheduled downtime, in seconds
##### Item ID ##### Item ID
Data from items with specified ID's (comma separated). Data from items with specified ID's (comma separated).
This mode is suitable for rendering charts in grafana by passing itemids as url params. This mode is suitable for rendering charts in grafana by passing itemids as url params.
1. Create multivalue template variable with type _Custom_, for example, `itemids`. 1. Create multivalue template variable with type _Custom_, for example, `itemids`.
1. Create graph with desired parameters and use `$itemids` in _Item IDs_ filed. 1. Create graph with desired parameters and use `$itemids` in _Item IDs_ filed.
1. Save dashboard. 1. Save dashboard.
1. Click to graph title and select _Share_ -> _Direct link rendered image_. 1. Click to graph title and select _Share_ -> _Direct link rendered image_.
1. Use this URL for graph png image and set `var-itemids` param to desired IDs. Note, for multiple IDs you should pass multiple params, like `&var-itemids=28276&var-itemids=28277`. 1. Use this URL for graph png image and set `var-itemids` param to desired IDs. Note, for multiple IDs you should pass multiple params, like `&var-itemids=28276&var-itemids=28277`.
##### Triggers ##### Triggers
Active triggers count for selected hosts or table data like Zabbix _System status_ panel on the main dashboard. Active triggers count for selected hosts or table data like Zabbix _System status_ panel on the main dashboard.

View File

@@ -17,24 +17,24 @@ System.register(['lodash', 'app/core/table_model', './constants'], function (_ex
} }
} }
/** /**
* Convert Zabbix API history.get response to Grafana format * Convert Zabbix API history.get response to Grafana format
* *
* @return {Array} Array of timeseries in Grafana format * @return {Array} Array of timeseries in Grafana format
* { * {
* target: "Metric name", * target: "Metric name",
* datapoints: [[<value>, <unixtime>], ...] * datapoints: [[<value>, <unixtime>], ...]
* } * }
*/ */
function convertHistory(history, items, addHostName, convertPointCallback) { function convertHistory(history, items, addHostName, convertPointCallback) {
/** /**
* Response should be in the format: * Response should be in the format:
* data: [ * data: [
* { * {
* target: "Metric name", * target: "Metric name",
* datapoints: [[<value>, <unixtime>], ...] * datapoints: [[<value>, <unixtime>], ...]
* }, ... * }, ...
* ] * ]
*/ */
// Group history by itemid // Group history by itemid

File diff suppressed because one or more lines are too long

View File

@@ -1,51 +1,51 @@
import _ from 'lodash'; import _ from 'lodash';
import dataProcessor from '../dataProcessor'; import dataProcessor from '../dataProcessor';
describe('dataProcessor', () => { describe('dataProcessor', () => {
let ctx = {}; let ctx = {};
beforeEach(() => { beforeEach(() => {
ctx.datapoints = [ ctx.datapoints = [
[[10, 1500000000000], [2, 1500000001000], [7, 1500000002000], [1, 1500000003000]], [[10, 1500000000000], [2, 1500000001000], [7, 1500000002000], [1, 1500000003000]],
[[9, 1500000000000], [3, 1500000001000], [4, 1500000002000], [8, 1500000003000]], [[9, 1500000000000], [3, 1500000001000], [4, 1500000002000], [8, 1500000003000]],
]; ];
}); });
describe('When apply groupBy() functions', () => { describe('When apply groupBy() functions', () => {
it('should return series average', () => { it('should return series average', () => {
let aggregateBy = dataProcessor.metricFunctions['groupBy']; let aggregateBy = dataProcessor.metricFunctions['groupBy'];
const avg2s = _.map(ctx.datapoints, (dp) => aggregateBy('2s', 'avg', dp)); const avg2s = _.map(ctx.datapoints, (dp) => aggregateBy('2s', 'avg', dp));
expect(avg2s).toEqual([ expect(avg2s).toEqual([
[[6, 1500000000000], [4, 1500000002000]], [[6, 1500000000000], [4, 1500000002000]],
[[6, 1500000000000], [6, 1500000002000]], [[6, 1500000000000], [6, 1500000002000]],
]); ]);
const avg10s = _.map(ctx.datapoints, (dp) => aggregateBy('10s', 'avg', dp)); const avg10s = _.map(ctx.datapoints, (dp) => aggregateBy('10s', 'avg', dp));
expect(avg10s).toEqual([ expect(avg10s).toEqual([
[[5, 1500000000000]], [[5, 1500000000000]],
[[6, 1500000000000]], [[6, 1500000000000]],
]); ]);
// not aligned // not aligned
const dp = [[10, 1500000001000], [2, 1500000002000], [7, 1500000003000], [1, 1500000004000]]; const dp = [[10, 1500000001000], [2, 1500000002000], [7, 1500000003000], [1, 1500000004000]];
expect(aggregateBy('2s', 'avg', dp)).toEqual([ expect(aggregateBy('2s', 'avg', dp)).toEqual([
[10, 1500000000000], [4.5, 1500000002000], [1, 1500000004000] [10, 1500000000000], [4.5, 1500000002000], [1, 1500000004000]
]); ]);
}); });
}); });
describe('When apply aggregateBy() functions', () => { describe('When apply aggregateBy() functions', () => {
it('should return series average', () => { it('should return series average', () => {
let aggregateBy = dataProcessor.metricFunctions['aggregateBy']; let aggregateBy = dataProcessor.metricFunctions['aggregateBy'];
const avg1s = aggregateBy('1s', 'avg', ctx.datapoints); const avg1s = aggregateBy('1s', 'avg', ctx.datapoints);
expect(avg1s).toEqual([ expect(avg1s).toEqual([
[9.5, 1500000000000], [2.5, 1500000001000], [5.5, 1500000002000], [4.5, 1500000003000] [9.5, 1500000000000], [2.5, 1500000001000], [5.5, 1500000002000], [4.5, 1500000003000]
]); ]);
const avg10s = aggregateBy('10s', 'avg', ctx.datapoints); const avg10s = aggregateBy('10s', 'avg', ctx.datapoints);
expect(avg10s).toEqual([ expect(avg10s).toEqual([
[5.5, 1500000000000] [5.5, 1500000000000]
]); ]);
}); });
}); });
}); });

View File

@@ -1,429 +1,429 @@
import _ from 'lodash'; import _ from 'lodash';
import Q, { Promise } from "q"; import Q, { Promise } from "q";
import {Datasource} from "../module"; import {Datasource} from "../module";
import {zabbixTemplateFormat} from "../datasource"; import {zabbixTemplateFormat} from "../datasource";
describe('ZabbixDatasource', () => { describe('ZabbixDatasource', () => {
let ctx = {}; let ctx = {};
beforeEach(() => { beforeEach(() => {
ctx.instanceSettings = { ctx.instanceSettings = {
jsonData: { jsonData: {
alerting: true, alerting: true,
username: 'zabbix', username: 'zabbix',
password: 'zabbix', password: 'zabbix',
trends: true, trends: true,
trendsFrom: '14d', trendsFrom: '14d',
trendsRange: '7d', trendsRange: '7d',
dbConnection: { dbConnection: {
enabled: false enabled: false
} }
} }
}; };
ctx.templateSrv = {}; ctx.templateSrv = {};
ctx.alertSrv = {}; ctx.alertSrv = {};
ctx.dashboardSrv = {}; ctx.dashboardSrv = {};
ctx.zabbixAlertingSrv = { ctx.zabbixAlertingSrv = {
setPanelAlertState: jest.fn(), setPanelAlertState: jest.fn(),
removeZabbixThreshold: jest.fn(), removeZabbixThreshold: jest.fn(),
}; };
ctx.zabbix = () => {}; ctx.zabbix = () => {};
ctx.ds = new Datasource(ctx.instanceSettings, ctx.templateSrv, ctx.alertSrv, ctx.dashboardSrv, ctx.zabbixAlertingSrv, ctx.zabbix); ctx.ds = new Datasource(ctx.instanceSettings, ctx.templateSrv, ctx.alertSrv, ctx.dashboardSrv, ctx.zabbixAlertingSrv, ctx.zabbix);
}); });
describe('When querying data', () => { describe('When querying data', () => {
beforeEach(() => { beforeEach(() => {
ctx.ds.replaceTemplateVars = (str) => str; ctx.ds.replaceTemplateVars = (str) => str;
ctx.ds.alertQuery = () => Q.when([]); ctx.ds.alertQuery = () => Q.when([]);
}); });
ctx.options = { ctx.options = {
targets: [ targets: [
{ {
group: {filter: ""}, group: {filter: ""},
host: {filter: ""}, host: {filter: ""},
application: {filter: ""}, application: {filter: ""},
item: {filter: ""} item: {filter: ""}
} }
], ],
range: {from: 'now-7d', to: 'now'} range: {from: 'now-7d', to: 'now'}
}; };
it('should return an empty array when no targets are set', (done) => { it('should return an empty array when no targets are set', (done) => {
let options = { let options = {
targets: [], targets: [],
range: {from: 'now-6h', to: 'now'} range: {from: 'now-6h', to: 'now'}
}; };
ctx.ds.query(options).then(result => { ctx.ds.query(options).then(result => {
expect(result.data.length).toBe(0); expect(result.data.length).toBe(0);
done(); done();
}); });
}); });
it('should use trends if it enabled and time more than trendsFrom', (done) => { it('should use trends if it enabled and time more than trendsFrom', (done) => {
let ranges = ['now-7d', 'now-168h', 'now-1M', 'now-1y']; let ranges = ['now-7d', 'now-168h', 'now-1M', 'now-1y'];
_.forEach(ranges, range => { _.forEach(ranges, range => {
ctx.options.range.from = range; ctx.options.range.from = range;
ctx.ds.queryNumericData = jest.fn(); ctx.ds.queryNumericData = jest.fn();
ctx.ds.query(ctx.options); ctx.ds.query(ctx.options);
// Check that useTrends options is true // Check that useTrends options is true
let callArgs = ctx.ds.queryNumericData.mock.calls[0]; let callArgs = ctx.ds.queryNumericData.mock.calls[0];
expect(callArgs[2]).toBe(true); expect(callArgs[2]).toBe(true);
ctx.ds.queryNumericData.mockClear(); ctx.ds.queryNumericData.mockClear();
}); });
done(); done();
}); });
it('shouldnt use trends if it enabled and time less than trendsFrom', (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']; let ranges = ['now-6d', 'now-167h', 'now-1h', 'now-30m', 'now-30s'];
_.forEach(ranges, range => { _.forEach(ranges, range => {
ctx.options.range.from = range; ctx.options.range.from = range;
ctx.ds.queryNumericData = jest.fn(); ctx.ds.queryNumericData = jest.fn();
ctx.ds.query(ctx.options); ctx.ds.query(ctx.options);
// Check that useTrends options is false // Check that useTrends options is false
let callArgs = ctx.ds.queryNumericData.mock.calls[0]; let callArgs = ctx.ds.queryNumericData.mock.calls[0];
expect(callArgs[2]).toBe(false); expect(callArgs[2]).toBe(false);
ctx.ds.queryNumericData.mockClear(); ctx.ds.queryNumericData.mockClear();
}); });
done(); done();
}); });
}); });
describe('When querying text data', () => { describe('When querying text data', () => {
beforeEach(() => { beforeEach(() => {
ctx.ds.replaceTemplateVars = (str) => str; ctx.ds.replaceTemplateVars = (str) => str;
ctx.ds.alertQuery = () => Q.when([]); ctx.ds.alertQuery = () => Q.when([]);
ctx.ds.zabbix.getHistory = jest.fn().mockReturnValue(Promise.resolve([ ctx.ds.zabbix.getHistory = jest.fn().mockReturnValue(Promise.resolve([
{clock: "1500010200", itemid:"10100", ns:"900111000", value:"Linux first"}, {clock: "1500010200", itemid:"10100", ns:"900111000", value:"Linux first"},
{clock: "1500010300", itemid:"10100", ns:"900111000", value:"Linux 2nd"}, {clock: "1500010300", itemid:"10100", ns:"900111000", value:"Linux 2nd"},
{clock: "1500010400", itemid:"10100", ns:"900111000", value:"Linux last"} {clock: "1500010400", itemid:"10100", ns:"900111000", value:"Linux last"}
])); ]));
ctx.ds.zabbix.getItemsFromTarget = jest.fn().mockReturnValue(Promise.resolve([ ctx.ds.zabbix.getItemsFromTarget = jest.fn().mockReturnValue(Promise.resolve([
{ {
hosts: [{hostid: "10001", name: "Zabbix server"}], hosts: [{hostid: "10001", name: "Zabbix server"}],
itemid: "10100", itemid: "10100",
name: "System information", name: "System information",
key_: "system.uname", key_: "system.uname",
} }
])); ]));
ctx.options = { ctx.options = {
range: {from: 'now-1h', to: 'now'}, range: {from: 'now-1h', to: 'now'},
targets: [ targets: [
{ {
group: {filter: ""}, group: {filter: ""},
host: {filter: "Zabbix server"}, host: {filter: "Zabbix server"},
application: {filter: ""}, application: {filter: ""},
item: {filter: "System information"}, item: {filter: "System information"},
textFilter: "", textFilter: "",
useCaptureGroups: true, useCaptureGroups: true,
mode: 2, mode: 2,
resultFormat: "table", resultFormat: "table",
options: { options: {
skipEmptyValues: false skipEmptyValues: false
} }
} }
], ],
}; };
}); });
it('should return data in table format', (done) => { it('should return data in table format', (done) => {
ctx.ds.query(ctx.options).then(result => { ctx.ds.query(ctx.options).then(result => {
expect(result.data.length).toBe(1); expect(result.data.length).toBe(1);
let tableData = result.data[0]; let tableData = result.data[0];
expect(tableData.columns).toEqual([ expect(tableData.columns).toEqual([
{text: 'Host'}, {text: 'Item'}, {text: 'Key'}, {text: 'Last value'} {text: 'Host'}, {text: 'Item'}, {text: 'Key'}, {text: 'Last value'}
]); ]);
expect(tableData.rows).toEqual([ expect(tableData.rows).toEqual([
['Zabbix server', 'System information', 'system.uname', 'Linux last'] ['Zabbix server', 'System information', 'system.uname', 'Linux last']
]); ]);
done(); done();
}); });
}); });
it('should extract value if regex with capture group is used', (done) => { it('should extract value if regex with capture group is used', (done) => {
ctx.options.targets[0].textFilter = "Linux (.*)"; ctx.options.targets[0].textFilter = "Linux (.*)";
ctx.ds.query(ctx.options).then(result => { ctx.ds.query(ctx.options).then(result => {
let tableData = result.data[0]; let tableData = result.data[0];
expect(tableData.rows[0][3]).toEqual('last'); expect(tableData.rows[0][3]).toEqual('last');
done(); done();
}); });
}); });
it('should skip item when last value is empty', () => { it('should skip item when last value is empty', () => {
ctx.ds.zabbix.getItemsFromTarget = jest.fn().mockReturnValue(Promise.resolve([ ctx.ds.zabbix.getItemsFromTarget = jest.fn().mockReturnValue(Promise.resolve([
{ {
hosts: [{hostid: "10001", name: "Zabbix server"}], hosts: [{hostid: "10001", name: "Zabbix server"}],
itemid: "10100", name: "System information", key_: "system.uname" itemid: "10100", name: "System information", key_: "system.uname"
}, },
{ {
hosts: [{hostid: "10002", name: "Server02"}], hosts: [{hostid: "10002", name: "Server02"}],
itemid: "90109", name: "System information", key_: "system.uname" itemid: "90109", name: "System information", key_: "system.uname"
} }
])); ]));
ctx.options.targets[0].options.skipEmptyValues = true; ctx.options.targets[0].options.skipEmptyValues = true;
ctx.ds.zabbix.getHistory = jest.fn().mockReturnValue(Promise.resolve([ ctx.ds.zabbix.getHistory = jest.fn().mockReturnValue(Promise.resolve([
{clock: "1500010200", itemid:"10100", ns:"900111000", value:"Linux first"}, {clock: "1500010200", itemid:"10100", ns:"900111000", value:"Linux first"},
{clock: "1500010300", itemid:"10100", ns:"900111000", value:"Linux 2nd"}, {clock: "1500010300", itemid:"10100", ns:"900111000", value:"Linux 2nd"},
{clock: "1500010400", itemid:"10100", ns:"900111000", value:"Linux last"}, {clock: "1500010400", itemid:"10100", ns:"900111000", value:"Linux last"},
{clock: "1500010200", itemid:"90109", ns:"900111000", value:"Non empty value"}, {clock: "1500010200", itemid:"90109", ns:"900111000", value:"Non empty value"},
{clock: "1500010500", itemid:"90109", ns:"900111000", value:""} {clock: "1500010500", itemid:"90109", ns:"900111000", value:""}
])); ]));
return ctx.ds.query(ctx.options).then(result => { return ctx.ds.query(ctx.options).then(result => {
let tableData = result.data[0]; let tableData = result.data[0];
expect(tableData.rows.length).toBe(1); expect(tableData.rows.length).toBe(1);
expect(tableData.rows[0][3]).toEqual('Linux last'); expect(tableData.rows[0][3]).toEqual('Linux last');
}); });
}); });
}); });
describe('When replacing template variables', () => { describe('When replacing template variables', () => {
function testReplacingVariable(target, varValue, expectedResult, done) { function testReplacingVariable(target, varValue, expectedResult, done) {
ctx.ds.templateSrv.replace = () => { ctx.ds.templateSrv.replace = () => {
return zabbixTemplateFormat(varValue); return zabbixTemplateFormat(varValue);
}; };
let result = ctx.ds.replaceTemplateVars(target); let result = ctx.ds.replaceTemplateVars(target);
expect(result).toBe(expectedResult); expect(result).toBe(expectedResult);
done(); done();
} }
/* /*
* Alphanumerics, spaces, dots, dashes and underscores * Alphanumerics, spaces, dots, dashes and underscores
* are allowed in Zabbix host name. * are allowed in Zabbix host name.
* 'AaBbCc0123 .-_' * 'AaBbCc0123 .-_'
*/ */
it('should return properly escaped regex', (done) => { it('should return properly escaped regex', (done) => {
let target = '$host'; let target = '$host';
let template_var_value = 'AaBbCc0123 .-_'; let template_var_value = 'AaBbCc0123 .-_';
let expected_result = '/^AaBbCc0123 \\.-_$/'; let expected_result = '/^AaBbCc0123 \\.-_$/';
testReplacingVariable(target, template_var_value, expected_result, done); testReplacingVariable(target, template_var_value, expected_result, done);
}); });
/* /*
* Single-value variable * Single-value variable
* $host = backend01 * $host = backend01
* $host => /^backend01|backend01$/ * $host => /^backend01|backend01$/
*/ */
it('should return proper regex for single value', (done) => { it('should return proper regex for single value', (done) => {
let target = '$host'; let target = '$host';
let template_var_value = 'backend01'; let template_var_value = 'backend01';
let expected_result = '/^backend01$/'; let expected_result = '/^backend01$/';
testReplacingVariable(target, template_var_value, expected_result, done); testReplacingVariable(target, template_var_value, expected_result, done);
}); });
/* /*
* Multi-value variable * Multi-value variable
* $host = [backend01, backend02] * $host = [backend01, backend02]
* $host => /^(backend01|backend01)$/ * $host => /^(backend01|backend01)$/
*/ */
it('should return proper regex for multi-value', (done) => { it('should return proper regex for multi-value', (done) => {
let target = '$host'; let target = '$host';
let template_var_value = ['backend01', 'backend02']; let template_var_value = ['backend01', 'backend02'];
let expected_result = '/^(backend01|backend02)$/'; let expected_result = '/^(backend01|backend02)$/';
testReplacingVariable(target, template_var_value, expected_result, done); testReplacingVariable(target, template_var_value, expected_result, done);
}); });
}); });
describe('When invoking metricFindQuery()', () => { describe('When invoking metricFindQuery()', () => {
beforeEach(() => { beforeEach(() => {
ctx.ds.replaceTemplateVars = (str) => str; ctx.ds.replaceTemplateVars = (str) => str;
ctx.ds.zabbix = { ctx.ds.zabbix = {
getGroups: jest.fn().mockReturnValue(Q.when([])), getGroups: jest.fn().mockReturnValue(Q.when([])),
getHosts: jest.fn().mockReturnValue(Q.when([])), getHosts: jest.fn().mockReturnValue(Q.when([])),
getApps: jest.fn().mockReturnValue(Q.when([])), getApps: jest.fn().mockReturnValue(Q.when([])),
getItems: jest.fn().mockReturnValue(Q.when([])) getItems: jest.fn().mockReturnValue(Q.when([]))
}; };
}); });
it('should return groups', (done) => { it('should return groups', (done) => {
const tests = [ const tests = [
{query: '*', expect: '/.*/'}, {query: '*', expect: '/.*/'},
{query: '', expect: ''}, {query: '', expect: ''},
{query: 'Backend', expect: 'Backend'}, {query: 'Backend', expect: 'Backend'},
{query: 'Back*', expect: 'Back*'}, {query: 'Back*', expect: 'Back*'},
]; ];
for (const test of tests) { for (const test of tests) {
ctx.ds.metricFindQuery(test.query); ctx.ds.metricFindQuery(test.query);
expect(ctx.ds.zabbix.getGroups).toBeCalledWith(test.expect); expect(ctx.ds.zabbix.getGroups).toBeCalledWith(test.expect);
ctx.ds.zabbix.getGroups.mockClear(); ctx.ds.zabbix.getGroups.mockClear();
} }
done(); done();
}); });
it('should return hosts', (done) => { it('should return hosts', (done) => {
const tests = [ const tests = [
{query: '*.*', expect: ['/.*/', '/.*/']}, {query: '*.*', expect: ['/.*/', '/.*/']},
{query: '.', expect: ['', '']}, {query: '.', expect: ['', '']},
{query: 'Backend.*', expect: ['Backend', '/.*/']}, {query: 'Backend.*', expect: ['Backend', '/.*/']},
{query: 'Back*.', expect: ['Back*', '']}, {query: 'Back*.', expect: ['Back*', '']},
]; ];
for (const test of tests) { for (const test of tests) {
ctx.ds.metricFindQuery(test.query); ctx.ds.metricFindQuery(test.query);
expect(ctx.ds.zabbix.getHosts).toBeCalledWith(test.expect[0], test.expect[1]); expect(ctx.ds.zabbix.getHosts).toBeCalledWith(test.expect[0], test.expect[1]);
ctx.ds.zabbix.getHosts.mockClear(); ctx.ds.zabbix.getHosts.mockClear();
} }
done(); done();
}); });
it('should return applications', (done) => { it('should return applications', (done) => {
const tests = [ const tests = [
{query: '*.*.*', expect: ['/.*/', '/.*/', '/.*/']}, {query: '*.*.*', expect: ['/.*/', '/.*/', '/.*/']},
{query: '.*.', expect: ['', '/.*/', '']}, {query: '.*.', expect: ['', '/.*/', '']},
{query: 'Backend.backend01.*', expect: ['Backend', 'backend01', '/.*/']}, {query: 'Backend.backend01.*', expect: ['Backend', 'backend01', '/.*/']},
{query: 'Back*.*.', expect: ['Back*', '/.*/', '']} {query: 'Back*.*.', expect: ['Back*', '/.*/', '']}
]; ];
for (const test of tests) { for (const test of tests) {
ctx.ds.metricFindQuery(test.query); ctx.ds.metricFindQuery(test.query);
expect(ctx.ds.zabbix.getApps).toBeCalledWith(test.expect[0], test.expect[1], test.expect[2]); expect(ctx.ds.zabbix.getApps).toBeCalledWith(test.expect[0], test.expect[1], test.expect[2]);
ctx.ds.zabbix.getApps.mockClear(); ctx.ds.zabbix.getApps.mockClear();
} }
done(); done();
}); });
it('should return items', (done) => { it('should return items', (done) => {
const tests = [ const tests = [
{query: '*.*.*.*', expect: ['/.*/', '/.*/', '', '/.*/']}, {query: '*.*.*.*', expect: ['/.*/', '/.*/', '', '/.*/']},
{query: '.*.*.*', expect: ['', '/.*/', '', '/.*/']}, {query: '.*.*.*', expect: ['', '/.*/', '', '/.*/']},
{query: 'Backend.backend01.*.*', expect: ['Backend', 'backend01', '', '/.*/']}, {query: 'Backend.backend01.*.*', expect: ['Backend', 'backend01', '', '/.*/']},
{query: 'Back*.*.cpu.*', expect: ['Back*', '/.*/', 'cpu', '/.*/']} {query: 'Back*.*.cpu.*', expect: ['Back*', '/.*/', 'cpu', '/.*/']}
]; ];
for (const test of tests) { for (const test of tests) {
ctx.ds.metricFindQuery(test.query); ctx.ds.metricFindQuery(test.query);
expect(ctx.ds.zabbix.getItems) expect(ctx.ds.zabbix.getItems)
.toBeCalledWith(test.expect[0], test.expect[1], test.expect[2], test.expect[3]); .toBeCalledWith(test.expect[0], test.expect[1], test.expect[2], test.expect[3]);
ctx.ds.zabbix.getItems.mockClear(); ctx.ds.zabbix.getItems.mockClear();
} }
done(); done();
}); });
it('should invoke method with proper arguments', (done) => { it('should invoke method with proper arguments', (done) => {
let query = '*.*'; let query = '*.*';
ctx.ds.metricFindQuery(query); ctx.ds.metricFindQuery(query);
expect(ctx.ds.zabbix.getHosts).toBeCalledWith('/.*/', '/.*/'); expect(ctx.ds.zabbix.getHosts).toBeCalledWith('/.*/', '/.*/');
done(); done();
}); });
}); });
describe('When querying alerts', () => { describe('When querying alerts', () => {
let options = {}; let options = {};
beforeEach(() => { beforeEach(() => {
ctx.ds.replaceTemplateVars = (str) => str; ctx.ds.replaceTemplateVars = (str) => str;
let targetItems = [{ let targetItems = [{
"itemid": "1", "itemid": "1",
"name": "test item", "name": "test item",
"key_": "test.key", "key_": "test.key",
"value_type": "3", "value_type": "3",
"hostid": "10631", "hostid": "10631",
"status": "0", "status": "0",
"state": "0", "state": "0",
"hosts": [{"hostid": "10631", "name": "Test host"}], "hosts": [{"hostid": "10631", "name": "Test host"}],
"item": "Test item" "item": "Test item"
}]; }];
ctx.ds.zabbix.getItemsFromTarget = () => Promise.resolve(targetItems); ctx.ds.zabbix.getItemsFromTarget = () => Promise.resolve(targetItems);
options = { options = {
"panelId": 10, "panelId": 10,
"targets": [{ "targets": [{
"application": {"filter": ""}, "application": {"filter": ""},
"group": {"filter": "Test group"}, "group": {"filter": "Test group"},
"host": {"filter": "Test host"}, "host": {"filter": "Test host"},
"item": {"filter": "Test item"}, "item": {"filter": "Test item"},
}] }]
}; };
}); });
it('should return threshold when comparative symbol is `less than`', () => { it('should return threshold when comparative symbol is `less than`', () => {
let itemTriggers = [{ let itemTriggers = [{
"triggerid": "15383", "triggerid": "15383",
"priority": "4", "priority": "4",
"expression": "{15915}<100", "expression": "{15915}<100",
}]; }];
ctx.ds.zabbix.getAlerts = () => Promise.resolve(itemTriggers); ctx.ds.zabbix.getAlerts = () => Promise.resolve(itemTriggers);
return ctx.ds.alertQuery(options) return ctx.ds.alertQuery(options)
.then(resp => { .then(resp => {
expect(resp.thresholds).toHaveLength(1); expect(resp.thresholds).toHaveLength(1);
expect(resp.thresholds[0]).toBe(100); expect(resp.thresholds[0]).toBe(100);
return resp; return resp;
}); });
}); });
it('should return threshold when comparative symbol is `less than or equal`', () => { it('should return threshold when comparative symbol is `less than or equal`', () => {
let itemTriggers = [{ let itemTriggers = [{
"triggerid": "15383", "triggerid": "15383",
"priority": "4", "priority": "4",
"expression": "{15915}<=100", "expression": "{15915}<=100",
}]; }];
ctx.ds.zabbix.getAlerts = () => Promise.resolve(itemTriggers); ctx.ds.zabbix.getAlerts = () => Promise.resolve(itemTriggers);
return ctx.ds.alertQuery(options) return ctx.ds.alertQuery(options)
.then(resp => { .then(resp => {
expect(resp.thresholds.length).toBe(1); expect(resp.thresholds.length).toBe(1);
expect(resp.thresholds[0]).toBe(100); expect(resp.thresholds[0]).toBe(100);
return resp; return resp;
}); });
}); });
it('should return threshold when comparative symbol is `greater than or equal`', () => { it('should return threshold when comparative symbol is `greater than or equal`', () => {
let itemTriggers = [{ let itemTriggers = [{
"triggerid": "15383", "triggerid": "15383",
"priority": "4", "priority": "4",
"expression": "{15915}>=30", "expression": "{15915}>=30",
}]; }];
ctx.ds.zabbix.getAlerts = () => Promise.resolve(itemTriggers); ctx.ds.zabbix.getAlerts = () => Promise.resolve(itemTriggers);
return ctx.ds.alertQuery(options) return ctx.ds.alertQuery(options)
.then(resp => { .then(resp => {
expect(resp.thresholds.length).toBe(1); expect(resp.thresholds.length).toBe(1);
expect(resp.thresholds[0]).toBe(30); expect(resp.thresholds[0]).toBe(30);
return resp; return resp;
}); });
}); });
it('should return threshold when comparative symbol is `equal`', () => { it('should return threshold when comparative symbol is `equal`', () => {
let itemTriggers = [{ let itemTriggers = [{
"triggerid": "15383", "triggerid": "15383",
"priority": "4", "priority": "4",
"expression": "{15915}=50", "expression": "{15915}=50",
}]; }];
ctx.ds.zabbix.getAlerts = () => Promise.resolve(itemTriggers); ctx.ds.zabbix.getAlerts = () => Promise.resolve(itemTriggers);
return ctx.ds.alertQuery(options) return ctx.ds.alertQuery(options)
.then(resp => { .then(resp => {
expect(resp.thresholds.length).toBe(1); expect(resp.thresholds.length).toBe(1);
expect(resp.thresholds[0]).toBe(50); expect(resp.thresholds[0]).toBe(50);
return resp; return resp;
}); });
}); });
}); });
}); });

View File

@@ -1,34 +1,34 @@
// import _ from 'lodash'; // import _ from 'lodash';
import ts from '../timeseries'; import ts from '../timeseries';
describe('timeseries processing functions', () => { describe('timeseries processing functions', () => {
describe('sumSeries()', () => { describe('sumSeries()', () => {
it('should properly sum series', (done) => { it('should properly sum series', (done) => {
let series = [ let series = [
[[0, 1], [1, 2], [1, 3]], [[0, 1], [1, 2], [1, 3]],
[[2, 1], [3, 2], [4, 3]] [[2, 1], [3, 2], [4, 3]]
]; ];
let expected = [[2, 1], [4, 2], [5, 3]]; let expected = [[2, 1], [4, 2], [5, 3]];
let result = ts.sumSeries(series); let result = ts.sumSeries(series);
expect(result).toEqual(expected); expect(result).toEqual(expected);
done(); done();
}); });
it('should properly sum series with nulls', (done) => { it('should properly sum series with nulls', (done) => {
// issue #286 // issue #286
let series = [ let series = [
[[1, 1], [1, 2], [1, 3]], [[1, 1], [1, 2], [1, 3]],
[[3, 2], [4, 3]] [[3, 2], [4, 3]]
]; ];
let expected = [[1, 1], [4, 2], [5, 3]]; let expected = [[1, 1], [4, 2], [5, 3]];
let result = ts.sumSeries(series); let result = ts.sumSeries(series);
expect(result).toEqual(expected); expect(result).toEqual(expected);
done(); done();
}); });
}); });
}); });

View File

@@ -1,141 +1,141 @@
import _ from 'lodash'; import _ from 'lodash';
import * as utils from '../utils'; import * as utils from '../utils';
describe('Utils', () => { describe('Utils', () => {
describe('expandItemName()', () => { describe('expandItemName()', () => {
it('should properly expand unquoted params', (done) => { it('should properly expand unquoted params', (done) => {
let test_cases = [ let test_cases = [
{ {
name: `CPU $2 time`, name: `CPU $2 time`,
key: `system.cpu.util[,user,avg1]`, key: `system.cpu.util[,user,avg1]`,
expected: "CPU user time" expected: "CPU user time"
}, },
{ {
name: `CPU $2 time - $3`, name: `CPU $2 time - $3`,
key: `system.cpu.util[,system,avg1]`, key: `system.cpu.util[,system,avg1]`,
expected: "CPU system time - avg1" expected: "CPU system time - avg1"
}, },
{ {
name: `CPU - $1 - $2 - $3`, name: `CPU - $1 - $2 - $3`,
key: `system.cpu.util[,system,avg1]`, key: `system.cpu.util[,system,avg1]`,
expected: "CPU - - system - avg1" expected: "CPU - - system - avg1"
} }
]; ];
_.each(test_cases, test_case => { _.each(test_cases, test_case => {
let expandedName = utils.expandItemName(test_case.name, test_case.key); let expandedName = utils.expandItemName(test_case.name, test_case.key);
expect(expandedName).toBe(test_case.expected); expect(expandedName).toBe(test_case.expected);
}); });
done(); done();
}); });
it('should properly expand quoted params with commas', (done) => { it('should properly expand quoted params with commas', (done) => {
let test_cases = [ let test_cases = [
{ {
name: `CPU $2 time`, name: `CPU $2 time`,
key: `system.cpu.util["type=user,value=avg",user]`, key: `system.cpu.util["type=user,value=avg",user]`,
expected: "CPU user time" expected: "CPU user time"
}, },
{ {
name: `CPU $1 time`, name: `CPU $1 time`,
key: `system.cpu.util["type=user,value=avg","user"]`, key: `system.cpu.util["type=user,value=avg","user"]`,
expected: "CPU type=user,value=avg time" expected: "CPU type=user,value=avg time"
}, },
{ {
name: `CPU $1 time $3`, name: `CPU $1 time $3`,
key: `system.cpu.util["type=user,value=avg",,"user"]`, key: `system.cpu.util["type=user,value=avg",,"user"]`,
expected: "CPU type=user,value=avg time user" expected: "CPU type=user,value=avg time user"
}, },
{ {
name: `CPU $1 $2 $3`, name: `CPU $1 $2 $3`,
key: `system.cpu.util["type=user,value=avg",time,"user"]`, key: `system.cpu.util["type=user,value=avg",time,"user"]`,
expected: "CPU type=user,value=avg time user" expected: "CPU type=user,value=avg time user"
} }
]; ];
_.each(test_cases, test_case => { _.each(test_cases, test_case => {
let expandedName = utils.expandItemName(test_case.name, test_case.key); let expandedName = utils.expandItemName(test_case.name, test_case.key);
expect(expandedName).toBe(test_case.expected); expect(expandedName).toBe(test_case.expected);
}); });
done(); done();
}); });
it('should properly expand array params', (done) => { it('should properly expand array params', (done) => {
let test_cases = [ let test_cases = [
{ {
name: `CPU $2 - $3 time`, name: `CPU $2 - $3 time`,
key: `system.cpu.util[,[user,system],avg1]`, key: `system.cpu.util[,[user,system],avg1]`,
expected: "CPU user,system - avg1 time" expected: "CPU user,system - avg1 time"
}, },
{ {
name: `CPU $2 - $3 time`, name: `CPU $2 - $3 time`,
key: `system.cpu.util[,["user,system",iowait],avg1]`, key: `system.cpu.util[,["user,system",iowait],avg1]`,
expected: `CPU "user,system",iowait - avg1 time` expected: `CPU "user,system",iowait - avg1 time`
}, },
{ {
name: `CPU - $2 - $3 - $4`, name: `CPU - $2 - $3 - $4`,
key: `system.cpu.util[,[],["user,system",iowait],avg1]`, key: `system.cpu.util[,[],["user,system",iowait],avg1]`,
expected: `CPU - - "user,system",iowait - avg1` expected: `CPU - - "user,system",iowait - avg1`
} }
]; ];
_.each(test_cases, test_case => { _.each(test_cases, test_case => {
let expandedName = utils.expandItemName(test_case.name, test_case.key); let expandedName = utils.expandItemName(test_case.name, test_case.key);
expect(expandedName).toBe(test_case.expected); expect(expandedName).toBe(test_case.expected);
}); });
done(); done();
}); });
}); });
describe('splitTemplateQuery()', () => { describe('splitTemplateQuery()', () => {
// Backward compatibility // Backward compatibility
it('should properly split query in old format', (done) => { it('should properly split query in old format', (done) => {
let test_cases = [ let test_cases = [
{ {
query: `/alu/./tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9{2}/`, query: `/alu/./tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9{2}/`,
expected: ['/alu/', '/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9{2}/'] expected: ['/alu/', '/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9{2}/']
}, },
{ {
query: `a.b.c.d`, query: `a.b.c.d`,
expected: ['a', 'b', 'c', 'd'] expected: ['a', 'b', 'c', 'd']
} }
]; ];
_.each(test_cases, test_case => { _.each(test_cases, test_case => {
let splitQuery = utils.splitTemplateQuery(test_case.query); let splitQuery = utils.splitTemplateQuery(test_case.query);
expect(splitQuery).toEqual(test_case.expected); expect(splitQuery).toEqual(test_case.expected);
}); });
done(); done();
}); });
it('should properly split query', (done) => { it('should properly split query', (done) => {
let test_cases = [ let test_cases = [
{ {
query: `{alu}{/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9]*/}`, query: `{alu}{/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9]*/}`,
expected: ['alu', '/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9]*/'] expected: ['alu', '/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9]*/']
}, },
{ {
query: `{alu}{/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9]{2}/}`, query: `{alu}{/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9]{2}/}`,
expected: ['alu', '/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9]{2}/'] expected: ['alu', '/tw-(nyc|que|brx|dwt|brk)-sta_(\w|\d)*-alu-[0-9]{2}/']
}, },
{ {
query: `{a}{b}{c}{d}`, query: `{a}{b}{c}{d}`,
expected: ['a', 'b', 'c', 'd'] expected: ['a', 'b', 'c', 'd']
}, },
{ {
query: `{a}{b.c.d}`, query: `{a}{b.c.d}`,
expected: ['a', 'b.c.d'] expected: ['a', 'b.c.d']
} }
]; ];
_.each(test_cases, test_case => { _.each(test_cases, test_case => {
let splitQuery = utils.splitTemplateQuery(test_case.query); let splitQuery = utils.splitTemplateQuery(test_case.query);
expect(splitQuery).toEqual(test_case.expected); expect(splitQuery).toEqual(test_case.expected);
}); });
done(); done();
}); });
}); });
}); });

View File

@@ -5,8 +5,8 @@ System.register(['lodash', './utils'], function (_export, _context) {
var _, utils, POINT_VALUE, POINT_TIMESTAMP, exportedFunctions; var _, utils, POINT_VALUE, POINT_TIMESTAMP, exportedFunctions;
/** /**
* Downsample time series by using given function (avg, min, max). * Downsample time series by using given function (avg, min, max).
*/ */
function downsample(datapoints, time_to, ms_interval, func) { function downsample(datapoints, time_to, ms_interval, func) {
var downsampledSeries = []; var downsampledSeries = [];
@@ -54,9 +54,9 @@ System.register(['lodash', './utils'], function (_export, _context) {
return downsampledSeries.reverse(); return downsampledSeries.reverse();
} }
/** /**
* Group points by given time interval * Group points by given time interval
* datapoints: [[<value>, <unixtime>], ...] * datapoints: [[<value>, <unixtime>], ...]
*/ */
function groupBy(datapoints, interval, groupByCallback) { function groupBy(datapoints, interval, groupByCallback) {
var ms_interval = utils.parseInterval(interval); var ms_interval = utils.parseInterval(interval);
@@ -120,9 +120,9 @@ System.register(['lodash', './utils'], function (_export, _context) {
return grouped_series; return grouped_series;
} }
/** /**
* Summarize set of time series into one. * Summarize set of time series into one.
* @param {datapoints[]} timeseries array of time series * @param {datapoints[]} timeseries array of time series
*/ */
function sumSeries(timeseries) { function sumSeries(timeseries) {
@@ -173,9 +173,9 @@ System.register(['lodash', './utils'], function (_export, _context) {
return datapoints; return datapoints;
} }
/** /**
* Simple delta. Calculate value delta between points. * Simple delta. Calculate value delta between points.
* @param {*} datapoints * @param {*} datapoints
*/ */
function delta(datapoints) { function delta(datapoints) {
var newSeries = []; var newSeries = [];
@@ -187,9 +187,9 @@ System.register(['lodash', './utils'], function (_export, _context) {
return newSeries; return newSeries;
} }
/** /**
* Calculates rate per second. Resistant to counter reset. * Calculates rate per second. Resistant to counter reset.
* @param {*} datapoints * @param {*} datapoints
*/ */
function rate(datapoints) { function rate(datapoints) {
var newSeries = []; var newSeries = [];
@@ -359,13 +359,13 @@ System.register(['lodash', './utils'], function (_export, _context) {
// Utility functions // // Utility functions //
/////////////////////// ///////////////////////
/** /**
* For given point calculate corresponding time frame. * For given point calculate corresponding time frame.
* *
* |__*_|_*__|___*| -> |*___|*___|*___| * |__*_|_*__|___*| -> |*___|*___|*___|
* *
* @param {*} timestamp * @param {*} timestamp
* @param {*} ms_interval * @param {*} ms_interval
*/ */
function getPointTimeFrame(timestamp, ms_interval) { function getPointTimeFrame(timestamp, ms_interval) {
return Math.floor(timestamp / ms_interval) * ms_interval; return Math.floor(timestamp / ms_interval) * ms_interval;
@@ -377,13 +377,13 @@ System.register(['lodash', './utils'], function (_export, _context) {
}); });
} }
/** /**
* Fill empty front and end of series by zeroes. * Fill empty front and end of series by zeroes.
* *
* | *** | | *** | * | *** | | *** |
* |___ ___| -> |*** ***| * |___ ___| -> |*** ***|
* @param {*} series * @param {*} series
* @param {*} timestamps * @param {*} timestamps
*/ */
function fillZeroes(series, timestamps) { function fillZeroes(series, timestamps) {
var prepend = []; var prepend = [];
@@ -401,8 +401,8 @@ System.register(['lodash', './utils'], function (_export, _context) {
return _.concat(_.concat(prepend, series), append); return _.concat(_.concat(prepend, series), append);
} }
/** /**
* Interpolate series with gaps * Interpolate series with gaps
*/ */
function interpolateSeries(series) { function interpolateSeries(series) {
var left, right; var left, right;

File diff suppressed because one or more lines are too long

View File

@@ -5,12 +5,12 @@ System.register(['lodash', 'moment'], function (_export, _context) {
var _, moment, MACRO_PATTERN, regexPattern; var _, moment, MACRO_PATTERN, regexPattern;
/** /**
* Expand Zabbix item name * Expand Zabbix item name
* *
* @param {string} name item name, ie "CPU $2 time" * @param {string} name item name, ie "CPU $2 time"
* @param {string} key item key, ie system.cpu.util[,system,avg1] * @param {string} key item key, ie system.cpu.util[,system,avg1]
* @return {string} expanded name, ie "CPU system time" * @return {string} expanded name, ie "CPU system time"
*/ */
function expandItemName(name, key) { function expandItemName(name, key) {
@@ -105,10 +105,10 @@ System.register(['lodash', 'moment'], function (_export, _context) {
return macro; return macro;
} }
/** /**
* Split template query to parts of zabbix entities * Split template query to parts of zabbix entities
* group.host.app.item -> [group, host, app, item] * group.host.app.item -> [group, host, app, item]
* {group}{host.com} -> [group, host.com] * {group}{host.com} -> [group, host.com]
*/ */
function splitTemplateQuery(query) { function splitTemplateQuery(query) {
var splitPattern = /\{[^\{\}]*\}|\{\/.*\/\}/g; var splitPattern = /\{[^\{\}]*\}|\{\/.*\/\}/g;
@@ -194,11 +194,11 @@ System.register(['lodash', 'moment'], function (_export, _context) {
return duration; return duration;
} }
/** /**
* Format acknowledges. * Format acknowledges.
* *
* @param {array} acknowledges array of Zabbix acknowledge objects * @param {array} acknowledges array of Zabbix acknowledge objects
* @return {string} HTML-formatted table * @return {string} HTML-formatted table
*/ */
_export('parseTimeShiftInterval', parseTimeShiftInterval); _export('parseTimeShiftInterval', parseTimeShiftInterval);
@@ -231,9 +231,9 @@ System.register(['lodash', 'moment'], function (_export, _context) {
} }
} }
/** /**
* Wrap function to prevent multiple calls * Wrap function to prevent multiple calls
* when waiting for result. * when waiting for result.
*/ */
_export('convertToZabbixAPIUrl', convertToZabbixAPIUrl); _export('convertToZabbixAPIUrl', convertToZabbixAPIUrl);

File diff suppressed because one or more lines are too long

View File

@@ -251,11 +251,11 @@ System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './za
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/** /**
* Find group, host, app or item by given name. * Find group, host, app or item by given name.
* @param list list of groups, apps or other * @param list list of groups, apps or other
* @param name visible name * @param name visible name
* @return array with finded element or empty array * @return array with finded element or empty array
*/ */
function findByName(list, name) { function findByName(list, name) {
var finded = _.find(list, { 'name': name }); var finded = _.find(list, { 'name': name });
@@ -266,13 +266,13 @@ System.register(['angular', 'lodash', './utils', './zabbixAPI.service.js', './za
} }
} }
/** /**
* Different hosts can contains applications and items with same name. * Different hosts can contains applications and items with same name.
* For this reason use _.filter, which return all elements instead _.find, * For this reason use _.filter, which return all elements instead _.find,
* which return only first finded. * which return only first finded.
* @param {[type]} list list of elements * @param {[type]} list list of elements
* @param {[type]} name app name * @param {[type]} name app name
* @return {[type]} array with finded element or empty array * @return {[type]} array with finded element or empty array
*/ */
function filterByName(list, name) { function filterByName(list, name) {
var finded = _.filter(list, { 'name': name }); var finded = _.filter(list, { 'name': name });

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -43,9 +43,9 @@ System.register(['angular'], function (_export, _context) {
this.backendSrv = backendSrv; this.backendSrv = backendSrv;
} }
/** /**
* Request data from Zabbix API * Request data from Zabbix API
* @return {object} response.result * @return {object} response.result
*/ */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -195,9 +195,9 @@ System.register(['angular', 'lodash'], function (_export, _context) {
return ZabbixCachingProxy; return ZabbixCachingProxy;
} }
/** /**
* Wrap zabbix API request to prevent multiple calls * Wrap zabbix API request to prevent multiple calls
* with same params when waiting for result. * with same params when waiting for result.
*/ */
function callAPIRequestOnce(func, promiseKeeper, argsHashFunc) { function callAPIRequestOnce(func, promiseKeeper, argsHashFunc) {
return function () { return function () {

File diff suppressed because one or more lines are too long

View File

@@ -28,9 +28,9 @@ System.register(['angular', 'lodash'], function (_export, _context) {
this.loadSQLDataSource(sqlDataSourceId); this.loadSQLDataSource(sqlDataSourceId);
} }
/** /**
* Try to load DS with given id to check it's exist. * Try to load DS with given id to check it's exist.
* @param {*} datasourceId ID of SQL data source * @param {*} datasourceId ID of SQL data source
*/ */

File diff suppressed because one or more lines are too long

View File

@@ -1,107 +1,107 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0" version="1.0"
id="Layer_1" id="Layer_1"
x="0px" x="0px"
y="0px" y="0px"
width="100px" width="100px"
height="100px" height="100px"
viewBox="692 0 100 100" viewBox="692 0 100 100"
style="enable-background:new 692 0 100 100;" style="enable-background:new 692 0 100 100;"
xml:space="preserve" xml:space="preserve"
inkscape:version="0.91 r" inkscape:version="0.91 r"
sodipodi:docname="zabbix_app_logo.svg" sodipodi:docname="zabbix_app_logo.svg"
enable-background="new"><metadata enable-background="new"><metadata
id="metadata13"><rdf:RDF><cc:Work id="metadata13"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs11"><linearGradient id="defs11"><linearGradient
id="SVGID_1_" id="SVGID_1_"
gradientUnits="userSpaceOnUse" gradientUnits="userSpaceOnUse"
x1="2.6005001" x1="2.6005001"
y1="65.475197" y1="65.475197"
x2="94.377701" x2="94.377701"
y2="30.245199"><stop y2="30.245199"><stop
id="stop34" id="stop34"
style="stop-color:#58595B" style="stop-color:#58595B"
offset="0.2583" /><stop offset="0.2583" /><stop
id="stop32" id="stop32"
style="stop-color:#646C70" style="stop-color:#646C70"
offset="0.2917" /><stop offset="0.2917" /><stop
id="stop30" id="stop30"
style="stop-color:#6C8087" style="stop-color:#6C8087"
offset="0.3398" /><stop offset="0.3398" /><stop
id="stop28" id="stop28"
style="stop-color:#6D8F9B" style="stop-color:#6D8F9B"
offset="0.3927" /><stop offset="0.3927" /><stop
id="stop26" id="stop26"
style="stop-color:#689BAA" style="stop-color:#689BAA"
offset="0.4499" /><stop offset="0.4499" /><stop
id="stop24" id="stop24"
style="stop-color:#5FA3B5" style="stop-color:#5FA3B5"
offset="0.5128" /><stop offset="0.5128" /><stop
id="stop22" id="stop22"
style="stop-color:#53A8BD" style="stop-color:#53A8BD"
offset="0.5837" /><stop offset="0.5837" /><stop
id="stop20" id="stop20"
style="stop-color:#47ABC2" style="stop-color:#47ABC2"
offset="0.6674" /><stop offset="0.6674" /><stop
id="stop18" id="stop18"
style="stop-color:#3FAEC5" style="stop-color:#3FAEC5"
offset="0.7759" /><stop offset="0.7759" /><stop
id="stop16" id="stop16"
style="stop-color:#3CAFC7" style="stop-color:#3CAFC7"
offset="1" /><stop offset="1" /><stop
id="stop14" id="stop14"
style="stop-color:#3BB0C9" style="stop-color:#3BB0C9"
offset="1" /></linearGradient></defs><sodipodi:namedview offset="1" /></linearGradient></defs><sodipodi:namedview
pagecolor="#ffffff" pagecolor="#ffffff"
bordercolor="#666666" bordercolor="#666666"
borderopacity="1" borderopacity="1"
objecttolerance="10" objecttolerance="10"
gridtolerance="10" gridtolerance="10"
guidetolerance="10" guidetolerance="10"
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:window-width="1615" inkscape:window-width="1615"
inkscape:window-height="1026" inkscape:window-height="1026"
id="namedview9" id="namedview9"
showgrid="false" showgrid="false"
inkscape:zoom="4.285" inkscape:zoom="4.285"
inkscape:cx="50.424685" inkscape:cx="50.424685"
inkscape:cy="23.581186" inkscape:cy="23.581186"
inkscape:window-x="65" inkscape:window-x="65"
inkscape:window-y="24" inkscape:window-y="24"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="g5194" /><style inkscape:current-layer="g5194" /><style
type="text/css" type="text/css"
id="style3"> id="style3">
.st0{fill:#787878;} .st0{fill:#787878;}
</style><g </style><g
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="g5194" id="g5194"
inkscape:label="Zabbix BG Original" inkscape:label="Zabbix BG Original"
style="display:inline"><rect style="display:inline"><rect
style="fill:#d40000;fill-opacity:1" style="fill:#d40000;fill-opacity:1"
id="rect5196" id="rect5196"
width="100" width="100"
height="100" height="100"
x="692" x="692"
y="0" /></g><g y="0" /></g><g
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer6" id="layer6"
inkscape:label="Zabbix Original Z" inkscape:label="Zabbix Original Z"
style="display:inline"><path style="display:inline"><path
d="m 715.54426,16.689227 52.91147,0 0,6.87033 -42.58255,52.167008 43.62047,0 0,7.584207 -54.9873,0 0,-6.871516 42.58255,-52.166552 -41.54464,0 0,-7.583477 z" d="m 715.54426,16.689227 52.91147,0 0,6.87033 -42.58255,52.167008 43.62047,0 0,7.584207 -54.9873,0 0,-6.871516 42.58255,-52.166552 -41.54464,0 0,-7.583477 z"
style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4169-6" id="path4169-6"
inkscape:connector-curvature="0" /></g></svg> inkscape:connector-curvature="0" /></g></svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

2
dist/module.js.map vendored
View File

@@ -1 +1 @@
{"version":3,"sources":["../src/module.js"],"names":["ZabbixAppConfigCtrl","loadPluginCss","dark","light"],"mappings":";;;;;;;;AAAQA,yB,qBAAAA,mB;;AACAC,mB,kBAAAA,a;;;;AAERA,oBAAc;AACZC,cAAM,gEADM;AAEZC,eAAO;AAFK,OAAd;;4BAMEH,mB","file":"module.js","sourcesContent":["import {ZabbixAppConfigCtrl} from './components/config';\nimport {loadPluginCss} from 'app/plugins/sdk';\n\nloadPluginCss({\n dark: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.dark.css',\n light: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.light.css'\n});\n\nexport {\n ZabbixAppConfigCtrl as ConfigCtrl\n};\n"]} {"version":3,"sources":["../src/module.js"],"names":["ZabbixAppConfigCtrl","loadPluginCss","dark","light"],"mappings":";;;;;;;;AAAQA,yB,qBAAAA,mB;;AACAC,mB,kBAAAA,a;;;;AAERA,oBAAc;AACZC,cAAM,gEADM;AAEZC,eAAO;AAFK,OAAd;;4BAMEH,mB","file":"module.js","sourcesContent":["import {ZabbixAppConfigCtrl} from './components/config';\r\nimport {loadPluginCss} from 'app/plugins/sdk';\r\n\r\nloadPluginCss({\r\n dark: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.dark.css',\r\n light: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.light.css'\r\n});\r\n\r\nexport {\r\n ZabbixAppConfigCtrl as ConfigCtrl\r\n};\r\n"]}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"sources":["../../src/panel-triggers/datasource-selector.directive.js"],"names":["angular","_","template","module","directive","scope","datasources","options","onChange","controller","DatasourceSelectorCtrl","controllerAs","$scope","dsOptions","multi","current","value","text","join","map","ds","selected","includes","updatedOptions","newDataSources","$$postDigest"],"mappings":";;;;;;;;;;;;;;;AAAOA,a;;AACAC,O;;;;;;;;;;;;;;;;;;;;;AAEDC,c;;;AAKNF,cACCG,MADD,CACQ,oBADR,EAECC,SAFD,CAEW,oBAFX,EAEiC,YAAM;AACrC,eAAO;AACLC,iBAAO;AACLC,yBAAa,GADR;AAELC,qBAAS,GAFJ;AAGLC,sBAAU;AAHL,WADF;AAMLC,sBAAYC,sBANP;AAOLC,wBAAc,MAPT;AAQLT,oBAAUA;AARL,SAAP;AAUD,OAbD;;AAeMQ,4B;;AAEJ;AACA,wCAAYE,MAAZ,EAAoB;AAAA;;AAClB,eAAKP,KAAL,GAAaO,MAAb;AACA,cAAIN,cAAcM,OAAON,WAAzB;AACA,cAAIC,UAAUK,OAAOL,OAArB;AACA,eAAKM,SAAL,GAAiB;AACfC,mBAAO,IADQ;AAEfC,qBAAS,EAACC,OAAOV,WAAR,EAAqBW,MAAMX,YAAYY,IAAZ,CAAiB,KAAjB,CAA3B,EAFM;AAGfX,qBAASN,EAAEkB,GAAF,CAAMZ,OAAN,EAAe,UAACa,EAAD,EAAQ;AAC9B,qBAAO,EAACH,MAAMG,EAAP,EAAWJ,OAAOI,EAAlB,EAAsBC,UAAUpB,EAAEqB,QAAF,CAAWhB,WAAX,EAAwBc,EAAxB,CAAhC,EAAP;AACD,aAFQ;AAHM,WAAjB;AAOD;;;;mCAEQG,c,EAAgB;AAAA;;AACvB,gBAAIC,iBAAiBD,eAAeR,OAAf,CAAuBC,KAA5C;AACA,iBAAKX,KAAL,CAAWC,WAAX,GAAyBkB,cAAzB;;AAEA;AACA,iBAAKnB,KAAL,CAAWoB,YAAX,CAAwB,YAAM;AAC5B,oBAAKpB,KAAL,CAAWG,QAAX;AACD,aAFD;AAGD","file":"datasource-selector.directive.js","sourcesContent":["import angular from 'angular';\nimport _ from 'lodash';\n\nconst template = `\n<value-select-dropdown variable=\"ctrl.dsOptions\" on-updated=\"ctrl.onChange(ctrl.dsOptions)\">\n</value-select-dropdown>\n`;\n\nangular\n.module('grafana.directives')\n.directive('datasourceSelector', () => {\n return {\n scope: {\n datasources: \"=\",\n options: \"=\",\n onChange: \"&\"\n },\n controller: DatasourceSelectorCtrl,\n controllerAs: 'ctrl',\n template: template\n };\n});\n\nclass DatasourceSelectorCtrl {\n\n /** @ngInject */\n constructor($scope) {\n this.scope = $scope;\n let datasources = $scope.datasources;\n let options = $scope.options;\n this.dsOptions = {\n multi: true,\n current: {value: datasources, text: datasources.join(\" + \")},\n options: _.map(options, (ds) => {\n return {text: ds, value: ds, selected: _.includes(datasources, ds)};\n })\n };\n }\n\n onChange(updatedOptions) {\n let newDataSources = updatedOptions.current.value;\n this.scope.datasources = newDataSources;\n\n // Run after model was changed\n this.scope.$$postDigest(() => {\n this.scope.onChange();\n });\n }\n}\n"]} {"version":3,"sources":["../../src/panel-triggers/datasource-selector.directive.js"],"names":["angular","_","template","module","directive","scope","datasources","options","onChange","controller","DatasourceSelectorCtrl","controllerAs","$scope","dsOptions","multi","current","value","text","join","map","ds","selected","includes","updatedOptions","newDataSources","$$postDigest"],"mappings":";;;;;;;;;;;;;;;AAAOA,a;;AACAC,O;;;;;;;;;;;;;;;;;;;;;AAEDC,c;;;AAKNF,cACCG,MADD,CACQ,oBADR,EAECC,SAFD,CAEW,oBAFX,EAEiC,YAAM;AACrC,eAAO;AACLC,iBAAO;AACLC,yBAAa,GADR;AAELC,qBAAS,GAFJ;AAGLC,sBAAU;AAHL,WADF;AAMLC,sBAAYC,sBANP;AAOLC,wBAAc,MAPT;AAQLT,oBAAUA;AARL,SAAP;AAUD,OAbD;;AAeMQ,4B;;AAEJ;AACA,wCAAYE,MAAZ,EAAoB;AAAA;;AAClB,eAAKP,KAAL,GAAaO,MAAb;AACA,cAAIN,cAAcM,OAAON,WAAzB;AACA,cAAIC,UAAUK,OAAOL,OAArB;AACA,eAAKM,SAAL,GAAiB;AACfC,mBAAO,IADQ;AAEfC,qBAAS,EAACC,OAAOV,WAAR,EAAqBW,MAAMX,YAAYY,IAAZ,CAAiB,KAAjB,CAA3B,EAFM;AAGfX,qBAASN,EAAEkB,GAAF,CAAMZ,OAAN,EAAe,UAACa,EAAD,EAAQ;AAC9B,qBAAO,EAACH,MAAMG,EAAP,EAAWJ,OAAOI,EAAlB,EAAsBC,UAAUpB,EAAEqB,QAAF,CAAWhB,WAAX,EAAwBc,EAAxB,CAAhC,EAAP;AACD,aAFQ;AAHM,WAAjB;AAOD;;;;mCAEQG,c,EAAgB;AAAA;;AACvB,gBAAIC,iBAAiBD,eAAeR,OAAf,CAAuBC,KAA5C;AACA,iBAAKX,KAAL,CAAWC,WAAX,GAAyBkB,cAAzB;;AAEA;AACA,iBAAKnB,KAAL,CAAWoB,YAAX,CAAwB,YAAM;AAC5B,oBAAKpB,KAAL,CAAWG,QAAX;AACD,aAFD;AAGD","file":"datasource-selector.directive.js","sourcesContent":["import angular from 'angular';\r\nimport _ from 'lodash';\r\n\r\nconst template = `\r\n<value-select-dropdown variable=\"ctrl.dsOptions\" on-updated=\"ctrl.onChange(ctrl.dsOptions)\">\r\n</value-select-dropdown>\r\n`;\r\n\r\nangular\r\n.module('grafana.directives')\r\n.directive('datasourceSelector', () => {\r\n return {\r\n scope: {\r\n datasources: \"=\",\r\n options: \"=\",\r\n onChange: \"&\"\r\n },\r\n controller: DatasourceSelectorCtrl,\r\n controllerAs: 'ctrl',\r\n template: template\r\n };\r\n});\r\n\r\nclass DatasourceSelectorCtrl {\r\n\r\n /** @ngInject */\r\n constructor($scope) {\r\n this.scope = $scope;\r\n let datasources = $scope.datasources;\r\n let options = $scope.options;\r\n this.dsOptions = {\r\n multi: true,\r\n current: {value: datasources, text: datasources.join(\" + \")},\r\n options: _.map(options, (ds) => {\r\n return {text: ds, value: ds, selected: _.includes(datasources, ds)};\r\n })\r\n };\r\n }\r\n\r\n onChange(updatedOptions) {\r\n let newDataSources = updatedOptions.current.value;\r\n this.scope.datasources = newDataSources;\r\n\r\n // Run after model was changed\r\n this.scope.$$postDigest(() => {\r\n this.scope.onChange();\r\n });\r\n }\r\n}\r\n"]}

View File

@@ -1 +1 @@
{"version":3,"sources":["../../src/panel-triggers/migrations.js"],"names":["migratePanelSchema","panel","isEmptyPanel","schemaVersion","getSchemaVersion","CURRENT_SCHEMA_VERSION","datasources","datasource","targets","triggers","lastChangeField","ageField","infoField","scroll","hideHostsInMaintenance","_","isEmpty","each","target","defaultsDeep","DEFAULT_TARGET"],"mappings":";;;;;;;AAMO,WAASA,kBAAT,CAA4BC,KAA5B,EAAmC;AACxC,QAAIC,aAAaD,KAAb,CAAJ,EAAyB;AACvB,aAAOA,KAAP;AACD;;AAED,QAAME,gBAAgBC,iBAAiBH,KAAjB,CAAtB;AACAA,UAAME,aAAN,GAAsBE,sBAAtB;;AAEA,QAAIF,gBAAgB,CAApB,EAAuB;AACrBF,YAAMK,WAAN,GAAoB,CAACL,MAAMM,UAAP,CAApB;AACAN,YAAMO,OAAN,GAAgB,EAAhB;AACAP,YAAMO,OAAN,CAAcP,MAAMK,WAAN,CAAkB,CAAlB,CAAd,IAAsCL,MAAMQ,QAA5C;;AAEA;AACA,aAAOR,MAAMQ,QAAb;AACA,aAAOR,MAAMM,UAAb;AACD;;AAED,QAAIJ,gBAAgB,CAApB,EAAuB;AACrB;AACA,aAAOF,MAAMS,eAAb;AACA,aAAOT,MAAMU,QAAb;AACA,aAAOV,MAAMW,SAAb;AACA,aAAOX,MAAMY,MAAb;AACA,aAAOZ,MAAMa,sBAAb;AACD;;AAED,QAAIX,gBAAgB,CAApB,EAAuB;AACrB,UAAIF,MAAMO,OAAN,IAAiB,CAACO,EAAEC,OAAF,CAAUf,MAAMO,OAAhB,CAAtB,EAAgD;AAC9CO,UAAEE,IAAF,CAAOhB,MAAMO,OAAb,EAAsB,UAACU,MAAD,EAAY;AAChCH,YAAEI,YAAF,CAAeD,MAAf,EAAuBE,cAAvB;AACD,SAFD;AAGD;AACF;;AAED,WAAOnB,KAAP;AACD;;gCApCeD,kB;;AAsChB,WAASI,gBAAT,CAA0BH,KAA1B,EAAiC;AAC/B,WAAOA,MAAME,aAAN,IAAuB,CAA9B;AACD;;AAED,WAASD,YAAT,CAAsBD,KAAtB,EAA6B;AAC3B,WAAO,CAACA,MAAMM,UAAP,IAAqB,CAACN,MAAMK,WAA5B,IAA2C,CAACL,MAAMQ,QAAlD,IAA8D,CAACR,MAAMO,OAA5E;AACD;;;AAlDMO,O;;AACCK,oB,wBAAAA,c;;;wCAGKf,sB,GAAyB,C","file":"migrations.js","sourcesContent":["import _ from 'lodash';\nimport {DEFAULT_TARGET} from './triggers_panel_ctrl';\n\n// Actual schema version\nexport const CURRENT_SCHEMA_VERSION = 4;\n\nexport function migratePanelSchema(panel) {\n if (isEmptyPanel(panel)) {\n return panel;\n }\n\n const schemaVersion = getSchemaVersion(panel);\n panel.schemaVersion = CURRENT_SCHEMA_VERSION;\n\n if (schemaVersion < 2) {\n panel.datasources = [panel.datasource];\n panel.targets = {};\n panel.targets[panel.datasources[0]] = panel.triggers;\n\n // delete old props\n delete panel.triggers;\n delete panel.datasource;\n }\n\n if (schemaVersion < 3) {\n // delete old props\n delete panel.lastChangeField;\n delete panel.ageField;\n delete panel.infoField;\n delete panel.scroll;\n delete panel.hideHostsInMaintenance;\n }\n\n if (schemaVersion < 4) {\n if (panel.targets && !_.isEmpty(panel.targets)) {\n _.each(panel.targets, (target) => {\n _.defaultsDeep(target, DEFAULT_TARGET);\n });\n }\n }\n\n return panel;\n}\n\nfunction getSchemaVersion(panel) {\n return panel.schemaVersion || 1;\n}\n\nfunction isEmptyPanel(panel) {\n return !panel.datasource && !panel.datasources && !panel.triggers && !panel.targets;\n}\n"]} {"version":3,"sources":["../../src/panel-triggers/migrations.js"],"names":["migratePanelSchema","panel","isEmptyPanel","schemaVersion","getSchemaVersion","CURRENT_SCHEMA_VERSION","datasources","datasource","targets","triggers","lastChangeField","ageField","infoField","scroll","hideHostsInMaintenance","_","isEmpty","each","target","defaultsDeep","DEFAULT_TARGET"],"mappings":";;;;;;;AAMO,WAASA,kBAAT,CAA4BC,KAA5B,EAAmC;AACxC,QAAIC,aAAaD,KAAb,CAAJ,EAAyB;AACvB,aAAOA,KAAP;AACD;;AAED,QAAME,gBAAgBC,iBAAiBH,KAAjB,CAAtB;AACAA,UAAME,aAAN,GAAsBE,sBAAtB;;AAEA,QAAIF,gBAAgB,CAApB,EAAuB;AACrBF,YAAMK,WAAN,GAAoB,CAACL,MAAMM,UAAP,CAApB;AACAN,YAAMO,OAAN,GAAgB,EAAhB;AACAP,YAAMO,OAAN,CAAcP,MAAMK,WAAN,CAAkB,CAAlB,CAAd,IAAsCL,MAAMQ,QAA5C;;AAEA;AACA,aAAOR,MAAMQ,QAAb;AACA,aAAOR,MAAMM,UAAb;AACD;;AAED,QAAIJ,gBAAgB,CAApB,EAAuB;AACrB;AACA,aAAOF,MAAMS,eAAb;AACA,aAAOT,MAAMU,QAAb;AACA,aAAOV,MAAMW,SAAb;AACA,aAAOX,MAAMY,MAAb;AACA,aAAOZ,MAAMa,sBAAb;AACD;;AAED,QAAIX,gBAAgB,CAApB,EAAuB;AACrB,UAAIF,MAAMO,OAAN,IAAiB,CAACO,EAAEC,OAAF,CAAUf,MAAMO,OAAhB,CAAtB,EAAgD;AAC9CO,UAAEE,IAAF,CAAOhB,MAAMO,OAAb,EAAsB,UAACU,MAAD,EAAY;AAChCH,YAAEI,YAAF,CAAeD,MAAf,EAAuBE,cAAvB;AACD,SAFD;AAGD;AACF;;AAED,WAAOnB,KAAP;AACD;;gCApCeD,kB;;AAsChB,WAASI,gBAAT,CAA0BH,KAA1B,EAAiC;AAC/B,WAAOA,MAAME,aAAN,IAAuB,CAA9B;AACD;;AAED,WAASD,YAAT,CAAsBD,KAAtB,EAA6B;AAC3B,WAAO,CAACA,MAAMM,UAAP,IAAqB,CAACN,MAAMK,WAA5B,IAA2C,CAACL,MAAMQ,QAAlD,IAA8D,CAACR,MAAMO,OAA5E;AACD;;;AAlDMO,O;;AACCK,oB,wBAAAA,c;;;wCAGKf,sB,GAAyB,C","file":"migrations.js","sourcesContent":["import _ from 'lodash';\r\nimport {DEFAULT_TARGET} from './triggers_panel_ctrl';\r\n\r\n// Actual schema version\r\nexport const CURRENT_SCHEMA_VERSION = 4;\r\n\r\nexport function migratePanelSchema(panel) {\r\n if (isEmptyPanel(panel)) {\r\n return panel;\r\n }\r\n\r\n const schemaVersion = getSchemaVersion(panel);\r\n panel.schemaVersion = CURRENT_SCHEMA_VERSION;\r\n\r\n if (schemaVersion < 2) {\r\n panel.datasources = [panel.datasource];\r\n panel.targets = {};\r\n panel.targets[panel.datasources[0]] = panel.triggers;\r\n\r\n // delete old props\r\n delete panel.triggers;\r\n delete panel.datasource;\r\n }\r\n\r\n if (schemaVersion < 3) {\r\n // delete old props\r\n delete panel.lastChangeField;\r\n delete panel.ageField;\r\n delete panel.infoField;\r\n delete panel.scroll;\r\n delete panel.hideHostsInMaintenance;\r\n }\r\n\r\n if (schemaVersion < 4) {\r\n if (panel.targets && !_.isEmpty(panel.targets)) {\r\n _.each(panel.targets, (target) => {\r\n _.defaultsDeep(target, DEFAULT_TARGET);\r\n });\r\n }\r\n }\r\n\r\n return panel;\r\n}\r\n\r\nfunction getSchemaVersion(panel) {\r\n return panel.schemaVersion || 1;\r\n}\r\n\r\nfunction isEmptyPanel(panel) {\r\n return !panel.datasource && !panel.datasources && !panel.triggers && !panel.targets;\r\n}\r\n"]}

View File

@@ -11,17 +11,17 @@ System.register(['./triggers_panel_ctrl', 'app/plugins/sdk', './datasource-selec
loadPluginCss = _appPluginsSdk.loadPluginCss; loadPluginCss = _appPluginsSdk.loadPluginCss;
}, function (_datasourceSelectorDirective) {}, function (_ackTooltipDirective) {}], }, function (_datasourceSelectorDirective) {}, function (_ackTooltipDirective) {}],
execute: function () { execute: function () {
/** /**
* Grafana-Zabbix * Grafana-Zabbix
* Zabbix plugin for Grafana. * Zabbix plugin for Grafana.
* http://github.com/alexanderzobnin/grafana-zabbix * http://github.com/alexanderzobnin/grafana-zabbix
* *
* Trigger panel. * Trigger panel.
* This feature sponsored by CORE IT * This feature sponsored by CORE IT
* http://www.coreit.fr * http://www.coreit.fr
* *
* Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com * Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com
* Licensed under the Apache License, Version 2.0 * Licensed under the Apache License, Version 2.0
*/ */
loadPluginCss({ loadPluginCss({

View File

@@ -1 +1 @@
{"version":3,"sources":["../../src/panel-triggers/module.js"],"names":["TriggerPanelCtrl","loadPluginCss","dark","light"],"mappings":";;;;;;;;AAaQA,sB,wBAAAA,gB;;AACAC,mB,kBAAAA,a;;;AAdR;;;;;;;;;;;;;AAkBAA,oBAAc;AACZC,cAAM,gEADM;AAEZC,eAAO;AAFK,OAAd;;2BAMEH,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 {TriggerPanelCtrl} from './triggers_panel_ctrl';\nimport {loadPluginCss} from 'app/plugins/sdk';\nimport './datasource-selector.directive';\nimport './ack-tooltip.directive';\n\nloadPluginCss({\n dark: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.dark.css',\n light: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.light.css'\n});\n\nexport {\n TriggerPanelCtrl as PanelCtrl\n};\n"]} {"version":3,"sources":["../../src/panel-triggers/module.js"],"names":["TriggerPanelCtrl","loadPluginCss","dark","light"],"mappings":";;;;;;;;AAaQA,sB,wBAAAA,gB;;AACAC,mB,kBAAAA,a;;;AAdR;;;;;;;;;;;;;AAkBAA,oBAAc;AACZC,cAAM,gEADM;AAEZC,eAAO;AAFK,OAAd;;2BAMEH,gB","file":"module.js","sourcesContent":["/**\r\n * Grafana-Zabbix\r\n * Zabbix plugin for Grafana.\r\n * http://github.com/alexanderzobnin/grafana-zabbix\r\n *\r\n * Trigger panel.\r\n * This feature sponsored by CORE IT\r\n * http://www.coreit.fr\r\n *\r\n * Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com\r\n * Licensed under the Apache License, Version 2.0\r\n */\r\n\r\nimport {TriggerPanelCtrl} from './triggers_panel_ctrl';\r\nimport {loadPluginCss} from 'app/plugins/sdk';\r\nimport './datasource-selector.directive';\r\nimport './ack-tooltip.directive';\r\n\r\nloadPluginCss({\r\n dark: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.dark.css',\r\n light: 'plugins/alexanderzobnin-zabbix-app/css/grafana-zabbix.light.css'\r\n});\r\n\r\nexport {\r\n TriggerPanelCtrl as PanelCtrl\r\n};\r\n"]}

View File

@@ -1 +1 @@
{"version":3,"sources":["../../src/panel-triggers/options_tab.js"],"names":["triggerPanelOptionsTab","restrict","scope","templateUrl","controller","TriggerPanelOptionsCtrl","$scope","editor","panelCtrl","ctrl","panel","fontSizes","ackFilters","sortByFields","text","value","showEventsFields"],"mappings":";;;;;;;;;;;;;AAuCO,WAASA,sBAAT,GAAkC;AACvC,WAAO;AACLC,gBAAU,GADL;AAELC,aAAO,IAFF;AAGLC,mBAAa,oFAHR;AAILC,kBAAYC;AAJP,KAAP;AAMD;;oCAPeL,sB;;;;;AA1BVK,6B;;AAEJ;AACA,uCAAYC,MAAZ,EAAoB;AAAA;;AAClBA,eAAOC,MAAP,GAAgB,IAAhB;AACA,aAAKC,SAAL,GAAiBF,OAAOG,IAAxB;AACA,aAAKC,KAAL,GAAa,KAAKF,SAAL,CAAeE,KAA5B;;AAEA,aAAKC,SAAL,GAAiB,CAAC,KAAD,EAAQ,KAAR,EAAe,MAAf,EAAuB,MAAvB,EAA+B,MAA/B,EAAuC,MAAvC,EAA+C,MAA/C,EAAuD,MAAvD,EAA+D,MAA/D,EAAuE,MAAvE,EAA+E,MAA/E,EAAuF,MAAvF,CAAjB;AACA,aAAKC,UAAL,GAAkB,CAChB,cADgB,EAEhB,gBAFgB,EAGhB,cAHgB,CAAlB;AAKA,aAAKC,YAAL,GAAoB,CAClB,EAAEC,MAAM,aAAR,EAAwBC,OAAO,YAA/B,EADkB,EAElB,EAAED,MAAM,UAAR,EAAwBC,OAAO,UAA/B,EAFkB,CAApB;AAIA,aAAKC,gBAAL,GAAwB,CACtB,EAAEF,MAAM,KAAR,EAAmBC,OAAO,CAAC,CAAD,EAAG,CAAH,CAA1B,EADsB,EAEtB,EAAED,MAAM,IAAR,EAAmBC,OAAO,CAAC,CAAD,CAA1B,EAFsB,EAGtB,EAAED,MAAM,UAAR,EAAoBC,OAAO,CAA3B,EAHsB,CAAxB;AAKD,O","file":"options_tab.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\nclass TriggerPanelOptionsCtrl {\n\n /** @ngInject */\n constructor($scope) {\n $scope.editor = this;\n this.panelCtrl = $scope.ctrl;\n this.panel = this.panelCtrl.panel;\n\n this.fontSizes = ['80%', '90%', '100%', '110%', '120%', '130%', '150%', '160%', '180%', '200%', '220%', '250%'];\n this.ackFilters = [\n 'all triggers',\n 'unacknowledged',\n 'acknowledged'\n ];\n this.sortByFields = [\n { text: 'last change', value: 'lastchange' },\n { text: 'severity', value: 'priority' }\n ];\n this.showEventsFields = [\n { text: 'All', value: [0,1] },\n { text: 'OK', value: [0] },\n { text: 'Problems', value: 1 }\n ];\n }\n}\n\nexport function triggerPanelOptionsTab() {\n return {\n restrict: 'E',\n scope: true,\n templateUrl: 'public/plugins/alexanderzobnin-zabbix-app/panel-triggers/partials/options_tab.html',\n controller: TriggerPanelOptionsCtrl,\n };\n}\n"]} {"version":3,"sources":["../../src/panel-triggers/options_tab.js"],"names":["triggerPanelOptionsTab","restrict","scope","templateUrl","controller","TriggerPanelOptionsCtrl","$scope","editor","panelCtrl","ctrl","panel","fontSizes","ackFilters","sortByFields","text","value","showEventsFields"],"mappings":";;;;;;;;;;;;;AAuCO,WAASA,sBAAT,GAAkC;AACvC,WAAO;AACLC,gBAAU,GADL;AAELC,aAAO,IAFF;AAGLC,mBAAa,oFAHR;AAILC,kBAAYC;AAJP,KAAP;AAMD;;oCAPeL,sB;;;;;AA1BVK,6B;;AAEJ;AACA,uCAAYC,MAAZ,EAAoB;AAAA;;AAClBA,eAAOC,MAAP,GAAgB,IAAhB;AACA,aAAKC,SAAL,GAAiBF,OAAOG,IAAxB;AACA,aAAKC,KAAL,GAAa,KAAKF,SAAL,CAAeE,KAA5B;;AAEA,aAAKC,SAAL,GAAiB,CAAC,KAAD,EAAQ,KAAR,EAAe,MAAf,EAAuB,MAAvB,EAA+B,MAA/B,EAAuC,MAAvC,EAA+C,MAA/C,EAAuD,MAAvD,EAA+D,MAA/D,EAAuE,MAAvE,EAA+E,MAA/E,EAAuF,MAAvF,CAAjB;AACA,aAAKC,UAAL,GAAkB,CAChB,cADgB,EAEhB,gBAFgB,EAGhB,cAHgB,CAAlB;AAKA,aAAKC,YAAL,GAAoB,CAClB,EAAEC,MAAM,aAAR,EAAwBC,OAAO,YAA/B,EADkB,EAElB,EAAED,MAAM,UAAR,EAAwBC,OAAO,UAA/B,EAFkB,CAApB;AAIA,aAAKC,gBAAL,GAAwB,CACtB,EAAEF,MAAM,KAAR,EAAmBC,OAAO,CAAC,CAAD,EAAG,CAAH,CAA1B,EADsB,EAEtB,EAAED,MAAM,IAAR,EAAmBC,OAAO,CAAC,CAAD,CAA1B,EAFsB,EAGtB,EAAED,MAAM,UAAR,EAAoBC,OAAO,CAA3B,EAHsB,CAAxB;AAKD,O","file":"options_tab.js","sourcesContent":["/**\r\n * Grafana-Zabbix\r\n * Zabbix plugin for Grafana.\r\n * http://github.com/alexanderzobnin/grafana-zabbix\r\n *\r\n * Trigger panel.\r\n * This feature sponsored by CORE IT\r\n * http://www.coreit.fr\r\n *\r\n * Copyright 2015 Alexander Zobnin alexanderzobnin@gmail.com\r\n * Licensed under the Apache License, Version 2.0\r\n */\r\n\r\nclass TriggerPanelOptionsCtrl {\r\n\r\n /** @ngInject */\r\n constructor($scope) {\r\n $scope.editor = this;\r\n this.panelCtrl = $scope.ctrl;\r\n this.panel = this.panelCtrl.panel;\r\n\r\n this.fontSizes = ['80%', '90%', '100%', '110%', '120%', '130%', '150%', '160%', '180%', '200%', '220%', '250%'];\r\n this.ackFilters = [\r\n 'all triggers',\r\n 'unacknowledged',\r\n 'acknowledged'\r\n ];\r\n this.sortByFields = [\r\n { text: 'last change', value: 'lastchange' },\r\n { text: 'severity', value: 'priority' }\r\n ];\r\n this.showEventsFields = [\r\n { text: 'All', value: [0,1] },\r\n { text: 'OK', value: [0] },\r\n { text: 'Problems', value: 1 }\r\n ];\r\n }\r\n}\r\n\r\nexport function triggerPanelOptionsTab() {\r\n return {\r\n restrict: 'E',\r\n scope: true,\r\n templateUrl: 'public/plugins/alexanderzobnin-zabbix-app/panel-triggers/partials/options_tab.html',\r\n controller: TriggerPanelOptionsCtrl,\r\n };\r\n}\r\n"]}

View File

@@ -1,97 +1,97 @@
<div class="triggers-panel-container"> <div class="triggers-panel-container">
<div class="triggers-panel-scroll"> <div class="triggers-panel-scroll">
<section class="card-section card-list-layout-list"> <section class="card-section card-list-layout-list">
<ol class="alert-rule-list"> <ol class="alert-rule-list">
<!-- Trigger list item --> <!-- Trigger list item -->
<li class="alert-rule-item zbx-trigger-card" ng-repeat="trigger in ctrl.currentTriggersPage" <li class="alert-rule-item zbx-trigger-card" ng-repeat="trigger in ctrl.currentTriggersPage"
ng-class="{'zbx-trigger-highlighted': ctrl.panel.highlightBackground}" ng-class="{'zbx-trigger-highlighted': ctrl.panel.highlightBackground}"
ng-style="ctrl.panel.highlightBackground && {background: ctrl.getBackground(trigger)}"> ng-style="ctrl.panel.highlightBackground && {background: ctrl.getBackground(trigger)}">
<!-- Heart icon --> <!-- Heart icon -->
<div class="alert-rule-item__icon" ng-style="!ctrl.panel.highlightBackground && {color: trigger.color}"> <div class="alert-rule-item__icon" ng-style="!ctrl.panel.highlightBackground && {color: trigger.color}">
<i class="icon-gf" ng-class="ctrl.getAlertIconClass(trigger)"></i> <i class="icon-gf" ng-class="ctrl.getAlertIconClass(trigger)"></i>
</div> </div>
<div class="alert-rule-item__body"> <div class="alert-rule-item__body">
<div class="alert-rule-item__header"> <div class="alert-rule-item__header">
<p class="alert-rule-item__name"> <p class="alert-rule-item__name">
<span class="zabbix-trigger-name">{{trigger.description}}</span> <span class="zabbix-trigger-name">{{trigger.description}}</span>
<span class="zabbix-hostname" ng-if="ctrl.panel.hostField || ctrl.panel.hostTechNameField"> <span class="zabbix-hostname" ng-if="ctrl.panel.hostField || ctrl.panel.hostTechNameField">
<i ng-if="trigger.maintenance" class="fa fa-wrench zbx-maintenance-icon"></i> <i ng-if="trigger.maintenance" class="fa fa-wrench zbx-maintenance-icon"></i>
{{ ctrl.formatHostName(trigger) }} {{ ctrl.formatHostName(trigger) }}
</span> </span>
<span class="zabbix-hostname" ng-if="ctrl.panel.hostGroups"> <span class="zabbix-hostname" ng-if="ctrl.panel.hostGroups">
{{ ctrl.formatHostGroups(trigger) }} {{ ctrl.formatHostGroups(trigger) }}
</span> </span>
<span class="zbx-trigger-tags" ng-if="ctrl.panel.showTags && trigger.tags"> <span class="zbx-trigger-tags" ng-if="ctrl.panel.showTags && trigger.tags">
<span ng-repeat="tag in trigger.tags" ng-click="ctrl.addTagFilter(tag, trigger.datasource)" <span ng-repeat="tag in trigger.tags" ng-click="ctrl.addTagFilter(tag, trigger.datasource)"
tag-color-from-name="tag.tag+tag.value" class="label label-tag zbx-tag"> tag-color-from-name="tag.tag+tag.value" class="label label-tag zbx-tag">
{{tag.tag}}: {{tag.value}} {{tag.tag}}: {{tag.value}}
</span> </span>
</span> </span>
</p> </p>
<div class="alert-rule-item__text"> <div class="alert-rule-item__text">
<span ng-if="ctrl.panel.statusField" class="zbx-trigger-state" <span ng-if="ctrl.panel.statusField" class="zbx-trigger-state"
ng-class="ctrl.getAlertStateClass(trigger)"> ng-class="ctrl.getAlertStateClass(trigger)">
{{ctrl.triggerStatusMap[trigger.value]}} {{ctrl.triggerStatusMap[trigger.value]}}
</span> </span>
<span ng-if="ctrl.panel.severityField" class="zbx-trigger-severity" <span ng-if="ctrl.panel.severityField" class="zbx-trigger-severity"
ng-class="ctrl.getAlertStateClass(trigger)" ng-class="ctrl.getAlertStateClass(trigger)"
ng-style="!ctrl.panel.highlightBackground && {color: trigger.color}"> ng-style="!ctrl.panel.highlightBackground && {color: trigger.color}">
{{trigger.severity}} {{trigger.severity}}
</span> </span>
<span class="alert-rule-item__time"> <span class="alert-rule-item__time">
{{trigger.age && "for " + trigger.age}} {{trigger.age && "for " + trigger.age}}
</span> </span>
<span class="zbx-description" <span class="zbx-description"
ng-if="ctrl.panel.descriptionField && !ctrl.panel.descriptionAtNewLine" ng-if="ctrl.panel.descriptionField && !ctrl.panel.descriptionAtNewLine"
ng-bind-html="trigger.comments"> ng-bind-html="trigger.comments">
</span> </span>
</div> </div>
<!-- If description at the new line --> <!-- If description at the new line -->
<div class="alert-rule-item__text" <div class="alert-rule-item__text"
ng-if="trigger.comments && ctrl.panel.descriptionField && ctrl.panel.descriptionAtNewLine"> ng-if="trigger.comments && ctrl.panel.descriptionField && ctrl.panel.descriptionAtNewLine">
<span class="alert-rule-item__info zbx-description zbx-description--newline" <span class="alert-rule-item__info zbx-description zbx-description--newline"
ng-bind-html="trigger.comments"> ng-bind-html="trigger.comments">
</span> </span>
</div> </div>
</div> </div>
</div> </div>
<!-- Datasource name --> <!-- Datasource name -->
<div class="alert-rule-item__time zabbix-trigger-source" ng-if="ctrl.panel.datasources.length > 1"> <div class="alert-rule-item__time zabbix-trigger-source" ng-if="ctrl.panel.datasources.length > 1">
<span> <span>
<i class="fa fa-database"></i> <i class="fa fa-database"></i>
{{trigger.datasource}} {{trigger.datasource}}
</span> </span>
</div> </div>
<div class="alert-rule-item__time zbx-trigger-lastchange"> <div class="alert-rule-item__time zbx-trigger-lastchange">
<span>{{trigger.lastchange || "last change unknown"}}</span> <span>{{trigger.lastchange || "last change unknown"}}</span>
<div class="trigger-info-block zbx-status-icons"> <div class="trigger-info-block zbx-status-icons">
<a ng-if="trigger.url" href="{{trigger.url}}" target="_blank"> <a ng-if="trigger.url" href="{{trigger.url}}" target="_blank">
<i class="fa fa-external-link"></i> <i class="fa fa-external-link"></i>
</a> </a>
<span ng-if="trigger.state === '1'" bs-tooltip="'{{trigger.error}}'"> <span ng-if="trigger.state === '1'" bs-tooltip="'{{trigger.error}}'">
<i class="fa fa-question-circle"></i> <i class="fa fa-question-circle"></i>
</span> </span>
<ack-tooltip ng-if="trigger.lastEvent" ack="trigger.acknowledges" trigger="trigger" <ack-tooltip ng-if="trigger.lastEvent" ack="trigger.acknowledges" trigger="trigger"
on-ack="ctrl.acknowledgeTrigger" context="ctrl"> on-ack="ctrl.acknowledgeTrigger" context="ctrl">
</ack-tooltip> </ack-tooltip>
</div> </div>
</div> </div>
</li> </li>
</ol> </ol>
</section> </section>
</div> </div>
</div> </div>
<div class="triggers-panel-footer"></div> <div class="triggers-panel-footer"></div>

View File

@@ -1,223 +1,223 @@
<div class="editor-row"> <div class="editor-row">
<div class="section gf-form-group"> <div class="section gf-form-group">
<h5 class="section-heading">Show fields</h5> <h5 class="section-heading">Show fields</h5>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-9" label-class="width-9"
label="Host name" label="Host name"
checked="ctrl.panel.hostField" checked="ctrl.panel.hostField"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-9" label-class="width-9"
label="Technical name" label="Technical name"
checked="ctrl.panel.hostTechNameField" checked="ctrl.panel.hostTechNameField"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-9" label-class="width-9"
label="Host groups" label="Host groups"
checked="ctrl.panel.hostGroups" checked="ctrl.panel.hostGroups"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-9" label-class="width-9"
label="Tags" label="Tags"
checked="ctrl.panel.showTags" checked="ctrl.panel.showTags"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-9" label-class="width-9"
label="Status" label="Status"
checked="ctrl.panel.statusField" checked="ctrl.panel.statusField"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-9" label-class="width-9"
label="Severity" label="Severity"
checked="ctrl.panel.severityField" checked="ctrl.panel.severityField"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-9" label-class="width-9"
label="Description" label="Description"
checked="ctrl.panel.descriptionField" checked="ctrl.panel.descriptionField"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" ng-if="ctrl.panel.descriptionField" <gf-form-switch class="gf-form" ng-if="ctrl.panel.descriptionField"
label-class="width-9" label-class="width-9"
label="At the new line" label="At the new line"
checked="ctrl.panel.descriptionAtNewLine" checked="ctrl.panel.descriptionAtNewLine"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
</div> </div>
<div class="section gf-form-group"> <div class="section gf-form-group">
<h5 class="section-heading">Options</h5> <h5 class="section-heading">Options</h5>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-15" label-class="width-15"
label="Show hosts in maintenance" label="Show hosts in maintenance"
checked="ctrl.panel.hostsInMaintenance" checked="ctrl.panel.hostsInMaintenance"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-8">Acknowledged</label> <label class="gf-form-label width-8">Acknowledged</label>
<div class="gf-form-select-wrapper width-12"> <div class="gf-form-select-wrapper width-12">
<select class="gf-form-input" <select class="gf-form-input"
ng-model="ctrl.panel.showTriggers" ng-model="ctrl.panel.showTriggers"
ng-options="f for f in editor.ackFilters" ng-options="f for f in editor.ackFilters"
ng-change="ctrl.refresh()"> ng-change="ctrl.refresh()">
</select> </select>
</div> </div>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-8">Sort by</label> <label class="gf-form-label width-8">Sort by</label>
<div class="gf-form-select-wrapper width-12"> <div class="gf-form-select-wrapper width-12">
<select class="gf-form-input" <select class="gf-form-input"
ng-model="ctrl.panel.sortTriggersBy" ng-model="ctrl.panel.sortTriggersBy"
ng-options="f.text for f in editor.sortByFields track by f.value" ng-options="f.text for f in editor.sortByFields track by f.value"
ng-change="ctrl.render()"> ng-change="ctrl.render()">
</select> </select>
</div> </div>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-8">Show events</label> <label class="gf-form-label width-8">Show events</label>
<div class="gf-form-select-wrapper width-12"> <div class="gf-form-select-wrapper width-12">
<select class="gf-form-input" <select class="gf-form-input"
ng-model="ctrl.panel.showEvents" ng-model="ctrl.panel.showEvents"
ng-options="f.text for f in editor.showEventsFields track by f.value" ng-options="f.text for f in editor.showEventsFields track by f.value"
ng-change="ctrl.refresh()"> ng-change="ctrl.refresh()">
</select> </select>
</div> </div>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-8">Limit triggers</label> <label class="gf-form-label width-8">Limit triggers</label>
<input class="gf-form-input width-5" <input class="gf-form-input width-5"
type="number" placeholder="100" type="number" placeholder="100"
ng-model="ctrl.panel.limit" ng-model="ctrl.panel.limit"
ng-model-onblur ng-change="ctrl.refresh()"> ng-model-onblur ng-change="ctrl.refresh()">
</div> </div>
</div> </div>
<div class="section gf-form-group"> <div class="section gf-form-group">
<h5 class="section-heading">View options</h5> <h5 class="section-heading">View options</h5>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-10">Font size</label> <label class="gf-form-label width-10">Font size</label>
<div class="gf-form-select-wrapper max-width-8"> <div class="gf-form-select-wrapper max-width-8">
<select class="gf-form-input" <select class="gf-form-input"
ng-model="ctrl.panel.fontSize" ng-model="ctrl.panel.fontSize"
ng-options="f for f in editor.fontSizes" ng-options="f for f in editor.fontSizes"
ng-change="ctrl.render()"></select> ng-change="ctrl.render()"></select>
</div> </div>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-10">Page size</label> <label class="gf-form-label width-10">Page size</label>
<input class="gf-form-input width-8" <input class="gf-form-input width-8"
type="number" placeholder="10" type="number" placeholder="10"
ng-model="ctrl.panel.pageSize" ng-model="ctrl.panel.pageSize"
ng-model-onblur ng-change="ctrl.render()"> ng-model-onblur ng-change="ctrl.render()">
</div> </div>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-10" label-class="width-10"
label="Highlight background" label="Highlight background"
checked="ctrl.panel.highlightBackground" checked="ctrl.panel.highlightBackground"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-10" label-class="width-10"
label="Highlight new events" label="Highlight new events"
checked="ctrl.panel.highlightNewEvents" checked="ctrl.panel.highlightNewEvents"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-10">Newer than</label> <label class="gf-form-label width-10">Newer than</label>
<input class="gf-form-input width-8" placeholder="1h" <input class="gf-form-input width-8" placeholder="1h"
ng-model="ctrl.panel.highlightNewerThan" ng-model="ctrl.panel.highlightNewerThan"
ng-model-onblur ng-change="ctrl.render()"> ng-model-onblur ng-change="ctrl.render()">
</div> </div>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-16" label-class="width-16"
label="Custom Last change format" label="Custom Last change format"
checked="ctrl.panel.customLastChangeFormat" checked="ctrl.panel.customLastChangeFormat"
on-change="ctrl.render()"> on-change="ctrl.render()">
</gf-form-switch> </gf-form-switch>
<div class="gf-form" ng-if="ctrl.panel.customLastChangeFormat"> <div class="gf-form" ng-if="ctrl.panel.customLastChangeFormat">
<label class="gf-form-label width-3"> <label class="gf-form-label width-3">
<a href="http://momentjs.com/docs/#/displaying/format/" target="_blank"> <a href="http://momentjs.com/docs/#/displaying/format/" target="_blank">
<tip>See moment.js dosc for time format.</tip> <tip>See moment.js dosc for time format.</tip>
</a> </a>
</label> </label>
<input class="gf-form-input width-18" <input class="gf-form-input width-18"
type="text" type="text"
placeholder="dddd, MMMM Do YYYY, h:mm:ss a" placeholder="dddd, MMMM Do YYYY, h:mm:ss a"
empty-to-null empty-to-null
ng-model-onblur ng-model-onblur
ng-model="ctrl.panel.lastChangeFormat" ng-model="ctrl.panel.lastChangeFormat"
ng-change="ctrl.render()"> ng-change="ctrl.render()">
</div> </div>
</div> </div>
<div class="section gf-form-group"> <div class="section gf-form-group">
<h5 class="section-heading">Triggers severity and colors</h5> <h5 class="section-heading">Triggers severity and colors</h5>
<div class="gf-form-inline" ng-repeat="trigger in ctrl.panel.triggerSeverity"> <div class="gf-form-inline" ng-repeat="trigger in ctrl.panel.triggerSeverity">
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-3">{{ trigger.priority }}</label> <label class="gf-form-label width-3">{{ trigger.priority }}</label>
<label class="gf-form-label triggers-severity-config" <label class="gf-form-label triggers-severity-config"
ng-style="{color: trigger.color}"> ng-style="{color: trigger.color}">
<i class="icon-gf" ng-class="ctrl.getAlertIconClassBySeverity(trigger)"></i> <i class="icon-gf" ng-class="ctrl.getAlertIconClassBySeverity(trigger)"></i>
</label> </label>
<input type="text" <input type="text"
class="gf-form-input width-12" class="gf-form-input width-12"
empty-to-null empty-to-null
ng-model="trigger.severity" ng-model="trigger.severity"
ng-model-onblur ng-model-onblur
ng-change="ctrl.render()"> ng-change="ctrl.render()">
<span class="gf-form-label"> <span class="gf-form-label">
<spectrum-picker ng-model="trigger.color" ng-change="ctrl.render()"></spectrum-picker> <spectrum-picker ng-model="trigger.color" ng-change="ctrl.render()"></spectrum-picker>
</span> </span>
</div> </div>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-0" label-class="width-0"
label="Show" label="Show"
checked="trigger.show" checked="trigger.show"
on-change="ctrl.refresh()"> on-change="ctrl.refresh()">
</gf-form-switch> </gf-form-switch>
</div> </div>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-3">&nbsp;</label> <label class="gf-form-label width-3">&nbsp;</label>
<label class="gf-form-label triggers-severity-config" <label class="gf-form-label triggers-severity-config"
ng-style="{color: ctrl.panel.ackEventColor}"> ng-style="{color: ctrl.panel.ackEventColor}">
<i class="icon-gf icon-gf-online"></i> <i class="icon-gf icon-gf-online"></i>
</label> </label>
<label class="gf-form-label width-12"> <label class="gf-form-label width-12">
Acknowledged color Acknowledged color
</label> </label>
<span class="gf-form-label"> <span class="gf-form-label">
<spectrum-picker ng-model="ctrl.panel.ackEventColor" ng-change="ctrl.render()"></spectrum-picker> <spectrum-picker ng-model="ctrl.panel.ackEventColor" ng-change="ctrl.render()"></spectrum-picker>
</span> </span>
</div> </div>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label-class="width-0" label-class="width-0"
label="Show" label="Show"
checked="ctrl.panel.markAckEvents" checked="ctrl.panel.markAckEvents"
on-change="ctrl.refresh()"> on-change="ctrl.refresh()">
</gf-form-switch> </gf-form-switch>
</div> </div>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-3">&nbsp;</label> <label class="gf-form-label width-3">&nbsp;</label>
<label class="gf-form-label triggers-severity-config" <label class="gf-form-label triggers-severity-config"
ng-style="{color: ctrl.panel.okEventColor}"> ng-style="{color: ctrl.panel.okEventColor}">
<i class="icon-gf icon-gf-online"></i> <i class="icon-gf icon-gf-online"></i>
</label> </label>
<label class="gf-form-label width-12"> <label class="gf-form-label width-12">
OK event color OK event color
</label> </label>
<span class="gf-form-label"> <span class="gf-form-label">
<spectrum-picker ng-model="ctrl.panel.okEventColor" ng-change="ctrl.render()"></spectrum-picker> <spectrum-picker ng-model="ctrl.panel.okEventColor" ng-change="ctrl.render()"></spectrum-picker>
</span> </span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,90 +1,90 @@
<div class="editor-row"> <div class="editor-row">
<div class="section gf-form-group"> <div class="section gf-form-group">
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-9">Data sources</label> <label class="gf-form-label width-9">Data sources</label>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<datasource-selector <datasource-selector
datasources="ctrl.panel.datasources" datasources="ctrl.panel.datasources"
options="editor.panelCtrl.available_datasources" options="editor.panelCtrl.available_datasources"
on-change="editor.datasourcesChanged()"> on-change="editor.datasourcesChanged()">
</datasource-selector> </datasource-selector>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="editor-row" ng-repeat="ds in ctrl.panel.datasources"> <div class="editor-row" ng-repeat="ds in ctrl.panel.datasources">
<div class="section gf-form-group"> <div class="section gf-form-group">
<h5 class="section-heading">{{ ds }}</h5> <h5 class="section-heading">{{ ds }}</h5>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Group</label> <label class="gf-form-label query-keyword width-7">Group</label>
<input type="text" <input type="text"
ng-model="ctrl.panel.targets[ds].group.filter" ng-model="ctrl.panel.targets[ds].group.filter"
bs-typeahead="editor.getGroupNames[ds]" bs-typeahead="editor.getGroupNames[ds]"
ng-blur="editor.parseTarget()" ng-blur="editor.parseTarget()"
data-min-length=0 data-min-length=0
data-items=100 data-items=100
class="gf-form-input" class="gf-form-input"
ng-class="{ ng-class="{
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].group.filter), 'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].group.filter),
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].group.filter) 'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].group.filter)
}"> }">
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword width-7">Host</label> <label class="gf-form-label query-keyword width-7">Host</label>
<input type="text" <input type="text"
ng-model="ctrl.panel.targets[ds].host.filter" ng-model="ctrl.panel.targets[ds].host.filter"
bs-typeahead="editor.getHostNames[ds]" bs-typeahead="editor.getHostNames[ds]"
ng-blur="editor.parseTarget()" ng-blur="editor.parseTarget()"
data-min-length=0 data-min-length=0
data-items=100 data-items=100
class="gf-form-input" class="gf-form-input"
ng-class="{ ng-class="{
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].host.filter), 'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].host.filter),
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].host.filter) 'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].host.filter)
}"> }">
</div> </div>
</div> </div>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form max-width-20"> <div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-7">Application</label> <label class="gf-form-label query-keyword width-7">Application</label>
<input type="text" <input type="text"
ng-model="ctrl.panel.targets[ds].application.filter" ng-model="ctrl.panel.targets[ds].application.filter"
bs-typeahead="editor.getApplicationNames[ds]" bs-typeahead="editor.getApplicationNames[ds]"
ng-blur="editor.parseTarget()" ng-blur="editor.parseTarget()"
data-min-length=0 data-min-length=0
data-items=100 data-items=100
class="gf-form-input" class="gf-form-input"
ng-class="{ ng-class="{
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].application.filter), 'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].application.filter),
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].application.filter) 'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].application.filter)
}"> }">
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword width-7">Trigger</label> <label class="gf-form-label query-keyword width-7">Trigger</label>
<input type="text" <input type="text"
ng-model="ctrl.panel.targets[ds].trigger.filter" ng-model="ctrl.panel.targets[ds].trigger.filter"
ng-blur="editor.parseTarget()" ng-blur="editor.parseTarget()"
placeholder="trigger name" placeholder="trigger name"
class="gf-form-input" class="gf-form-input"
ng-style="ctrl.panel.targets[ds].trigger.style" ng-style="ctrl.panel.targets[ds].trigger.style"
ng-class="{ ng-class="{
'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].trigger.filter), 'zbx-variable': editor.isVariable(ctrl.panel.targets[ds].trigger.filter),
'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].trigger.filter) 'zbx-regex': editor.isRegex(ctrl.panel.targets[ds].trigger.filter)
}" }"
empty-to-null> empty-to-null>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword width-7">Tags</label> <label class="gf-form-label query-keyword width-7">Tags</label>
<input type="text" class="gf-form-input" <input type="text" class="gf-form-input"
ng-model="ctrl.panel.targets[ds].tags.filter" ng-model="ctrl.panel.targets[ds].tags.filter"
ng-blur="editor.parseTarget()" ng-blur="editor.parseTarget()"
placeholder="tag1:value1, tag2:value2"> placeholder="tag1:value1, tag2:value2">
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,12 +1,12 @@
{ {
"type": "panel", "type": "panel",
"name": "Zabbix Triggers", "name": "Zabbix Triggers",
"id": "alexanderzobnin-zabbix-triggers-panel", "id": "alexanderzobnin-zabbix-triggers-panel",
"info": { "info": {
"author": { "author": {
"name": "Alexander Zobnin", "name": "Alexander Zobnin",
"url": "https://github.com/alexanderzobnin/grafana-zabbix" "url": "https://github.com/alexanderzobnin/grafana-zabbix"
} }
} }
} }

View File

@@ -1,77 +1,77 @@
import _ from 'lodash'; import _ from 'lodash';
import {TriggerPanelCtrl} from '../triggers_panel_ctrl'; import {TriggerPanelCtrl} from '../triggers_panel_ctrl';
import {DEFAULT_TARGET, DEFAULT_SEVERITY, PANEL_DEFAULTS} from '../triggers_panel_ctrl'; import {DEFAULT_TARGET, DEFAULT_SEVERITY, PANEL_DEFAULTS} from '../triggers_panel_ctrl';
import {CURRENT_SCHEMA_VERSION} from '../migrations'; import {CURRENT_SCHEMA_VERSION} from '../migrations';
describe('Triggers Panel schema migration', () => { describe('Triggers Panel schema migration', () => {
let ctx = {}; let ctx = {};
let datasourceSrvMock = { let datasourceSrvMock = {
getMetricSources: () => { getMetricSources: () => {
return [{ meta: {id: 'alexanderzobnin-zabbix-datasource'}, value: {}, name: 'zabbix_default' }]; return [{ meta: {id: 'alexanderzobnin-zabbix-datasource'}, value: {}, name: 'zabbix_default' }];
}, },
get: () => Promise.resolve({}) get: () => Promise.resolve({})
}; };
let timeoutMock = () => {}; let timeoutMock = () => {};
beforeEach(() => { beforeEach(() => {
ctx = { ctx = {
scope: { scope: {
panel: { panel: {
datasource: 'zabbix', datasource: 'zabbix',
triggers: DEFAULT_TARGET, triggers: DEFAULT_TARGET,
hostField: true, hostField: true,
statusField: false, statusField: false,
severityField: false, severityField: false,
lastChangeField: true, lastChangeField: true,
ageField: true, ageField: true,
infoField: true, infoField: true,
limit: 10, limit: 10,
showTriggers: 'all triggers', showTriggers: 'all triggers',
hideHostsInMaintenance: false, hideHostsInMaintenance: false,
sortTriggersBy: { text: 'last change', value: 'lastchange' }, sortTriggersBy: { text: 'last change', value: 'lastchange' },
showEvents: { text: 'Problems', value: '1' }, showEvents: { text: 'Problems', value: '1' },
triggerSeverity: DEFAULT_SEVERITY, triggerSeverity: DEFAULT_SEVERITY,
okEventColor: 'rgba(0, 245, 153, 0.45)', okEventColor: 'rgba(0, 245, 153, 0.45)',
ackEventColor: 'rgba(0, 0, 0, 0)', ackEventColor: 'rgba(0, 0, 0, 0)',
scroll: true, scroll: true,
pageSize: 10, pageSize: 10,
fontSize: '100%', fontSize: '100%',
} }
} }
}; };
}); });
it('should update old panel schema', () => { it('should update old panel schema', () => {
let updatedPanelCtrl = new TriggerPanelCtrl(ctx.scope, {}, timeoutMock, datasourceSrvMock, {}, {}, {}); let updatedPanelCtrl = new TriggerPanelCtrl(ctx.scope, {}, timeoutMock, datasourceSrvMock, {}, {}, {});
let expected = _.defaultsDeep({ let expected = _.defaultsDeep({
schemaVersion: CURRENT_SCHEMA_VERSION, schemaVersion: CURRENT_SCHEMA_VERSION,
datasources: ['zabbix'], datasources: ['zabbix'],
targets: { targets: {
'zabbix': DEFAULT_TARGET 'zabbix': DEFAULT_TARGET
}, },
statusField: false, statusField: false,
severityField: false, severityField: false,
limit: 10, limit: 10,
okEventColor: 'rgba(0, 245, 153, 0.45)', okEventColor: 'rgba(0, 245, 153, 0.45)',
ackEventColor: 'rgba(0, 0, 0, 0)' ackEventColor: 'rgba(0, 0, 0, 0)'
}, PANEL_DEFAULTS); }, PANEL_DEFAULTS);
expect(updatedPanelCtrl.panel).toEqual(expected); expect(updatedPanelCtrl.panel).toEqual(expected);
}); });
it('should create new panel with default schema', () => { it('should create new panel with default schema', () => {
ctx.scope.panel = {}; ctx.scope.panel = {};
let updatedPanelCtrl = new TriggerPanelCtrl(ctx.scope, {}, {}, datasourceSrvMock, {}, {}, {}); let updatedPanelCtrl = new TriggerPanelCtrl(ctx.scope, {}, {}, datasourceSrvMock, {}, {}, {});
let expected = _.defaultsDeep({ let expected = _.defaultsDeep({
schemaVersion: CURRENT_SCHEMA_VERSION, schemaVersion: CURRENT_SCHEMA_VERSION,
datasources: ['zabbix_default'], datasources: ['zabbix_default'],
targets: { targets: {
'zabbix_default': DEFAULT_TARGET 'zabbix_default': DEFAULT_TARGET
} }
}, PANEL_DEFAULTS); }, PANEL_DEFAULTS);
expect(updatedPanelCtrl.panel).toEqual(expected); expect(updatedPanelCtrl.panel).toEqual(expected);
}); });
}); });

View File

@@ -1,283 +1,283 @@
import _ from 'lodash'; import _ from 'lodash';
import {TriggerPanelCtrl} from '../triggers_panel_ctrl'; import {TriggerPanelCtrl} from '../triggers_panel_ctrl';
import {PANEL_DEFAULTS, DEFAULT_TARGET} from '../triggers_panel_ctrl'; import {PANEL_DEFAULTS, DEFAULT_TARGET} from '../triggers_panel_ctrl';
// import { create } from 'domain'; // import { create } from 'domain';
describe('TriggerPanelCtrl', () => { describe('TriggerPanelCtrl', () => {
let ctx = {}; let ctx = {};
let datasourceSrvMock, zabbixDSMock; let datasourceSrvMock, zabbixDSMock;
let timeoutMock = () => {}; let timeoutMock = () => {};
let createPanelCtrl; let createPanelCtrl;
beforeEach(() => { beforeEach(() => {
ctx = {scope: {panel: PANEL_DEFAULTS}}; ctx = {scope: {panel: PANEL_DEFAULTS}};
zabbixDSMock = { zabbixDSMock = {
replaceTemplateVars: () => {}, replaceTemplateVars: () => {},
zabbix: { zabbix: {
getTriggers: jest.fn().mockReturnValue([generateTrigger("1"), generateTrigger("1")]), getTriggers: jest.fn().mockReturnValue([generateTrigger("1"), generateTrigger("1")]),
getAcknowledges: jest.fn().mockReturnValue(Promise.resolve([])) getAcknowledges: jest.fn().mockReturnValue(Promise.resolve([]))
} }
}; };
datasourceSrvMock = { datasourceSrvMock = {
getMetricSources: () => { getMetricSources: () => {
return [ return [
{ meta: {id: 'alexanderzobnin-zabbix-datasource'}, value: {}, name: 'zabbix_default' }, { meta: {id: 'alexanderzobnin-zabbix-datasource'}, value: {}, name: 'zabbix_default' },
{ meta: {id: 'alexanderzobnin-zabbix-datasource'}, value: {}, name: 'zabbix' }, { meta: {id: 'alexanderzobnin-zabbix-datasource'}, value: {}, name: 'zabbix' },
{ meta: {id: 'graphite'}, value: {}, name: 'graphite' }, { meta: {id: 'graphite'}, value: {}, name: 'graphite' },
]; ];
}, },
get: () => Promise.resolve(zabbixDSMock) get: () => Promise.resolve(zabbixDSMock)
}; };
createPanelCtrl = () => new TriggerPanelCtrl(ctx.scope, {}, timeoutMock, datasourceSrvMock, {}, {}, {}); createPanelCtrl = () => new TriggerPanelCtrl(ctx.scope, {}, timeoutMock, datasourceSrvMock, {}, {}, {});
const getTriggersResp = [ const getTriggersResp = [
[ [
createTrigger({ createTrigger({
triggerid: "1", lastchange: "1510000010", priority: 5, lastEvent: {eventid: "11"}, hosts: [{maintenance_status: '1'}] triggerid: "1", lastchange: "1510000010", priority: 5, lastEvent: {eventid: "11"}, hosts: [{maintenance_status: '1'}]
}), }),
createTrigger({ createTrigger({
triggerid: "2", lastchange: "1510000040", priority: 3, lastEvent: {eventid: "12"} triggerid: "2", lastchange: "1510000040", priority: 3, lastEvent: {eventid: "12"}
}), }),
], ],
[ [
createTrigger({triggerid: "3", lastchange: "1510000020", priority: 4, lastEvent: {eventid: "13"}}), createTrigger({triggerid: "3", lastchange: "1510000020", priority: 4, lastEvent: {eventid: "13"}}),
createTrigger({triggerid: "4", lastchange: "1510000030", priority: 2, lastEvent: {eventid: "14"}}), createTrigger({triggerid: "4", lastchange: "1510000030", priority: 2, lastEvent: {eventid: "14"}}),
] ]
]; ];
// Simulate 2 data sources // Simulate 2 data sources
zabbixDSMock.zabbix.getTriggers = jest.fn() zabbixDSMock.zabbix.getTriggers = jest.fn()
.mockReturnValueOnce(getTriggersResp[0]) .mockReturnValueOnce(getTriggersResp[0])
.mockReturnValueOnce(getTriggersResp[1]); .mockReturnValueOnce(getTriggersResp[1]);
zabbixDSMock.zabbix.getAcknowledges = jest.fn() zabbixDSMock.zabbix.getAcknowledges = jest.fn()
.mockReturnValue(Promise.resolve([defaultEvent])); .mockReturnValue(Promise.resolve([defaultEvent]));
ctx.panelCtrl = createPanelCtrl(); ctx.panelCtrl = createPanelCtrl();
}); });
describe('When adding new panel', () => { describe('When adding new panel', () => {
it('should suggest all zabbix data sources', () => { it('should suggest all zabbix data sources', () => {
ctx.scope.panel = {}; ctx.scope.panel = {};
let panelCtrl = createPanelCtrl(); let panelCtrl = createPanelCtrl();
expect(panelCtrl.available_datasources).toEqual([ expect(panelCtrl.available_datasources).toEqual([
'zabbix_default', 'zabbix' 'zabbix_default', 'zabbix'
]); ]);
}); });
it('should load first zabbix data source as default', () => { it('should load first zabbix data source as default', () => {
ctx.scope.panel = {}; ctx.scope.panel = {};
let panelCtrl = createPanelCtrl(); let panelCtrl = createPanelCtrl();
expect(panelCtrl.panel.datasources).toEqual([ expect(panelCtrl.panel.datasources).toEqual([
'zabbix_default' 'zabbix_default'
]); ]);
}); });
}); });
describe('When refreshing panel', () => { describe('When refreshing panel', () => {
beforeEach(() => { beforeEach(() => {
ctx.scope.panel.datasources = ['zabbix_default', 'zabbix']; ctx.scope.panel.datasources = ['zabbix_default', 'zabbix'];
ctx.scope.panel.targets = { ctx.scope.panel.targets = {
'zabbix_default': DEFAULT_TARGET, 'zabbix_default': DEFAULT_TARGET,
'zabbix': DEFAULT_TARGET 'zabbix': DEFAULT_TARGET
}; };
ctx.panelCtrl = createPanelCtrl(); ctx.panelCtrl = createPanelCtrl();
}); });
it('should format triggers', (done) => { it('should format triggers', (done) => {
ctx.panelCtrl.onRefresh().then(() => { ctx.panelCtrl.onRefresh().then(() => {
let formattedTrigger = _.find(ctx.panelCtrl.triggerList, {triggerid: "1"}); let formattedTrigger = _.find(ctx.panelCtrl.triggerList, {triggerid: "1"});
expect(formattedTrigger.host).toBe('backend01'); expect(formattedTrigger.host).toBe('backend01');
expect(formattedTrigger.hostTechName).toBe('backend01_tech'); expect(formattedTrigger.hostTechName).toBe('backend01_tech');
expect(formattedTrigger.datasource).toBe('zabbix_default'); expect(formattedTrigger.datasource).toBe('zabbix_default');
expect(formattedTrigger.severity).toBe('Disaster'); expect(formattedTrigger.severity).toBe('Disaster');
expect(formattedTrigger.maintenance).toBe(true); expect(formattedTrigger.maintenance).toBe(true);
expect(formattedTrigger.age).toBeTruthy(); expect(formattedTrigger.age).toBeTruthy();
expect(formattedTrigger.lastchange).toBeTruthy(); expect(formattedTrigger.lastchange).toBeTruthy();
done(); done();
}); });
}); });
it('should sort triggers by time by default', (done) => { it('should sort triggers by time by default', (done) => {
ctx.panelCtrl.onRefresh().then(() => { ctx.panelCtrl.onRefresh().then(() => {
let trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid'); let trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid');
expect(trigger_ids).toEqual([ expect(trigger_ids).toEqual([
'2', '4', '3', '1' '2', '4', '3', '1'
]); ]);
done(); done();
}); });
}); });
it('should sort triggers by severity', (done) => { it('should sort triggers by severity', (done) => {
ctx.panelCtrl.panel.sortTriggersBy = { text: 'severity', value: 'priority' }; ctx.panelCtrl.panel.sortTriggersBy = { text: 'severity', value: 'priority' };
ctx.panelCtrl.onRefresh().then(() => { ctx.panelCtrl.onRefresh().then(() => {
let trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid'); let trigger_ids = _.map(ctx.panelCtrl.triggerList, 'triggerid');
expect(trigger_ids).toEqual([ expect(trigger_ids).toEqual([
'1', '3', '2', '4' '1', '3', '2', '4'
]); ]);
done(); done();
}); });
}); });
it('should add acknowledges to trigger', (done) => { it('should add acknowledges to trigger', (done) => {
ctx.panelCtrl.onRefresh().then(() => { ctx.panelCtrl.onRefresh().then(() => {
let trigger = getTriggerById(1, ctx); let trigger = getTriggerById(1, ctx);
expect(trigger.acknowledges).toHaveLength(1); expect(trigger.acknowledges).toHaveLength(1);
expect(trigger.acknowledges[0].message).toBe("event ack"); expect(trigger.acknowledges[0].message).toBe("event ack");
expect(getTriggerById(2, ctx).acknowledges).toBe(undefined); expect(getTriggerById(2, ctx).acknowledges).toBe(undefined);
expect(getTriggerById(3, ctx).acknowledges).toBe(undefined); expect(getTriggerById(3, ctx).acknowledges).toBe(undefined);
expect(getTriggerById(4, ctx).acknowledges).toBe(undefined); expect(getTriggerById(4, ctx).acknowledges).toBe(undefined);
done(); done();
}); });
}); });
}); });
describe('When formatting triggers', () => { describe('When formatting triggers', () => {
beforeEach(() => { beforeEach(() => {
ctx.panelCtrl = createPanelCtrl(); ctx.panelCtrl = createPanelCtrl();
}); });
it('should handle new lines in trigger description', () => { it('should handle new lines in trigger description', () => {
ctx.panelCtrl.setTriggerSeverity = jest.fn((trigger) => trigger); ctx.panelCtrl.setTriggerSeverity = jest.fn((trigger) => trigger);
let trigger = {comments: "this is\ndescription"}; let trigger = {comments: "this is\ndescription"};
const formattedTrigger = ctx.panelCtrl.formatTrigger(trigger); const formattedTrigger = ctx.panelCtrl.formatTrigger(trigger);
expect(formattedTrigger.comments).toBe("this is<br>description"); expect(formattedTrigger.comments).toBe("this is<br>description");
}); });
it('should format host name to display (default)', (done) => { it('should format host name to display (default)', (done) => {
ctx.panelCtrl.onRefresh().then(() => { ctx.panelCtrl.onRefresh().then(() => {
let trigger = getTriggerById(1, ctx); let trigger = getTriggerById(1, ctx);
let hostname = ctx.panelCtrl.formatHostName(trigger); let hostname = ctx.panelCtrl.formatHostName(trigger);
expect(hostname).toBe('backend01'); expect(hostname).toBe('backend01');
done(); done();
}); });
}); });
it('should format host name to display (tech name)', (done) => { it('should format host name to display (tech name)', (done) => {
ctx.panelCtrl.panel.hostField = false; ctx.panelCtrl.panel.hostField = false;
ctx.panelCtrl.panel.hostTechNameField = true; ctx.panelCtrl.panel.hostTechNameField = true;
ctx.panelCtrl.onRefresh().then(() => { ctx.panelCtrl.onRefresh().then(() => {
let trigger = getTriggerById(1, ctx); let trigger = getTriggerById(1, ctx);
let hostname = ctx.panelCtrl.formatHostName(trigger); let hostname = ctx.panelCtrl.formatHostName(trigger);
expect(hostname).toBe('backend01_tech'); expect(hostname).toBe('backend01_tech');
done(); done();
}); });
}); });
it('should format host name to display (both tech and visible)', (done) => { it('should format host name to display (both tech and visible)', (done) => {
ctx.panelCtrl.panel.hostField = true; ctx.panelCtrl.panel.hostField = true;
ctx.panelCtrl.panel.hostTechNameField = true; ctx.panelCtrl.panel.hostTechNameField = true;
ctx.panelCtrl.onRefresh().then(() => { ctx.panelCtrl.onRefresh().then(() => {
let trigger = getTriggerById(1, ctx); let trigger = getTriggerById(1, ctx);
let hostname = ctx.panelCtrl.formatHostName(trigger); let hostname = ctx.panelCtrl.formatHostName(trigger);
expect(hostname).toBe('backend01 (backend01_tech)'); expect(hostname).toBe('backend01 (backend01_tech)');
done(); done();
}); });
}); });
it('should hide hostname if both visible and tech name checkboxes unset', (done) => { it('should hide hostname if both visible and tech name checkboxes unset', (done) => {
ctx.panelCtrl.panel.hostField = false; ctx.panelCtrl.panel.hostField = false;
ctx.panelCtrl.panel.hostTechNameField = false; ctx.panelCtrl.panel.hostTechNameField = false;
ctx.panelCtrl.onRefresh().then(() => { ctx.panelCtrl.onRefresh().then(() => {
let trigger = getTriggerById(1, ctx); let trigger = getTriggerById(1, ctx);
let hostname = ctx.panelCtrl.formatHostName(trigger); let hostname = ctx.panelCtrl.formatHostName(trigger);
expect(hostname).toBe(""); expect(hostname).toBe("");
done(); done();
}); });
}); });
}); });
describe('When formatting acknowledges', () => { describe('When formatting acknowledges', () => {
beforeEach(() => { beforeEach(() => {
ctx.panelCtrl = createPanelCtrl(); ctx.panelCtrl = createPanelCtrl();
}); });
it('should build proper user name', () => { it('should build proper user name', () => {
const ack = { const ack = {
alias: 'alias', name: 'name', surname: 'surname' alias: 'alias', name: 'name', surname: 'surname'
}; };
const formatted = ctx.panelCtrl.formatAcknowledge(ack); const formatted = ctx.panelCtrl.formatAcknowledge(ack);
expect(formatted.user).toBe('alias (name surname)'); expect(formatted.user).toBe('alias (name surname)');
}); });
it('should return empty name if it is not defined', () => { it('should return empty name if it is not defined', () => {
const formatted = ctx.panelCtrl.formatAcknowledge({}); const formatted = ctx.panelCtrl.formatAcknowledge({});
expect(formatted.user).toBe(''); expect(formatted.user).toBe('');
}); });
}); });
}); });
const defaultTrigger = { const defaultTrigger = {
"triggerid": "13565", "triggerid": "13565",
"value": "1", "value": "1",
"groups": [{"groupid": "1", "name": "Backend"}] , "groups": [{"groupid": "1", "name": "Backend"}] ,
"hosts": [{"host": "backend01_tech", "hostid": "10001","maintenance_status": "0", "name": "backend01"}] , "hosts": [{"host": "backend01_tech", "hostid": "10001","maintenance_status": "0", "name": "backend01"}] ,
"lastEvent": { "lastEvent": {
"eventid": "11", "eventid": "11",
"clock": "1507229064", "clock": "1507229064",
"ns": "556202037", "ns": "556202037",
"acknowledged": "1", "acknowledged": "1",
"value": "1", "value": "1",
"object": "0", "object": "0",
"source": "0", "source": "0",
"objectid": "13565", "objectid": "13565",
}, },
"tags": [] , "tags": [] ,
"lastchange": "1440259530", "lastchange": "1440259530",
"priority": "2", "priority": "2",
"description": "Lack of free swap space on server", "description": "Lack of free swap space on server",
"comments": "It probably means that the systems requires\nmore physical memory.", "comments": "It probably means that the systems requires\nmore physical memory.",
"url": "https://host.local/path", "url": "https://host.local/path",
"templateid": "0", "expression": "{13174}<50", "manual_close": "0", "correlation_mode": "0", "templateid": "0", "expression": "{13174}<50", "manual_close": "0", "correlation_mode": "0",
"correlation_tag": "", "recovery_mode": "0", "recovery_expression": "", "state": "0", "status": "0", "correlation_tag": "", "recovery_mode": "0", "recovery_expression": "", "state": "0", "status": "0",
"flags": "0", "type": "0", "items": [] , "error": "" "flags": "0", "type": "0", "items": [] , "error": ""
}; };
const defaultEvent = { const defaultEvent = {
"eventid": "11", "eventid": "11",
"acknowledges": [ "acknowledges": [
{ {
"acknowledgeid": "185", "acknowledgeid": "185",
"action": "0", "action": "0",
"alias": "api", "alias": "api",
"clock": "1512382246", "clock": "1512382246",
"eventid": "11", "eventid": "11",
"message": "event ack", "message": "event ack",
"name": "api", "name": "api",
"surname": "user", "surname": "user",
"userid": "3" "userid": "3"
} }
], ],
"clock": "1507229064", "clock": "1507229064",
"ns": "556202037", "ns": "556202037",
"acknowledged": "1", "acknowledged": "1",
"value": "1", "value": "1",
"object": "0", "object": "0",
"source": "0", "source": "0",
"objectid": "1", "objectid": "1",
}; };
function generateTrigger(id, timestamp, severity) { function generateTrigger(id, timestamp, severity) {
let trigger = _.cloneDeep(defaultTrigger); let trigger = _.cloneDeep(defaultTrigger);
trigger.triggerid = id.toString(); trigger.triggerid = id.toString();
if (severity) { if (severity) {
trigger.priority = severity.toString(); trigger.priority = severity.toString();
} }
if (timestamp) { if (timestamp) {
trigger.lastchange = timestamp; trigger.lastchange = timestamp;
} }
return trigger; return trigger;
} }
function createTrigger(props) { function createTrigger(props) {
let trigger = _.cloneDeep(defaultTrigger); let trigger = _.cloneDeep(defaultTrigger);
trigger = _.merge(trigger, props); trigger = _.merge(trigger, props);
trigger.lastEvent.objectid = trigger.triggerid; trigger.lastEvent.objectid = trigger.triggerid;
return trigger; return trigger;
} }
function getTriggerById(id, ctx) { function getTriggerById(id, ctx) {
return _.find(ctx.panelCtrl.triggerList, {triggerid: id.toString()}); return _.find(ctx.panelCtrl.triggerList, {triggerid: id.toString()});
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

110
dist/plugin.json vendored
View File

@@ -1,55 +1,55 @@
{ {
"type": "app", "type": "app",
"name": "Zabbix", "name": "Zabbix",
"id": "alexanderzobnin-zabbix-app", "id": "alexanderzobnin-zabbix-app",
"info": { "info": {
"description": "Zabbix plugin for Grafana", "description": "Zabbix plugin for Grafana",
"author": { "author": {
"name": "Alexander Zobnin", "name": "Alexander Zobnin",
"url": "https://github.com/alexanderzobnin" "url": "https://github.com/alexanderzobnin"
}, },
"keywords": ["zabbix"], "keywords": ["zabbix"],
"logos": { "logos": {
"small": "img/zabbix_app_logo.svg", "small": "img/zabbix_app_logo.svg",
"large": "img/zabbix_app_logo.svg" "large": "img/zabbix_app_logo.svg"
}, },
"links": [ "links": [
{"name": "GitHub", "url": "https://github.com/alexanderzobnin/grafana-zabbix"}, {"name": "GitHub", "url": "https://github.com/alexanderzobnin/grafana-zabbix"},
{"name": "Docs", "url": "http://docs.grafana-zabbix.org"}, {"name": "Docs", "url": "http://docs.grafana-zabbix.org"},
{"name": "License", "url": "https://github.com/alexanderzobnin/grafana-zabbix/blob/master/LICENSE"} {"name": "License", "url": "https://github.com/alexanderzobnin/grafana-zabbix/blob/master/LICENSE"}
], ],
"screenshots": [ "screenshots": [
{"name": "Showcase", "path": "img/screenshot-showcase.png"}, {"name": "Showcase", "path": "img/screenshot-showcase.png"},
{"name": "Dashboard", "path": "img/screenshot-dashboard01.png"}, {"name": "Dashboard", "path": "img/screenshot-dashboard01.png"},
{"name": "Annotations", "path": "img/screenshot-annotations.png"}, {"name": "Annotations", "path": "img/screenshot-annotations.png"},
{"name": "Metric Editor", "path": "img/screenshot-metric_editor.png"}, {"name": "Metric Editor", "path": "img/screenshot-metric_editor.png"},
{"name": "Triggers", "path": "img/screenshot-triggers.png"} {"name": "Triggers", "path": "img/screenshot-triggers.png"}
], ],
"version": "3.9.0", "version": "3.9.0",
"updated": "2018-03-23" "updated": "2018-03-23"
}, },
"includes": [ "includes": [
{ {
"type": "datasource", "type": "datasource",
"name": "Zabbix Datasource" "name": "Zabbix Datasource"
}, },
{ {
"type": "panel", "type": "panel",
"name": "Triggers Panel" "name": "Triggers Panel"
}, },
{ {
"type": "dashboard", "type": "dashboard",
"name": "Zabbix Server Dashboard", "name": "Zabbix Server Dashboard",
"path": "dashboards/zabbix_server_dashboard.json", "path": "dashboards/zabbix_server_dashboard.json",
"addToNav": true, "addToNav": true,
"defaultNav": true "defaultNav": true
} }
], ],
"dependencies": { "dependencies": {
"grafanaVersion": "5.x", "grafanaVersion": "5.x",
"plugins": [] "plugins": []
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -22,7 +22,7 @@
"url": "https://github.com/alexanderzobnin/grafana-zabbix/issues" "url": "https://github.com/alexanderzobnin/grafana-zabbix/issues"
}, },
"devDependencies": { "devDependencies": {
"babel": "~6.5.1", "babel": "^6.23.0",
"babel-jest": "^21.2.0", "babel-jest": "^21.2.0",
"babel-plugin-transform-es2015-for-of": "^6.6.0", "babel-plugin-transform-es2015-for-of": "^6.6.0",
"babel-plugin-transform-es2015-modules-systemjs": "^6.5.0", "babel-plugin-transform-es2015-modules-systemjs": "^6.5.0",
@@ -46,12 +46,16 @@
"jsdom": "~11.3.0", "jsdom": "~11.3.0",
"jshint-stylish": "^2.1.0", "jshint-stylish": "^2.1.0",
"load-grunt-tasks": "~3.2.0", "load-grunt-tasks": "~3.2.0",
"moment": "~2.21.0", "moment": "^2.22.1",
"q": "~1.4.1", "q": "~1.4.1",
"tether-drop": "^1.4.2" "tether-drop": "^1.4.2"
}, },
"dependencies": { "dependencies": {
"loadash": "^1.0.0",
"lodash": "~4.0.0", "lodash": "~4.0.0",
"node-gyp": "^3.6.2",
"node-sass": "^3.13.1",
"python2": "0.0.1",
"systemjs": "^0.20.19" "systemjs": "^0.20.19"
}, },
"homepage": "http://grafana-zabbix.org" "homepage": "http://grafana-zabbix.org"

View File

@@ -36,6 +36,33 @@ function limit(order, n, orderByFunc, timeseries) {
} }
} }
function removeAboveValue(n, datapoints) {
return _.map(datapoints, point => {
return [
(point[0] > n) ? null : point[0],
point[1]
];
});
}
function removeBelowValue(n, datapoints) {
return _.map(datapoints, point => {
return [
(point[0] < n) ? null : point[0],
point[1]
];
});
}
function transformNull(n, datapoints) {
return _.map(datapoints, point => {
return [
(point[0] !== null) ? point[0] : n,
point[1]
];
});
}
function sortSeries(direction, timeseries) { function sortSeries(direction, timeseries) {
return _.orderBy(timeseries, [function (ts) { return _.orderBy(timeseries, [function (ts) {
return ts.target.toLowerCase(); return ts.target.toLowerCase();
@@ -121,6 +148,7 @@ let metricFunctions = {
rate: rate, rate: rate,
movingAverage: simpleMovingAverage, movingAverage: simpleMovingAverage,
exponentialMovingAverage: expMovingAverage, exponentialMovingAverage: expMovingAverage,
transformNull: transformNull,
aggregateBy: aggregateByWrapper, aggregateBy: aggregateByWrapper,
// Predefined aggs // Predefined aggs
percentil: percentil, percentil: percentil,
@@ -131,6 +159,8 @@ let metricFunctions = {
sum: _.partial(aggregateWrapper, SUM), sum: _.partial(aggregateWrapper, SUM),
count: _.partial(aggregateWrapper, COUNT), count: _.partial(aggregateWrapper, COUNT),
sumSeries: sumSeries, sumSeries: sumSeries,
removeAboveValue: removeAboveValue,
removeBelowValue: removeBelowValue,
top: _.partial(limit, 'top'), top: _.partial(limit, 'top'),
bottom: _.partial(limit, 'bottom'), bottom: _.partial(limit, 'bottom'),
sortSeries: sortSeries, sortSeries: sortSeries,

View File

@@ -76,6 +76,15 @@ addFuncDef({
defaultParams: [0.2], defaultParams: [0.2],
}); });
addFuncDef({
name: 'transformNull',
category: 'Transform',
params: [
{name: 'number', type: 'float'}
],
defaultParams: [0],
});
// Aggregate // Aggregate
addFuncDef({ addFuncDef({
@@ -161,6 +170,24 @@ addFuncDef({
// Filter // Filter
addFuncDef({
name: 'removeAboveValue',
category: 'Filter',
params: [
{name: 'number', type: 'float'},
],
defaultParams: [0],
});
addFuncDef({
name: 'removeBelowValue',
category: 'Filter',
params: [
{name: 'number', type: 'float'},
],
defaultParams: [0],
});
addFuncDef({ addFuncDef({
name: 'top', name: 'top',
category: 'Filter', category: 'Filter',