feat(jellyseer): stat widgets + rich Requests tab (slice 3/3)

Frontend for Jellyseerr request stats, reusing the generic stat abstraction.

- api/jellyseerr.ts + hooks/useJellyseer.ts: fetchJellyseerrStats +
  useJellyseerrStats (polls /api/jellyseerr/stats, no-retry; shares the backend
  cache with the widgets).
- Two reusable widgets backed by the stat/stats_overview kinds:
  - RequestStatWidget: a single selected stat (big value + label).
  - RequestsOverviewWidget: a MetricCard grid of all stats + a recent-requests
    list with status/media-status badges.
- registry.ts: Jellyfin gains `stat` (a dropdown over
  total/pending/approved/declined/processing/available — the "extract one stat
  into a widget" affordance, rendered as a Select via the existing enum UI) and
  `stats_overview` widget kinds, wired to the new components.
- RequestsTab rewritten: live stats grid (6 counts) + recent-requests list +
  a hint to pin individual stats via the Request stat widget. Reads
  jellyseerr_url from config and the now-secret jellyseerr_api_key from
  secrets_set.

Tests: RequestStatWidget + RequestsOverviewWidget rendering/error; RequestsTab
not-configured CTA, configured stats grid, and error states. 184/184 frontend
tests pass; tsc + ESLint clean.
This commit is contained in:
Developer
2026-07-12 13:59:08 +00:00
parent e25240c2f3
commit 0b039529f6
17 changed files with 444 additions and 70 deletions
+37
View File
@@ -10,6 +10,8 @@ import { PrometheusMetricWidget } from "../widgets/PrometheusMetricWidget";
import { QbittorrentActiveTorrentsWidget } from "../widgets/QbittorrentActiveTorrentsWidget";
import { QbittorrentSpeedWidget } from "../widgets/QbittorrentSpeedWidget";
import { QbittorrentTotalsWidget } from "../widgets/QbittorrentTotalsWidget";
import { RequestStatWidget } from "../widgets/RequestStatWidget";
import { RequestsOverviewWidget } from "../widgets/RequestsOverviewWidget";
import { SshTaskWidget } from "../widgets/SshTaskWidget";
import { StaticWidget } from "../widgets/StaticWidget";
import type {
@@ -252,6 +254,41 @@ export const SERVICE_REGISTRY: Record<string, ServiceBinding> = {
configSchema: { type: "object", properties: {}, required: [] },
component: JellyfinNowPlayingWidget,
},
{
kind: "stat",
name: "Request stat",
description: "A single Jellyseerr request statistic (e.g. pending requests).",
refreshIntervalMs: 60_000,
defaultConfig: { stat: "pending" },
configSchema: {
type: "object",
properties: {
stat: {
type: "string",
enum: [
"total",
"pending",
"approved",
"declined",
"processing",
"available",
],
description: "Which request count to display",
},
},
required: [],
},
component: RequestStatWidget,
},
{
kind: "stats_overview",
name: "Requests overview",
description: "All Jellyseerr request stats plus a recent-requests list.",
refreshIntervalMs: 60_000,
defaultConfig: {},
configSchema: { type: "object", properties: {}, required: [] },
component: RequestsOverviewWidget,
},
],
},
nextcloud: {