refactor(web): all banners through the shared Banner component — success variant, non-dismissible, action slot, extra classes #289
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab!289
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/283"
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?
Closes #283
ErrorBanneralready rendered a dismissible banner witherrorandnoticevariants — yet 33 inline<div class="banner …">copies survived across the app shell, most routes and both settings trees. They existed because the component's API didn't cover what those sites needed: non-dismissible rendering, a success variant, and extra-class passthrough. So this extends the API to the needs actually found in the codebase, then migrates every copy.The API, extended (not forked)
variant'success'—role="status", like'notice'onDismissactionReset, paused-scheduleRe-enable, cloneRetry)classafk-strip-paused,clone-error)messagedeliberately stays astringprop and never becomes a JSX slot: text-only, never HTML, is the v0 sticky-banner property this component exists to guarantee. Banner bodies carry strings the app didn't write — git remote errors, agent output, server replies.Why
ErrorBanner→BannerThe issue allowed either extending
ErrorBanneror generalising to aBannerit delegates to. I renamed it (git mv, same file extended) rather than leaving a delegating alias: it renders the success variant now, and a component named for one of its three variants is what invited the 33 copies in the first place. Two names for one thing would leave every future author guessing which to reach for. All former call sites pass identical props under the new name.Migration
All 33 sites, grouped: app shell + top-level routes (6 files), repo/issue routes (7), repo-settings (10), global settings (4).
Markup is preserved byte-for-byte at every site — same classes in the same order, same
role, same text — so there is no visual change. Specifics worth reviewing:onDismisswas invented anywhere. Every migrated site had no dismiss button and still has none; the ~24 pre-existing dismissible sites keep theirs.<Match>wrapper (a<Switch>branch) is kept. An enclosing<Show>was collapsed only where its condition was exactly the message —<Show when={form.note()}>becomes<Banner message={form.note()} variant="success" />, sinceBannerdoes that truthinessShowinternally. Where the condition was something else (paused(),clone_status === 'error',repo.error !== undefined), the<Show>stays and the<Banner>goes inside it.Tests
New colocated
Banner.test.tsx(15 cases,SectionCard/FormCardstyle) pinning: variant and role asserted as one pair per variant (split assertions would pass while drifting apart); the text-not-HTML property (asserted viaquerySelector('b') === null, sincetextContentcan't tell an escaped<b>from a live one); absent-vs-disabled dismiss; exact class strings so order is the contract; and the action slot's position between text and dismiss.Verification
Full gate, locally, all green:
npm run lint— cleannpm run format:check— cleannpm test— 72 files, 1030 tests passing (was 71 / 1015 onmain; +15 from the new file, no existing test changed to accommodate the refactor)npm run build— succeedsgrep -rn 'class="banner' web/src --include=*.tsxoutside tests matches onlyBanner.tsxErrorBanneridentifier remains in the treeOne judgement call to flag
docs/adr/0019namesErrorBanner.tsxin its Status section, listing the files that ADR's diff touched at the time. I left it: an ADR is a historical record of a past decision, and rewriting it to sayBanner.tsxwould falsify what was true then. Happy to update it if this repo treats ADR file lists as a live index instead.[autoland] verdict: pass
PASS — verified against the green
ci / native (pull_request)aggregate (npm run lint, format:check, npm test, npm run build, plus the Go build/test/lint legs); no local re-run needed. ci-nix correctly did not run — it is path-gated on **/*.nix, flake.lock, go.mod, go.sum, none of which this diff touches.Conventions: Conventional Commits title,
Closes #283present, head branch afk/283, branch is a fast-forward of main (d4ea730) — no conflict.Diff scope matches issue #283's acceptance criteria, each verified:
actionslot andclasspassthrough — extended in place via git mv, not forked.The author's call to leave docs/adr/0019's Status file list naming ErrorBanner.tsx is right — that section records the diff that ADR shipped at the time, not a live index.