From aac573a48d2536ded87d8c6abed75233adc4e215 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 16 Oct 2024 07:57:35 -0700 Subject: [PATCH 01/32] =?UTF-8?q?Enhancement:=20npm=20widget=20support=20?= =?UTF-8?q?=E2=89=A5=20v2.12=20(#4140)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/widgets/npm/component.jsx | 4 ++-- src/widgets/npm/proxy.js | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/widgets/npm/component.jsx b/src/widgets/npm/component.jsx index 06ac91ebe..e9f7e871f 100644 --- a/src/widgets/npm/component.jsx +++ b/src/widgets/npm/component.jsx @@ -21,8 +21,8 @@ export default function Component({ service }) { ); } - const enabled = infoData.filter((c) => c.enabled === 1).length; - const disabled = infoData.filter((c) => c.enabled === 0).length; + const enabled = infoData.filter((c) => !!c.enabled).length; + const disabled = infoData.filter((c) => !c.enabled).length; const total = infoData.length; return ( diff --git a/src/widgets/npm/proxy.js b/src/widgets/npm/proxy.js index 92a0140bf..3f1e34950 100644 --- a/src/widgets/npm/proxy.js +++ b/src/widgets/npm/proxy.js @@ -30,7 +30,7 @@ async function login(loginUrl, username, password, service) { cache.put(`${tokenCacheKey}.${service}`, data.token, expiration - 5 * 60 * 1000); // expiration -5 minutes } } catch (e) { - logger.error(`Error ${status} logging into npm`, authResponse[2]); + logger.error(`Error ${status} logging into npm`, JSON.stringify(authResponse[2])); } return [status, data.token ?? data]; } @@ -50,7 +50,6 @@ export default async function npmProxyHandler(req, res) { const loginUrl = `${widget.url}/api/tokens`; let status; - let contentType; let data; let token = cache.get(`${tokenCacheKey}.${service}`); @@ -62,7 +61,7 @@ export default async function npmProxyHandler(req, res) { } } - [status, contentType, data] = await httpProxy(url, { + [status, , data] = await httpProxy(url, { method: "GET", headers: { "Content-Type": "application/json", @@ -81,7 +80,7 @@ export default async function npmProxyHandler(req, res) { } // eslint-disable-next-line no-unused-vars - [status, contentType, data] = await httpProxy(url, { + [status, , data] = await httpProxy(url, { method: "GET", headers: { "Content-Type": "application/json", From c3476774022c4155b38ad62155fd63b1b06f2e9e Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 16 Oct 2024 16:04:26 -0700 Subject: [PATCH 02/32] Remove a random commented out line --- src/widgets/uptimekuma/widget.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/widgets/uptimekuma/widget.js b/src/widgets/uptimekuma/widget.js index 4f5ab6029..a81069d73 100644 --- a/src/widgets/uptimekuma/widget.js +++ b/src/widgets/uptimekuma/widget.js @@ -1,4 +1,3 @@ -// import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; import genericProxyHandler from "utils/proxy/handlers/generic"; const widget = { From 7cbba1ff9043c171db648d5b4b508db5f63ee97e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Sch=C3=A4ffer?= Date: Fri, 25 Oct 2024 11:07:35 +0200 Subject: [PATCH 03/32] Fix: remove deprecated meta tag (#4191) --- src/pages/_document.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/_document.jsx b/src/pages/_document.jsx index 64dd73064..bfe3fc933 100644 --- a/src/pages/_document.jsx +++ b/src/pages/_document.jsx @@ -8,7 +8,7 @@ export default function Document() { name="description" content="A highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations." /> - + From bf2efce74d4218025646975bb1a19c9589b77654 Mon Sep 17 00:00:00 2001 From: Mark <3046690+markp-mckinney@users.noreply.github.com> Date: Sat, 26 Oct 2024 20:24:46 -0700 Subject: [PATCH 04/32] Chore: filter Radarr movie response (#4199) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- src/widgets/radarr/widget.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/widgets/radarr/widget.js b/src/widgets/radarr/widget.js index 7ce412c6e..7d370378d 100644 --- a/src/widgets/radarr/widget.js +++ b/src/widgets/radarr/widget.js @@ -12,7 +12,10 @@ const widget = { wanted: jsonArrayFilter(data, (item) => item.monitored && !item.hasFile && item.isAvailable).length, have: jsonArrayFilter(data, (item) => item.hasFile).length, missing: jsonArrayFilter(data, (item) => item.monitored && !item.hasFile).length, - all: asJson(data), + all: asJson(data).map((entry) => ({ + title: entry.title, + id: entry.id, + })), }), }, "queue/status": { From e9a31bafab42c92757866e73a40c5849232b7c51 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 27 Oct 2024 20:16:32 -0700 Subject: [PATCH 05/32] Update PR guidelines --- docs/widgets/authoring/getting-started.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/widgets/authoring/getting-started.md b/docs/widgets/authoring/getting-started.md index a01b2eee0..4b9126ea7 100644 --- a/docs/widgets/authoring/getting-started.md +++ b/docs/widgets/authoring/getting-started.md @@ -48,15 +48,14 @@ self-hosted / open-source alternative, we ask that any widgets, etc. are develop ## New Feature Guidelines -- New features should be linked to an existing feature request with at least 10 'up-votes'. The purpose of this requirement is to avoid the addition (and maintenance) of features that might only benefit a small number of users. -- If you have ideas for a larger feature, please open a discussion first. -- Please note that though it is a requirement, a discussion with 10 'up-votes' in no way guarantees that a PR will be merged. +- New features should usually be linked to an existing feature request. The purpose of this requirement is to avoid the addition (and maintenance) of features that might only benefit a small number of users. +- If you have ideas for a larger feature you may want to open a discussion first. ## Service Widget Guidelines To ensure cohesiveness of various widgets, the following should be used as a guide for developing new widgets: -- Please only submit widgets that have been requested and have at least 10 'up-votes'. The purpose of this requirement is to avoid the addition (and maintenance) of service widgets that might only benefit a small number of users. +- Please only submit widgets that target a feature request discussion with at least 10 'up-votes'. The purpose of this requirement is to avoid the addition (and maintenance) of service widgets that might only benefit a small number of users. - Note that we reserve the right to decline widgets for projects that are very young (eg < ~1y) or those with a small reach (eg low GitHub stars). Again, this is in an effort to keep overall widget maintenance under control. - Widgets should be only one row of blocks - Widgets should be no more than 4 blocks wide and generally conform to the styling / design choices of other widgets From 2a6debbc79cd496b654611a948173e585def2dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Jasi=C5=84ski?= Date: Mon, 28 Oct 2024 15:58:24 +0100 Subject: [PATCH 06/32] Documentation: Typo in LubeLogger widget documentation (#4205) --- docs/widgets/services/lubelogger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/widgets/services/lubelogger.md b/docs/widgets/services/lubelogger.md index baa0e4d59..cf2b64396 100644 --- a/docs/widgets/services/lubelogger.md +++ b/docs/widgets/services/lubelogger.md @@ -8,7 +8,7 @@ Learn more about [LubeLogger](https://github.com/hargata/lubelog) (v1.3.7 or hig The widget comes in two 'flavors', one shows data for all vehicles or for just a specific vehicle with the `vehicleID` parameter. Allowed fields: `["vehicles", "serviceRecords", "reminders"]`. -For the single-vehicle version: `["vehicle", "serviceRecords", "reminders", "nextReminder"] +For the single-vehicle version: `["vehicle", "serviceRecords", "reminders", "nextReminder"]`. ```yaml widget: From 261c907f524e7c9280a70b813d038ad7f6fc9fd8 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:27:11 -0700 Subject: [PATCH 07/32] Documentation: add correct pihole v6 password info --- docs/widgets/services/pihole.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/widgets/services/pihole.md b/docs/widgets/services/pihole.md index c8ab83ae7..d77b2dfc7 100644 --- a/docs/widgets/services/pihole.md +++ b/docs/widgets/services/pihole.md @@ -14,5 +14,5 @@ widget: type: pihole url: http://pi.hole.or.ip version: 6 # required if running v6 or higher, defaults to 5 - key: yourpiholeapikey # optional + key: yourpiholeapikey # optional, in v6 can be your password or app password ``` From 0aea6a6c3ffdc93ca6414e0b84b99ff31ce6f00d Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:37:18 -0700 Subject: [PATCH 08/32] Fix: pyload widget - encode proxy params (#4210) --- src/widgets/pyload/proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/pyload/proxy.js b/src/widgets/pyload/proxy.js index 9cdd52310..d9469d1cb 100644 --- a/src/widgets/pyload/proxy.js +++ b/src/widgets/pyload/proxy.js @@ -15,7 +15,7 @@ async function fetchFromPyloadAPI(url, sessionId, params, service) { const options = { body: params ? Object.keys(params) - .map((prop) => `${prop}=${params[prop]}`) + .map((prop) => `${prop}=${encodeURIComponent(params[prop])}`) .join("&") : `session=${sessionId}`, method: "POST", From 3af86ffebb7e9942fe6b1551ab9bb9b443959fea Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Wed, 30 Oct 2024 00:17:09 -0400 Subject: [PATCH 09/32] Fix: text overflowing in bookmarks (#4217) Co-Authored-By: shamoon <4887959+shamoon@users.noreply.github.com> --- src/components/bookmarks/group.jsx | 2 +- src/components/bookmarks/item.jsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/bookmarks/group.jsx b/src/components/bookmarks/group.jsx index b13aeac12..3a9f8323a 100644 --- a/src/components/bookmarks/group.jsx +++ b/src/components/bookmarks/group.jsx @@ -20,7 +20,7 @@ export default function BookmarksGroup({ bookmarks, layout, disableCollapse, gro className={classNames( "bookmark-group", layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/4 lg:basis-1/5 xl:basis-1/6", - layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1", + layout?.header === false ? "flex-1 px-1 -my-1 overflow-hidden" : "flex-1 p-1 overflow-hidden", )} > diff --git a/src/components/bookmarks/item.jsx b/src/components/bookmarks/item.jsx index dcfcd43fd..690970890 100644 --- a/src/components/bookmarks/item.jsx +++ b/src/components/bookmarks/item.jsx @@ -29,9 +29,9 @@ export default function Item({ bookmark }) { )} {!bookmark.icon && bookmark.abbr} -
-
{bookmark.name}
-
+
+
{bookmark.name}
+
{description}
From 3736c1fcababba4ccb43e2c02aba1523d52b70a9 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:20:08 -0700 Subject: [PATCH 10/32] Fix: use same unit default for openmeteo widget and api (#4227) --- src/pages/api/widgets/openmeteo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/api/widgets/openmeteo.js b/src/pages/api/widgets/openmeteo.js index b34938b15..e63847b43 100644 --- a/src/pages/api/widgets/openmeteo.js +++ b/src/pages/api/widgets/openmeteo.js @@ -2,7 +2,7 @@ import cachedFetch from "utils/proxy/cached-fetch"; export default async function handler(req, res) { const { latitude, longitude, units, cache, timezone } = req.query; - const degrees = units === "imperial" ? "fahrenheit" : "celsius"; + const degrees = units === "metric" ? "celsius" : "fahrenheit"; const timezeone = timezone ?? "auto"; const apiUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=sunrise,sunset¤t_weather=true&temperature_unit=${degrees}&timezone=${timezeone}`; return res.send(await cachedFetch(apiUrl, cache)); From e6cf86ed4a06a48bfb34d7c0217325395f754bad Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Thu, 31 Oct 2024 22:09:23 -0700 Subject: [PATCH 11/32] Enhancement: use duration for audiobookshelf tottal, refactor uptime (#4229) --- docs/widgets/authoring/translations.md | 2 +- next-i18next.config.js | 14 +++++++------- public/locales/en/common.json | 2 +- src/components/widgets/resources/uptime.jsx | 2 +- src/widgets/audiobookshelf/component.jsx | 7 ++----- src/widgets/frigate/component.jsx | 2 +- src/widgets/fritzbox/component.jsx | 2 +- src/widgets/openwrt/methods/system.jsx | 2 +- src/widgets/stash/component.jsx | 4 ++-- src/widgets/truenas/component.jsx | 2 +- src/widgets/uptimerobot/component.jsx | 4 ++-- 11 files changed, 20 insertions(+), 23 deletions(-) diff --git a/docs/widgets/authoring/translations.md b/docs/widgets/authoring/translations.md index 13473f05b..77ad07038 100644 --- a/docs/widgets/authoring/translations.md +++ b/docs/widgets/authoring/translations.md @@ -71,7 +71,7 @@ Homepage provides a set of common translations that you can use in your widgets. | `common.ms` | `1,000 ms` | Format a number in milliseconds. | | `common.date` | `2024-01-01` | Format a date. | | `common.relativeDate` | `1 day ago` | Format a relative date. | -| `common.uptime` | `1 day, 1 hour` | Format an uptime. | +| `common.duration` | `1 day, 1 hour` | Format an duration. | ### Text diff --git a/next-i18next.config.js b/next-i18next.config.js index 96483cc3f..a1b5c7b3f 100644 --- a/next-i18next.config.js +++ b/next-i18next.config.js @@ -84,12 +84,12 @@ function prettyBytes(number, options) { return `${prefix + numberString} ${unit}`; } -function uptime(uptimeInSeconds, i18next) { - const mo = Math.floor(uptimeInSeconds / (3600 * 24 * 31)); - const d = Math.floor((uptimeInSeconds % (3600 * 24 * 31)) / (3600 * 24)); - const h = Math.floor((uptimeInSeconds % (3600 * 24)) / 3600); - const m = Math.floor((uptimeInSeconds % 3600) / 60); - const s = Math.floor(uptimeInSeconds % 60); +function duration(durationInSeconds, i18next) { + const mo = Math.floor(durationInSeconds / (3600 * 24 * 31)); + const d = Math.floor((durationInSeconds % (3600 * 24 * 31)) / (3600 * 24)); + const h = Math.floor((durationInSeconds % (3600 * 24)) / 3600); + const m = Math.floor((durationInSeconds % 3600) / 60); + const s = Math.floor(durationInSeconds % 60); const moDisplay = mo > 0 ? mo + i18next.t("common.months") : ""; const dDisplay = d > 0 ? d + i18next.t("common.days") : ""; @@ -156,7 +156,7 @@ module.exports = { i18next.services.formatter.add("relativeDate", (value, lng, options) => relativeDate(new Date(value), new Intl.RelativeTimeFormat(lng, { ...options })), ); - i18next.services.formatter.add("uptime", (value, lng) => uptime(value, i18next)); + i18next.services.formatter.add("duration", (value, lng) => duration(value, i18next)); }, type: "3rdParty", }, diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 384f44bef..fd52aef4a 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -13,7 +13,7 @@ "ms": "{{value, number}}", "date": "{{value, date}}", "relativeDate": "{{value, relativeDate}}", - "uptime": "{{value, uptime}}", + "duration": "{{value, duration}}", "months": "mo", "days": "d", "hours": "h", diff --git a/src/components/widgets/resources/uptime.jsx b/src/components/widgets/resources/uptime.jsx index 025d1aa53..2fac0fcdf 100644 --- a/src/components/widgets/resources/uptime.jsx +++ b/src/components/widgets/resources/uptime.jsx @@ -25,7 +25,7 @@ export default function Uptime({ refresh = 1500 }) { return ( diff --git a/src/widgets/audiobookshelf/component.jsx b/src/widgets/audiobookshelf/component.jsx index 406a81c28..6eb786381 100755 --- a/src/widgets/audiobookshelf/component.jsx +++ b/src/widgets/audiobookshelf/component.jsx @@ -39,11 +39,8 @@ export default function Component({ service }) { diff --git a/src/widgets/frigate/component.jsx b/src/widgets/frigate/component.jsx index 43b566e8e..ac77be51b 100644 --- a/src/widgets/frigate/component.jsx +++ b/src/widgets/frigate/component.jsx @@ -40,7 +40,7 @@ export default function Component({ service }) { /> diff --git a/src/widgets/fritzbox/component.jsx b/src/widgets/fritzbox/component.jsx index 5939f9edc..c3ea1bf64 100644 --- a/src/widgets/fritzbox/component.jsx +++ b/src/widgets/fritzbox/component.jsx @@ -44,7 +44,7 @@ export default function Component({ service }) { return ( - + diff --git a/src/widgets/openwrt/methods/system.jsx b/src/widgets/openwrt/methods/system.jsx index 7be8aa29b..0a8146cc0 100644 --- a/src/widgets/openwrt/methods/system.jsx +++ b/src/widgets/openwrt/methods/system.jsx @@ -20,7 +20,7 @@ export default function Component({ service }) { return ( - + ); diff --git a/src/widgets/stash/component.jsx b/src/widgets/stash/component.jsx index 3d64c4902..b7c259a89 100644 --- a/src/widgets/stash/component.jsx +++ b/src/widgets/stash/component.jsx @@ -46,12 +46,12 @@ export default function Component({ service }) { - + - + - + {enablePools && diff --git a/src/widgets/uptimerobot/component.jsx b/src/widgets/uptimerobot/component.jsx index 274854019..b2027a6f1 100644 --- a/src/widgets/uptimerobot/component.jsx +++ b/src/widgets/uptimerobot/component.jsx @@ -58,7 +58,7 @@ export default function Component({ service }) { break; case 2: status = t("uptimerobot.up"); - uptime = t("common.uptime", { value: monitor.logs[0].duration }); + uptime = t("common.duration", { value: monitor.logs[0].duration }); logIndex = 1; break; case 8: @@ -73,7 +73,7 @@ export default function Component({ service }) { } const lastDown = new Date(monitor.logs[logIndex].datetime * 1000).toLocaleString(); - const downDuration = t("common.uptime", { value: monitor.logs[logIndex].duration }); + const downDuration = t("common.duration", { value: monitor.logs[logIndex].duration }); const hideDown = logIndex === 1 && monitor.logs[logIndex].type !== 1; return ( From b7ca6244ddb0e0e01538a2e8f8136ce0a6ee3958 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 09:25:25 -0700 Subject: [PATCH 12/32] Chore(deps-dev): Bump tailwindcss from 3.4.13 to 3.4.14 (#4232) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- pnpm-lock.yaml | 23 ++++++++++++----------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 000b9b1a4..83c37bafe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "postcss": "^8.4.47", "prettier": "^3.2.5", "tailwind-scrollbar": "^3.0.5", - "tailwindcss": "^3.4.13", + "tailwindcss": "^3.4.14", "typescript": "^5.6.2" }, "optionalDependencies": { @@ -7713,9 +7713,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.13", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz", - "integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==", + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", "dev": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", diff --git a/package.json b/package.json index 6f6c09f28..09edba3d8 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "postcss": "^8.4.47", "prettier": "^3.2.5", "tailwind-scrollbar": "^3.0.5", - "tailwindcss": "^3.4.13", + "tailwindcss": "^3.4.14", "typescript": "^5.6.2" }, "optionalDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3eed63f82..9587852c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,7 +108,7 @@ importers: devDependencies: '@tailwindcss/forms': specifier: ^0.5.8 - version: 0.5.9(tailwindcss@3.4.13) + version: 0.5.9(tailwindcss@3.4.14) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.47) @@ -147,10 +147,10 @@ importers: version: 3.3.3 tailwind-scrollbar: specifier: ^3.0.5 - version: 3.1.0(tailwindcss@3.4.13) + version: 3.1.0(tailwindcss@3.4.14) tailwindcss: - specifier: ^3.4.13 - version: 3.4.13 + specifier: ^3.4.14 + version: 3.4.14 typescript: specifier: ^5.6.2 version: 5.6.2 @@ -1151,6 +1151,7 @@ packages: eslint@8.57.1: resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@9.6.1: @@ -2510,8 +2511,8 @@ packages: peerDependencies: tailwindcss: 3.x - tailwindcss@3.4.13: - resolution: {integrity: sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==} + tailwindcss@3.4.14: + resolution: {integrity: sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==} engines: {node: '>=14.0.0'} hasBin: true @@ -2956,10 +2957,10 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tailwindcss/forms@0.5.9(tailwindcss@3.4.13)': + '@tailwindcss/forms@0.5.9(tailwindcss@3.4.14)': dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.4.13 + tailwindcss: 3.4.14 '@tanstack/react-virtual@3.10.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -5355,11 +5356,11 @@ snapshots: systeminformation@5.23.5: {} - tailwind-scrollbar@3.1.0(tailwindcss@3.4.13): + tailwind-scrollbar@3.1.0(tailwindcss@3.4.14): dependencies: - tailwindcss: 3.4.13 + tailwindcss: 3.4.14 - tailwindcss@3.4.13: + tailwindcss@3.4.14: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 From be4da9d010d588d80eceaca43ff474e1eed64319 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 09:25:47 -0700 Subject: [PATCH 13/32] Chore(deps): Bump urbackup-server-api from 0.52.0 to 0.52.1 (#4233) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 9 ++++----- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 83c37bafe..089bb5643 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "swr": "^1.3.0", "systeminformation": "^5.23.2", "tough-cookie": "^4.1.3", - "urbackup-server-api": "^0.52.0", + "urbackup-server-api": "^0.52.1", "winston": "^3.11.0", "xml-js": "^1.6.11" }, @@ -8186,10 +8186,9 @@ } }, "node_modules/urbackup-server-api": { - "version": "0.52.0", - "resolved": "https://registry.npmjs.org/urbackup-server-api/-/urbackup-server-api-0.52.0.tgz", - "integrity": "sha512-KfroCFZEWCuCkWye1F1JwI2fkO1za/Mf1a8TNGTujzxU0ZGzDqhA1zCOcvV97q7nH1TKFNpw5tMZ06fSCKv2UA==", - "license": "MIT", + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/urbackup-server-api/-/urbackup-server-api-0.52.1.tgz", + "integrity": "sha512-gAxF9MdXxnceqUr/1Uj2LuGZQb/bvZ3Ply9zH/UTSWGkwKL5C0qMPrBvKRyTHbPMG/NBuHF6BzavkF7GNvOLew==", "dependencies": { "async-mutex": "^0.5.0", "node-fetch": "^2.7.0" diff --git a/package.json b/package.json index 09edba3d8..492c0ebab 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "swr": "^1.3.0", "systeminformation": "^5.23.2", "tough-cookie": "^4.1.3", - "urbackup-server-api": "^0.52.0", + "urbackup-server-api": "^0.52.1", "winston": "^3.11.0", "xml-js": "^1.6.11" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9587852c5..5b2bdb8a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -93,8 +93,8 @@ importers: specifier: ^4.1.3 version: 4.1.4 urbackup-server-api: - specifier: ^0.52.0 - version: 0.52.0 + specifier: ^0.52.1 + version: 0.52.1 winston: specifier: ^3.11.0 version: 3.14.2 @@ -2650,8 +2650,8 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - urbackup-server-api@0.52.0: - resolution: {integrity: sha512-KfroCFZEWCuCkWye1F1JwI2fkO1za/Mf1a8TNGTujzxU0ZGzDqhA1zCOcvV97q7nH1TKFNpw5tMZ06fSCKv2UA==} + urbackup-server-api@0.52.1: + resolution: {integrity: sha512-gAxF9MdXxnceqUr/1Uj2LuGZQb/bvZ3Ply9zH/UTSWGkwKL5C0qMPrBvKRyTHbPMG/NBuHF6BzavkF7GNvOLew==} uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -5537,7 +5537,7 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.0 - urbackup-server-api@0.52.0: + urbackup-server-api@0.52.1: dependencies: async-mutex: 0.5.0 node-fetch: 2.7.0 From bf0a7663028647a127758821a75e82132c5ae946 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 09:28:10 -0700 Subject: [PATCH 14/32] Chore(deps-dev): Bump typescript from 5.6.2 to 5.6.3 (#4234) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++-- package.json | 2 +- pnpm-lock.yaml | 98 +++++++++++++++++++++++------------------------ 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index 089bb5643..d776bec05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,7 +56,7 @@ "prettier": "^3.2.5", "tailwind-scrollbar": "^3.0.5", "tailwindcss": "^3.4.14", - "typescript": "^5.6.2" + "typescript": "^5.6.3" }, "optionalDependencies": { "osx-temperature-sensor": "^1.0.8" @@ -8102,9 +8102,9 @@ } }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 492c0ebab..d6cb010e9 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "prettier": "^3.2.5", "tailwind-scrollbar": "^3.0.5", "tailwindcss": "^3.4.14", - "typescript": "^5.6.2" + "typescript": "^5.6.3" }, "optionalDependencies": { "osx-temperature-sensor": "^1.0.8" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b2bdb8a6..cb94df4a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -117,16 +117,16 @@ importers: version: 8.57.1 eslint-config-airbnb: specifier: ^19.0.4 - version: 19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1) + version: 19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1) eslint-config-next: specifier: ^14.2.3 - version: 14.2.8(eslint@8.57.1)(typescript@5.6.2) + version: 14.2.8(eslint@8.57.1)(typescript@5.6.3) eslint-config-prettier: specifier: ^9.1.0 version: 9.1.0(eslint@8.57.1) eslint-plugin-import: specifier: ^2.29.1 - version: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + version: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: specifier: ^6.8.0 version: 6.10.0(eslint@8.57.1) @@ -152,8 +152,8 @@ importers: specifier: ^3.4.14 version: 3.4.14 typescript: - specifier: ^5.6.2 - version: 5.6.2 + specifier: ^5.6.3 + version: 5.6.3 packages: @@ -2625,8 +2625,8 @@ packages: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} - typescript@5.6.2: - resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true @@ -3016,13 +3016,13 @@ snapshots: '@types/triple-beam@1.3.5': {} - '@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2)': + '@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3) '@typescript-eslint/scope-manager': 7.2.0 - '@typescript-eslint/type-utils': 7.2.0(eslint@8.57.1)(typescript@5.6.2) - '@typescript-eslint/utils': 7.2.0(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/type-utils': 7.2.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/utils': 7.2.0(eslint@8.57.1)(typescript@5.6.3) '@typescript-eslint/visitor-keys': 7.2.0 debug: 4.3.6 eslint: 8.57.1 @@ -3030,22 +3030,22 @@ snapshots: ignore: 5.3.2 natural-compare: 1.4.0 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.6.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2)': + '@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 7.2.0 '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 7.2.0 debug: 4.3.6 eslint: 8.57.1 optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -3054,21 +3054,21 @@ snapshots: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/visitor-keys': 7.2.0 - '@typescript-eslint/type-utils@7.2.0(eslint@8.57.1)(typescript@5.6.2)': + '@typescript-eslint/type-utils@7.2.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.2) - '@typescript-eslint/utils': 7.2.0(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.3) + '@typescript-eslint/utils': 7.2.0(eslint@8.57.1)(typescript@5.6.3) debug: 4.3.6 eslint: 8.57.1 - ts-api-utils: 1.3.0(typescript@5.6.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@7.2.0': {} - '@typescript-eslint/typescript-estree@7.2.0(typescript@5.6.2)': + '@typescript-eslint/typescript-estree@7.2.0(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/visitor-keys': 7.2.0 @@ -3077,20 +3077,20 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.6.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.2.0(eslint@8.57.1)(typescript@5.6.2)': + '@typescript-eslint/utils@7.2.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 7.2.0 '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.3) eslint: 8.57.1 semver: 7.6.3 transitivePeerDependencies: @@ -3760,41 +3760,41 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1): + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: confusing-browser-globals: 1.0.11 eslint: 8.57.1 - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) object.assign: 4.1.5 object.entries: 1.1.8 semver: 6.3.1 - eslint-config-airbnb@19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1): + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) eslint-plugin-react: 7.37.1(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) object.assign: 4.1.5 object.entries: 1.1.8 - eslint-config-next@14.2.8(eslint@8.57.1)(typescript@5.6.2): + eslint-config-next@14.2.8(eslint@8.57.1)(typescript@5.6.3): dependencies: '@next/eslint-plugin-next': 14.2.8 '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/eslint-plugin': 7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2) - '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/eslint-plugin': 7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1) + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) eslint-plugin-react: 7.37.1(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - eslint-import-resolver-webpack - eslint-plugin-import-x @@ -3812,37 +3812,37 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.6 enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.0 is-bun-module: 1.1.0 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -3853,7 +3853,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -3864,7 +3864,7 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.2) + '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -5455,9 +5455,9 @@ snapshots: triple-beam@1.4.1: {} - ts-api-utils@1.3.0(typescript@5.6.2): + ts-api-utils@1.3.0(typescript@5.6.3): dependencies: - typescript: 5.6.2 + typescript: 5.6.3 ts-interface-checker@0.1.13: {} @@ -5516,7 +5516,7 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - typescript@5.6.2: {} + typescript@5.6.3: {} unbox-primitive@1.0.2: dependencies: From 6fd2b6b6dc990368bb83b8625fc66856e699a604 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 09:38:19 -0700 Subject: [PATCH 15/32] Chore(deps-dev): Bump eslint-plugin-import from 2.30.0 to 2.31.0 (#4236) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 21 +++++++------- package.json | 2 +- pnpm-lock.yaml | 73 ++++++++++++++++++++++++++++++++++------------- 3 files changed, 64 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index d776bec05..14b7d054a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "eslint-config-airbnb": "^19.0.4", "eslint-config-next": "^14.2.3", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.1", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.1", @@ -3135,11 +3135,10 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.9.0.tgz", - "integrity": "sha512-McVbYmwA3NEKwRQY5g4aWMdcZE5xZxV8i8l7CqJSrameuGSQJtSWaL/LxTEzSKKaCcOhlpDR8XEfYXWPrdo/ZQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -3163,11 +3162,10 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", - "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, - "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -3177,7 +3175,7 @@ "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.9.0", + "eslint-module-utils": "^2.12.0", "hasown": "^2.0.2", "is-core-module": "^2.15.1", "is-glob": "^4.0.3", @@ -3186,13 +3184,14 @@ "object.groupby": "^1.0.3", "object.values": "^1.2.0", "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "node_modules/eslint-plugin-import/node_modules/debug": { diff --git a/package.json b/package.json index d6cb010e9..8be8d3623 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "eslint-config-airbnb": "^19.0.4", "eslint-config-next": "^14.2.3", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.1", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb94df4a0..d73d36c6f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -117,7 +117,7 @@ importers: version: 8.57.1 eslint-config-airbnb: specifier: ^19.0.4 - version: 19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1) + version: 19.0.4(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1) eslint-config-next: specifier: ^14.2.3 version: 14.2.8(eslint@8.57.1)(typescript@5.6.3) @@ -125,8 +125,8 @@ importers: specifier: ^9.1.0 version: 9.1.0(eslint@8.57.1) eslint-plugin-import: - specifier: ^2.29.1 - version: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + specifier: ^2.31.0 + version: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: specifier: ^6.8.0 version: 6.10.0(eslint@8.57.1) @@ -1077,6 +1077,27 @@ packages: eslint-plugin-import-x: optional: true + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + eslint-module-utils@2.9.0: resolution: {integrity: sha512-McVbYmwA3NEKwRQY5g4aWMdcZE5xZxV8i8l7CqJSrameuGSQJtSWaL/LxTEzSKKaCcOhlpDR8XEfYXWPrdo/ZQ==} engines: {node: '>=4'} @@ -1098,12 +1119,12 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-plugin-import@2.30.0: - resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} + eslint-plugin-import@2.31.0: + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 peerDependenciesMeta: '@typescript-eslint/parser': optional: true @@ -3760,20 +3781,20 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1): + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: confusing-browser-globals: 1.0.11 eslint: 8.57.1 - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) object.assign: 4.1.5 object.entries: 1.1.8 semver: 6.3.1 - eslint-config-airbnb@19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1): + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) eslint-plugin-react: 7.37.1(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) @@ -3788,8 +3809,8 @@ snapshots: '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) eslint-plugin-react: 7.37.1(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) @@ -3812,37 +3833,48 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.6 enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.0 is-bun-module: 1.1.0 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3) + eslint: 8.57.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -3853,7 +3885,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -3862,6 +3894,7 @@ snapshots: object.groupby: 1.0.3 object.values: 1.2.0 semver: 6.3.1 + string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3) 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 16/32] 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, From 7c3dcf20ef00357c64d311d6426e29868fde37fc Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:11:01 -0800 Subject: [PATCH 17/32] Create reaction-comments.yml --- .github/workflows/reaction-comments.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/reaction-comments.yml diff --git a/.github/workflows/reaction-comments.yml b/.github/workflows/reaction-comments.yml new file mode 100644 index 000000000..f3a0e67d8 --- /dev/null +++ b/.github/workflows/reaction-comments.yml @@ -0,0 +1,20 @@ +name: 'Reaction Comments' + +on: + issue_comment: + types: [created, edited] + pull_request_review_comment: + types: [created, edited] + schedule: + - cron: '0 0 * * *' + +permissions: + actions: write + issues: write + pull-requests: write + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/reaction-comments@v4 From 912ae0adfc4fd5e78a05e91b8321aae70161ad6d Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 5 Nov 2024 12:39:41 -0800 Subject: [PATCH 18/32] Feature: Beszel service widget (#4251) --- docs/widgets/services/beszel.md | 20 ++++++ docs/widgets/services/index.md | 1 + mkdocs.yml | 1 + public/locales/en/common.json | 11 ++++ src/utils/config/service-helpers.js | 7 ++ src/widgets/beszel/component.jsx | 60 +++++++++++++++++ src/widgets/beszel/proxy.js | 99 +++++++++++++++++++++++++++++ src/widgets/beszel/widget.js | 14 ++++ src/widgets/components.js | 1 + src/widgets/widgets.js | 2 + 10 files changed, 216 insertions(+) create mode 100644 docs/widgets/services/beszel.md create mode 100644 src/widgets/beszel/component.jsx create mode 100644 src/widgets/beszel/proxy.js create mode 100644 src/widgets/beszel/widget.js diff --git a/docs/widgets/services/beszel.md b/docs/widgets/services/beszel.md new file mode 100644 index 000000000..3cc828b9d --- /dev/null +++ b/docs/widgets/services/beszel.md @@ -0,0 +1,20 @@ +--- +title: Beszel +description: Beszel Widget Configuration +--- + +Learn more about [Beszel]() + +The widget has two modes, a single system with detailed info if `systemId` is provided, or an overview of all systems if `systemId` is not provided. + +Allowed fields for 'overview' mode: `["systems", "up"]` +Allowed fields for a single system: `["name", "status", "updated", "cpu", "memory", "disk", "network"]` + +```yaml +widget: + type: beszel + url: http://beszel.host.or.ip + username: username # email + password: password + systemId: systemId # optional +``` diff --git a/docs/widgets/services/index.md b/docs/widgets/services/index.md index 3dee2a05d..83ad0fed0 100644 --- a/docs/widgets/services/index.md +++ b/docs/widgets/services/index.md @@ -14,6 +14,7 @@ You can also find a list of all available service widgets in the sidebar navigat - [Autobrr](autobrr.md) - [Azure DevOps](azuredevops.md) - [Bazarr](bazarr.md) +- [Beszel](beszel.md) - [Caddy](caddy.md) - [Calendar](calendar.md) - [Calibre-Web](calibre-web.md) diff --git a/mkdocs.yml b/mkdocs.yml index 94af034d7..cd4668920 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -37,6 +37,7 @@ nav: - widgets/services/autobrr.md - widgets/services/azuredevops.md - widgets/services/bazarr.md + - widgets/services/beszel.md - widgets/services/caddy.md - widgets/services/calendar.md - widgets/services/calibre-web.md diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 38ee3e857..bdde0a34b 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -967,5 +967,16 @@ "status": "Status", "online": "Online", "offline": "Offline" + }, + "beszel": { + "name": "Name", + "systems": "Systems", + "up": "Up", + "status": "Status", + "updated": "Updated", + "cpu": "CPU", + "memory": "MEM", + "disk": "Disk", + "network": "NET" } } diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 9d55ce43a..63dfb6082 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -368,6 +368,9 @@ export function cleanServiceGroups(groups) { repositoryId, userEmail, + // beszel + systemId, + // calendar firstDayInWeek, integrations, @@ -511,6 +514,10 @@ export function cleanServiceGroups(groups) { if (repositoryId) cleanedService.widget.repositoryId = repositoryId; } + if (type === "beszel") { + if (systemId) cleanedService.widget.systemId = systemId; + } + if (type === "coinmarketcap") { if (currency) cleanedService.widget.currency = currency; if (symbols) cleanedService.widget.symbols = symbols; diff --git a/src/widgets/beszel/component.jsx b/src/widgets/beszel/component.jsx new file mode 100644 index 000000000..1d35b6e94 --- /dev/null +++ b/src/widgets/beszel/component.jsx @@ -0,0 +1,60 @@ +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 { systemId } = widget; + + const { data: systems, error: systemsError } = useWidgetAPI(widget, "systems"); + + const MAX_ALLOWED_FIELDS = 4; + if (!widget.fields?.length > 0) { + widget.fields = systemId ? ["name", "status", "cpu", "memory"] : ["systems", "up"]; + } + if (widget.fields?.length > MAX_ALLOWED_FIELDS) { + widget.fields = widget.fields.slice(0, MAX_ALLOWED_FIELDS); + } + + if (systemsError) { + return ; + } + + if (!systems) { + return ( + + + + + ); + } + + if (systemId) { + const system = systems.items.find((item) => item.id === systemId); + + return ( + + + + + + + + + + ); + } + + const upTotal = systems.items.filter((item) => item.status === "up").length; + + return ( + + + + + ); +} diff --git a/src/widgets/beszel/proxy.js b/src/widgets/beszel/proxy.js new file mode 100644 index 000000000..5f70a10d2 --- /dev/null +++ b/src/widgets/beszel/proxy.js @@ -0,0 +1,99 @@ +import cache from "memory-cache"; + +import getServiceWidget from "utils/config/service-helpers"; +import { formatApiCall } from "utils/proxy/api-helpers"; +import { httpProxy } from "utils/proxy/http"; +import widgets from "widgets/widgets"; +import createLogger from "utils/logger"; + +const proxyName = "beszelProxyHandler"; +const tokenCacheKey = `${proxyName}__token`; +const logger = createLogger(proxyName); + +async function login(loginUrl, username, password, service) { + const authResponse = await httpProxy(loginUrl, { + method: "POST", + body: JSON.stringify({ identity: username, password }), + headers: { + "Content-Type": "application/json", + }, + }); + + const status = authResponse[0]; + let data = authResponse[2]; + try { + data = JSON.parse(Buffer.from(authResponse[2]).toString()); + + if (status === 200) { + cache.put(`${tokenCacheKey}.${service}`, data.token); + } + } catch (e) { + logger.error(`Error ${status} logging into beszel`, JSON.stringify(authResponse[2])); + } + return [status, data.token ?? data]; +} + +export default async function beszelProxyHandler(req, res) { + const { group, service, endpoint } = req.query; + + if (group && service) { + const widget = await getServiceWidget(group, service); + + if (!widgets?.[widget.type]?.api) { + return res.status(403).json({ error: "Service does not support API calls" }); + } + + if (widget) { + const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); + const loginUrl = formatApiCall(widgets[widget.type].api, { endpoint: "admins/auth-with-password", ...widget }); + + let status; + let data; + + let token = cache.get(`${tokenCacheKey}.${service}`); + if (!token) { + [status, token] = await login(loginUrl, widget.username, widget.password, service); + if (status !== 200) { + logger.debug(`HTTTP ${status} logging into npm api: ${token}`); + return res.status(status).send(token); + } + } + + [status, , data] = await httpProxy(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + if (status === 403) { + logger.debug(`HTTTP ${status} retrieving data from npm api, logging in and trying again.`); + cache.del(`${tokenCacheKey}.${service}`); + [status, token] = await login(loginUrl, widget.username, widget.password, service); + + if (status !== 200) { + logger.debug(`HTTTP ${status} logging into npm api: ${data}`); + return res.status(status).send(data); + } + + // eslint-disable-next-line no-unused-vars + [status, , data] = await httpProxy(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + } + + if (status !== 200) { + return res.status(status).send(data); + } + + return res.send(data); + } + } + + return res.status(400).json({ error: "Invalid proxy service type" }); +} diff --git a/src/widgets/beszel/widget.js b/src/widgets/beszel/widget.js new file mode 100644 index 000000000..508c1debb --- /dev/null +++ b/src/widgets/beszel/widget.js @@ -0,0 +1,14 @@ +import beszelProxyHandler from "./proxy"; + +const widget = { + api: "{url}/api/{endpoint}", + proxyHandler: beszelProxyHandler, + + mappings: { + systems: { + endpoint: "collections/systems/records?page=1&perPage=500&sort=%2Bcreated", + }, + }, +}; + +export default widget; diff --git a/src/widgets/components.js b/src/widgets/components.js index 8453e5275..50564e493 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -8,6 +8,7 @@ const components = { autobrr: dynamic(() => import("./autobrr/component")), azuredevops: dynamic(() => import("./azuredevops/component")), bazarr: dynamic(() => import("./bazarr/component")), + beszel: dynamic(() => import("./beszel/component")), caddy: dynamic(() => import("./caddy/component")), calendar: dynamic(() => import("./calendar/component")), calibreweb: dynamic(() => import("./calibreweb/component")), diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index a1af3661b..40b121aef 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -5,6 +5,7 @@ import authentik from "./authentik/widget"; import autobrr from "./autobrr/widget"; import azuredevops from "./azuredevops/widget"; import bazarr from "./bazarr/widget"; +import beszel from "./beszel/widget"; import caddy from "./caddy/widget"; import calendar from "./calendar/widget"; import calibreweb from "./calibreweb/widget"; @@ -133,6 +134,7 @@ const widgets = { autobrr, azuredevops, bazarr, + beszel, caddy, calibreweb, changedetectionio, From 794ec127cd2d27a35666f54f67cf3966893f32a6 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 6 Nov 2024 10:24:09 -0800 Subject: [PATCH 19/32] Enhancement: quicklaunch fill search suggestion on arrowright (#4256) --- src/components/quicklaunch.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/quicklaunch.jsx b/src/components/quicklaunch.jsx index f20890652..9f55f973c 100644 --- a/src/components/quicklaunch.jsx +++ b/src/components/quicklaunch.jsx @@ -98,6 +98,12 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea } else if (event.key === "ArrowUp" && currentItemIndex > 0) { setCurrentItemIndex(currentItemIndex - 1); event.preventDefault(); + } else if ( + event.key === "ArrowRight" && + results[currentItemIndex] && + results[currentItemIndex].type === "searchSuggestion" + ) { + setSearchString(results[currentItemIndex].name); } } From e938c3ac1e6933d78459b370b088948ad554331f Mon Sep 17 00:00:00 2001 From: Felix Cornelius <9767036+fcornelius@users.noreply.github.com> Date: Tue, 12 Nov 2024 01:42:14 +0100 Subject: [PATCH 20/32] Feature: Prometheus Metric service widget (#4269) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/widgets/services/index.md | 1 + docs/widgets/services/prometheusmetric.md | 67 ++++++++++++ mkdocs.yml | 1 + src/utils/config/service-helpers.js | 9 +- src/widgets/components.js | 1 + src/widgets/prometheusmetric/component.jsx | 115 +++++++++++++++++++++ src/widgets/prometheusmetric/widget.js | 16 +++ src/widgets/widgets.js | 2 + 8 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 docs/widgets/services/prometheusmetric.md create mode 100644 src/widgets/prometheusmetric/component.jsx create mode 100644 src/widgets/prometheusmetric/widget.js diff --git a/docs/widgets/services/index.md b/docs/widgets/services/index.md index 83ad0fed0..8ea2e9331 100644 --- a/docs/widgets/services/index.md +++ b/docs/widgets/services/index.md @@ -98,6 +98,7 @@ You can also find a list of all available service widgets in the sidebar navigat - [Plex](plex.md) - [Portainer](portainer.md) - [Prometheus](prometheus.md) +- [Prometheus Metric](prometheusmetric.md) - [Prowlarr](prowlarr.md) - [Proxmox](proxmox.md) - [Proxmox Backup Server](proxmoxbackupserver.md) diff --git a/docs/widgets/services/prometheusmetric.md b/docs/widgets/services/prometheusmetric.md new file mode 100644 index 000000000..19397aa7e --- /dev/null +++ b/docs/widgets/services/prometheusmetric.md @@ -0,0 +1,67 @@ +--- +title: Prometheus Metric +description: Prometheus Metric Widget Configuration +--- + +Learn more about [Querying Prometheus](https://prometheus.io/docs/prometheus/latest/querying/basics/). + +This widget can show metrics for your service defined by PromQL queries which are requested from a running Prometheus instance. + +Quries can be defined in the `metrics` array of the widget along with a label to be used to present the metric value. You can optionally specify a global `refreshInterval` in milliseconds and/or define the `refreshInterval` per metric. Inside the optional `format` object of a metric various formatting styles and transformations can be applied (see below). + +```yaml +widget: + type: prometheusmetric + url: https://prometheus.host.or.ip + refreshInterval: 10000 # optional - in milliseconds, defaults to 10s + metrics: + - label: Metric 1 + query: alertmanager_alerts{state="active"} + - label: Metric 2 + query: apiserver_storage_size_bytes{node="mynode"} + format: + type: bytes + - label: Metric 3 + query: avg(prometheus_notifications_latency_seconds) + format: + type: number + suffix: s + options: + maximumFractionDigits: 4 + - label: Metric 4 + query: time() + refreshInterval: 1000 # will override global refreshInterval + format: + type: date + scale: 1000 + options: + timeStyle: medium +``` + +## Formatting + +Supported values for `format.type` are `text`, `number`, `percent`, `bytes`, `bits`, `bbytes`, `bbits`, `byterate`, `bibyterate`, `bitrate`, `bibitrate`, `date`, `duration`, `relativeDate`, and `text` which is the default. + +The `dateStyle` and `timeStyle` options of the `date` format are passed directly to [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat) and the `style` and `numeric` options of `relativeDate` are passed to [Intl.RelativeTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat). For the `number` format, options of [Intl.NumberFormat](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat) can be used, e.g. `maximumFractionDigits` or `minimumFractionDigits`. + +### Data Transformation + +You can manipulate your metric value with the following tools: `scale`, `prefix` and `suffix`, for example: + +```yaml +- query: my_custom_metric{} + label: Metric 1 + format: + type: number + scale: 1000 # multiplies value by a number or fraction string e.g. 1/16 +- query: my_custom_metric{} + label: Metric 2 + format: + type: number + prefix: "$" # prefixes value with given string +- query: my_custom_metric{} + label: Metric 3 + format: + type: number + suffix: "€" # suffixes value with given string +``` diff --git a/mkdocs.yml b/mkdocs.yml index cd4668920..42abce301 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -121,6 +121,7 @@ nav: - widgets/services/plex.md - widgets/services/portainer.md - widgets/services/prometheus.md + - widgets/services/prometheusmetric.md - widgets/services/prowlarr.md - widgets/services/proxmox.md - widgets/services/proxmoxbackupserver.md diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 63dfb6082..1566a135b 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -418,7 +418,7 @@ export function cleanServiceGroups(groups) { pointsLimit, diskUnits, - // glances, customapi, iframe + // glances, customapi, iframe, prometheusmetric refreshInterval, // hdhomerun @@ -461,6 +461,9 @@ export function cleanServiceGroups(groups) { // opnsense, pfsense wan, + // prometheusmetric + metrics, + // proxmox node, @@ -646,6 +649,10 @@ export function cleanServiceGroups(groups) { if (type === "vikunja") { if (enableTaskList !== undefined) cleanedService.widget.enableTaskList = !!enableTaskList; } + if (type === "prometheusmetric") { + if (metrics) cleanedService.widget.metrics = metrics; + if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval; + } } return cleanedService; diff --git a/src/widgets/components.js b/src/widgets/components.js index 50564e493..7e6b68e14 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -95,6 +95,7 @@ const components = { plex: dynamic(() => import("./plex/component")), portainer: dynamic(() => import("./portainer/component")), prometheus: dynamic(() => import("./prometheus/component")), + prometheusmetric: dynamic(() => import("./prometheusmetric/component")), prowlarr: dynamic(() => import("./prowlarr/component")), proxmox: dynamic(() => import("./proxmox/component")), pterodactyl: dynamic(() => import("./pterodactyl/component")), diff --git a/src/widgets/prometheusmetric/component.jsx b/src/widgets/prometheusmetric/component.jsx new file mode 100644 index 000000000..347aaa0c2 --- /dev/null +++ b/src/widgets/prometheusmetric/component.jsx @@ -0,0 +1,115 @@ +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"; + +function formatValue(t, metric, rawValue) { + if (!rawValue) return "-"; + + let value = rawValue; + + // Scale the value. Accepts either a number to multiply by or a string + // like "12/345". + const scale = metric?.format?.scale; + if (typeof scale === "number") { + value *= scale; + } else if (typeof scale === "string" && scale.includes("/")) { + const parts = scale.split("/"); + const numerator = parts[0] ? parseFloat(parts[0]) : 1; + const denominator = parts[1] ? parseFloat(parts[1]) : 1; + value = (value * numerator) / denominator; + } else { + value = parseFloat(value); + } + + // Format the value using a known type and optional options. + switch (metric?.format?.type) { + case "text": + break; + default: + value = t(`common.${metric.format.type}`, { value, ...metric.format?.options }); + } + + // Apply fixed prefix. + const prefix = metric?.format?.prefix; + if (prefix) { + value = `${prefix}${value}`; + } + + // Apply fixed suffix. + const suffix = metric?.format?.suffix; + if (suffix) { + value = `${value}${suffix}`; + } + + return value; +} + +export default function Component({ service }) { + const { t } = useTranslation(); + + const { widget } = service; + + const { metrics = [], refreshInterval = 10000 } = widget; + + let prometheusmetricError; + + const prometheusmetricData = new Map( + metrics.slice(0, 4).map((metric) => { + // disable the rule that hooks should not be called from a callback, + // because we don't need a strong guarantee of hook execution order here. + // eslint-disable-next-line react-hooks/rules-of-hooks + const { data: resultData, error: resultError } = useWidgetAPI(widget, "query", { + query: metric.query, + refreshInterval: Math.max(1000, metric.refreshInterval ?? refreshInterval), + }); + if (resultError) { + prometheusmetricError = resultError; + } + return [metric.key ?? metric.label, resultData]; + }), + ); + + if (prometheusmetricError) { + return ; + } + + if (!prometheusmetricData) { + return ( + + {metrics.slice(0, 4).map((item) => ( + + ))} + + ); + } + + function getResultValue(data) { + // Fetches the first metric result from the Prometheus query result data. + // The first element in the result value is the timestamp which is ignored here. + const resultType = data?.data?.resultType; + const result = data?.data?.result; + + switch (resultType) { + case "vector": + return result?.[0]?.value?.[1]; + case "scalar": + return result?.[1]; + default: + return ""; + } + } + + return ( + + {metrics.map((metric) => ( + + ))} + + ); +} diff --git a/src/widgets/prometheusmetric/widget.js b/src/widgets/prometheusmetric/widget.js new file mode 100644 index 000000000..22137b0d7 --- /dev/null +++ b/src/widgets/prometheusmetric/widget.js @@ -0,0 +1,16 @@ +import genericProxyHandler from "utils/proxy/handlers/generic"; + +const widget = { + api: "{url}/api/v1/{endpoint}", + proxyHandler: genericProxyHandler, + + mappings: { + query: { + method: "GET", + endpoint: "query", + params: ["query"], + }, + }, +}; + +export default widget; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index 40b121aef..4d76fa070 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -87,6 +87,7 @@ import plantit from "./plantit/widget"; import plex from "./plex/widget"; import portainer from "./portainer/widget"; import prometheus from "./prometheus/widget"; +import prometheusmetric from "./prometheusmetric/widget"; import prowlarr from "./prowlarr/widget"; import proxmox from "./proxmox/widget"; import pterodactyl from "./pterodactyl/widget"; @@ -218,6 +219,7 @@ const widgets = { plex, portainer, prometheus, + prometheusmetric, prowlarr, proxmox, pterodactyl, From 1a22065c3a08b0b1bd0e807aeb3f0040fe618f49 Mon Sep 17 00:00:00 2001 From: John <34685272+Johnomated@users.noreply.github.com> Date: Mon, 11 Nov 2024 19:15:26 -0600 Subject: [PATCH 21/32] Fix: use session_key instead of Id in tautulli component to resolve unique key warning (#4278) --- src/widgets/tautulli/component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/tautulli/component.jsx b/src/widgets/tautulli/component.jsx index b540c6d70..ba94f1439 100644 --- a/src/widgets/tautulli/component.jsx +++ b/src/widgets/tautulli/component.jsx @@ -205,7 +205,7 @@ export default function Component({ service }) {
{playing.map((session) => ( Date: Tue, 12 Nov 2024 01:52:51 +0000 Subject: [PATCH 22/32] Feature: suwayomi Service Widget (#4273) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/widgets/services/suwayomi.md | 20 ++++ public/locales/en/common.json | 10 ++ src/widgets/components.js | 1 + src/widgets/suwayomi/component.jsx | 40 +++++++ src/widgets/suwayomi/proxy.js | 175 +++++++++++++++++++++++++++++ src/widgets/suwayomi/widget.js | 8 ++ src/widgets/widgets.js | 2 + 7 files changed, 256 insertions(+) create mode 100644 docs/widgets/services/suwayomi.md create mode 100644 src/widgets/suwayomi/component.jsx create mode 100644 src/widgets/suwayomi/proxy.js create mode 100644 src/widgets/suwayomi/widget.js diff --git a/docs/widgets/services/suwayomi.md b/docs/widgets/services/suwayomi.md new file mode 100644 index 000000000..216725981 --- /dev/null +++ b/docs/widgets/services/suwayomi.md @@ -0,0 +1,20 @@ +--- +title: Suwayomi +description: Suwayomi Widget Configuration +--- + +Learn more about [Suwayomi](https://github.com/Suwayomi/Suwayomi-Server). + +Allowed fields: ["download", "nondownload", "read", "unread", "downloadedread", "downloadedunread", "nondownloadedread", "nondownloadedunread"] + +The widget defaults to the first four above. If more than four fields are provided, only the first 4 are displayed. +Category IDs can be obtained from the url when navigating to it, `?tab={categoryID}`. + +```yaml +widget: + type: suwayomi + url: http://suwayomi.host.or.ip + username: username #optional + password: password #optional + category: 0 #optional, defaults to all categories +``` diff --git a/public/locales/en/common.json b/public/locales/en/common.json index bdde0a34b..81576984e 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -309,6 +309,16 @@ "stopped": "Stopped", "total": "Total" }, + "suwayomi": { + "download": "Downloaded", + "nondownload": "Non-Downloaded", + "read": "Read", + "unread": "Unread", + "downloadedread": "Downloaded & Read", + "downloadedunread": "Downloaded & Unread", + "nondownloadedread": "Non-Downloaded & Read", + "nondownloadedunread": "Non-Downloaded & Unread" + }, "tailscale": { "address": "Address", "expires": "Expires", diff --git a/src/widgets/components.js b/src/widgets/components.js index 7e6b68e14..3cba84d2d 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -114,6 +114,7 @@ const components = { stocks: dynamic(() => import("./stocks/component")), strelaysrv: dynamic(() => import("./strelaysrv/component")), swagdashboard: dynamic(() => import("./swagdashboard/component")), + suwayomi: dynamic(() => import("./suwayomi/component")), tailscale: dynamic(() => import("./tailscale/component")), tandoor: dynamic(() => import("./tandoor/component")), tautulli: dynamic(() => import("./tautulli/component")), diff --git a/src/widgets/suwayomi/component.jsx b/src/widgets/suwayomi/component.jsx new file mode 100644 index 000000000..b7c34820f --- /dev/null +++ b/src/widgets/suwayomi/component.jsx @@ -0,0 +1,40 @@ +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: suwayomiData, error: suwayomiError } = useWidgetAPI(widget); + + if (suwayomiError) { + return ; + } + + if (!suwayomiData) { + if (!widget.fields || widget.fields.length === 0) { + widget.fields = ["download", "nondownload", "read", "unread"]; + } else if (widget.fields.length > 4) { + widget.fields = widget.fields.slice(0, 4); + } + return ( + + {widget.fields.map((field) => ( + + ))} + + ); + } + + return ( + + {suwayomiData.map((data) => ( + + ))} + + ); +} diff --git a/src/widgets/suwayomi/proxy.js b/src/widgets/suwayomi/proxy.js new file mode 100644 index 000000000..d4d716752 --- /dev/null +++ b/src/widgets/suwayomi/proxy.js @@ -0,0 +1,175 @@ +import { httpProxy } from "utils/proxy/http"; +import { formatApiCall } from "utils/proxy/api-helpers"; +import getServiceWidget from "utils/config/service-helpers"; +import createLogger from "utils/logger"; +import widgets from "widgets/widgets"; + +const proxyName = "suwayomiProxyHandler"; +const logger = createLogger(proxyName); + +const countsToExtract = { + download: { + condition: (c) => c.isDownloaded, + gqlCondition: "isDownloaded: true", + }, + nondownload: { + condition: (c) => !c.isDownloaded, + gqlCondition: "isDownloaded: false", + }, + read: { + condition: (c) => c.isRead, + gqlCondition: "isRead: true", + }, + unread: { + condition: (c) => !c.isRead, + gqlCondition: "isRead: false", + }, + downloadedread: { + condition: (c) => c.isDownloaded && c.isRead, + gqlCondition: "isDownloaded: true, isRead: true", + }, + downloadedunread: { + condition: (c) => c.isDownloaded && !c.isRead, + gqlCondition: "isDownloaded: true, isRead: false", + }, + nondownloadedread: { + condition: (c) => !c.isDownloaded && c.isRead, + gqlCondition: "isDownloaded: false, isRead: true", + }, + nondownloadedunread: { + condition: (c) => !c.isDownloaded && !c.isRead, + gqlCondition: "isDownloaded: false, isRead: false", + }, +}; + +function makeBody(fields, category = "all") { + if (Number.isNaN(Number(category))) { + let query = ""; + fields.forEach((field) => { + query += ` + ${field}: chapters( + condition: {${countsToExtract[field].gqlCondition}} + filter: {inLibrary: {equalTo: true}} + ) { + totalCount + }`; + }); + return JSON.stringify({ + operationName: "Counts", + query: ` + query Counts { + ${query} + }`, + }); + } + + return JSON.stringify({ + operationName: "category", + query: ` + query category($id: Int!) { + category(id: $id) { + # name + mangas { + nodes { + chapters { + nodes { + isRead + isDownloaded + } + } + } + } + } + }`, + variables: { + id: Number(category), + }, + }); +} + +function extractCounts(responseJSON, fields) { + if (!("category" in responseJSON.data)) { + return fields.map((field) => ({ + count: responseJSON.data[field].totalCount, + label: `suwayomi.${field}`, + })); + } + const tmp = responseJSON.data.category.mangas.nodes.reduce( + (accumulator, manga) => { + manga.chapters.nodes.forEach((chapter) => { + fields.forEach((field, i) => { + if (countsToExtract[field].condition(chapter)) { + accumulator[i] += 1; + } + }); + }); + return accumulator; + }, + [0, 0, 0, 0], + ); + return fields.map((field, i) => ({ + count: tmp[i], + label: `suwayomi.${field}`, + })); +} + +export default async function suwayomiProxyHandler(req, res) { + const { group, service, endpoint } = req.query; + + if (!group || !service) { + logger.debug("Invalid or missing service '%s' or group '%s'", service, group); + return res.status(400).json({ error: "Invalid proxy service type" }); + } + + const widget = await getServiceWidget(group, service); + + if (!widget) { + logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); + return res.status(400).json({ error: "Invalid proxy service type" }); + } + + if (!widget.fields || widget.fields.length === 0) { + widget.fields = ["download", "nondownload", "read", "unread"]; + } else if (widget.fields.length > 4) { + widget.fields = widget.fields.slice(0, 4); + } + + const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); + + const body = makeBody(widget.fields, widget.category); + + const headers = { + "Content-Type": "application/json", + }; + + if (widget.username && widget.password) { + headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`; + } + + const [status, contentType, data] = await httpProxy(url, { + method: "POST", + body, + headers, + }); + + if (status === 401) { + logger.error("Invalid or missing username or password for service '%s' in group '%s'", service, group); + return res.status(status).send({ error: { message: "401: unauthorized, username or password is incorrect." } }); + } + + if (status !== 200) { + logger.error( + "Error getting data from Suwayomi for service '%s' in group '%s': %d. Data: %s", + service, + group, + status, + data, + ); + return res.status(status).send({ error: { message: "Error getting data. body: %s, data: %s", body, data } }); + } + + const returnData = extractCounts(JSON.parse(data), widget.fields); + + if (contentType) res.setHeader("Content-Type", contentType); + return res.status(status).send(returnData); +} diff --git a/src/widgets/suwayomi/widget.js b/src/widgets/suwayomi/widget.js new file mode 100644 index 000000000..e2ed509c6 --- /dev/null +++ b/src/widgets/suwayomi/widget.js @@ -0,0 +1,8 @@ +import suwayomiProxyHandler from "./proxy"; + +const widget = { + api: "{url}/api/graphql", + proxyHandler: suwayomiProxyHandler, +}; + +export default widget; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index 4d76fa070..791103789 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -105,6 +105,7 @@ import stash from "./stash/widget"; import stocks from "./stocks/widget"; import strelaysrv from "./strelaysrv/widget"; import swagdashboard from "./swagdashboard/widget"; +import suwayomi from "./suwayomi/widget"; import tailscale from "./tailscale/widget"; import tandoor from "./tandoor/widget"; import tautulli from "./tautulli/widget"; @@ -238,6 +239,7 @@ const widgets = { stocks, strelaysrv, swagdashboard, + suwayomi, tailscale, tandoor, tautulli, From d87d347aa3d95abf1e24eb9691e34da1243af508 Mon Sep 17 00:00:00 2001 From: Abey Thomas Date: Tue, 12 Nov 2024 06:19:04 -0800 Subject: [PATCH 23/32] Documentation: corrections Beszel widget docs (#4282) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/widgets/services/beszel.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/widgets/services/beszel.md b/docs/widgets/services/beszel.md index 3cc828b9d..6a5cc2691 100644 --- a/docs/widgets/services/beszel.md +++ b/docs/widgets/services/beszel.md @@ -3,10 +3,12 @@ title: Beszel description: Beszel Widget Configuration --- -Learn more about [Beszel]() +Learn more about [Beszel](https://github.com/henrygd/beszel) The widget has two modes, a single system with detailed info if `systemId` is provided, or an overview of all systems if `systemId` is not provided. +The `systemID` in the `id` field on the collections page of Beszel. + Allowed fields for 'overview' mode: `["systems", "up"]` Allowed fields for a single system: `["name", "status", "updated", "cpu", "memory", "disk", "network"]` From 535be37befafc5d9e3636d60492a7efc241981eb Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:31:36 -0800 Subject: [PATCH 24/32] Fix: fix some instances of HTTTP --- src/widgets/beszel/proxy.js | 6 +++--- src/widgets/calendar/proxy.js | 2 +- src/widgets/npm/proxy.js | 6 +++--- src/widgets/omada/proxy.js | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/widgets/beszel/proxy.js b/src/widgets/beszel/proxy.js index 5f70a10d2..04083e420 100644 --- a/src/widgets/beszel/proxy.js +++ b/src/widgets/beszel/proxy.js @@ -54,7 +54,7 @@ export default async function beszelProxyHandler(req, res) { if (!token) { [status, token] = await login(loginUrl, widget.username, widget.password, service); if (status !== 200) { - logger.debug(`HTTTP ${status} logging into npm api: ${token}`); + logger.debug(`HTTP ${status} logging into npm api: ${token}`); return res.status(status).send(token); } } @@ -68,12 +68,12 @@ export default async function beszelProxyHandler(req, res) { }); if (status === 403) { - logger.debug(`HTTTP ${status} retrieving data from npm api, logging in and trying again.`); + logger.debug(`HTTP ${status} retrieving data from npm api, logging in and trying again.`); cache.del(`${tokenCacheKey}.${service}`); [status, token] = await login(loginUrl, widget.username, widget.password, service); if (status !== 200) { - logger.debug(`HTTTP ${status} logging into npm api: ${data}`); + logger.debug(`HTTP ${status} logging into npm api: ${data}`); return res.status(status).send(data); } diff --git a/src/widgets/calendar/proxy.js b/src/widgets/calendar/proxy.js index 996ea3241..cf754424f 100644 --- a/src/widgets/calendar/proxy.js +++ b/src/widgets/calendar/proxy.js @@ -21,7 +21,7 @@ export default async function calendarProxyHandler(req, res) { if (contentType) res.setHeader("Content-Type", contentType); if (status !== 200) { - logger.debug(`HTTTP ${status} retrieving data from integration URL ${integration.url} : ${data}`); + logger.debug(`HTTP ${status} retrieving data from integration URL ${integration.url} : ${data}`); return res.status(status).send(data); } diff --git a/src/widgets/npm/proxy.js b/src/widgets/npm/proxy.js index 3f1e34950..978254f81 100644 --- a/src/widgets/npm/proxy.js +++ b/src/widgets/npm/proxy.js @@ -56,7 +56,7 @@ export default async function npmProxyHandler(req, res) { if (!token) { [status, token] = await login(loginUrl, widget.username, widget.password, service); if (status !== 200) { - logger.debug(`HTTTP ${status} logging into npm api: ${token}`); + logger.debug(`HTTP ${status} logging into npm api: ${token}`); return res.status(status).send(token); } } @@ -70,12 +70,12 @@ export default async function npmProxyHandler(req, res) { }); if (status === 403) { - logger.debug(`HTTTP ${status} retrieving data from npm api, logging in and trying again.`); + logger.debug(`HTTP ${status} retrieving data from npm api, logging in and trying again.`); cache.del(`${tokenCacheKey}.${service}`); [status, token] = await login(loginUrl, widget.username, widget.password, service); if (status !== 200) { - logger.debug(`HTTTP ${status} logging into npm api: ${data}`); + logger.debug(`HTTP ${status} logging into npm api: ${data}`); return res.status(status).send(data); } diff --git a/src/widgets/omada/proxy.js b/src/widgets/omada/proxy.js index ac3453a86..8e8994a5b 100644 --- a/src/widgets/omada/proxy.js +++ b/src/widgets/omada/proxy.js @@ -138,7 +138,7 @@ export default async function omadaProxyHandler(req, res) { const sitesResponseData = JSON.parse(data); if (status !== 200 || sitesResponseData.errorCode > 0) { - logger.debug(`HTTTP ${status} getting sites list: ${sitesResponseData.msg}`); + logger.debug(`HTTP ${status} getting sites list: ${sitesResponseData.msg}`); return res .status(status) .json({ error: { message: "Error getting sites list", url, data: sitesResponseData } }); From d82fbc3026b1dd1c50d8d75f6d73e598b3dc0f41 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:34:26 -0800 Subject: [PATCH 25/32] Enhancement: allow widgets to specify default headers, fix buffer error output (#4287) --- src/utils/proxy/handlers/generic.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/utils/proxy/handlers/generic.js b/src/utils/proxy/handlers/generic.js index e4717469a..c6b9236b3 100644 --- a/src/utils/proxy/handlers/generic.js +++ b/src/utils/proxy/handlers/generic.js @@ -23,7 +23,7 @@ export default async function genericProxyHandler(req, res, map) { formatApiCall(widgets[widget.type].api, { endpoint, ...widget }).replace(/(?<=\?.*)\?/g, "&"), ); - const headers = req.extraHeaders ?? widget.headers ?? {}; + const headers = req.extraHeaders ?? widget.headers ?? widgets[widget.type].headers ?? {}; if (widget.username && widget.password) { headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`; @@ -75,7 +75,13 @@ export default async function genericProxyHandler(req, res, map) { url.port ? `:${url.port}` : "", url.pathname, ); - return res.status(status).json({ error: { message: "HTTP Error", url: sanitizeErrorURL(url), resultData } }); + return res.status(status).json({ + error: { + message: "HTTP Error", + url: sanitizeErrorURL(url), + resultData: Buffer.isBuffer(resultData) ? Buffer.from(resultData).toString() : resultData, + }, + }); } return res.status(status).send(resultData); From e730a0ceb0467dcca7a54e6ef3b352ee214f0f92 Mon Sep 17 00:00:00 2001 From: dhenry437 Date: Thu, 14 Nov 2024 01:57:03 +1100 Subject: [PATCH 26/32] Documentation: Highlight Unifi widget needs local account (#4290) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/widgets/info/unifi_controller.md | 6 +++++- docs/widgets/services/unifi-controller.md | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/widgets/info/unifi_controller.md b/docs/widgets/info/unifi_controller.md index 420029f57..b77d8ed00 100644 --- a/docs/widgets/info/unifi_controller.md +++ b/docs/widgets/info/unifi_controller.md @@ -5,7 +5,11 @@ description: Unifi Controller Information Widget Configuration _(Find the Unifi Controller service widget [here](../services/unifi-controller.md))_ -You can display general connectivity status from your Unifi (Network) Controller. When authenticating you will want to use a local account that has at least read privileges. +You can display general connectivity status from your Unifi (Network) Controller. + +!!! + + When authenticating you will want to use a local account that has at least read privileges. An optional 'site' parameter can be supplied, if it is not the widget will use the default site for the controller. diff --git a/docs/widgets/services/unifi-controller.md b/docs/widgets/services/unifi-controller.md index 3e0b3af5c..d137c2a95 100644 --- a/docs/widgets/services/unifi-controller.md +++ b/docs/widgets/services/unifi-controller.md @@ -7,7 +7,11 @@ Learn more about [Unifi Controller](https://ui.com/). _(Find the Unifi Controller information widget [here](../info/unifi_controller.md))_ -You can display general connectivity status from your Unifi (Network) Controller. When authenticating you will want to use a local account that has at least read privileges. +You can display general connectivity status from your Unifi (Network) Controller. + +!!! + + When authenticating you will want to use a local account that has at least read privileges. An optional 'site' parameter can be supplied, if it is not the widget will use the default site for the controller. From 250351f735d33cfdbffce9e80be4f8de4a93aac7 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 17 Nov 2024 16:16:18 -0800 Subject: [PATCH 27/32] Fix: use duration for audiobookshelf books too See #4228 --- src/widgets/audiobookshelf/component.jsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/widgets/audiobookshelf/component.jsx b/src/widgets/audiobookshelf/component.jsx index 6eb786381..06439e8fc 100755 --- a/src/widgets/audiobookshelf/component.jsx +++ b/src/widgets/audiobookshelf/component.jsx @@ -46,11 +46,8 @@ export default function Component({ service }) { From adde687331294185a652202e99ef8fa2e5351e80 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 18 Nov 2024 07:31:05 -0800 Subject: [PATCH 28/32] Try publish to docker hub --- .github/workflows/docker-publish.yml | 35 ++++++++-------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 368040cca..2ac8b3e8a 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -26,8 +26,6 @@ on: merge_group: env: - # Use docker.io for Docker Hub if empty - REGISTRY: ghcr.io # github.repository as / IMAGE_NAME: ${{ github.repository }} @@ -66,14 +64,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - # Install the cosign tool except on PR - # https://github.com/sigstore/cosign-installer - - name: Install cosign - if: github.event_name != 'pull_request' - uses: sigstore/cosign-installer@main - with: - cosign-release: 'v1.13.1' # optional - # Setup QEMU # https://github.com/marketplace/actions/docker-setup-buildx#with-qemu - name: Setup QEMU @@ -99,9 +89,15 @@ jobs: if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} # Extract metadata (tags, labels) for Docker # https://github.com/docker/metadata-action @@ -109,7 +105,9 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: | + ${{ env.IMAGE_NAME }} + ghcr.io/${{ env.IMAGE_NAME }} flavor: | latest=auto @@ -133,19 +131,6 @@ jobs: cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max - # Sign the resulting Docker image digest except on PRs. - # This will only write to the public Rekor transparency log when the Docker - # repository is public to avoid leaking data. If you would like to publish - # transparency data even for private images, pass --force to cosign below. - # https://github.com/sigstore/cosign -# - name: Sign the published Docker image -# if: ${{ github.event_name != 'pull_request' }} -# env: -# COSIGN_EXPERIMENTAL: "true" -# # This step uses the identity token to provision an ephemeral certificate -# # against the sigstore community Fulcio instance. -# run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign {}@${{ steps.build-and-push.outputs.digest }} - # Temp fix # https://github.com/docker/build-push-action/issues/252 # https://github.com/moby/buildkit/issues/1896 From 4a3a4c846e122707e6bb6eacd5805be33e5236bf Mon Sep 17 00:00:00 2001 From: Felix Cornelius <9767036+fcornelius@users.noreply.github.com> Date: Tue, 19 Nov 2024 22:59:52 +0100 Subject: [PATCH 29/32] Feature: Add ArgoCD widget (#4305) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/widgets/services/argocd.md | 33 ++++++++++++++ docs/widgets/services/index.md | 1 + mkdocs.yml | 1 + public/locales/en/common.json | 10 +++++ src/utils/proxy/handlers/credentialed.js | 1 + src/widgets/argocd/component.jsx | 52 ++++++++++++++++++++++ src/widgets/argocd/widget.js | 14 ++++++ src/widgets/components.js | 1 + src/widgets/prometheusmetric/component.jsx | 1 + src/widgets/widgets.js | 2 + 10 files changed, 116 insertions(+) create mode 100644 docs/widgets/services/argocd.md create mode 100644 src/widgets/argocd/component.jsx create mode 100644 src/widgets/argocd/widget.js diff --git a/docs/widgets/services/argocd.md b/docs/widgets/services/argocd.md new file mode 100644 index 000000000..6a81b8db9 --- /dev/null +++ b/docs/widgets/services/argocd.md @@ -0,0 +1,33 @@ +--- +title: ArgoCD +description: ArgoCD Widget Configuration +--- + +Learn more about [ArgoCD](https://argo-cd.readthedocs.io/en/stable/). + +Allowed fields (limited to a max of 4): `["apps", "synced", "outOfSync", "healthy", "progressing", "degraded", "suspended", "missing"]` + +```yaml +widget: + type: argocd + url: http://argocd.host.or.ip:port + key: argocdapikey +``` + +You can generate an API key either by creating a bearer token for an existing account, see [Authorization](https://argo-cd.readthedocs.io/en/latest/developer-guide/api-docs/#authorization) (not recommended) or create a new local user account with limited privileges and generate an authentication token for this account. To do this the steps are: + +- [Create a new local user](https://argo-cd.readthedocs.io/en/stable/operator-manual/user-management/#create-new-user) and give it the `apiKey` capability +- Setup [RBAC configuration](https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/#rbac-configuration) for your the user and give it readonly access to your ArgoCD resources, e.g. by giving it the `role:readonly` role. +- In your ArgoCD project under _Settings / Accounts_ open the newly created account and in the _Tokens_ section click on _Generate New_ to generate an access token, optionally specifying an expiry date. + +If you installed ArgoCD via the official Helm chart, the account creation and rbac config can be achived by overriding these helm values: + +```yaml +configs: + cm: + accounts.readonly: apiKey + rbac: + policy.csv: "g, readonly, role:readonly" +``` + +This creates a new account called `readonly` and attaches the `role:readonly` role to it. diff --git a/docs/widgets/services/index.md b/docs/widgets/services/index.md index 8ea2e9331..ae506f086 100644 --- a/docs/widgets/services/index.md +++ b/docs/widgets/services/index.md @@ -8,6 +8,7 @@ search: You can also find a list of all available service widgets in the sidebar navigation. - [Adguard Home](adguard-home.md) +- [ArgoCD](argocd.md) - [Atsumeru](atsumeru.md) - [Audiobookshelf](audiobookshelf.md) - [Authentik](authentik.md) diff --git a/mkdocs.yml b/mkdocs.yml index 42abce301..1e9d59cc8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -31,6 +31,7 @@ nav: - "Service Widgets": - widgets/services/index.md - widgets/services/adguard-home.md + - widgets/services/argocd.md - widgets/services/atsumeru.md - widgets/services/audiobookshelf.md - widgets/services/authentik.md diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 81576984e..ab7dcfc92 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -988,5 +988,15 @@ "memory": "MEM", "disk": "Disk", "network": "NET" + }, + "argocd": { + "apps": "Apps", + "synced": "Synced", + "outOfSync": "Out Of Sync", + "healthy": "Healthy", + "degraded": "Degraded", + "progressing": "Progressing", + "missing": "Missing", + "suspended": "Suspended" } } diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index eb2aab69a..8d4340c2a 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -36,6 +36,7 @@ export default async function credentialedProxyHandler(req, res, map) { headers["X-gotify-Key"] = `${widget.key}`; } else if ( [ + "argocd", "authentik", "cloudflared", "ghostfolio", diff --git a/src/widgets/argocd/component.jsx b/src/widgets/argocd/component.jsx new file mode 100644 index 000000000..d3b519363 --- /dev/null +++ b/src/widgets/argocd/component.jsx @@ -0,0 +1,52 @@ +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 { widget } = service; + + if (!widget.fields) { + widget.fields = ["apps", "synced", "outOfSync", "healthy"]; + } + + const MAX_ALLOWED_FIELDS = 4; + if (widget.fields.length > MAX_ALLOWED_FIELDS) { + widget.fields = widget.fields.slice(0, MAX_ALLOWED_FIELDS); + } + + const { data: appsData, error: appsError } = useWidgetAPI(widget, "applications"); + + const appCounts = widget.fields.map((status) => { + if (status === "apps") { + return { status, count: appsData?.items?.length }; + } + const count = appsData?.items?.filter( + (item) => + item.status?.sync?.status.toLowerCase() === status.toLowerCase() || + item.status?.health?.status.toLowerCase() === status.toLowerCase(), + ).length; + return { status, count }; + }); + + if (appsError) { + return ; + } + + if (!appsData) { + return ( + + {appCounts.map((a) => ( + + ))} + + ); + } + + return ( + + {appCounts.map((a) => ( + + ))} + + ); +} diff --git a/src/widgets/argocd/widget.js b/src/widgets/argocd/widget.js new file mode 100644 index 000000000..5030adaa1 --- /dev/null +++ b/src/widgets/argocd/widget.js @@ -0,0 +1,14 @@ +import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; + +const widget = { + api: "{url}/api/v1/{endpoint}", + proxyHandler: credentialedProxyHandler, + + mappings: { + applications: { + endpoint: "applications", + }, + }, +}; + +export default widget; diff --git a/src/widgets/components.js b/src/widgets/components.js index 3cba84d2d..aa476c464 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -2,6 +2,7 @@ import dynamic from "next/dynamic"; const components = { adguard: dynamic(() => import("./adguard/component")), + argocd: dynamic(() => import("./argocd/component")), atsumeru: dynamic(() => import("./atsumeru/component")), audiobookshelf: dynamic(() => import("./audiobookshelf/component")), authentik: dynamic(() => import("./authentik/component")), diff --git a/src/widgets/prometheusmetric/component.jsx b/src/widgets/prometheusmetric/component.jsx index 347aaa0c2..350a6b7dd 100644 --- a/src/widgets/prometheusmetric/component.jsx +++ b/src/widgets/prometheusmetric/component.jsx @@ -5,6 +5,7 @@ import Block from "components/services/widget/block"; import useWidgetAPI from "utils/proxy/use-widget-api"; function formatValue(t, metric, rawValue) { + if (!metric?.format) return rawValue; if (!rawValue) return "-"; let value = rawValue; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index 791103789..0cad5346d 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -1,4 +1,5 @@ import adguard from "./adguard/widget"; +import argocd from "./argocd/widget"; import atsumeru from "./atsumeru/widget"; import audiobookshelf from "./audiobookshelf/widget"; import authentik from "./authentik/widget"; @@ -130,6 +131,7 @@ import zabbix from "./zabbix/widget"; const widgets = { adguard, + argocd, atsumeru, audiobookshelf, authentik, 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 30/32] 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 000000000..5baa9268e --- /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 1e9d59cc8..5b350d717 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 ab7dcfc92..5abb9a4b9 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 1566a135b..ea82c7352 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 aa476c464..bea37cf2e 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 000000000..523ecea79 --- /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 000000000..2c8a34757 --- /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 0cad5346d..8eb3f51fc 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 31/32] 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 000000000..a92434d83 --- /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 ae506f086..894a31f6e 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 5b350d717..a19d3b839 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 5abb9a4b9..484f76b5c 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 8d4340c2a..cbe0422ae 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 bea37cf2e..19f41d4ae 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 000000000..fb6f898f7 --- /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 000000000..26f77a777 --- /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 8eb3f51fc..9d4bb935d 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 32/32] 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 06685f3af..29ab6b38d 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: