Fix #270: releases UI redesign + upload crash #279

Merged
crueber merged 2 commits from fix/issue-270 into main 2026-09-10 11:53:41 +00:00
Owner

Fixes #270 (three parts: upload crash, list redesign, detail redesign — web-only, no new endpoints, no new deps).

Crash (§1): Release.jsx onFile reset the file input via e.currentTarget after the upload await; Solid nulls currentTarget on yield → TypeError toasted as assetCannot set properties of null. Now captures the input in a let fileInput ref, resets the captured element in a finally. Grep audit of all pages: no other e.currentTarget-after-await handler (remaining uses are synchronous).

List: single-column like Issues — Latest sidebar deleted (folded into the first row: latest chip + key-asset quick-downloads), heading + toolbar (Releases h2, Refresh, primary New release), All/Drafts/Prereleases client-side pills (filterReleases, counts), name-led divider rows (tag mono, badges, excerptBody excerpt, asset count, DateTime), Older pagination, Empty kept (+ filtered-empty text).

Detail: name-led h1 (tag fallback) + meta row (tag/badges/date/author/sha), regrouped top-right actions (Edit / Publish primary / Delete danger / Refresh), composer-section edit form, assets as data-table with staged Hashing→Uploading role=status + drop zone (page pre-hashes via sha256Hex, digest passed through so the SDK skips its internal hash).

Decisions (docs/go/12_web_ui.md same change): #35 sidebar deleted; #50 one-CTA rule superseded (toolbar CTA always, Issues parity).

Tests: node --test web/test/unit/*.test.js 548/548 pass (incl. 6 new filterReleases/excerptBody cases); vite build clean; served bundle contains all new strings, zero stale sidebar refs. Live API seed verified (push tags → PUT releases → POST asset → list/latest shapes). Browser drive BLOCKED: shared obscura CDP daemon rejects target creation (/json/new empty) and the existing tab refuses attach (No page for session) — no console-error pass possible from here; needs a reviewer with a working browser daemon (list, detail, upload incl. crash scenario, both themes).

Fixes #270 (three parts: upload crash, list redesign, detail redesign — web-only, no new endpoints, no new deps). **Crash (§1):** `Release.jsx` `onFile` reset the file input via `e.currentTarget` after the upload await; Solid nulls `currentTarget` on yield → TypeError toasted as `assetCannot set properties of null`. Now captures the input in a `let fileInput` ref, resets the captured element in a `finally`. Grep audit of all pages: no other `e.currentTarget`-after-`await` handler (remaining uses are synchronous). **List:** single-column like Issues — Latest sidebar deleted (folded into the first row: `latest` chip + key-asset quick-downloads), heading + toolbar (Releases h2, Refresh, primary New release), All/Drafts/Prereleases client-side pills (`filterReleases`, counts), name-led divider rows (tag mono, badges, `excerptBody` excerpt, asset count, DateTime), Older pagination, Empty kept (+ filtered-empty text). **Detail:** name-led h1 (tag fallback) + meta row (tag/badges/date/author/sha), regrouped top-right actions (Edit / Publish primary / Delete danger / Refresh), composer-section edit form, assets as data-table with staged Hashing→Uploading `role=status` + drop zone (page pre-hashes via `sha256Hex`, digest passed through so the SDK skips its internal hash). **Decisions (docs/go/12_web_ui.md same change):** #35 sidebar deleted; #50 one-CTA rule superseded (toolbar CTA always, Issues parity). **Tests:** `node --test web/test/unit/*.test.js` 548/548 pass (incl. 6 new filterReleases/excerptBody cases); `vite build` clean; served bundle contains all new strings, zero stale sidebar refs. Live API seed verified (push tags → PUT releases → POST asset → list/latest shapes). Browser drive BLOCKED: shared obscura CDP daemon rejects target creation (/json/new empty) and the existing tab refuses attach (No page for session) — no console-error pass possible from here; needs a reviewer with a working browser daemon (list, detail, upload incl. crash scenario, both themes).
Crash first (12_web_ui REDESIGNED entry): Release.jsx onFile reset the
file input via e.currentTarget after the upload await; Solid nulls
currentTarget on yield, so the reset threw and toasted
'assetCannot set properties of null'. Capture the input in a let ref
and reset the captured element in a finally. Audit: no other
e.currentTarget-after-await handler in the pages.

List: single-column like Issues (Latest sidebar deleted, folded into the
first row as latest chip + key-asset quick-downloads), heading + toolbar
(Releases h2, Refresh, primary New release), All/Drafts/Prereleases
client-side pills (filterReleases), name-led divider rows with tag mono,
badges, excerptBody excerpt, asset count, DateTime, Older pagination,
Empty kept. Detail: name-led h1 + meta row, regrouped actions
(Edit/Publish primary/Delete danger/Refresh), composer-section edit
form, data-table assets with staged Hashing/Uploading status + drop
zone (page pre-hashes via sha256Hex and passes the digest through).

Decision: #35 sidebar deleted (duplicated first row); #50 one-CTA rule
superseded (toolbar CTA always, Issues parity). No new endpoints, no
new deps.
Release.jsx captured the upload input synchronously from the event
(const input = e.currentTarget) but also carried a dead 'let fileInput'
with ref={fileInput} - Solid ignores a non-function ref, so it never
assigned. Remove both; the event-capture + finally reset is the fix.
Doc entry said 'let fileInput ref'; now matches the code.
Sign in to join this conversation.
No description provided.