diff --git a/docs/widgets/services/fileflows.md b/docs/widgets/services/fileflows.md index e05ca527a..a0d37b3ea 100644 --- a/docs/widgets/services/fileflows.md +++ b/docs/widgets/services/fileflows.md @@ -5,10 +5,19 @@ description: Fileflows Widget Configuration Learn more about [FileFlows](https://github.com/revenz/FileFlows). -Allowed fields: `["queue", "processing", "processed", "time"]`. +Allowed fields: `["queue", "processing", "processed", "time"]` (version 1) or `["queue", "processing", "processed", "failed"]` (version 2). + +| FileFlows Version | Homepage Widget Version | +| ----------------- | ----------------------- | +| < 26.10 | 1 (default) | +| >= 26.10 | 2 | + +Version 2 uses the ["Fenrus Dashboard Endpoint"](https://fileflows.com/docs/webconsole/config/settings/general#fenrus-dashboard-endpoint), which must be enabled. Use the token shown there as the `key`. ```yaml widget: type: fileflows url: http://your.fileflows.host:port + version: 2 # optional, defaults to 1 + key: yourfenrustoken # required for version 2 ``` diff --git a/public/locales/en/common.json b/public/locales/en/common.json index f818143d6..978685a35 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -790,7 +790,8 @@ "queue": "Queue", "processing": "Processing", "processed": "Processed", - "time": "Time" + "time": "Time", + "failed": "Failed" }, "firefly": { "networth": "Net Worth", diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 98375b765..b82e4696d 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -619,6 +619,7 @@ export function cleanServiceGroups(groups) { [ "authentik", "beszel", + "fileflows", "glances", "immich", "jellyfin", diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index 37c80c363..756c4e57f 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -130,6 +130,10 @@ export default async function credentialedProxyHandler(req, res, map) { headers.Authorization = widget.key; } else if (widget.type === "gitlab") { headers["PRIVATE-TOKEN"] = widget.key; + } else if (widget.type === "fileflows") { + if (widget.key) { + headers["X-Webhook-Token"] = `${widget.key}`; + } } else if (widget.type === "speedtest") { if (widget.key) { // v1 does not require a key diff --git a/src/utils/proxy/handlers/credentialed.test.js b/src/utils/proxy/handlers/credentialed.test.js index 6f1eb91bb..206f83a44 100644 --- a/src/utils/proxy/handlers/credentialed.test.js +++ b/src/utils/proxy/handlers/credentialed.test.js @@ -40,6 +40,7 @@ vi.mock("widgets/widgets", () => ({ checkmk: { api: "{url}/{endpoint}" }, stocks: { api: "{url}/{endpoint}" }, speedtest: { api: "{url}/{endpoint}" }, + fileflows: { api: "{url}/{endpoint}" }, tubearchivist: { api: "{url}/{endpoint}" }, autobrr: { api: "{url}/{endpoint}" }, jellystat: { api: "{url}/{endpoint}" }, @@ -328,6 +329,7 @@ describe("utils/proxy/handlers/credentialed", () => { [{ type: "trilium", url: "http://x", key: "k" }, { Authorization: "k" }], [{ type: "gitlab", url: "http://x", key: "k" }, { "PRIVATE-TOKEN": "k" }], [{ type: "speedtest", url: "http://x", key: "k" }, { Authorization: "Bearer k" }], + [{ type: "fileflows", url: "http://x", key: "k" }, { "X-Webhook-Token": "k" }], [ { type: "azuredevops", url: "http://x", key: "k" }, { Authorization: `Basic ${Buffer.from("$:k").toString("base64")}` }, diff --git a/src/widgets/fileflows/component.jsx b/src/widgets/fileflows/component.jsx index 46f46c884..f33e05283 100755 --- a/src/widgets/fileflows/component.jsx +++ b/src/widgets/fileflows/component.jsx @@ -8,8 +8,9 @@ export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; + const version = widget.version ?? 1; - const { data: fileflowsData, error: fileflowsError } = useWidgetAPI(widget, "status"); + const { data: fileflowsData, error: fileflowsError } = useWidgetAPI(widget, version === 2 ? "status_v2" : "status"); if (fileflowsError) { return ; @@ -21,7 +22,18 @@ export default function Component({ service }) { - + {version === 2 ? : } + + ); + } + + if (version === 2) { + return ( + + + + + ); } diff --git a/src/widgets/fileflows/component.test.jsx b/src/widgets/fileflows/component.test.jsx index 5b0e42771..a9a45e76c 100644 --- a/src/widgets/fileflows/component.test.jsx +++ b/src/widgets/fileflows/component.test.jsx @@ -62,4 +62,23 @@ describe("widgets/fileflows/component", () => { expectBlockValue(container, "fileflows.processed", 3); expectBlockValue(container, "fileflows.time", "0:00"); }); + + it("uses the webhook endpoint and fields for version 2", () => { + useWidgetAPI.mockReturnValue({ + data: { Unprocessed: 4, Processing: 1, Processed: 10, Failed: 2 }, + error: undefined, + }); + + const widget = { type: "fileflows", url: "http://x", version: 2 }; + const { container } = renderWithProviders(, { + settings: { hideErrors: false }, + }); + + expect(useWidgetAPI).toHaveBeenCalledWith(widget, "status_v2"); + expectBlockValue(container, "fileflows.queue", 4); + expectBlockValue(container, "fileflows.processing", 1); + expectBlockValue(container, "fileflows.processed", 10); + expectBlockValue(container, "fileflows.failed", 2); + expect(screen.queryByText("fileflows.time")).not.toBeInTheDocument(); + }); }); diff --git a/src/widgets/fileflows/widget.js b/src/widgets/fileflows/widget.js index ffa9c0d86..5a39ef8fa 100755 --- a/src/widgets/fileflows/widget.js +++ b/src/widgets/fileflows/widget.js @@ -1,12 +1,15 @@ -import genericProxyHandler from "utils/proxy/handlers/generic"; +import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; const widget = { - api: "{url}/api/{endpoint}", - proxyHandler: genericProxyHandler, + api: "{url}/{endpoint}", + proxyHandler: credentialedProxyHandler, mappings: { status: { - endpoint: "status", + endpoint: "api/status", + }, + status_v2: { + endpoint: "webhook/fenrus", }, }, };