From 6921a3f6e28d2c725fb5ec778954928c2fa996dd Mon Sep 17 00:00:00 2001
From: Mitchell <37925797+ping-localhost@users.noreply.github.com>
Date: Thu, 29 Aug 2024 09:09:17 +0200
Subject: [PATCH] Added Zabbix service widget
---
docs/widgets/authoring/proxies.md | 27 +++++++++++++-
docs/widgets/services/index.md | 1 +
docs/widgets/services/zabbix.md | 19 ++++++++++
mkdocs.yml | 1 +
public/locales/en/common.json | 6 ++++
src/utils/proxy/handlers/jsonrpc.js | 19 ++++++----
src/widgets/components.js | 1 +
src/widgets/widgets.js | 2 ++
src/widgets/zabbix/component.jsx | 56 +++++++++++++++++++++++++++++
src/widgets/zabbix/widget.js | 12 +++++++
10 files changed, 136 insertions(+), 8 deletions(-)
create mode 100644 docs/widgets/services/zabbix.md
create mode 100644 src/widgets/zabbix/component.jsx
create mode 100644 src/widgets/zabbix/widget.js
diff --git a/docs/widgets/authoring/proxies.md b/docs/widgets/authoring/proxies.md
index 220af4ad0..15cdb6703 100644
--- a/docs/widgets/authoring/proxies.md
+++ b/docs/widgets/authoring/proxies.md
@@ -79,7 +79,21 @@ By default the key is passed as an `X-API-Key` header. If you need to pass the k
### `jsonrpcProxyHandler`
-A proxy handler that makes authenticated JSON-RPC requests to the specified API endpoint. Where the endpoint is the method to call.
+A proxy handler that makes authenticated JSON-RPC requests to the specified API endpoint, either using username + password or an API token.
+The endpoint is the method to call and queryParams are used as the parameters.
+
+=== "component.js"
+
+ ```js
+ import Container from "components/services/widget/container";
+ import useWidgetAPI from "utils/proxy/use-widget-api";
+
+ export default function Component({ service }) {
+ const { widget } = service;
+
+ const { data, error } = useWidgetAPI(widget, 'trigger', { "triggerids": "14062", "output": "extend", "selectFunctions": "extend" });
+ }
+ ```
=== "widget.js"
@@ -93,6 +107,7 @@ A proxy handler that makes authenticated JSON-RPC requests to the specified API
mappings: {
total: { endpoint: "total" },
average: { endpoint: "average" },
+ trigger: { endpoint: "trigger.get" },
},
};
```
@@ -110,6 +125,16 @@ A proxy handler that makes authenticated JSON-RPC requests to the specified API
password: your-password
```
+ ```yaml
+ - Your Widget:
+ icon: yourwidget.svg
+ href: https://example.com/
+ widget:
+ type: yourwidget
+ url: http://127.0.0.1:1337
+ key: your-api-token
+ ```
+
### `synologyProxyHandler`
A proxy handler that makes authenticated requests to the specified Synology API endpoint. This is used exclusively for Synology DSM services.
diff --git a/docs/widgets/services/index.md b/docs/widgets/services/index.md
index c39ac0f09..f86a622b4 100644
--- a/docs/widgets/services/index.md
+++ b/docs/widgets/services/index.md
@@ -127,3 +127,4 @@ You can also find a list of all available service widgets in the sidebar navigat
- [WGEasy](wgeasy.md)
- [WhatsUpDocker](whatsupdocker.md)
- [xTeVe](xteve.md)
+- [Zabbix](zabbix.md)
diff --git a/docs/widgets/services/zabbix.md b/docs/widgets/services/zabbix.md
new file mode 100644
index 000000000..e7f18c416
--- /dev/null
+++ b/docs/widgets/services/zabbix.md
@@ -0,0 +1,19 @@
+---
+title: Zabbix
+description: Zabbix Widget Configuration
+---
+
+Learn more about [Zabbix](https://github.com/zabbix/zabbix).
+
+See the [Zabbix documentation](https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/users/api_tokens) for details on generating API tokens.
+
+The widget supports (at least) Zibbax server version 7.0.
+
+Allowed fields: `["warning", "average", "high", "disaster"]`.
+
+```yaml
+widget:
+ type: zabbix
+ url: http://zabbix.host.or.ip/zabbix
+ key: your-api-key
+```
diff --git a/mkdocs.yml b/mkdocs.yml
index d48cc35e0..9ea4d0012 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -151,6 +151,7 @@ nav:
- widgets/services/wgeasy.md
- widgets/services/whatsupdocker.md
- widgets/services/xteve.md
+ - widgets/services/zabbix.md
- "Information Widgets":
- widgets/info/index.md
- widgets/info/datetime.md
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index fabf5d84d..f7056d9df 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -918,5 +918,11 @@
"links": "Links",
"collections": "Collections",
"tags": "Tags"
+ },
+ "zabbix": {
+ "warning": "Warning",
+ "average": "Average",
+ "high": "High",
+ "disaster": "Disaster"
}
}
diff --git a/src/utils/proxy/handlers/jsonrpc.js b/src/utils/proxy/handlers/jsonrpc.js
index b1b080fd0..c202f7061 100644
--- a/src/utils/proxy/handlers/jsonrpc.js
+++ b/src/utils/proxy/handlers/jsonrpc.js
@@ -8,14 +8,18 @@ import widgets from "widgets/widgets";
const logger = createLogger("jsonrpcProxyHandler");
-export async function sendJsonRpcRequest(url, method, params, username, password) {
+export async function sendJsonRpcRequest(url, method, params, widget) {
const headers = {
- "content-type": "application/json",
- accept: "application/json",
+ Accept: "application/json-rpc",
+ "Content-Type": "application/json-rpc",
};
- if (username && password) {
- headers.authorization = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
+ if (widget.username && widget.password) {
+ headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`;
+ }
+
+ if (widget.key) {
+ headers.Authorization = `Bearer ${widget.key}`;
}
const client = new JSONRPCClient(async (rpcRequest) => {
@@ -61,7 +65,8 @@ export async function sendJsonRpcRequest(url, method, params, username, password
}
export default async function jsonrpcProxyHandler(req, res) {
- const { group, service, endpoint: method } = req.query;
+ const { group, service, endpoint: method, query } = req.query;
+ const params = query ? JSON.parse(query) : null;
if (group && service) {
const widget = await getServiceWidget(group, service);
@@ -75,7 +80,7 @@ export default async function jsonrpcProxyHandler(req, res) {
const url = formatApiCall(api, { ...widget });
// eslint-disable-next-line no-unused-vars
- const [status, contentType, data] = await sendJsonRpcRequest(url, method, null, widget.username, widget.password);
+ const [status, contentType, data] = await sendJsonRpcRequest(url, method, params, widget);
return res.status(status).end(data);
}
}
diff --git a/src/widgets/components.js b/src/widgets/components.js
index b2d6659e3..566c0423a 100644
--- a/src/widgets/components.js
+++ b/src/widgets/components.js
@@ -126,6 +126,7 @@ const components = {
wgeasy: dynamic(() => import("./wgeasy/component")),
whatsupdocker: dynamic(() => import("./whatsupdocker/component")),
xteve: dynamic(() => import("./xteve/component")),
+ zabbix: dynamic(() => import("./zabbix/component")),
};
export default components;
diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js
index f4e55d57c..6e0362ce0 100644
--- a/src/widgets/widgets.js
+++ b/src/widgets/widgets.js
@@ -118,6 +118,7 @@ import whatsupdocker from "./whatsupdocker/widget";
import xteve from "./xteve/widget";
import urbackup from "./urbackup/widget";
import romm from "./romm/widget";
+import zabbix from "./zabbix/widget";
const widgets = {
adguard,
@@ -243,6 +244,7 @@ const widgets = {
wgeasy,
whatsupdocker,
xteve,
+ zabbix,
};
export default widgets;
diff --git a/src/widgets/zabbix/component.jsx b/src/widgets/zabbix/component.jsx
new file mode 100644
index 000000000..aab46f5fd
--- /dev/null
+++ b/src/widgets/zabbix/component.jsx
@@ -0,0 +1,56 @@
+import { useTranslation } from "next-i18next";
+
+import Container from "components/services/widget/container";
+import Block from "components/services/widget/block";
+import useWidgetAPI from "utils/proxy/use-widget-api";
+
+const PriorityWarning = "2";
+const PriorityAverage = "3";
+const PriorityHigh = "4";
+const PriorityDisaster = "5";
+
+const triggerParams = {
+ output: ["triggerid", "description", "priority"],
+ filter: {
+ value: 1,
+ },
+ sortfield: "priority",
+ sortorder: "DESC",
+ monitored: "true",
+};
+
+export default function Component({ service }) {
+ const { t } = useTranslation();
+ const { widget } = service;
+
+ const { data: zabbixData, error: zabbixError } = useWidgetAPI(widget, "trigger", triggerParams);
+
+ if (zabbixError) {
+ return ;
+ }
+
+ if (!zabbixData) {
+ return (
+
+
+
+
+
+
+ );
+ }
+
+ const warning = zabbixData.filter((item) => item.priority === PriorityWarning).length;
+ const average = zabbixData.filter((item) => item.priority === PriorityAverage).length;
+ const high = zabbixData.filter((item) => item.priority === PriorityHigh).length;
+ const disaster = zabbixData.filter((item) => item.priority === PriorityDisaster).length;
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/widgets/zabbix/widget.js b/src/widgets/zabbix/widget.js
new file mode 100644
index 000000000..76641f243
--- /dev/null
+++ b/src/widgets/zabbix/widget.js
@@ -0,0 +1,12 @@
+import jsonrpcProxyHandler from "utils/proxy/handlers/jsonrpc";
+
+const widget = {
+ api: "{url}/api_jsonrpc.php",
+ proxyHandler: jsonrpcProxyHandler,
+
+ mappings: {
+ trigger: { endpoint: "trigger.get" },
+ },
+};
+
+export default widget;