diff --git a/docs/widgets/services/index.md b/docs/widgets/services/index.md index de8c4ce61..e982fb9b9 100644 --- a/docs/widgets/services/index.md +++ b/docs/widgets/services/index.md @@ -101,7 +101,6 @@ You can also find a list of all available service widgets in the sidebar navigat - [OpenMediaVault](openmediavault.md) - [OpenWRT](openwrt.md) - [OPNsense](opnsense.md) -- [Overseerr](overseerr.md) - [PaperlessNGX](paperlessngx.md) - [Peanut](peanut.md) - [pfSense](pfsense.md) diff --git a/docs/widgets/services/overseerr.md b/docs/widgets/services/overseerr.md deleted file mode 100644 index 4d3d6bb1d..000000000 --- a/docs/widgets/services/overseerr.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Overseerr -description: Overseerr Widget Configuration ---- - -Learn more about [Overseerr](https://github.com/sct/overseerr). - -Find your API key under `Settings > General`. - -Allowed fields: `["pending", "approved", "available", "processing"]`. - -```yaml -widget: - type: overseerr - url: http://overseerr.host.or.ip - key: apikeyapikeyapikeyapikeyapikey -``` diff --git a/docs/widgets/services/seerr.md b/docs/widgets/services/seerr.md index 09f460bbe..1067b3017 100644 --- a/docs/widgets/services/seerr.md +++ b/docs/widgets/services/seerr.md @@ -7,9 +7,9 @@ Learn more about [Seerr](https://github.com/seerr-team/seerr). Find your API key under `Settings > General > API Key`. -_Note that Jellyseerr was merged with Overseerr and renamed Seerr. Use `type: seerr` (legacy `type: jellyseerr` is aliased)._ +_Jellyseerr and Overseerr merged into Seerr. Use `type: seerr` (legacy `type: jellyseerr` and `type: overseerr` are aliased)._ -Allowed fields: `["pending", "approved", "available", "completed", "issues"]`. +Allowed fields: `["pending", "approved", "available", "completed", "processing", "issues"]`. Default fields: `["pending", "approved", "completed"]`. ```yaml diff --git a/mkdocs.yml b/mkdocs.yml index 5452d74cd..9004552e8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -124,7 +124,6 @@ nav: - widgets/services/openmediavault.md - widgets/services/opnsense.md - widgets/services/openwrt.md - - widgets/services/overseerr.md - widgets/services/pangolin.md - widgets/services/paperlessngx.md - widgets/services/peanut.md diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 738b14945..76245f286 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -294,13 +294,8 @@ "approved": "Approved", "available": "Available", "completed": "Completed", - "issues": "Open Issues" - }, - "overseerr": { - "pending": "Pending", "processing": "Processing", - "approved": "Approved", - "available": "Available" + "issues": "Open Issues" }, "netalertx": { "total": "Total", diff --git a/src/components/services/widget/container.jsx b/src/components/services/widget/container.jsx index e5962e445..28ab4b330 100644 --- a/src/components/services/widget/container.jsx +++ b/src/components/services/widget/container.jsx @@ -9,6 +9,8 @@ import { buildHighlightConfig } from "utils/highlights"; const ALIASED_WIDGETS = { pialert: "netalertx", hoarder: "karakeep", + jellyseerr: "seerr", + overseerr: "seerr", }; export default function Container({ error = false, children, service }) { diff --git a/src/components/services/widget/container.test.jsx b/src/components/services/widget/container.test.jsx index e41118720..d1e731410 100644 --- a/src/components/services/widget/container.test.jsx +++ b/src/components/services/widget/container.test.jsx @@ -58,6 +58,26 @@ describe("components/services/widget/container", () => { expect(screen.getByTestId("karakeep.count")).toBeInTheDocument(); }); + it("supports seerr aliases when filtering (jellyseerr/overseerr -> seerr)", () => { + renderWithProviders( + + + , + { settings: {} }, + ); + + expect(screen.getByTestId("seerr.pending")).toBeInTheDocument(); + + renderWithProviders( + + + , + { settings: {} }, + ); + + expect(screen.getByTestId("seerr.processing")).toBeInTheDocument(); + }); + it("returns null when errors are hidden via settings.hideErrors", () => { const { container } = renderWithProviders( diff --git a/src/widgets/components.js b/src/widgets/components.js index d0c2419d2..64043ad53 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -97,7 +97,7 @@ const components = { ombi: dynamic(() => import("./ombi/component")), opendtu: dynamic(() => import("./opendtu/component")), opnsense: dynamic(() => import("./opnsense/component")), - overseerr: dynamic(() => import("./overseerr/component")), + overseerr: dynamic(() => import("./seerr/component")), openmediavault: dynamic(() => import("./openmediavault/component")), openwrt: dynamic(() => import("./openwrt/component")), paperlessngx: dynamic(() => import("./paperlessngx/component")), diff --git a/src/widgets/seerr/component.jsx b/src/widgets/seerr/component.jsx index 18da887b5..382d81213 100644 --- a/src/widgets/seerr/component.jsx +++ b/src/widgets/seerr/component.jsx @@ -8,7 +8,6 @@ const MAX_ALLOWED_FIELDS = 4; export default function Component({ service }) { const { widget } = service; - widget.fields = widget?.fields?.length ? widget.fields.slice(0, MAX_ALLOWED_FIELDS) : seerrDefaultFields; const isIssueEnabled = widget.fields.includes("issues"); @@ -21,11 +20,12 @@ export default function Component({ service }) { if (!statsData || (isIssueEnabled && !issueData)) { return ( - - - - - + + + + + + ); } @@ -38,11 +38,12 @@ export default function Component({ service }) { return ( - - - - - + + + + + + ); } diff --git a/src/widgets/seerr/component.test.jsx b/src/widgets/seerr/component.test.jsx index a05687a00..a1c51f5c0 100644 --- a/src/widgets/seerr/component.test.jsx +++ b/src/widgets/seerr/component.test.jsx @@ -30,9 +30,59 @@ describe("widgets/seerr/component", () => { expect(screen.getByText("seerr.approved")).toBeInTheDocument(); expect(screen.getByText("seerr.completed")).toBeInTheDocument(); expect(screen.queryByText("seerr.available")).toBeNull(); + expect(screen.queryByText("seerr.processing")).toBeNull(); expect(screen.queryByText("seerr.issues")).toBeNull(); }); + it("supports jellyseerr as a legacy alias to seerr", () => { + useWidgetAPI + .mockReturnValueOnce({ data: undefined, error: undefined }) // request/count + .mockReturnValueOnce({ data: undefined, error: undefined }); // issue/count disabled (endpoint = "") + + const service = { widget: { type: "jellyseerr", url: "http://x" } }; + const { container } = renderWithProviders(, { settings: { hideErrors: false } }); + + expect(service.widget.fields).toEqual(seerrDefaultFields); + expect(useWidgetAPI.mock.calls[1][1]).toBe(""); + expect(container.querySelectorAll(".service-block")).toHaveLength(3); + expect(screen.getByText("seerr.pending")).toBeInTheDocument(); + expect(screen.getByText("seerr.approved")).toBeInTheDocument(); + expect(screen.getByText("seerr.completed")).toBeInTheDocument(); + }); + + it("supports overseerr as a legacy alias with the same default fields", () => { + useWidgetAPI + .mockReturnValueOnce({ data: undefined, error: undefined }) // request/count + .mockReturnValueOnce({ data: undefined, error: undefined }); // issue/count disabled (endpoint = "") + + const service = { widget: { type: "overseerr", url: "http://x" } }; + const { container } = renderWithProviders(, { settings: { hideErrors: false } }); + + expect(service.widget.fields).toEqual(seerrDefaultFields); + expect(useWidgetAPI.mock.calls[1][1]).toBe(""); + expect(container.querySelectorAll(".service-block")).toHaveLength(3); + expect(screen.getByText("seerr.pending")).toBeInTheDocument(); + expect(screen.getByText("seerr.approved")).toBeInTheDocument(); + expect(screen.getByText("seerr.completed")).toBeInTheDocument(); + }); + + it("keeps processing as a separate optional field", () => { + useWidgetAPI + .mockReturnValueOnce({ data: { pending: 1, processing: 2, approved: 3, available: 4 }, error: undefined }) + .mockReturnValueOnce({ data: undefined, error: undefined }); // issue/count disabled (endpoint = "") + + const service = { + widget: { type: "overseerr", url: "http://x", fields: ["pending", "processing", "approved", "available"] }, + }; + const { container } = renderWithProviders(, { settings: { hideErrors: false } }); + + expect(useWidgetAPI.mock.calls[1][1]).toBe(""); + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expect(screen.getByText("seerr.processing")).toBeInTheDocument(); + expect(screen.getByText("2")).toBeInTheDocument(); + expect(screen.queryByText("seerr.completed")).toBeNull(); + }); + it("renders issues when enabled (and calls the issue/count endpoint)", () => { useWidgetAPI .mockReturnValueOnce({ data: { pending: 1, approved: 2, available: 3, completed: 4 }, error: undefined }) diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index af4d875ca..52f26d103 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -90,7 +90,6 @@ import opendtu from "./opendtu/widget"; import openmediavault from "./openmediavault/widget"; import openwrt from "./openwrt/widget"; import opnsense from "./opnsense/widget"; -import overseerr from "./overseerr/widget"; import pangolin from "./pangolin/widget"; import paperlessngx from "./paperlessngx/widget"; import peanut from "./peanut/widget"; @@ -244,7 +243,7 @@ const widgets = { ombi, opendtu, opnsense, - overseerr, + overseerr: seerr, openmediavault, openwrt, paperlessngx,