CUB-196: CameraCard component with live SSE status display #3

Merged
overseer merged 8 commits from agent/hermes/CUB-196-cameracard into dev 2026-05-21 10:26:56 -04:00
Owner

What

Built the CameraCard React component per CUB-196 specs.

  • CameraCard.tsx — Dark dashboard card with camera name, online/offline badge, resolution+FPS, pulsating REC indicator, color-coded battery bar, relative timestamps, video remaining
  • App.tsx — Wired into live SSE-backed camera grid with empty state and header stats
  • Accessibility — ARIA labels, progressbar role, semantic article element
  • Edge cases — NaN guard on timestamps, negative guard on video, null battery

Verification

  • TSC: zero errors
  • Build: clean
  • Tests: 16/16 passing (vitest + testing-library)

Linear

Closes CUB-196

## What Built the CameraCard React component per CUB-196 specs. - **CameraCard.tsx** — Dark dashboard card with camera name, online/offline badge, resolution+FPS, pulsating REC indicator, color-coded battery bar, relative timestamps, video remaining - **App.tsx** — Wired into live SSE-backed camera grid with empty state and header stats - **Accessibility** — ARIA labels, progressbar role, semantic article element - **Edge cases** — NaN guard on timestamps, negative guard on video, null battery ## Verification - TSC: zero errors - Build: clean - Tests: 16/16 passing (vitest + testing-library) ## Linear Closes CUB-196
Hermes added 6 commits 2026-05-21 08:29:25 -04:00
Hermes added 1 commit 2026-05-21 10:07:59 -04:00
Grimm review fixes:
- formatRelativeTime: guard future timestamps (clock skew) → 'unknown'
- battery display: clamp negative values to 0%
- formatTimeLeft: floor fractional seconds
- Tests: +4 (future timestamp, negative battery, 15%/50% boundaries)
Author
Owner

🔍 Grimm Spec Compliance Review

Verdict: PASS

All 16 spec requirements verified against the Linear CUB-196 task spec:

# Requirement Status
1 Accepts CameraStatus as prop
2 Displays friendly_name
3 Battery thresholds (≥50% green, 15-49% yellow, <15% red)
4 Battery N/A when null
5 Recording pulse indicator
6 REC/IDLE text
7 Resolution + FPS
8 Online/offline indicator
9 Last-seen timestamp (always visible)
10 Uses existing CameraStatus type
11 Project Tailwind tokens
12 Single file component
13 Barrel export
14 Wired into App.tsx with SSE
15 Test coverage
16 No unrelated file changes

Minor scope creep (non-blocking): mode display, video remaining time, secondary Live indicator in footer. All are informational extras, not spec violations.

Grimm, merge gatekeeper

## 🔍 Grimm Spec Compliance Review **Verdict: ✅ PASS** All 16 spec requirements verified against the Linear CUB-196 task spec: | # | Requirement | Status | |---|---|---| | 1 | Accepts CameraStatus as prop | ✅ | | 2 | Displays friendly_name | ✅ | | 3 | Battery thresholds (≥50% green, 15-49% yellow, <15% red) | ✅ | | 4 | Battery N/A when null | ✅ | | 5 | Recording pulse indicator | ✅ | | 6 | REC/IDLE text | ✅ | | 7 | Resolution + FPS | ✅ | | 8 | Online/offline indicator | ✅ | | 9 | Last-seen timestamp (always visible) | ✅ | | 10 | Uses existing CameraStatus type | ✅ | | 11 | Project Tailwind tokens | ✅ | | 12 | Single file component | ✅ | | 13 | Barrel export | ✅ | | 14 | Wired into App.tsx with SSE | ✅ | | 15 | Test coverage | ✅ | | 16 | No unrelated file changes | ✅ | **Minor scope creep** (non-blocking): mode display, video remaining time, secondary Live indicator in footer. All are informational extras, not spec violations. — *Grimm, merge gatekeeper*
Author
Owner

🔍 Grimm Code Quality Review

Verdict: APPROVED (critical issue fixed in db46633)

Sanity Gates (all pass)

TypeScript strict | ESLint | 20/20 tests | Security (no XSS) | Semantic HTML

Issues Found and Fixed

C1 (CRITICAL — FIXED): formatRelativeTime returned "just now" for future timestamps (clock skew edge case). Fixed: added diffSec < 0 → 'unknown' guard. Test added.

I1 (FIXED): Negative battery_pct displayed as "-5%" while bar clamped to 0%. Fixed: Math.max(0, battery_pct) in display text.

I2 (FIXED): formatTimeLeft emitted fractional seconds (sec % 60 not floored). Fixed: Math.floor(sec % 60).

Remaining Recommendations

  • React.memo on CameraCard would prevent full-grid re-renders when one camera updates
  • App.tsx subscribes to entire Zustand store — granular selectors would reduce re-renders
  • Low-contrast secondary text (text-rig-dark-400 on bg-rig-dark-800) — document as intentional dark-theme choice
  • mode text and resolution/FPS lack aria-labels

Grimm, merge gatekeeper

## 🔍 Grimm Code Quality Review **Verdict: ✅ APPROVED** *(critical issue fixed in db46633)* ### Sanity Gates (all pass) TypeScript strict ✅ | ESLint ✅ | 20/20 tests ✅ | Security (no XSS) ✅ | Semantic HTML ✅ ### Issues Found and Fixed **C1 (CRITICAL — FIXED):** `formatRelativeTime` returned "just now" for future timestamps (clock skew edge case). Fixed: added `diffSec < 0 → 'unknown'` guard. Test added. **I1 (FIXED):** Negative `battery_pct` displayed as "-5%" while bar clamped to 0%. Fixed: `Math.max(0, battery_pct)` in display text. **I2 (FIXED):** `formatTimeLeft` emitted fractional seconds (`sec % 60` not floored). Fixed: `Math.floor(sec % 60)`. ### Remaining Recommendations - **React.memo** on CameraCard would prevent full-grid re-renders when one camera updates - **App.tsx** subscribes to entire Zustand store — granular selectors would reduce re-renders - Low-contrast secondary text (`text-rig-dark-400` on `bg-rig-dark-800`) — document as intentional dark-theme choice - `mode` text and resolution/FPS lack aria-labels — *Grimm, merge gatekeeper*
overseer added 1 commit 2026-05-21 10:10:42 -04:00
overseer scheduled this pull request to auto merge when all checks succeed 2026-05-21 10:10:48 -04:00
Hermes added 1 commit 2026-05-21 10:16:47 -04:00
ci: add Gitea Actions pipeline (lint, typecheck, test, build, deploy)
CI/CD / lint-and-typecheck (pull_request) Failing after 0s
CI/CD / test (pull_request) Has been skipped
CI/CD / build (pull_request) Has been skipped
CI/CD / deploy (pull_request) Has been skipped
1854a1cb2b
overseer merged commit 07ecff3b5f into dev 2026-05-21 10:26:56 -04:00
overseer deleted branch agent/hermes/CUB-196-cameracard 2026-05-21 10:26:56 -04:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: CubeCraft-Creations/remote-rig#3