From 73d9428e5d2d9c84fa4be190a2aab0aef916ed1d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 18 May 2026 23:22:01 +0000 Subject: [PATCH] feat(ui): D.5c migrate Patches per-group sections to DeviceRack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR 8 of 16 in the UI consistency overhaul. Patches section follows the Mix Chain (D.5b / PR #73) shape — each processing-stage group becomes a ; the progress badge becomes a . Branched off main. Single-file PR — AnalysisResults.tsx. Migration: - Per-group
+

heading → . - patches-applied-progress: hand-rolled span → . data-testid preserved. Also includes a bug fix carried over from D.5b: the `name` prop is now a JSX fragment instead of a template literal. groupIcon('BASS PROCESSING') returns an SVG node; template-literal interpolation stringified it to "[object Object]" — visually broken in production AND a hidden test regression that PR #73 narrowly avoided because the Patches section still rendered the raw

with the SVG, satisfying analysisResultsUi.test.ts:448's `/lucide-audio-waveform[\s\S]{0,200}BASS PROCESSING/` regex via Patches alone. Migrating Patches in this PR would have removed the last unbroken match site and failed the test — so both Mix Chain and Patches now use the JSX-fragment form and the SVG renders in both groups as intended. Deferred (same scope as D.5b): - Per-card
outer wrapper NOT migrated to . The card has rich state-dependent styling (bg-bg-card hover, conditional border-l-2 for applied, overflow-hidden) that would need Panel extensions. - AppliedCheckbox NOT migrated to Radix Checkbox primitive (would change green→orange palette; existing button has equivalent a11y). Preserved verbatim: - data-testids: patches-applied-progress, applied-checkbox, patch-headline-*, citation-row-*. - Visible text: group names + emojis/SVG, "applied", "Sources", Transcription-derived, etc. - The exact `grid gap-4 grid-cols-1 sm:grid-cols-2` className (now appears in both Mix Chain and Patches racks, still ≥2 occurrences per analysisResultsUi.test.ts:440). - All data-text-role attributes. - CitationBlock + CitationHeadline internals. Verified: lint clean, 628/628 unit tests passing (including analysisResultsUi.test.ts which now correctly asserts both the grid className AND the lucide-audio-waveform SVG class for BASS PROCESSING), build clean (AnalysisResults chunk 254 KB / 63 KB gz). https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe --- apps/ui/src/components/AnalysisResults.tsx | 52 +++++++++++++++------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/apps/ui/src/components/AnalysisResults.tsx b/apps/ui/src/components/AnalysisResults.tsx index 322626fa..e6c46f81 100644 --- a/apps/ui/src/components/AnalysisResults.tsx +++ b/apps/ui/src/components/AnalysisResults.tsx @@ -2041,11 +2041,19 @@ export function AnalysisResults({ + {groupIcon(group.name)} {group.name} + + } status="idle" > {/* Audit-preserved annotation paragraph kept here so @@ -2200,12 +2208,13 @@ export function AnalysisResults({ rightSlot={
{audioContentHash && patchAppliedCount > 0 && ( - {patchAppliedCount} of {patchCards.length} applied - + )}
@@ -2218,14 +2227,23 @@ export function AnalysisResults({ bass patch without scanning all 8 cards. */}
{patchGroups.map((group) => ( -
-

- {groupIcon(group.name)} {group.name} -

- + SVG) renders as a real React node — the + // template-literal version stringifies it to "[object + // Object]" and analysisResultsUi.test.ts:448 fails. + name={ + <> + {groupIcon(group.name)} {group.name} + + } + status="idle" + > + {/* Keep the exact className — analysisResultsUi.test.ts:440 + expects ≥2 occurrences of `grid gap-4 grid-cols-1 + sm:grid-cols-2` across Mix Chain + Patches. */}
{group.cards.map((patch) => { const isOpen = !!openPatch[patch.id]; @@ -2342,7 +2360,7 @@ export function AnalysisResults({ ); })}
-
+ ))}