feat(386): Auto-Tune per-channel DetailPanel slide-over (SPA) #432

Merged
timothy merged 2 commits from feat/386-autotune-detailpanel into main 2026-07-18 01:54:39 +02:00
Owner

Adds a right-hand Configure slide-over to each Auto-Tune Preview row, making a proposed channel editable before bulk-create. Binds only to the shipped #384/#385 backend (no new endpoints).

fixes #386

What shipped

  • New reusable SlideOver primitive (components/overlay.tsx) sharing a useOverlayBehavior hook (focus/scroll-lock/Escape/scrim) with Dialog.
  • Extracted the Channel Builder advanced-options model to builder/advancedOptions.tsx (enum catalogs, ADVANCED_KEYS, effectiveValue, INHERIT/omit useAdvancedOverrides hook). ChannelBuilder imports it unchanged — its test suite passes byte-for-byte. The DetailPanel writes its own field JSX over the same hook: shared logic, per-screen layout.
  • Panes: identity (name/number + uploadArtwork logo dropzone), Playback (Shuffle→advanced.playbackOrder, Always-playing→advanced.playoutMode), per-channel template picker, Advanced disclosure, lean read-only Query&size, read-only Content-sources via the new getAutoTuneChannelMembers (GET /members).
  • Screen-scoped §8 unsaved-changes guard + an Edited row badge.

Scope reconciliation (issue body was stale on weights)

The create DTO has no rotation-weight/exclude field — #385 split those to #425. So this PR defers to #425 the per-source weight steppers + query corrections (an in-pane #425 hint marks the read-only state as intentional), and drops the MiniEpg, bug-initials generator, and "generated query" text (no backend truth; the proposal carries no query string).

Verification

  • 808 web tests green (incl. panel-open, override→payload, empty-name-not-Edited, re-preview-clears-overrides); lint + build clean.
  • Cold adversarial review: no blockers; 3 Mediums fixed (Order-row shuffle, empty-field edited-flag mismatch, stale-overrides-on-re-preview).
  • Live-E2E (local instance, seeded TV library): browser drive of preview → Configure → toggle Shuffle → Create; the created channel's schedule shows PlaybackOrder=Shuffle (overridden) vs SeasonEpisode (axis default), confirming the override flows UI → SPA → backend → playout.

Docs

spa-conventions §11 (SlideOver + shared advanced-options), decisions.md #386 entry.

🤖 Generated with Claude Code

Adds a right-hand **Configure** slide-over to each Auto-Tune Preview row, making a proposed channel editable before bulk-create. Binds only to the shipped #384/#385 backend (no new endpoints). fixes #386 ## What shipped - **New reusable `SlideOver` primitive** (`components/overlay.tsx`) sharing a `useOverlayBehavior` hook (focus/scroll-lock/Escape/scrim) with `Dialog`. - **Extracted the Channel Builder advanced-options model** to `builder/advancedOptions.tsx` (enum catalogs, `ADVANCED_KEYS`, `effectiveValue`, INHERIT/omit `useAdvancedOverrides` hook). ChannelBuilder imports it unchanged — its test suite passes byte-for-byte. The DetailPanel writes its own field JSX over the same hook: shared logic, per-screen layout. - **Panes:** identity (name/number + `uploadArtwork` logo dropzone), Playback (Shuffle→`advanced.playbackOrder`, Always-playing→`advanced.playoutMode`), per-channel template picker, Advanced disclosure, lean read-only Query&size, read-only Content-sources via the new `getAutoTuneChannelMembers` (`GET /members`). - Screen-scoped §8 unsaved-changes guard + an **Edited** row badge. ## Scope reconciliation (issue body was stale on weights) The create DTO has **no** rotation-weight/exclude field — #385 split those to **#425**. So this PR **defers to #425** the per-source weight steppers + query corrections (an in-pane #425 hint marks the read-only state as intentional), and **drops** the MiniEpg, bug-initials generator, and "generated query" text (no backend truth; the proposal carries no query string). ## Verification - 808 web tests green (incl. panel-open, override→payload, empty-name-not-Edited, re-preview-clears-overrides); lint + build clean. - Cold adversarial review: no blockers; 3 Mediums fixed (Order-row shuffle, empty-field edited-flag mismatch, stale-overrides-on-re-preview). - **Live-E2E** (local instance, seeded TV library): browser drive of preview → Configure → toggle Shuffle → Create; the created channel's schedule shows `PlaybackOrder=Shuffle` (overridden) vs `SeasonEpisode` (axis default), confirming the override flows UI → SPA → backend → playout. ## Docs spa-conventions §11 (SlideOver + shared advanced-options), decisions.md #386 entry. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
timothy added 2 commits 2026-07-18 01:32:53 +02:00
Adds a right-hand "Configure" slide-over to each Auto-Tune Preview row, making
a proposed channel editable before bulk-create — against the shipped #384/#385
backend only, so no control lacks a wire target.

- New reusable SlideOver primitive (components/overlay.tsx), sharing a
  useOverlayBehavior hook (focus/scroll-lock/Escape/scrim) with Dialog.
- Extract the Channel Builder's advanced-options model to builder/advancedOptions.tsx
  (enum catalogs, ADVANCED_KEYS, effectiveValue, INHERIT/omit useAdvancedOverrides
  hook); ChannelBuilder imports it unchanged (its tests pass byte-for-byte). The
  DetailPanel writes its own field JSX over the same hook — shared logic, per-screen
  layout.
- Panes: identity (name/number + logo upload), Playback (Shuffle/Always-playing →
  advanced.playbackOrder/playoutMode), per-channel template picker, Advanced
  disclosure, lean read-only Query&size, read-only Content-sources via GET /members.
- getAutoTuneChannelMembers API client (#384 read endpoint) + tests.
- Screen-scoped §8 unsaved-changes guard + "Edited" row badge.
- Dropped as backend-less decoration: MiniEpg, bug-initials generator, query text.
  Deferred to #425 with an in-pane hint: per-source weight steppers + corrections.
- Docs: spa-conventions §11 (SlideOver + shared advanced-options), decisions.md.

Refs #386
fix(386): address cold-review findings on the DetailPanel
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 11s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 1m16s
Build ErsatzTV Image / CI image pin matches docker/ci (pull_request) Successful in 5s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 5s
Build ErsatzTV Image / decisions.md append-only (pull_request) Successful in 5s
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 14m16s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 17m48s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 20m16s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
56fffacfd4
Cold adversarial review (no blockers, 3 real Mediums):
- Query&size "Order" row ignored the Shuffle toggle (dead ?? fallback showing
  the static axis order); now reflects shuffleOn, consistent with the subtitle.
- Clearing Name/Number to '' flagged the row Edited + armed the unsaved-changes
  guard, but the payload reverted to the proposal default — the two "edited"
  derivations disagreed. overrideEdited now ignores an empty (inherited) value.
- runPreview did not clear per-channel overrides, so edits (incl. pinned numbers)
  silently carried into a re-generated batch → collision risk. Fresh preview now
  resets overrides/detailKey/logo cache.
Tests: empty-name-not-Edited + re-preview-clears-overrides.

Live-E2E (local instance, seeded TV library): preview → Configure → toggle
Shuffle → Create verified end-to-end; the created channel's schedule shows
PlaybackOrder=Shuffle (overridden) vs SeasonEpisode (axis default), confirming
the per-channel override flows UI → SPA → backend → playout.

Refs #386
Author
Owner

Review-verdict: MERGEABLE @ 56fffacfd4

Cold adversarial review of the diff — no blockers; 3 Mediums (Order-row shuffle display, empty-field edited-flag mismatch, stale-overrides-on-re-preview) all fixed in the follow-up commit. A scoped re-review of that fix commit confirmed all three correct + complete with non-vacuous tests, no regressions. Live-E2E green (browser drive; created channel schedule shows PlaybackOrder=Shuffle for the overridden channel vs SeasonEpisode axis-default). 808 web tests + lint + build clean.

Review-verdict: MERGEABLE @ 56fffacfd4e041d85d1e5c8d5f7f14c9e0d4e64b Cold adversarial review of the diff — no blockers; 3 Mediums (Order-row shuffle display, empty-field edited-flag mismatch, stale-overrides-on-re-preview) all fixed in the follow-up commit. A scoped re-review of that fix commit confirmed all three correct + complete with non-vacuous tests, no regressions. Live-E2E green (browser drive; created channel schedule shows PlaybackOrder=Shuffle for the overridden channel vs SeasonEpisode axis-default). 808 web tests + lint + build clean.
timothy merged commit 6204e30c7c into main 2026-07-18 01:54:39 +02:00
timothy deleted branch feat/386-autotune-detailpanel 2026-07-18 01:54:40 +02:00
Sign in to join this conversation.