From c12a5c01f61bf488959ecb6fcd6b30469c26f998 Mon Sep 17 00:00:00 2001 From: erelender <20099086+erelender@users.noreply.github.com> Date: Tue, 5 Nov 2024 20:02:33 +0300 Subject: [PATCH] Feature: Headscale Service Widget (#4247) --- docs/widgets/services/headscale.md | 19 +++++++++++ docs/widgets/services/index.md | 1 + mkdocs.yml | 1 + public/locales/en/common.json | 8 +++++ src/utils/proxy/handlers/credentialed.js | 1 + src/widgets/components.js | 1 + src/widgets/headscale/component.jsx | 43 ++++++++++++++++++++++++ src/widgets/headscale/widget.js | 14 ++++++++ src/widgets/widgets.js | 2 ++ 9 files changed, 90 insertions(+) create mode 100644 docs/widgets/services/headscale.md create mode 100644 src/widgets/headscale/component.jsx create mode 100644 src/widgets/headscale/widget.js diff --git a/docs/widgets/services/headscale.md b/docs/widgets/services/headscale.md new file mode 100644 index 000000000..c6da54f5c --- /dev/null +++ b/docs/widgets/services/headscale.md @@ -0,0 +1,19 @@ +--- +title: Headscale +description: Headscale Widget Configuration +--- + +Learn more about [Headscale](https://headscale.net/). + +You will need to generate an API access token from the [command line](https://headscale.net/ref/remote-cli/#create-an-api-key) using `headscale apikeys create` command. + +To find your node ID, you can use `headscale nodes list` command. + +Allowed fields: `["name", "address", "last_seen", "status"]`. + +```yaml +widget: + type: headscale + nodeId: nodeid + key: headscaleapiaccesstoken +``` diff --git a/docs/widgets/services/index.md b/docs/widgets/services/index.md index 91f91d383..3dee2a05d 100644 --- a/docs/widgets/services/index.md +++ b/docs/widgets/services/index.md @@ -44,6 +44,7 @@ You can also find a list of all available service widgets in the sidebar navigat - [Gotify](gotify.md) - [Grafana](grafana.md) - [HDHomeRun](hdhomerun.md) +- [Headscale](headscale.md) - [Healthchecks](healthchecks.md) - [Home Assistant](homeassistant.md) - [HomeBox](homebox.md) diff --git a/mkdocs.yml b/mkdocs.yml index 0667e5eaa..94af034d7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -67,6 +67,7 @@ nav: - widgets/services/gotify.md - widgets/services/grafana.md - widgets/services/hdhomerun.md + - widgets/services/headscale.md - widgets/services/healthchecks.md - widgets/services/homeassistant.md - widgets/services/homebox.md diff --git a/public/locales/en/common.json b/public/locales/en/common.json index fd52aef4a..38ee3e857 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -959,5 +959,13 @@ "tasks7d": "Tasks Due This Week", "tasksOverdue": "Overdue Tasks", "tasksInProgress": "Tasks In Progress" + }, + "headscale": { + "name": "Name", + "address": "Address", + "last_seen": "Last Seen", + "status": "Status", + "online": "Online", + "offline": "Offline" } } diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index b1b9922c6..eb2aab69a 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -39,6 +39,7 @@ export default async function credentialedProxyHandler(req, res, map) { "authentik", "cloudflared", "ghostfolio", + "headscale", "linkwarden", "mealie", "netalertx", diff --git a/src/widgets/components.js b/src/widgets/components.js index 62bd479f5..8453e5275 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -41,6 +41,7 @@ const components = { gotify: dynamic(() => import("./gotify/component")), grafana: dynamic(() => import("./grafana/component")), hdhomerun: dynamic(() => import("./hdhomerun/component")), + headscale: dynamic(() => import("./headscale/component")), peanut: dynamic(() => import("./peanut/component")), homeassistant: dynamic(() => import("./homeassistant/component")), homebox: dynamic(() => import("./homebox/component")), diff --git a/src/widgets/headscale/component.jsx b/src/widgets/headscale/component.jsx new file mode 100644 index 000000000..361aa756f --- /dev/null +++ b/src/widgets/headscale/component.jsx @@ -0,0 +1,43 @@ +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"; + +export default function Component({ service }) { + const { t } = useTranslation(); + const { widget } = service; + + const { data: nodeData, error: nodeError } = useWidgetAPI(widget, "node"); + + if (nodeError) { + return ; + } + + if (!nodeData) { + return ( + + + + + + + ); + } + + const { + givenName, + ipAddresses: [address], + lastSeen, + online, + } = nodeData.node; + + return ( + + + + + + + ); +} diff --git a/src/widgets/headscale/widget.js b/src/widgets/headscale/widget.js new file mode 100644 index 000000000..a05059fba --- /dev/null +++ b/src/widgets/headscale/widget.js @@ -0,0 +1,14 @@ +import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; + +const widget = { + api: "{url}/api/v1/{endpoint}/{nodeId}", + proxyHandler: credentialedProxyHandler, + + mappings: { + node: { + endpoint: "node", + }, + }, +}; + +export default widget; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index faff57eb4..a1af3661b 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -35,6 +35,7 @@ import gluetun from "./gluetun/widget"; import gotify from "./gotify/widget"; import grafana from "./grafana/widget"; import hdhomerun from "./hdhomerun/widget"; +import headscale from "./headscale/widget"; import homeassistant from "./homeassistant/widget"; import homebox from "./homebox/widget"; import homebridge from "./homebridge/widget"; @@ -161,6 +162,7 @@ const widgets = { gotify, grafana, hdhomerun, + headscale, homeassistant, homebox, homebridge,