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).
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.
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)
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
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
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 main2026-07-18 01:54:39 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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
SlideOverprimitive (components/overlay.tsx) sharing auseOverlayBehaviorhook (focus/scroll-lock/Escape/scrim) withDialog.builder/advancedOptions.tsx(enum catalogs,ADVANCED_KEYS,effectiveValue, INHERIT/omituseAdvancedOverrideshook). 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.uploadArtworklogo 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 newgetAutoTuneChannelMembers(GET /members).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
PlaybackOrder=Shuffle(overridden) vsSeasonEpisode(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
Review-verdict: MERGEABLE @
56fffacfd4Cold 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.