Add Jellyfin Now Playing + Grafana Panel embed widgets
Two new additive widget kinds: Jellyfin 'now_playing': like the existing 'activity' widget but filters to only sessions with active playback (NowPlayingItem present + not paused). Shows who's actually watching right now. The 'activity' kind is unchanged (shows all sessions including idle). Grafana 'panel': embeds a single Grafana panel directly in the app via an iframe, using Grafana's /d-solo/ endpoint (renders one panel without dashboard chrome, kiosk=tv). Configurable dashboard_uid, panel_id, and time range (from/to, defaults now-1h/now). Includes a fallback 'Open in Grafana' link for when embedding is blocked by X-Frame-Options/CSP. The 'link' kind is unchanged (still builds a deep-link URL). Backend: new widget configs + definitions on jellyfin/grafana; source adapter logic (session filter for now_playing; d-solo embed URL for panel); 6 new tests. Frontend: JellyfinNowPlayingWidget + GrafanaPanelWidget components; registry bindings; 6 new tests. 278 backend tests pass (+6); 127 frontend tests pass (+6); lint/build green both sides.
This commit is contained in:
@@ -2,7 +2,9 @@ import type { ComponentType } from "react";
|
||||
import { AlertmanagerAlertsWidget } from "../widgets/AlertmanagerAlertsWidget";
|
||||
import { BackupsWidget } from "../widgets/BackupsWidget";
|
||||
import { GrafanaLinkWidget } from "../widgets/GrafanaLinkWidget";
|
||||
import { GrafanaPanelWidget } from "../widgets/GrafanaPanelWidget";
|
||||
import { JellyfinWidget } from "../widgets/JellyfinWidget";
|
||||
import { JellyfinNowPlayingWidget } from "../widgets/JellyfinNowPlayingWidget";
|
||||
import { PrometheusMetricWidget } from "../widgets/PrometheusMetricWidget";
|
||||
import { SshTaskWidget } from "../widgets/SshTaskWidget";
|
||||
import { StaticWidget } from "../widgets/StaticWidget";
|
||||
@@ -86,6 +88,29 @@ export const SERVICE_REGISTRY: Record<string, ServiceBinding> = {
|
||||
},
|
||||
component: GrafanaLinkWidget,
|
||||
},
|
||||
{
|
||||
kind: "panel",
|
||||
name: "Panel embed",
|
||||
description: "Embed a Grafana panel directly.",
|
||||
refreshIntervalMs: 0,
|
||||
defaultConfig: {
|
||||
dashboard_uid: "",
|
||||
panel_id: 1,
|
||||
from_ts: "now-1h",
|
||||
to_ts: "now",
|
||||
},
|
||||
configSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
dashboard_uid: { type: "string" },
|
||||
panel_id: { type: "integer" },
|
||||
from_ts: { type: "string" },
|
||||
to_ts: { type: "string" },
|
||||
},
|
||||
required: ["dashboard_uid", "panel_id"],
|
||||
},
|
||||
component: GrafanaPanelWidget,
|
||||
},
|
||||
],
|
||||
},
|
||||
prometheus: {
|
||||
@@ -122,6 +147,15 @@ export const SERVICE_REGISTRY: Record<string, ServiceBinding> = {
|
||||
configSchema: { type: "object", properties: {}, required: [] },
|
||||
component: JellyfinWidget,
|
||||
},
|
||||
{
|
||||
kind: "now_playing",
|
||||
name: "Now Playing",
|
||||
description: "Only sessions actively playing media.",
|
||||
refreshIntervalMs: 30_000,
|
||||
defaultConfig: {},
|
||||
configSchema: { type: "object", properties: {}, required: [] },
|
||||
component: JellyfinNowPlayingWidget,
|
||||
},
|
||||
],
|
||||
},
|
||||
nextcloud: {
|
||||
|
||||
Reference in New Issue
Block a user