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 06ac91ebe9c..e9f7e871fda 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 92a0140bf29..3f1e34950e8 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 4f5ab60297f..a81069d7314 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 64dd7306435..bfe3fc933ce 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 7ce412c6e5f..7d370378d56 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 a01b2eee0f1..4b9126ea776 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 baa0e4d59f6..cf2b6439624 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 c8ab83ae75a..d77b2dfc7f0 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 9cdd523100c..d9469d1cb0f 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 b13aeac127c..3a9f8323a31 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 dcfcd43fda8..69097089011 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 b34938b1549..e63847b43bf 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 13473f05bd1..77ad0703872 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 96483cc3f0e..a1b5c7b3fc5 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 384f44befcb..fd52aef4aba 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 025d1aa53ca..2fac0fcdf0f 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 406a81c28c3..6eb7863812e 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 43b566e8e1d..ac77be51b0e 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 5939f9edc01..c3ea1bf6436 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 7be8aa29b98..0a8146cc0b5 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 3d64c490278..b7c259a8960 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 2748540192a..b2027a6f17a 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 000b9b1a472..83c37bafeef 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 6f6c09f28a9..09edba3d896 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 3eed63f82d3..9587852c5a5 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 83c37bafeef..089bb564303 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 09edba3d896..492c0ebab28 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 9587852c5a5..5b2bdb8a6f8 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 089bb564303..d776bec05d8 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 492c0ebab28..d6cb010e906 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 5b2bdb8a6f8..cb94df4a005 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 d776bec05d8..14b7d054a4f 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 d6cb010e906..8be8d3623e6 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 cb94df4a005..d73d36c6f2f 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 00000000000..c6da54f5cea --- /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 91f91d38316..3dee2a05dd4 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 0667e5eaa66..94af034d70d 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 fd52aef4aba..38ee3e857b1 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 b1b9922c644..eb2aab69a5f 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 62bd479f559..8453e52751c 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 00000000000..361aa756f26 --- /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 00000000000..a05059fba53 --- /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 faff57eb4da..a1af3661b95 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 00000000000..f3a0e67d892 --- /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 00000000000..3cc828b9d4b --- /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 3dee2a05dd4..83ad0fed0f6 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 94af034d70d..cd46689204b 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 38ee3e857b1..bdde0a34b6b 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 9d55ce43af9..63dfb608209 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 00000000000..1d35b6e94d3 --- /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 00000000000..5f70a10d237 --- /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 00000000000..508c1debb39 --- /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 8453e52751c..50564e4932e 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 a1af3661b95..40b121aef8c 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 f2089065275..9f55f973c8c 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 83ad0fed0f6..8ea2e9331fa 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 00000000000..19397aa7e59 --- /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 cd46689204b..42abce30152 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 63dfb608209..1566a135b3d 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 50564e4932e..7e6b68e14b9 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 00000000000..347aaa0c21d --- /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 00000000000..22137b0d7de --- /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 40b121aef8c..4d76fa0707f 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 b540c6d700a..ba94f143938 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 00000000000..216725981b7 --- /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 bdde0a34b6b..81576984e7b 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 7e6b68e14b9..3cba84d2d21 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 00000000000..b7c34820f6b --- /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 00000000000..d4d7167520b --- /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 00000000000..e2ed509c614 --- /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 4d76fa0707f..7911037895e 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 3cc828b9d4b..6a5cc269102 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 5f70a10d237..04083e4209a 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 996ea3241e3..cf754424f4a 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 3f1e34950e8..978254f815c 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 ac3453a86d6..8e8994a5ba3 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 e4717469ad7..c6b9236b3f5 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 420029f573a..b77d8ed0043 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 3e0b3af5ccb..d137c2a9539 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 6eb7863812e..06439e8fcb4 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 368040cca2d..2ac8b3e8a53 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 00000000000..6a81b8db9bc --- /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 8ea2e9331fa..ae506f08678 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 42abce30152..1e9d59cc8ac 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 81576984e7b..ab7dcfc9274 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 eb2aab69a5f..8d4340c2af2 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 00000000000..d3b519363cd --- /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 00000000000..5030adaa160 --- /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 3cba84d2d21..aa476c4640b 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 347aaa0c21d..350a6b7dd5d 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 7911037895e..0cad5346d4a 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 00000000000..5baa9268e35 --- /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 1e9d59cc8ac..5b350d71796 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 ab7dcfc9274..5abb9a4b9b6 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 1566a135b3d..ea82c7352cb 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 aa476c4640b..bea37cf2e7a 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 00000000000..523ecea7922 --- /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 00000000000..2c8a3475795 --- /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 0cad5346d4a..8eb3f51fcbe 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 00000000000..a92434d8305 --- /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 ae506f08678..894a31f6e49 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 5b350d71796..a19d3b8393c 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 5abb9a4b9b6..484f76b5c45 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 8d4340c2af2..cbe0422ae00 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 bea37cf2e7a..19f41d4ae28 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 00000000000..fb6f898f7c9 --- /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 00000000000..26f77a7774f --- /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 8eb3f51fcbe..9d4bb935d85 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 06685f3af0e..29ab6b38de6 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: