docs: record Wave 8 tracks 8.D/8.G/8.J/8.L landed

This commit is contained in:
daniel-c-harvey
2026-06-13 20:18:04 -04:00
parent eeab0a1c4c
commit 18f4b596f2
2 changed files with 53 additions and 7 deletions
+50
View File
@@ -34,6 +34,56 @@ The single-track-per-release rule for Session/Mix is enforced only in the CMS fo
---
### 9.8 Wave 8 — Remediation (partial: tracks 8.D, 8.G, 8.J, 8.L landed; 8.A8.C, 8.E, 8.F, 8.H8.I, 8.K, 8.M remain pending)
**Landed:** 2026-06-13 on dev (four tracks).
Daniel tested the landed Phase 9 surface (Waves 17) and produced a punch-list. Wave 8 is remediation — the gap between what the specs *built* and what hands-on use *wants*. Full design, acceptance criteria, and dependencies: `product-notes/phase-9-wave-8-remediation.md`. The wave spans CMS, public site, and label polish. Four tracks landed; remaining tracks (8.A8.C, 8.E, 8.F, 8.H8.I) are blocked on architectural work or dependencies; 8.K (Mix Visualizer) is pulled out of Phase-9-completion scope (post-Phase-9 wave, design-complete); 8.M (legacy-form retirement) is a code-surface-reduction follow-on that trails.
**8.D — Type column chip reads "Session" / "DJ Mix" for non-Cuts**
- **What:** The cross-medium releases grid's Type column must not show a Cut-only `ReleaseType` chip (Single/EP/Album) for Session/Mix rows. For non-Cut media the chip reads the medium name — **"Session"** or **"DJ Mix"**.
- **Why:** The CMS Release Archive grid and the `ALL`-tab grid show all releases together. When a Session or Mix row renders a Cut-only `ReleaseType` value, the UI contradicts the medium taxonomy — a Session row should read "Session," not "Single/EP/Album."
- **Shape:** The Type cell was rendering `@context.Release.ReleaseType` unconditionally. Per Phase 9 read-model design, `ReleaseDto.ReleaseType` is nullable and nulled for non-Cut media at the mapping point. The cell becomes medium-aware: when `Medium == Cut`, show `ReleaseType`; otherwise show the medium's display name from a lookup (no hardcoded switch — a future medium's label comes free from the enum + lookup entry).
- **Acceptance criteria:** Cut row's Type chip shows Single/EP/Album; Session row shows "Session"; Mix row shows "DJ Mix"; no row shows a Cut-only `ReleaseType` for a non-Cut medium.
**Completion note:** The Type cell in `CmsAlbumBrowser.razor` was refactored to a single ternary: when `Medium == Cut`, renders `ReleaseType?.ToString() ?? "—"` (reusing the existing em-dash empty-cell idiom used by Genre and Release-Date cells); otherwise renders from `private static readonly IReadOnlyDictionary<ReleaseMedium, string> MediumTypeLabels` with entries `[ReleaseMedium.Session] = "Session"` and `[ReleaseMedium.Mix] = "DJ Mix"`. Dictionary name is **MediumTypeLabels**. A `@using DeepDrftModels.Enums` was added. Future non-Cut media require exactly one new dictionary entry — no markup change. Acceptance criteria met; Type column now correctly shows "Session" / "DJ Mix" for non-Cut rows.
---
**8.G — "Album Name" → "Release Name" label**
- **What:** The `AlbumHeaderFields` form's first-field label reads **"Release Name"**, not "Album Name."
- **Why:** The field now covers Cuts, Sessions, and Mixes — not just albums. "Release Name" is the accurate noun.
- **Shape:** Rename `Label="Album Name"``Label="Release Name"` and the `RequiredError` string in `AlbumHeaderFields.razor`. Check placeholder/help text for consistency.
- **Acceptance criteria:** The first field of the release header form reads "Release Name"; the required-validation message references "Release Name."
**Completion note:** `AlbumHeaderFields.razor` `Label` and `RequiredError` changed "Album Name" → "Release Name". Matching validation message strings in `BatchEdit.razor` and `BatchUpload.razor` were updated to "Release Name is required" for consistency. Three files total; trivial rename, acceptance criteria met immediately.
---
**8.J — ARCHIVE popover click does not close (bug)**
- **What:** Clicking a popover child leaves the pure-CSS hover dropdown stuck open on SPA navigation. The desktop ARCHIVE menu (a hover-triggered `.dd-nav-dropdown`) has no JS dismissal — it hides only when cursor leaves or focus moves out. After enhanced SPA nav (Blazor keeps the DOM), the cursor often remains over the parent, so the dropdown stays visible.
- **Why:** Dead affordance. An admin clicks "Sessions" in the dropdown, the nav updates in-place, and the dropdown stays floating over the new content, blocking clicks. Dismissal must be explicit (JS-based, not CSS-only).
- **Shape:** Detect SPA navigation and trigger a dismissal handler. The existing `DeepDrftMenu.razor` / `DeepDrftMenu.razor.css` structure carries `.dd-nav-dropdown` with `:hover` and `:focus-within` CSS triggers. A JS `DismissDropdown()` function or a Blazor `@onmouseleave` handler on the parent can close the dropdown imperatively after nav. Coordinate with 8.I: if 8.I flattens the nav and removes the popover entirely on desktop (the three media become inline appbar items), the dismissal logic only survives on breakpoints/sub-menus where a popover remains. Fix applies where the popover still exists.
- **Acceptance criteria:** Clicking a popover child (e.g. "Sessions") closes the dropdown; no dropdown floats after SPA navigation. Desktop and mobile both dismiss correctly.
**Completion note:** `DeepDrftMenu.razor.css` updated with a new `.dd-nav-item-collapsed` rule (scoped `.dd-nav-item-parent.dd-nav-item-collapsed .dd-nav-dropdown`) using `!important` to override both the `:hover` and `:focus-within` show rules. Razor state: collapse tracked in `private readonly HashSet<string> _collapsedDropdowns = []` keyed by `navPage.Route`; parent `<li>` gets the class via `_collapsedDropdowns.Contains(navPage.Route)`. Child link's `@onclick` calls `CollapseDropdown(navPage.Route)` (adds route to set); parent `<li>`'s `@onmouseleave` AND `@onfocusout` both call `ResetDropdown(navPage.Route)` (removes it). Per-parent keying enables multiple independent dropdowns; `@onfocusout` reset lets keyboard users re-enable dropdown without mouse pass. Mirrors existing `CloseMobileMenu` pattern. The dropdown no longer floats after SPA navigation; acceptance criteria met.
---
**8.L — Consolidate release name + track name for single-track releases**
- **What:** For single-track media (Session and Mix), the UI presents **a single name** (Release Name). The track name is **derived from it automatically** on save and kept synced — the admin never enters or sees a separate "Track Name" field. Cuts (multi-track) remain unaffected (separate release and per-track names). This is a consolidation: today these forms surface *two* name inputs for media with only one logical name.
- **Why:** A Session or Mix is a single work with one name. Surfacing a separate "Track Name" invites divergence (release "Lowcountry Live #3" whose track is "untitled-master-final") and a confusing authoring experience. The name consolidation removes that redundancy.
- **Shape:** On **create** (`BatchUpload`, single-track medium): the form presents one name field (Release Name, via 8.G rename); no separate Track Name input. On save, `_tracks[0].TrackName` is set equal to the Release Name. On **edit** (`BatchEdit`, single-track medium): the form presents one name field (Release Name); the per-row Track Name editor is suppressed (via a flag passed to `BatchTrackDetail`). On save, the track's `TrackName` is set equal to the (possibly edited) Release Name — they stay synced. Switching the medium selector mid-form re-drives which name fields are visible (one name for Session/Mix; release + per-track names for Cut) without losing entered data.
- **Acceptance criteria:** Single-track (Session/Mix) **create** path shows one name field (Release Name) with no separate Track Name input; on save, `TrackName == ReleaseName`. Single-track **edit** path shows one name field (Release Name); switching to Cut shows both; the form does not lose entered data on selector change. Track name stays synced with release name on edit (changing Release Name updates the track name). Cuts (multi-track) unaffected — Release Name and per-track Track Names are distinct. Legacy `TrackNew`/`TrackEdit` forms are **out of 8.L scope** (their retirement is 8.M). No public-site changes needed (public detail/gallery views already key off release title only).
**Completion note:** `BatchTrackDetail.razor` gained `[Parameter] public bool ShowTrackName { get; set; } = true;` and wraps Track Name `<MudTextField>` in `@if (ShowTrackName)`. `BatchUpload.razor` removes Track Name input on single-track branch, sets `_tracks[0].TrackName = _albumName` in `SubmitAsync` (after non-empty `_albumName` validation, before upload loop). `BatchEdit.razor` passes `ShowTrackName="@(!MediumRules.CardinalityOf(_medium).IsSingleTrack)"` to `BatchTrackDetail` and syncs `_tracks[0].TrackName = _albumName` in `SaveAsync`. The "is single-track" decision is driven by shared `MediumRules.CardinalityOf(_medium).IsSingleTrack` declaration (same one used by upload service and §9.7 invariant) — not a hardcoded Session/Mix check. Default `true` keeps Cut path and BatchUpload's Cut branch (passing no `ShowTrackName`) showing the field. No `MudForm`/`EditForm` wrapper exists, so hiding the field has no validation-deadlock effect. Single-track forms now present one name, consolidating two-field redundancy; Cuts unaffected with Release Name and per-track names distinct. Acceptance criteria met; Wave 8 track 8.L consolidates form UX to match single-track-per-medium design intent.
---
### 9.6 Wave 6 — Gap Closure
**Landed:** 2026-06-13 on dev.