From c21827667ac475a4cebf46bf33650033922cd465 Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 7 Jul 2026 12:22:30 +0200 Subject: [PATCH 1/2] feat(web): dedicated channel edit screen for SPA parity (#146) Add a full ChannelEditScreen so the SPA can edit an existing channel (the list/builder could only create). Mirrors the Blazor ChannelEditor field set via hydrate-then-PUT against GET/PUT /api/channels/{id}. - api/channels.ts: getChannelById + updateChannel (typed from generated ChannelViewModel / UpdateChannelRequest). - screens/ChannelEditScreen.tsx: section-rail form (General, Playout, Streaming, Stream selection, Music video, Branding) following the SettingsScreen draft/saved dirtiness + floating save bar pattern. Logo upload reuses uploadArtwork; option data via existing pickers clients. - App.tsx: /app/edit-channel/{id} route (allowSubPaths, screen parses the id); repoint the channel-table edit pencil at it. - Tests: API-client GET/PUT + screen hydrate/edit-save/404 coverage. Deferred per scope: ExternalLogoUrl (backend contract gap), and the /channels/numbers bulk renumber (existing Renumber toolbar = parity). Language codes / stream selector / credits template are free-text inputs (no enumeration endpoints exist); mirror-source list can't filter to Generated-only (ChannelResponseModel omits playoutSource). Co-Authored-By: Claude Fable 5 --- web/src/App.tsx | 23 +- web/src/api/channels.test.ts | 92 +++ web/src/api/channels.ts | 13 + web/src/screens/ChannelEditScreen.test.tsx | 133 +++ web/src/screens/ChannelEditScreen.tsx | 894 +++++++++++++++++++++ 5 files changed, 1154 insertions(+), 1 deletion(-) create mode 100644 web/src/api/channels.test.ts create mode 100644 web/src/screens/ChannelEditScreen.test.tsx create mode 100644 web/src/screens/ChannelEditScreen.tsx diff --git a/web/src/App.tsx b/web/src/App.tsx index 763935d37..a0b6f159f 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -54,6 +54,7 @@ import { } from 'lucide-react'; import chicoryMarkUrl from '../../design-system/assets/chicory-mark.svg'; import { ChannelBuilderScreen } from './builder/ChannelBuilder'; +import { ChannelEditScreen } from './screens/ChannelEditScreen'; import { SettingsScreen } from './screens/SettingsScreen'; import { navigateToPath } from './routing'; import { @@ -124,6 +125,7 @@ type ScreenId = | 'dashboard' | 'channels' | 'builder' + | 'editChannel' | 'guide' | 'schedules' | 'playouts' @@ -181,6 +183,21 @@ const routes: ScreenRoute[] = [ primaryAction: 'Create Channel', placeholder: 'Channel builder workspace' }, + { + // Not in the sidebar nav; reached via the edit pencil on the channel table. The + // screen owns parsing the {id} suffix (see ChannelEditScreen), so it opts into + // sub-paths like /app/edit-channel/5. + id: 'editChannel', + path: '/app/edit-channel', + label: 'Edit Channel', + title: 'Edit Channel', + kicker: 'Channel', + description: 'Full channel editor: identity, playout, streaming, selection and branding.', + icon: