Repository navigation
fix(frontend): render every status badge with shared tones and labels - #1374
Conversation
Status badges picked their colors per page: "pending" was blue in RI exchange history and amber on Purchases, "running" was orange in one table and blue in another, and RI exchange printed the raw lowercase status. lib/status-badge.ts is the single place that maps a status from any API to a tone (success, warning, danger, info, muted) and to display text, plus helpers that render the shared .badge markup with the label escaped. Unknown statuses are muted, never green. It lives in lib/ rather than utils.ts because most suites mock utils wholesale. The callers move over in the next commit. Refs LeanerCloud#737 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plans, planned purchases, RI exchange history, registrations and the Purchases history now render `.badge .badge-<tone>` from lib/status-badge.ts, so the same status has one color and one label on every page (RI exchange shows "Pending", not "pending"). - components.css: one .badge pill whose tones come from base.css tokens (all >= 4.5:1). The .status-badge variants, the dead .badge-admin / -user / -readonly rectangles and the planned-purchases Bootstrap palette in tables.css are removed. The orange #ffe0b2/#e65100 pair (2.99:1) is gone. - Not-finished statuses (pending, notified, scheduled, running, processing) are amber everywhere, matching what the Purchases history already did; paused/canceled/expired/disabled are muted. - Plan "Manual" is info (blue) instead of the orange warning: it is a valid configuration, not a problem. - Planned purchase rows no longer tint all their text by status (a running row had blue text next to its badge); paused rows stay dimmed. - The Unsaved-changes pill and the provider-disabled banner use the warn tokens instead of two more ad-hoc amber palettes. Refs LeanerCloud#737 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reached
This review includes 18 billable files and costs up to $4.50. Or wait 59 minutes for your next included review. View limit details
Comment |
Conflicts: - frontend/src/riexchange.ts (renderExchangeHistory row): main (LeanerCloud#284) renders an empty payment_due as a dash instead of a lone "$"; this branch renders the status cell with statusBadgeHtml() instead of the removed getStatusBadgeClass(). Combined: main's payment_due cell plus this branch's shared status badge. - frontend/src/styles/components.css: main (LeanerCloud#318) added the .upfront-in-monthly / .upfront-in-monthly-note rules right above the "Purchase detail status badges" block that this branch deletes. Kept main's new rules and dropped the .status-badge.* block (nothing renders .status-badge any more; css.test.ts pins its absence). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts: - frontend/src/plans.ts: imports kept both (status-badge + main's purchase-row-guards). Planned-purchase status cell keeps main's LeanerCloud#181 layout (.status-badges wrapper, Overdue badge, .overdue-hint) with this branch's statusBadgeHtml(status) as the status pill; the Overdue badge is now badgeHtml('danger', 'Overdue', ...) instead of the retired .status-badge class. - frontend/src/riexchange.ts: imports kept both (skeletonText from main + statusBadgeHtml). History status cell uses statusBadgeHtml(rec.status) followed by main's LeanerCloud#1348 error line (.status-detail). - frontend/src/history.ts: imports kept both (status-badge + main's local-date). Semantic fixes in this merge: - __tests__/riexchange-audit-321.test.ts (main): expects the shared .badge.badge-danger with "Failed" instead of .status-badge "failed". - __tests__/css.test.ts: the retired-variant check is now /\.status-badge\b/ so main's LeanerCloud#181 .status-badges wrapper rule does not trip it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts: - frontend/src/riexchange.ts: import block. Main (LeanerCloud#1333) replaced the skeletonText import with showSkeletonText; this branch added the statusBadgeHtml import. Kept main's skeleton import and this branch's status-badge import. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts: - frontend/src/styles/components.css: main (LeanerCloud#1378 typography tokens) only swapped literal font weights for --cudly-fw-* tokens inside the .status-badge and .badge-admin/-user/-readonly rules, which this branch removes; kept the removal. In .badge kept this branch's line-height: var(--cudly-lh-tight) and white-space: nowrap together with main's tokenized font weight and radius. - frontend/src/styles/tables.css: main only tokenized the font weight of the planned-purchases Bootstrap badge palette, which this branch replaces with the shared .badge tones; kept this branch's .planned-purchase-row.status-paused dimming rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): APPROVE Blocking:
|
|
Local verification at
|
|
Marked ready and merged by IAmJSD's agent, at IAmJSD's request (IAmJSD reviewed the before/after screenshots; cristim is traveling), after the independent review and local verification above, all at |
Status badges came in four shapes with conflicting colors: "pending" was blue in RI exchange history and amber on Purchases, "running" was orange in one table and blue in another, there were four warning palettes (one at 2.99:1 contrast), and RI exchange printed the raw lowercase status. This PR adds one status-to-tone and status-to-label map and moves every status badge onto the same
.badgepill built from tokens.Closes #737
What changed
frontend/src/lib/status-badge.ts:statusTone(status)maps every status from every API to one of five tones (success, warning, danger, info, muted);statusLabel(status)gives display text (in_progress-> "In Progress",canceled/cancelled-> "Cancelled", otherwise title case);badgeClass/badgeHtml/statusBadgeHtmlrender<span class="badge badge-<tone>">with the label escaped. Unknown statuses are muted, never green.plans.ts(plan status, health, overdue, planned-purchase status),riexchange.ts(history status; the page-localgetStatusBadgeClassis removed),modules/registrations.ts, andhistory.ts(statusBadgeHTMLfolds the lifecycle onto a display status and calls the shared map, with the same tones and labels as before).utils.tsgetStatusBadgereturns a tone.components.csskeeps one.badgepill whose five tones come frombase.csstokens. Removed: the.status-badgevariants, the unused.badge-admin/-user/-readonlyrectangles, the planned-purchases Bootstrap badge palette intables.css, and the whole-row status text colors (only paused rows stay dimmed). The Unsaved-changes pill and the provider-disabled banner (settings.css) use the warn tokens too.status-badge.test.ts(33 tests), new badge class/label cases inriexchange.test.ts, and updatedplans,utils,css,xss-purchase-statustests andri-exchange-confirmation.spec.ts(expects "Completed" instead of "completed").Commits:
da125a8a(shared map),1c894d70(callers and CSS).Why this approach
The existing class names (
.badge,.badge-success/-warning/-danger/-info/-muted) are kept instead of the issue's BEM--variants, because.badge-*is already used across history, users, API keys and settings, plus about 20 tests; renaming would be churn with no visual gain. The map lives inlib/instead ofutils.ts(the issue's suggestion) because 16 suites mock../utilswholesale and would lose the new functions. Tone rule: anything not finished yet (pending, notified, scheduled, running, processing, partial) is amber, which is what the Purchases history, the most-used page, already did. Blue info is reserved for non-status tags. All five tone pairs meet 4.5:1 contrast.Screenshots
Before is main (
a14dc8f2), after is this branch. Both are headless Chromium at 1440x900 against the repo's mocked e2e API.Verification
Run on this branch's head
1c894d70on top of maina14dc8f2, fromfrontend/:npm run lint: 0 errors (142 warnings already on main, unchanged). Typecheck and build pass.--randomizeexceptriexchange.test.ts, which fails 29openExchangeModal/fillQuoteFromRItests under random order on maina14dc8f2as well (same seed, unchanged copy), so that is an existing order dependency.e2e-local.sh): 157/157 passed.scripts/test-git-secrets-allowlist.sh: 137 PASS.Notes for review
Design choices to check:
white-space: nowrap, so the planned-purchases Status column is a little wider.Not touched:
.badge-groupinusers/userList.tshas no CSS rule (it renders as an uncolored pill), and two#137333text colors insettings.cssare not badges.Overlaps
status-badge badge-dangernext to the planned-purchase status. After this branch it should becomebadge badge-danger, and its status cell markup will conflict inplans.ts.components.css/settings.cssrules; expect textual conflicts.history.ts/plans.ts/utils.tsnearby; chore(frontend): low-severity table and CSS hygiene fixes #725 and fix(frontend): coverage bars always green regardless of coverage #726 edittables.css.Note for the UI owner
This changes UI code that @cristim owns. IAmJSD reviewed the before/after screenshots and asked for it to be merged; any design point you disagree with can be a follow-up.
🤖 Generated with Claude Code