From 2d157e900d1dea424869c61af83984501af268ff Mon Sep 17 00:00:00 2001 From: Mitchell R Date: Sat, 23 May 2026 01:29:05 +0200 Subject: [PATCH] feat(cameras): health indicator on list page (green/yellow/red dot + status badge) --- .../service-admin-http/routes-admin.ts | 4 +- server/src/web-templates/admin-pages.tsx | 37 ++++++++++++------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/server/src/plugins/service-admin-http/routes-admin.ts b/server/src/plugins/service-admin-http/routes-admin.ts index 4bfc562..5cc8625 100644 --- a/server/src/plugins/service-admin-http/routes-admin.ts +++ b/server/src/plugins/service-admin-http/routes-admin.ts @@ -489,10 +489,12 @@ export function registerAdminRoutes(app: H3, deps: AdminDeps): void { const user = event.context.user!; const cameras = deps.repo.listCameras(); const streamCounts = new Map(); + const activeKiosks = new Map(); // camera_id → count of kiosks rendering for (const cam of cameras) { streamCounts.set(cam.id, deps.repo.listCameraStreams(cam.id).length); + activeKiosks.set(cam.id, deps.repo.listKiosksRenderingCamera(cam.id).length); } - return htmlPage(CamerasPage({ user: user.username, cameras, streamCounts })); + return htmlPage(CamerasPage({ user: user.username, cameras, streamCounts, activeKiosks })); }); app.get("/admin/cameras/new", (event) => { diff --git a/server/src/web-templates/admin-pages.tsx b/server/src/web-templates/admin-pages.tsx index 47730f6..85abb53 100644 --- a/server/src/web-templates/admin-pages.tsx +++ b/server/src/web-templates/admin-pages.tsx @@ -114,6 +114,7 @@ interface CamerasProps { user: string; cameras: Camera[]; streamCounts: Map; + activeKiosks: Map; } export function CamerasPage(props: CamerasProps) { @@ -137,19 +138,29 @@ export function CamerasPage(props: CamerasProps) { {props.cameras.length === 0 ? ( No cameras configured ) : ( - props.cameras.map((cam) => ( - - {cam.name} - {cam.type.toUpperCase()} - {String(props.streamCounts.get(cam.id) ?? 0)} - - {cam.enabled - ? Enabled - : Disabled - } - - - )) + props.cameras.map((cam) => { + const streams = props.streamCounts.get(cam.id) ?? 0; + const active = props.activeKiosks.get(cam.id) ?? 0; + const health = !cam.enabled ? "gray" + : streams === 0 ? "red" + : active > 0 ? "green" + : "yellow"; + const healthLabel = !cam.enabled ? "Disabled" + : streams === 0 ? "No streams" + : active > 0 ? `Live (${active} kiosk${active > 1 ? "s" : ""})` + : "Idle"; + return ( + + + + {cam.name} + + {cam.type.toUpperCase()} + {String(streams)} + {healthLabel} + + ); + }) )}