spectator updates

This commit is contained in:
legop3
2025-11-24 00:40:11 -05:00
parent c1c78585ba
commit 9ba7f8fd7a
6 changed files with 21 additions and 51 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -11,8 +11,8 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
<title>Multi Roomba Rover</title>
<script type="module" crossorigin src="/assets/index-Cx2yYVpk.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-sMfSpjY4.css">
<script type="module" crossorigin src="/assets/index-Bu0ya-aM.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-B8zLJlAS.css">
</head>
<body>
<div id="root"></div>
+5 -4
View File
@@ -39,11 +39,12 @@ function buildWhepUrlForSource(source) {
function passesMode(socket) {
const mode = getMode();
if (mode === MODES.LOCKDOWN && !isLockdownAdmin(socket)) {
return false;
if (mode === MODES.LOCKDOWN) {
return isLockdownAdmin(socket);
}
if (mode === MODES.ADMIN && !isAdmin(socket)) {
return false;
if (mode === MODES.ADMIN) {
const role = getRole(socket);
return role === 'spectator' || isAdmin(socket);
}
return true;
}
+4 -35
View File
@@ -1,4 +1,3 @@
import { useMemo } from 'react';
import { SettingsProvider } from '../settings/index.js';
import { useSession } from '../context/SessionContext.jsx';
import { useSpectatorMode } from '../hooks/useSpectatorMode.js';
@@ -10,22 +9,6 @@ import UserListPanel from '../components/UserListPanel.jsx';
import ChatPanel from '../components/ChatPanel.jsx';
import LogPanel from '../components/LogPanel.jsx';
function SpectatorStatus({ connected, ready, rosterCount, mode, blocked }) {
return (
<div className="flex flex-wrap items-center gap-0.5 text-sm">
<span className={`px-0.5 py-0.5 font-semibold ${connected ? 'bg-emerald-500/20 text-emerald-200' : 'bg-red-500/20 text-red-200'}`}>
{connected ? 'Connected' : 'Disconnected'}
</span>
<span className={`px-0.5 py-0.5 ${ready ? 'bg-blue-600/40 text-blue-100' : 'bg-slate-700 text-slate-200'}`}>
Spectator mode {ready ? 'active' : 'pending…'}
</span>
<span className="bg-slate-800 px-0.5 py-0.5 text-slate-200">Rovers: {rosterCount}</span>
<span className="bg-slate-800 px-0.5 py-0.5 text-slate-200">Mode: {mode || 'unknown'}</span>
{blocked && <span className="bg-red-700/60 px-0.5 py-0.5 text-red-100">Spectate blocked</span>}
</div>
);
}
function TelemetrySummary({ frame }) {
const sensors = frame?.sensors || {};
const updated = frame?.receivedAt ? new Date(frame.receivedAt).toLocaleTimeString() : null;
@@ -87,7 +70,7 @@ function RoverRow({ roster, frames, videoSources, session }) {
return <p className="col-span-full text-slate-400">No rovers registered.</p>;
}
return (
<section className="grid grid-cols-1 gap-0.5 md:grid-cols-2 xl:grid-cols-3">
<section className="grid grid-cols-1 gap-0.5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{roster.map((rover) => (
<RoverSpectatorCard
key={rover.id}
@@ -120,30 +103,16 @@ function LogsRow() {
}
export default function SpectatorApp() {
const { connected, session } = useSession();
const spectatorReady = useSpectatorMode();
const { session } = useSession();
useSpectatorMode();
const frames = useTelemetryFrames();
const roster = session?.roster ?? [];
const videoSources = useVideoRequests(roster.map((rover) => rover.id));
const blocked = session?.mode === 'lockdown';
const status = useMemo(
() => ({ connected, ready: spectatorReady, rosterCount: roster.length, mode: session?.mode, blocked }),
[blocked, connected, roster.length, session?.mode, spectatorReady],
);
return (
<SettingsProvider>
<div className="min-h-screen bg-black text-slate-100">
<main className="mx-auto flex max-w-7xl flex-col gap-0.5 px-0.5 py-0.5">
<header className="space-y-0.5">
<h1 className="text-4xl font-semibold text-white">Spectator Console</h1>
<p className="text-slate-400">Live rover telemetry & logs. This view is read-only.</p>
<SpectatorStatus {...status} />
{blocked && (
<p className="text-sm text-amber-300">Lockdown active. Spectator view will resume automatically when access returns.</p>
)}
</header>
<main className="flex flex-col gap-0.5 p-0.5">
<RoverRow roster={roster} frames={frames} videoSources={videoSources} session={session} />
<SecondaryRow />
<LogsRow />