SPA media browse/detail: add-to-* affordances, per-show scan, per-episode info/troubleshoot entries missing (blocks #91 phase b) #209

Closed
opened 2026-07-09 21:40:11 +02:00 by timothy · 2 comments
Owner

From the #203 mutation-depth sweep (2026-07-09). Read-path parity of the media surface is genuinely solid (browse/pagination/search/detail/drill-in per the accepted parentId decision; /app/media/images/browser is fully parity-OK). Mutation-depth parity is systematically absent:

Tier 1 — capability lost outright (no SPA path at all):

  • Per-show Quick/Deep Scan: POST /api/libraries/{id}/scan-show exists (LibrariesController.cs:29) with zero SPA callers (Blazor TelevisionSeasonList.razor:62–73,308–320).
  • Per-episode Media Info dialog: API works for episodes (GET /api/media-items/{id}/info), no UI path invokes it (episode cards have no actions, no detail page).
  • Per-episode Troubleshoot Playback entry point: hand-built ?mediaItem={id} URL only (parity doc already admits this).
  • Cross-show season search/browse (/media/tv/seasons?query=…): MediaBrowseScreen KINDS deliberately has no seasons entry; drill-in only lists one show's seasons.

Tier 2 — direction inverted, not recorded as a decision:

  • Every add-to-collection / add-to-playlist / add-to-schedule affordance (per-item and multi-select on all 9 list pages + 4 detail pages) exists only from the inverse direction (collection/playlist/schedule editor pickers). Real workflow regression ("I'm looking at this movie, add it to X"). Either build the shared "Add to…" affordance (same component as the search-screen issue) or record an explicit accepted-deviation entry in docs/decisions.md.
  • Stale pointer: MediaDetailScreen.tsx:524 claims these are "tracked by #153/#155" — both closed without adding them; nothing tracked this until now.

Tier 3 — minor: LetterBar A–Z jump; metadata chips/actor links rendered as dead tags; reduced episode/music-video card metadata. (Also: parity doc understates /media/tv/episodes — browse is actually FULL via kind=episodes.)

Severity: MUST-FIX for Tier 1 + a decision (build or waive) on Tier 2 before Blazor removal. Refs: #91, #203.

From the #203 mutation-depth sweep (2026-07-09). Read-path parity of the media surface is genuinely solid (browse/pagination/search/detail/drill-in per the accepted `parentId` decision; `/app/media/images/browser` is fully parity-OK). Mutation-depth parity is systematically absent: **Tier 1 — capability lost outright (no SPA path at all):** - **Per-show Quick/Deep Scan**: `POST /api/libraries/{id}/scan-show` exists (`LibrariesController.cs:29`) with **zero SPA callers** (Blazor `TelevisionSeasonList.razor:62–73,308–320`). - **Per-episode Media Info dialog**: API works for episodes (`GET /api/media-items/{id}/info`), no UI path invokes it (episode cards have no actions, no detail page). - **Per-episode Troubleshoot Playback entry point**: hand-built `?mediaItem={id}` URL only (parity doc already admits this). - **Cross-show season search/browse** (`/media/tv/seasons?query=…`): `MediaBrowseScreen` KINDS deliberately has no seasons entry; drill-in only lists one show's seasons. **Tier 2 — direction inverted, not recorded as a decision:** - Every add-to-collection / add-to-playlist / add-to-schedule affordance (per-item and multi-select on all 9 list pages + 4 detail pages) exists only from the inverse direction (collection/playlist/schedule editor pickers). Real workflow regression ("I'm looking at this movie, add it to X"). Either build the shared "Add to…" affordance (same component as the search-screen issue) or record an explicit accepted-deviation entry in docs/decisions.md. - Stale pointer: `MediaDetailScreen.tsx:524` claims these are "tracked by #153/#155" — both closed without adding them; nothing tracked this until now. **Tier 3 — minor:** LetterBar A–Z jump; metadata chips/actor links rendered as dead tags; reduced episode/music-video card metadata. (Also: parity doc understates `/media/tv/episodes` — browse is actually FULL via `kind=episodes`.) **Severity: MUST-FIX for Tier 1 + a decision (build or waive) on Tier 2** before Blazor removal. Refs: #91, #203.
Author
Owner

Work started (session 2026-07-09, branch feat/208-209-add-to). Recon complete. Plan: shared Add-to dialogs (collection/playlist/schedule) as reusable SPA components + two small new endpoints (POST /api/playlists/{id}/items wrapping the existing AddItemsToPlaylist command; GET /api/search/all-items exposing QuerySearchIndexAllItems for the query-based Add All flow — mirrors Blazor's two-step materialize-then-add, no new business logic). Per-show scan reuses POST /api/libraries/{id}/scan-show. Wiring: search cards (nav + per-card add + multi-select + add-all + save-as-smart-collection), browse tiles, all four detail screens, per-episode info/troubleshoot/add.

Work started (session 2026-07-09, branch `feat/208-209-add-to`). Recon complete. Plan: shared Add-to dialogs (collection/playlist/schedule) as reusable SPA components + two small new endpoints (`POST /api/playlists/{id}/items` wrapping the existing `AddItemsToPlaylist` command; `GET /api/search/all-items` exposing `QuerySearchIndexAllItems` for the query-based Add All flow — mirrors Blazor's two-step materialize-then-add, no new business logic). Per-show scan reuses `POST /api/libraries/{id}/scan-show`. Wiring: search cards (nav + per-card add + multi-select + add-all + save-as-smart-collection), browse tiles, all four detail screens, per-episode info/troubleshoot/add.
Author
Owner

Closed via PR #216 (merged to main, c63cadb8).

What was done: shared Add-to layer web/src/media/addTo/ (AddToCollectionDialog with inline create, AddToPlaylistDialog, AddToScheduleDialog replicating AddProgramScheduleItem.ForMediaItem defaults, SaveAsSmartCollectionDialog, AddToMenu popover) + MediaPosterCard actions slot; wired into search (card drill-in, per-card add, Select mode + selection bar, query-wide Add All, Save As Smart Collection) and media browse/detail (tiles + multi-select w/ select-all-on-page, all four detail screens, per-show Quick/Deep scan gated to Plex/Jellyfin/Emby, per-episode Media Info + Troubleshoot, seasons browse kind added, stale #153/#155 pointer removed). New endpoints: POST /api/playlists/{id}/items (AddItemsToPlaylist handler hardened to reject system playlists — latent Blazor-path gap), GET /api/search/all-items.

Verification: 477 web + 974 .NET tests; live E2E on a seeded local instance (screenshots e2e-216-*); adversarial review APPROVE-WITH-FIXES, all MINORs fixed in-PR. E2E found + fixed: add-to-schedule gated to shows/seasons/artists (server validator only accepts those per-media-item CollectionTypes — matches Blazor's ForMediaItem call sites). CI flake root-caused: mount-debounce timer wiped in-progress selections (real UX race) — fixed with a no-change guard.

Deferred/follow-ups: #217 (add-items validates only 4/10 kinds — pre-existing), #218 (fresh-DB Playouts badge), review nits (last-used-collection memory, detailBrowseItem cast cleanup). Accepted deviations recorded in docs/decisions.md 2026-07-10 (Select toggle, per-card target superset, schedule-kind gating).

Docs updated: blazor-route-parity.md (verdict rows → PARITY-OK, seasons + troubleshoot-entry rows), decisions.md, spa-conventions.md §5c, api-conventions artifacts (v1.json, endpoint-index), e2e-local.md + e2e-local.sh stale-asset fix.

**Closed via PR #216** (merged to main, c63cadb8). **What was done**: shared Add-to layer `web/src/media/addTo/` (AddToCollectionDialog with inline create, AddToPlaylistDialog, AddToScheduleDialog replicating AddProgramScheduleItem.ForMediaItem defaults, SaveAsSmartCollectionDialog, AddToMenu popover) + MediaPosterCard `actions` slot; wired into search (card drill-in, per-card add, Select mode + selection bar, query-wide Add All, Save As Smart Collection) and media browse/detail (tiles + multi-select w/ select-all-on-page, all four detail screens, per-show Quick/Deep scan gated to Plex/Jellyfin/Emby, per-episode Media Info + Troubleshoot, seasons browse kind added, stale #153/#155 pointer removed). New endpoints: POST /api/playlists/{id}/items (AddItemsToPlaylist handler hardened to reject system playlists — latent Blazor-path gap), GET /api/search/all-items. **Verification**: 477 web + 974 .NET tests; live E2E on a seeded local instance (screenshots e2e-216-*); adversarial review APPROVE-WITH-FIXES, all MINORs fixed in-PR. E2E found + fixed: add-to-schedule gated to shows/seasons/artists (server validator only accepts those per-media-item CollectionTypes — matches Blazor's ForMediaItem call sites). CI flake root-caused: mount-debounce timer wiped in-progress selections (real UX race) — fixed with a no-change guard. **Deferred/follow-ups**: #217 (add-items validates only 4/10 kinds — pre-existing), #218 (fresh-DB Playouts badge), review nits (last-used-collection memory, detailBrowseItem cast cleanup). Accepted deviations recorded in docs/decisions.md 2026-07-10 (Select toggle, per-card target superset, schedule-kind gating). **Docs updated**: blazor-route-parity.md (verdict rows → PARITY-OK, seasons + troubleshoot-entry rows), decisions.md, spa-conventions.md §5c, api-conventions artifacts (v1.json, endpoint-index), e2e-local.md + e2e-local.sh stale-asset fix.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: timothy/ersatztv#209