Round 7 added the int32 check inside `isSearchPickerOption` — the place the defect was found — which left every other door into editor state open. A malformed successful response carrying `1.5` or `2147483648` still entered `draft` through list-backed options and through the selection restored from the detail read, keeping Save enabled and sending a value the API cannot bind, while the identical value arriving via SearchPicker was correctly rejected. The predicate now lives once, in `web/src/api/selectionId.ts`, and sits on every path by which an id from the wire becomes editor state. The class crosses all three screens, not just the one the finding named, so all three are covered: - RerunCollectionsScreen: `toPickerOptions` (3 list branches) + `draftFromRerun` - PlaylistsScreen: `toPickerOptions` (3 list branches) + `draftFromItem` (4 id fields) - FillerPresetsScreen: `draftFromPreset` (5 id fields) + the collection-family browse options - pickers.tsx: `isSearchPickerOption` now delegates rather than carrying its own copy An unbindable id is treated as ABSENT, never coerced — rounding 1.5 to 1 would submit a DIFFERENT record — so it surfaces as "no selection" with Save disabled and a visible reason; an option that cannot be selected safely is dropped rather than rendered. Five regressions assert zero writes are reachable via each previously-unguarded path. Also corrects two of my own test descriptions, per the review: the padded-ETag test is a regression guard rather than a round-7 defect demonstration (Headers strips outer whitespace before the app sees it), and the late-settlement test guards the abort/race COMPOSITION — what it actually fails is an abort-only implementation whose fetch ignores its signal, which is why its stub ignores `init.signal`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
41 lines
1.2 KiB
TypeScript
41 lines
1.2 KiB
TypeScript
export * from './artwork';
|
|
export * from './auth';
|
|
export * from './autoTune';
|
|
export * from './blocks';
|
|
export * from './channels';
|
|
export * from './channelTemplates';
|
|
export * from './client';
|
|
export * from './collections';
|
|
export * from './dashboard';
|
|
export * from './decos';
|
|
export * from './decoTemplates';
|
|
export * from './ffmpegProfiles';
|
|
export * from './fillerPresets';
|
|
export * from './graphicsElements';
|
|
export * from './guide';
|
|
export * from './imageFolders';
|
|
export * from './languages';
|
|
export * from './libraries';
|
|
export * from './libraryBrowse';
|
|
export * from './selectionId';
|
|
export * from './logs';
|
|
export * from './maintenance';
|
|
export * from './mediaDetail';
|
|
export * from './mediaItems';
|
|
export * from './mediaSources';
|
|
export * from './multiCollections';
|
|
export * from './paging';
|
|
export * from './pickers';
|
|
export * from './playlists';
|
|
export * from './playoutHistory';
|
|
export * from './playouts';
|
|
export * from './rerunCollections';
|
|
export * from './schedules';
|
|
export * from './search';
|
|
export * from './settings';
|
|
export * from './templates';
|
|
export * from './trakt';
|
|
export * from './troubleshoot';
|
|
export * from './useChannelsQuery';
|
|
export * from './watermarks';
|