From 94bbcbe1fb868f8b60cefe5331d581760fecde32 Mon Sep 17 00:00:00 2001 From: Florian Geckeler <43751896+fgeck@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:32:04 +0100 Subject: [PATCH 1/3] Feature: Spoolman Widget (#3959) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/widgets/services/spoolman.md | 15 +++++++ mkdocs.yml | 1 + public/locales/en/common.json | 3 ++ src/utils/config/service-helpers.js | 6 +++ src/widgets/components.js | 1 + src/widgets/spoolman/component.jsx | 63 +++++++++++++++++++++++++++++ src/widgets/spoolman/widget.js | 14 +++++++ src/widgets/widgets.js | 2 + 8 files changed, 105 insertions(+) create mode 100644 docs/widgets/services/spoolman.md create mode 100644 src/widgets/spoolman/component.jsx create mode 100644 src/widgets/spoolman/widget.js diff --git a/docs/widgets/services/spoolman.md b/docs/widgets/services/spoolman.md new file mode 100644 index 00000000..5baa9268 --- /dev/null +++ b/docs/widgets/services/spoolman.md @@ -0,0 +1,15 @@ +--- +title: Spoolman +description: Spoolman Widget Configuration +--- + +Learn more about [Spoolman](https://github.com/Donkie/Spoolman). + +4 spools are displayed by default. If more than 4 spools are configured in spoolman you can use the spoolIds configuration option to control which are displayed. + +```yaml +widget: + type: spoolman + url: http://spoolman.host.or.ip + spoolIds: [1, 2, 3, 4] # optional +``` diff --git a/mkdocs.yml b/mkdocs.yml index 1e9d59cc..5b350d71 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -138,6 +138,7 @@ nav: - widgets/services/scrutiny.md - widgets/services/sonarr.md - widgets/services/speedtest-tracker.md + - widgets/services/spoolman.md - widgets/services/stash.md - widgets/services/stocks.md - widgets/services/swagdashboard.md diff --git a/public/locales/en/common.json b/public/locales/en/common.json index ab7dcfc9..5abb9a4b 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -998,5 +998,8 @@ "progressing": "Progressing", "missing": "Missing", "suspended": "Suspended" + }, + "spoolman": { + "loading": "Loading" } } diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 1566a135..ea82c735 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -492,6 +492,9 @@ export function cleanServiceGroups(groups) { // technitium range, + + // spoolman + spoolIds, } = cleanedService.widget; let fieldsList = fields; @@ -653,6 +656,9 @@ export function cleanServiceGroups(groups) { if (metrics) cleanedService.widget.metrics = metrics; if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval; } + if (type === "spoolman") { + if (spoolIds !== undefined) cleanedService.widget.spoolIds = spoolIds; + } } return cleanedService; diff --git a/src/widgets/components.js b/src/widgets/components.js index aa476c46..bea37cf2 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -111,6 +111,7 @@ const components = { scrutiny: dynamic(() => import("./scrutiny/component")), sonarr: dynamic(() => import("./sonarr/component")), speedtest: dynamic(() => import("./speedtest/component")), + spoolman: dynamic(() => import("./spoolman/component")), stash: dynamic(() => import("./stash/component")), stocks: dynamic(() => import("./stocks/component")), strelaysrv: dynamic(() => import("./strelaysrv/component")), diff --git a/src/widgets/spoolman/component.jsx b/src/widgets/spoolman/component.jsx new file mode 100644 index 00000000..523ecea7 --- /dev/null +++ b/src/widgets/spoolman/component.jsx @@ -0,0 +1,63 @@ +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; + + // eslint-disable-next-line prefer-const + let { data: spoolData, error: spoolError } = useWidgetAPI(widget, "spools"); + + if (spoolError) { + return ; + } + + if (!spoolData) { + const nBlocksGuess = widget.spoolIds?.length ?? 4; + return ( + + {[...Array(nBlocksGuess)].map((_, i) => ( + // eslint-disable-next-line react/no-array-index-key + + ))} + + ); + } + + if (spoolData.error || spoolData.message) { + return ; + } + + if (spoolData.length === 0) { + return ( + + + + ); + } + + if (widget.spoolIds?.length) { + spoolData = spoolData.filter((spool) => widget.spoolIds.includes(spool.id)); + } + + if (spoolData.length > 4) { + spoolData = spoolData.slice(0, 4); + } + + return ( + + {spoolData.map((spool) => ( + + ))} + + ); +} diff --git a/src/widgets/spoolman/widget.js b/src/widgets/spoolman/widget.js new file mode 100644 index 00000000..2c8a3475 --- /dev/null +++ b/src/widgets/spoolman/widget.js @@ -0,0 +1,14 @@ +import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; + +const widget = { + api: "{url}/api/v1/{endpoint}", + proxyHandler: credentialedProxyHandler, + + mappings: { + spools: { + endpoint: "spool", + }, + }, +}; + +export default widget; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index 0cad5346..8eb3f51f 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -102,6 +102,7 @@ import sabnzbd from "./sabnzbd/widget"; import scrutiny from "./scrutiny/widget"; import sonarr from "./sonarr/widget"; import speedtest from "./speedtest/widget"; +import spoolman from "./spoolman/widget"; import stash from "./stash/widget"; import stocks from "./stocks/widget"; import strelaysrv from "./strelaysrv/widget"; @@ -237,6 +238,7 @@ const widgets = { scrutiny, sonarr, speedtest, + spoolman, stash, stocks, strelaysrv, From 2b8647b2ef61d6eab8cfc34a629506131ca9df44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Urs=20Kr=C3=B6ll?= <109229014+UrsKroell@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:07:17 +0100 Subject: [PATCH 2/3] Feature: gitlab service widget (#4317) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/widgets/services/gitlab.md | 20 +++++++++++++ docs/widgets/services/index.md | 1 + mkdocs.yml | 1 + public/locales/en/common.json | 6 ++++ src/utils/proxy/handlers/credentialed.js | 2 ++ src/widgets/components.js | 1 + src/widgets/gitlab/component.jsx | 36 ++++++++++++++++++++++++ src/widgets/gitlab/widget.js | 13 +++++++++ src/widgets/widgets.js | 2 ++ 9 files changed, 82 insertions(+) create mode 100644 docs/widgets/services/gitlab.md create mode 100644 src/widgets/gitlab/component.jsx create mode 100644 src/widgets/gitlab/widget.js diff --git a/docs/widgets/services/gitlab.md b/docs/widgets/services/gitlab.md new file mode 100644 index 00000000..a92434d8 --- /dev/null +++ b/docs/widgets/services/gitlab.md @@ -0,0 +1,20 @@ +--- +title: Gitlab +description: Gitlab Widget Configuration +--- + +Learn more about [Gitlab](https://gitlab.com). + +API requires a personal access token with either `read_api` or `api` permission. See the [gitlab documentation](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#create-a-personal-access-token) for details on generating one. + +Your Gitlab user ID can be found on [your profile page](https://support.circleci.com/hc/en-us/articles/20761157174043-How-to-find-your-GitLab-User-ID). + +Allowed fields: `["events", "issues", "merges", "projects"]`. + +```yaml +widget: + type: gitlab + url: http://gitlab.host.or.ip:port + key: personal-access-token + user_id: 123456 +``` diff --git a/docs/widgets/services/index.md b/docs/widgets/services/index.md index ae506f08..894a31f6 100644 --- a/docs/widgets/services/index.md +++ b/docs/widgets/services/index.md @@ -41,6 +41,7 @@ You can also find a list of all available service widgets in the sidebar navigat - [Gatus](gatus.md) - [Ghostfolio](ghostfolio.md) - [Gitea](gitea.md) +- [Gitlab](gitlab.md) - [Glances](glances.md) - [Gluetun](gluetun.md) - [Gotify](gotify.md) diff --git a/mkdocs.yml b/mkdocs.yml index 5b350d71..a19d3b83 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -64,6 +64,7 @@ nav: - widgets/services/gatus.md - widgets/services/ghostfolio.md - widgets/services/gitea.md + - widgets/services/gitlab.md - widgets/services/glances.md - widgets/services/gluetun.md - widgets/services/gotify.md diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 5abb9a4b..484f76b5 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -1001,5 +1001,11 @@ }, "spoolman": { "loading": "Loading" + }, + "gitlab": { + "groups": "Groups", + "issues": "Issues", + "merges": "Merge Requests", + "projects": "Projects" } } diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index 8d4340c2..cbe0422a 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -94,6 +94,8 @@ export default async function credentialedProxyHandler(req, res, map) { } } else if (widget.type === "wgeasy") { headers.Authorization = widget.password; + } else if (widget.type === "gitlab") { + headers["PRIVATE-TOKEN"] = widget.key; } else { headers["X-API-Key"] = `${widget.key}`; } diff --git a/src/widgets/components.js b/src/widgets/components.js index bea37cf2..19f41d4a 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -38,6 +38,7 @@ const components = { gatus: dynamic(() => import("./gatus/component")), ghostfolio: dynamic(() => import("./ghostfolio/component")), gitea: dynamic(() => import("./gitea/component")), + gitlab: dynamic(() => import("./gitlab/component")), glances: dynamic(() => import("./glances/component")), gluetun: dynamic(() => import("./gluetun/component")), gotify: dynamic(() => import("./gotify/component")), diff --git a/src/widgets/gitlab/component.jsx b/src/widgets/gitlab/component.jsx new file mode 100644 index 00000000..fb6f898f --- /dev/null +++ b/src/widgets/gitlab/component.jsx @@ -0,0 +1,36 @@ +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: gitlabCounts, error: gitlabCountsError } = useWidgetAPI(widget, "counts"); + + if (gitlabCountsError) { + return ; + } + + if (!gitlabCounts) { + return ( + + + + + + + ); + } + + return ( + + + + + + + ); +} diff --git a/src/widgets/gitlab/widget.js b/src/widgets/gitlab/widget.js new file mode 100644 index 00000000..26f77a77 --- /dev/null +++ b/src/widgets/gitlab/widget.js @@ -0,0 +1,13 @@ +import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; + +const widget = { + api: "{url}/api/v4/{endpoint}", + proxyHandler: credentialedProxyHandler, + mappings: { + counts: { + endpoint: "users/{user_id}/associations_count", + }, + }, +}; + +export default widget; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index 8eb3f51f..9d4bb935 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -32,6 +32,7 @@ import gamedig from "./gamedig/widget"; import gatus from "./gatus/widget"; import ghostfolio from "./ghostfolio/widget"; import gitea from "./gitea/widget"; +import gitlab from "./gitlab/widget"; import glances from "./glances/widget"; import gluetun from "./gluetun/widget"; import gotify from "./gotify/widget"; @@ -164,6 +165,7 @@ const widgets = { gatus, ghostfolio, gitea, + gitlab, glances, gluetun, gotify, From 56972535c7a38e2e03cca4ae61443ac2e52d9f34 Mon Sep 17 00:00:00 2001 From: Simon Emms Date: Fri, 22 Nov 2024 15:41:48 +0000 Subject: [PATCH 3/3] Documentation: additional explainer for the pod-selector (#4316) --- docs/configs/kubernetes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/configs/kubernetes.md b/docs/configs/kubernetes.md index 06685f3a..29ab6b38 100644 --- a/docs/configs/kubernetes.md +++ b/docs/configs/kubernetes.md @@ -100,6 +100,8 @@ If you are using multiple instances of homepage, an `instance` annotation can be If you have a single service that needs to be shown on multiple specific instances of homepage (but not on all of them), the service can be annotated by multiple `instance.name` annotations, where `name` can be the names of your specific multiple homepage instances. For example, a service that is annotated with `gethomepage.dev/instance.public: ""` and `gethomepage.dev/instance.internal: ""` will be shown on `public` and `internal` homepage instances. +Use the `gethomepage.dev/pod-selector` selector to specify the pod used for the health check. For example, a service that is annotated with `gethomepage.dev/pod-selector: app.kubernetes.io/name=deployment` would link to a pod with the label `app.kubernetes.io/name: deployment`. + ### Traefik IngressRoute support Homepage can also read ingresses defined using the Traefik IngressRoute custom resource definition. Due to the complex nature of Traefik routing rules, it is required for the `gethomepage.dev/href` annotation to be set: