Extract Dashboard and Guide screens from App.tsx #246

Closed
opened 2026-07-11 12:50:17 +02:00 by timothy · 3 comments
Owner

Child of #243.

Scope

Extract the two remaining medium-sized App-owned screens as separately reviewable PRs:

  • DashboardScreen.tsx: health/status panels, on-air cards, dashboard helpers.
  • GuideScreen.tsx: guide loading/error state, rows/program blocks, clipping/time-position helpers, and the mount-owned 60-second now-clock interval.

Each screen gets a colocated test file. Shared helpers are extracted only when two independent screens genuinely consume them.

Completed outside this issue

LibrariesScreen was extracted from App.tsx as part of #202 slice S4 (99fab8e0). It is not remaining #246 scope.

Sequencing

  • Dashboard and Guide are independent implementation slices and may be prepared in parallel in separate worktrees.
  • Land them as separate PRs. Rebase the second branch on current origin/main after the first lands; never merge main into it.
  • Do not mix feature work or shell/routing redesign into these structural extractions.

Acceptance criteria

  • Polling, timer, subscription, mount/unmount, and stale-request lifecycles retain their existing semantics.
  • Guide clipping, live-highlighting, now-marker, and time-position calculations move with their tests unchanged.
  • Dashboard health, on-air, progress, and status calculations move with their tests unchanged.
  • App-level tests retain composition/routing coverage only; detailed screen behavior moves to self-contained colocated screen tests with scoped fetch mocks.
  • No API, route, styling, or intentional behavior changes.
  • Each extraction is independently revertible and reviewable.

Done-when

  • Dashboard implementation and detailed tests are screen-owned; App retains only composition smoke.
  • Dashboard full web test/lint/typecheck/build and API-generation checks pass.
  • Dashboard PR CI is green and adversarial review passed on its current head.
  • Guide implementation, 60-second timer, helpers, and detailed tests are screen-owned; App retains only composition smoke.
  • Guide full web test/lint/typecheck/build and API-generation checks pass.
  • Guide PR CI is green and adversarial review passed on its current head.
  • No API, route, CSS, or intentional behavior change was introduced.
Child of https://gitea.tblindustries.be/timothy/ersatztv/issues/243. ## Scope Extract the two remaining medium-sized App-owned screens as **separately reviewable PRs**: - `DashboardScreen.tsx`: health/status panels, on-air cards, dashboard helpers. - `GuideScreen.tsx`: guide loading/error state, rows/program blocks, clipping/time-position helpers, and the mount-owned 60-second now-clock interval. Each screen gets a colocated test file. Shared helpers are extracted only when two independent screens genuinely consume them. ## Completed outside this issue `LibrariesScreen` was extracted from `App.tsx` as part of #202 slice S4 (`99fab8e0`). It is not remaining #246 scope. ## Sequencing - Dashboard and Guide are independent implementation slices and may be prepared in parallel in separate worktrees. - Land them as separate PRs. Rebase the second branch on current `origin/main` after the first lands; never merge `main` into it. - Do not mix feature work or shell/routing redesign into these structural extractions. ## Acceptance criteria - Polling, timer, subscription, mount/unmount, and stale-request lifecycles retain their existing semantics. - Guide clipping, live-highlighting, now-marker, and time-position calculations move with their tests unchanged. - Dashboard health, on-air, progress, and status calculations move with their tests unchanged. - App-level tests retain composition/routing coverage only; detailed screen behavior moves to self-contained colocated screen tests with scoped fetch mocks. - No API, route, styling, or intentional behavior changes. - Each extraction is independently revertible and reviewable. ## Done-when - [x] Dashboard implementation and detailed tests are screen-owned; App retains only composition smoke. - [x] Dashboard full web test/lint/typecheck/build and API-generation checks pass. - [x] Dashboard PR CI is green and adversarial review passed on its current head. - [x] Guide implementation, 60-second timer, helpers, and detailed tests are screen-owned; App retains only composition smoke. - [x] Guide full web test/lint/typecheck/build and API-generation checks pass. - [x] Guide PR CI is green and adversarial review passed on its current head. - [x] No API, route, CSS, or intentional behavior change was introduced.
timothy added this to the ChicoryTV modularization milestone 2026-07-11 12:50:17 +02:00
timothy added the enhancementpriority: mediumfrontend labels 2026-07-11 12:50:17 +02:00
Author
Owner

Batch B (Libraries) is already DONE — re-scope this issue to Batch A only. (Independent plan re-review, adversarial-reviewer#24, 2026-07-12.)

LibrariesScreen was extracted from App.tsx as part of #202 (slice S4, 99fab8e0 "extract LibrariesScreen from App.tsx"). Current main (9e2d1608) imports LibrariesScreen from ./screens/LibrariesScreen and App.tsx owns no inline Libraries render block. The #202-collision gate this issue documented is moot — the collision was avoided because #202 performed the extraction itself.

Remaining scope = Batch A: DashboardScreen + GuideScreen, both eligible now (no dependency):

  • Dashboard: inline at App.tsx 1146-1197 (+ helpers 932-1144), rendered from ScreenContent at 2633. No timer; useDashboardQuery is one-shot, useDashboardHealthQuery owns its own activeRef — all in api/dashboard.ts. Presentational move.
  • Guide: inline at App.tsx 1234-1344 (+ helpers 1203-1477), rendered at 2649. Carry the 60s now-clock setInterval (App.tsx 1239, cleanup 1244) with the screen — mount-only, correctly needs no current-guard. Data polling (30s channel-state) lives in api/guide.ts:132, not App.tsx.

Suggest closing/renaming this issue to "Extract Dashboard + Guide (Batch A)" and recording Batch B as completed via #202 S4.

**Batch B (Libraries) is already DONE — re-scope this issue to Batch A only.** (Independent plan re-review, [adversarial-reviewer#24](https://gitea.tblindustries.be/timothy/adversarial-reviewer/issues/24), 2026-07-12.) `LibrariesScreen` was extracted from `App.tsx` **as part of #202** (slice S4, `99fab8e0` "extract LibrariesScreen from App.tsx"). Current `main` (`9e2d1608`) imports `LibrariesScreen` from `./screens/LibrariesScreen` and App.tsx owns no inline Libraries render block. The #202-collision gate this issue documented is moot — the collision was avoided because #202 performed the extraction itself. **Remaining scope = Batch A: `DashboardScreen` + `GuideScreen`**, both eligible now (no dependency): - Dashboard: inline at App.tsx `1146-1197` (+ helpers `932-1144`), rendered from `ScreenContent` at `2633`. No timer; `useDashboardQuery` is one-shot, `useDashboardHealthQuery` owns its own `activeRef` — all in `api/dashboard.ts`. Presentational move. - Guide: inline at App.tsx `1234-1344` (+ helpers `1203-1477`), rendered at `2649`. **Carry the 60s now-clock `setInterval` (App.tsx `1239`, cleanup `1244`)** with the screen — mount-only, correctly needs no current-guard. Data polling (30s channel-state) lives in `api/guide.ts:132`, not App.tsx. Suggest closing/renaming this issue to "Extract Dashboard + Guide (Batch A)" and recording Batch B as completed via #202 S4.
timothy added the in-progress label 2026-07-15 20:57:39 +02:00
Author
Owner

Claiming the remaining Batch A scope: extract DashboardScreen and GuideScreen from App.tsx as independently reviewable, behavior-preserving changes. Libraries is already complete through #202 and is explicitly out of scope. I will work from a fresh origin/main worktree, preserve the Guide timer/polling semantics, keep detailed tests colocated with each screen, and run the full web/API-generation gate before handoff.

Claiming the remaining Batch A scope: extract DashboardScreen and GuideScreen from App.tsx as independently reviewable, behavior-preserving changes. Libraries is already complete through #202 and is explicitly out of scope. I will work from a fresh origin/main worktree, preserve the Guide timer/polling semantics, keep detailed tests colocated with each screen, and run the full web/API-generation gate before handoff.
timothy changed title from Extract Dashboard, Guide, and Libraries screens from App.tsx to Extract Dashboard and Guide screens from App.tsx 2026-07-15 21:01:01 +02:00
Author
Owner

Done

What was done: Extracted the remaining App-owned Dashboard and Guide screens into separate, independently reviewable modules and landed them through PR #360 and PR #359. Dashboard now owns its status/on-air helpers and detailed tests. Guide now owns its rendering, clipping/time-position helpers, mount-owned 60-second now clock, and detailed tests; channel-state polling remains in api/guide.ts. App retains shell composition and thin route smoke coverage.

Root cause: n/a — this was a behavior-preserving modularization task, not a bug fix or incident.

Files changed: web/src/App.tsx, web/src/App.test.tsx, web/src/screens/DashboardScreen.tsx, web/src/screens/DashboardScreen.test.tsx, web/src/screens/GuideScreen.tsx, and web/src/screens/GuideScreen.test.tsx.

Verification: Final rebased state passed 86 Vitest files / 762 tests, ESLint, TypeScript typecheck, production build, API-generation sync, and git diff --check. Both PRs passed all required CI checks. Independent adversarial reviews were mergeable on Dashboard head bceffef856bb43efb7d638511ea1e066afa3075c and final Guide head 3876809a83088b5c6f3393cb56d00cd296cf5efe.

Deferred: none.

Follow-up issues: none.

Docs updated: no docs/skills impact; API, routes, CSS, runtime behavior, and project conventions did not change.

## Done **What was done**: Extracted the remaining App-owned Dashboard and Guide screens into separate, independently reviewable modules and landed them through PR #360 and PR #359. Dashboard now owns its status/on-air helpers and detailed tests. Guide now owns its rendering, clipping/time-position helpers, mount-owned 60-second now clock, and detailed tests; channel-state polling remains in `api/guide.ts`. App retains shell composition and thin route smoke coverage. **Root cause**: n/a — this was a behavior-preserving modularization task, not a bug fix or incident. **Files changed**: `web/src/App.tsx`, `web/src/App.test.tsx`, `web/src/screens/DashboardScreen.tsx`, `web/src/screens/DashboardScreen.test.tsx`, `web/src/screens/GuideScreen.tsx`, and `web/src/screens/GuideScreen.test.tsx`. **Verification**: Final rebased state passed 86 Vitest files / 762 tests, ESLint, TypeScript typecheck, production build, API-generation sync, and `git diff --check`. Both PRs passed all required CI checks. Independent adversarial reviews were mergeable on Dashboard head `bceffef856bb43efb7d638511ea1e066afa3075c` and final Guide head `3876809a83088b5c6f3393cb56d00cd296cf5efe`. **Deferred**: none. **Follow-up issues**: none. **Docs updated**: no docs/skills impact; API, routes, CSS, runtime behavior, and project conventions did not change.
timothy removed the in-progress label 2026-07-15 21:59:44 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: timothy/ersatztv#246