+
{t('menu.units')}
- {t('menu.system')}
-
- {t('menu.ballDetection')}
- {ballDetectionValue}
- {cameraStatus.available ? (
-
- ) : null}
-
- {Object.keys(simStatuses).length > 0 ? (
-
- {t('menu.simulators')}
-
-
+ {t('menu.liveView')}
+
+ {mode === 'timed' ? (
+ {
+ const next = Number(id);
+ if (isLiveViewDurationMs(next)) {
+ setDurationMs(next);
+ }
+ }}
+ />
) : null}
-
-
>
);
diff --git a/ui/src/components/panel/PanelFooter.test.tsx b/ui/src/components/panel/PanelFooter.test.tsx
index 4db73231..824c13de 100644
--- a/ui/src/components/panel/PanelFooter.test.tsx
+++ b/ui/src/components/panel/PanelFooter.test.tsx
@@ -20,7 +20,6 @@ function render(
ballDetected={false}
debugRecording={false}
powerStatus={powerStatus}
- onShutdown={() => {}}
/>
).replace(//g, '');
}
@@ -58,14 +57,14 @@ describe('PanelFooter', () => {
}
});
- it('hides units and battery on Players, Camera, and Debug while keeping shutdown visible', () => {
+ it('hides units, battery, and shutdown on Players, Camera, and Debug', () => {
for (const view of ['players', 'camera', 'debug'] as const) {
const html = render(view, 4, null);
- expect(html).toContain('panel-footer__meta');
+ expect(html).not.toContain('panel-footer__meta');
expect(html).not.toContain('mph / yds');
expect(html).not.toContain('power-status');
- expect(html).toContain('panel-footer__power');
+ expect(html).not.toContain('panel-footer__power');
}
});
@@ -96,12 +95,12 @@ describe('PanelFooter', () => {
expect(html).toContain('41%');
});
- it('keeps the shutdown power control visible on every panel without battery telemetry', () => {
+ it('does not keep shutdown in the footer on any panel', () => {
for (const view of ['live', 'stats', 'shots', 'camera', 'players', 'debug'] as const) {
const html = render(view, 0, null);
- expect(html).toContain('panel-footer__power');
- expect(html).toContain('aria-label="Shut down"');
+ expect(html).not.toContain('panel-footer__power');
+ expect(html).not.toContain('aria-label="Shut down"');
}
});
diff --git a/ui/src/components/panel/PanelFooter.tsx b/ui/src/components/panel/PanelFooter.tsx
index 91b90ad5..ba0dbcc5 100644
--- a/ui/src/components/panel/PanelFooter.tsx
+++ b/ui/src/components/panel/PanelFooter.tsx
@@ -15,7 +15,6 @@ interface PanelFooterProps {
currentView: PanelView;
onChangeView: (view: PanelView) => void;
onOpenMenu: () => void;
- onShutdown: () => void;
menuOpen: boolean;
shotCount: number;
cameraStreaming: boolean;
@@ -34,7 +33,7 @@ const VIEWS_WITH_UNITS: ReadonlySet
= new Set(['live', 'stats', 'shot
/**
* Bottom bar: menu button, divider-separated panel tabs, and view meta on the
- * right. Panel actions live in `PanelHeader`.
+ * right. Panel actions and shutdown live in `PanelHeader`.
*
* The mockup footer shows four tabs; Players and Debug are extra working
* screens. Burying either behind a gesture makes them unreachable on the kiosk.
@@ -43,7 +42,6 @@ export function PanelFooter({
currentView,
onChangeView,
onOpenMenu,
- onShutdown,
menuOpen,
shotCount,
cameraStreaming,
@@ -110,22 +108,12 @@ export function PanelFooter({
/>
-