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:
@@ -99,10 +99,10 @@ def test_authentik_service_definition():
|
||||
|
||||
|
||||
def test_definitions_declare_widget_kinds():
|
||||
assert {wk.kind for wk in get_service_definition("grafana").widget_kinds} == {"link"}
|
||||
assert {wk.kind for wk in get_service_definition("grafana").widget_kinds} == {"link", "panel"}
|
||||
assert {wk.kind for wk in get_service_definition("prometheus").widget_kinds} == {"metric"}
|
||||
assert {wk.kind for wk in get_service_definition("alertmanager").widget_kinds} == {"active_alerts"}
|
||||
assert {wk.kind for wk in get_service_definition("jellyfin").widget_kinds} == {"activity"}
|
||||
assert {wk.kind for wk in get_service_definition("jellyfin").widget_kinds} == {"activity", "now_playing"}
|
||||
assert get_service_definition("nextcloud").widget_kinds == []
|
||||
assert get_service_definition("authentik").widget_kinds == []
|
||||
assert {wk.kind for wk in get_service_definition("backups").widget_kinds} == {"summary"}
|
||||
@@ -184,7 +184,7 @@ def test_service_type_includes_secret_and_widget_metadata(client):
|
||||
response = client.get("/api/services/types")
|
||||
grafana = next(item for item in response.json() if item["service_type"] == "grafana")
|
||||
assert [sf["key"] for sf in grafana["secret_fields"]] == ["api_key"]
|
||||
assert [wk["kind"] for wk in grafana["widget_kinds"]] == ["link"]
|
||||
assert [wk["kind"] for wk in grafana["widget_kinds"]] == ["link", "panel"]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user