Releases UI: redesign list + detail pages to match the other tabs, and fix the asset-upload crash ("Cannot set properties of null (setting 'value')") #270
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub#270
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Three problems in the releases surface: the list and detail pages don't match the design language of the sibling tabs, and asset upload crashes with a JS error toast.
1. Asset upload crash (the bug — smallest, fix first)
Uploading an asset shows a toast:
assetCannot set properties of null (setting 'value').Root cause:
web/src/pages/Release.jsx:70-85onFilereads and then resets the file input after an await:In SolidJS the event object's
currentTargetis nulled/recycled once the handler yields — after theawait,e.currentTargetisnull, and setting.valuethrowsTypeError, which thecatchreports with the"asset"prefix → the exact toast text.Fix: capture the input element in a
letref (let fileInput) and reset viafileInput.value = ""instead of the event object. Same class of bug may exist in otheronChangehandlers that touche.currentTargetafter an await — grep the pages for the pattern while in here.2. Releases list page doesn't match the sibling tabs
web/src/pages/Releases.jsxrenders a two-column layout (grid lg:grid-cols-[1fr_320px], :80) with a plaincard-listof tag-name rows and a Latest-release sidebar. Compare with the tabs it should match:Issues.jsx:62-77): page heading ("Issues", text-lg), filter row (state select, search input), toolbar buttons (Labels / Milestones / New issue) right-aligned with theprimaryCTA treatment, open/closed state chips.primary-styled, and rows show only tag/name/date/asset-count — no body excerpt, no draft/prerelease filter, no pagination affordance beyond a bare "more" button.Design direction (match the established language):
New releaseasbtn primary, keep refresh.ReleaseBadgeschips (exists), release name as the primary text (currently the reverse — tag dominates, name is muted meta), body excerpt (first line/plain-text ofbody), asset count, publish date via<DateTime>. Draft/prerelease filter chips (all / drafts / prereleases) client-side over the loaded page — no new endpoint.Emptycomponent) already exists and is fine — keep.3. Release detail page doesn't match either
web/src/pages/Release.jsx:100-148renders tag + badges + rendered body in one card with a button row (edit / publish / delete / refresh) inline beneath the notes. Issues to align:h1is the tag in mono; the release name is anh2below. Compare Repo/Issue pages where the human title leads. Suggest: name ash1(fallback to tag when unnamed —ReleaseNewalready defaults name to tag), tag + badges + date as the meta row.ml-autorefresh. Match the issue detail's affordance placement (actions grouped top-right or under the header per the repo's established pattern) and use thedangertreatment consistently for delete (it exists —btn danger— but sits mid-row).data-tableor the card-list conventions), and a clearer upload affordance (button + drop hint) with a busy state that reflects upload progress (currently the whole page'sbusyflag disables buttons but gives no progress indication for large files — client hashes via crypto.subtle before streaming, which can take seconds on big assets with zero feedback).Acceptance criteria
pnpmheadless tests still green (update any snapshot/assertions the redesign touches).Fix is up: #279 (branch
fix/issue-270, web-only, no new endpoints/deps). Crash fixed via captured input ref (+ page audit clean); list/detail redesigned per the issue with Latest folded into the first row.node --test548/548 green,vite buildclean. One gap: the shared CDP daemon here rejects target creation and tab attach, so the zero-console-error browser pass (list/detail/upload incl. crash scenario, both themes) still needs a reviewer with a working browser daemon — noted in the PR description.Review of PR #279 (fix/issue-270, commit
af27b50+ review fixupe40b31d):CRASH FIX — correct. onFile captures the input synchronously (const input = e.currentTarget) and uploadFile never touches the event object; reset happens on the captured element in .finally with setUpload(null)/setBusy(false) in uploadFile's own finally (web/src/pages/Release.jsx:82-113). Audit of other async event handlers (IssueNew onPaste/onDrop extract files + preventDefault synchronously before await; Pull/ReleaseNew/Commit/Import/Keys only preventDefault before await) confirms the author's no-other-after-await claim — nothing missed.
LIST — matches Issues language: Releases h2 + right-aligned Refresh + primary New release (toolbar kept on the empty page too, superseding the #50 one-CTA rule — documented); All/Drafts/Prereleases pills (role=group, aria-pressed, counts) filter the loaded page client-side via filterReleases (no new endpoint); rows are name-led divider rows with tag mono, badges, excerptBody excerpt, asset count + DateTime; Latest folds into the matching first-page row only (filter==all, no cursor, tag match — no duplication with the old sidebar, which is deleted per the #35 supersede note); Older pagination; Empty kept for both empty and filtered-empty states.
DETAIL — name-led h1 with tag fallback, meta row (tag mono + badges + DateTime + author + short tag sha), regrouped actions (Edit / Publish primary when draft / Delete danger / Refresh), composer-section edit form (IssueNew/PullNew convention), assets as data-table (icon/name-link/size/short-sha + download/delete, overflow-x-auto) with staged Hashing…/Uploading… role=status affordance. Page pre-hashes via sha256Hex (web/sdk/src/releases.js) and passes the digest so the SDK skips its internal hash — verified SDK accepts {sha256}. No new deps, no new endpoints. Dark+light classes throughout (.pill/.chip/.btn danger/btn-active/data-table all exist in ui.css/base.css).
DOC — 12_web_ui.md REDESIGNED (#270) entry accurate, incl. #35/#50 supersede notes.
REVIEW FIXUP (pushed
e40b31d): removed dead 'let fileInput' + ref={fileInput} — Solid ignores non-function refs so it never assigned; the event-capture is the real fix. Doc wording aligned.VERIFY: node --test web/test/unit/*.test.js 548 pass / 0 fail; vite build clean (504 kB chunk-size warning only, pre-existing). Browser run explicitly skipped per instructions (node tests + reasoning only).
RECOMMENDATION: ready to merge.
Fixed by PR #279 incl. review dead-ref fix (upload crash fixed + audit clean, Issues-parity list/detail; 548/548), merged. Closing.