feat(web-ui): add Playout tile to home screen

Fetches /playout/channels separately and degrades silently when the
endpoint or schema is absent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Zac 2026-05-30 14:59:59 +00:00
parent ca71e47035
commit f837e57969

View file

@ -23,12 +23,19 @@ function Home({ navigate }) {
// Pull live counts so the tile subtitles ("34 assets", "0 live", "3 running") // Pull live counts so the tile subtitles ("34 assets", "0 live", "3 running")
// reflect what's actually in the DB right now, not a stale boot-time cache. // reflect what's actually in the DB right now, not a stale boot-time cache.
const [cards, setCards] = React.useState({}); const [cards, setCards] = React.useState({});
// Playout has no /metrics/home card yet (and the playout schema may not be
// migrated on every install); fetch /playout/channels separately and degrade
// silently the tile just shows "No channels" if the endpoint isn't there.
const [playoutChannels, setPlayoutChannels] = React.useState(null);
React.useEffect(() => { React.useEffect(() => {
let cancelled = false; let cancelled = false;
const load = () => { const load = () => {
window.ZAMPP_API.fetch('/metrics/home?hours=1') window.ZAMPP_API.fetch('/metrics/home?hours=1')
.then(d => { if (!cancelled) setCards(d?.cards || {}); }) .then(d => { if (!cancelled) setCards(d?.cards || {}); })
.catch(() => {}); .catch(() => {});
window.ZAMPP_API.fetch('/playout/channels')
.then(d => { if (!cancelled) setPlayoutChannels(Array.isArray(d) ? d : []); })
.catch(() => { if (!cancelled) setPlayoutChannels([]); });
}; };
load(); load();
const t = setInterval(load, 30_000); const t = setInterval(load, 30_000);
@ -63,6 +70,21 @@ function Home({ navigate }) {
: totalRecs + ' configured', : totalRecs + ' configured',
desc: 'SDI · SRT · RTMP ingest. Start, stop, schedule.', desc: 'SDI · SRT · RTMP ingest. Start, stop, schedule.',
}, },
{
id: 'playout',
label: 'Playout',
icon: 'monitor',
tone: 'accent',
sub: (() => {
if (playoutChannels === null) return '·';
const total = playoutChannels.length;
const onAir = playoutChannels.filter(c => c.status === 'running').length;
if (total === 0) return 'No channels';
if (onAir > 0) return onAir + ' on air · ' + total + ' channel' + (total === 1 ? '' : 's');
return total + ' channel' + (total === 1 ? '' : 's');
})(),
desc: 'Master Control. SDI · NDI · SRT · RTMP playout, playlists, as-run.',
},
{ {
id: '__premiere', id: '__premiere',
label: 'Premiere panel', label: 'Premiere panel',