Skip to content

feat(web): compact two-line History rows on phones - #983

Merged
mforce merged 3 commits into
mainfrom
feat/980-history-phone-rows
Sep 28, 2026
Merged

mforce merged 3 commits into
mainfrom
feat/980-history-phone-rows

Conversation

@mforce

@mforce mforce commented Sep 27, 2026

Copy link
Copy Markdown
Owner

Below the 900px switch, History drops its ten-column ledger for one two-line button per entry. Fifteen rows fit a 390x844 screen where six did, and the row's actions moved into a Details dialog behind a tap instead of sitting off the right edge. Desktop keeps the full table unchanged.

Closes #980

What changed

Phone (below md/900px). One <ul> of two-line rows, each a ButtonBase with aria-haspopup="dialog", a 44px floor and the row's own text as its accessible name. Line 1 is date, flock and the app's dot-plus-label status. Line 2 is total, the cracked/dirty/discarded triple and deaths, with the figures in <strong>. Voided rows stay muted. Filters, summary and "load more" are untouched.

The Details dialog. The app's own Dialog, carrying Cracked, Dirty, Discarded, Condition, Graded and the record-history line, with the row's actions at the bottom: Audit history (admins), edit (editable drafts), adjust and void (admins, correctable rows). The close X is the header's. Tap, Enter and Space all open it; Escape closes it and focus returns to the row.

Dialog gained compactTitle. h4 instead of h2, still an <h2> element and still the dialog's accessible name. At 390px the h2 scale wraps "09/24/2026 · Sim House B" onto two lines and pushes the record's own values off the first screenful.

ProvenanceCell split into ProvenanceCell + ProvenanceSummary. The dialog's History line is the same fact as the desktop column's, so it reuses the component rather than re-deriving #494/#653's created-vs-changed rule. The cell's white-space: nowrap stays conditional on the same provenanceFacts(...).empty the summary reads, so nothing moves on desktop.

docs/designs/822-mui-revamp.md row: "Ledger (#831: Sales, Stock, Inventory, History, Expenses, plus Feed, Water, Reports)" (line 234). Everything here is a reuse of Dialog, FieldConsole's CONSOLE_LINK_SX, statusCell's dot-plus-label treatment, FarmDate, ProvenanceSummary and MD_UP_QUERY — no new component.

Decisions taken

  • One rowActions(e) helper drives both surfaces' gates. The desktop Actions cell and the phone dialog render different layouts from the same three booleans, so a role gate cannot drift between them. Mutating any of the three turns both test files red.
  • Both corrections close Details rather than stacking on it. Adjust reopens the same entry in a form, and a stale Details behind it would show pre-adjust numbers on close. Stated cost: the void's per-row busy spinner has no home on the phone, so the phone shows only the page's success or error line. busy still makes every mutating control inert, so a double-submit is impossible.
  • rowSummary is one <Trans> key per locale, so word choice and order stay the translator's; <strong> marks only the figures. count is the mortality number and drives the plural, so a single death reads "1 death" (same shape as dashboard:trendDayTip).
  • The phone list is a <ul aria-label={t("title")}>. It gives assistive tech a row count and the harness a catalog-keyed locator, instead of a class the feat(web): convert the Dashboard and app shell to MUI (#829) #883 selector guard would have to police.
  • Help and the glossary are unchanged, deliberately. The three mistakesRow*Fix strings say "History → adjust"; they name a screen and a control, not a layout, and both still exist under those labels at both widths. No new domain concept appeared, so specs/product/GLOSSARY.md has nothing to gain.
  • The Status column's GlossaryLink is desktop-only. The phone list has no header row to hang it on, and adding one would cost the vertical space this issue exists to reclaim.

Tests

Measured on this machine, not recalled.

suite base a5f159c1 head 9bbdc95f
web vitest 148 files, 3632 tests, all green 149 files, 3646 tests, all green
Playwright quick suite (both projects) — 124 passed, 1 skipped

New: web/src/routes/HistoryPage.phone.test.tsx (13 cases), one case in Dialog.test.tsx, one @phone case in phone.spec.ts. HistoryPage.test.tsx gained stubMatchMedia(true) in its beforeEach — every case in that file is about the desktop ledger, and jsdom's missing matchMedia would otherwise resolve them to the phone branch. Its 81 cases are otherwise untouched and green.

Mutation checks

Each mutation was applied to the source, the named spec run, and the source restored.

mutation result
isDesktop = true (phone branch never taken) RED — 11 phone unit cases
isDesktop = false (desktop branch never taken) RED — "keeps the desktop ledger above the boundary"
viewHistory: isAdmin → true RED — 2 cases across both files
correct: isAdmin && correctable(e) → isAdmin RED
edit: status === "Draft" && flockEditable(e) → true RED
row loses aria-haspopup="dialog" RED
deaths reads discardedEggs RED
details dialog's onClose becomes a no-op RED
adjust stacks on Details instead of replacing it RED
Dialog's returnFocusTo.current = null RED
compactTitle ignored (variant="h2") RED
count={2} (plural never selected) RED
phone row py: 1 → py: 2.5, rebuilt image RED — "only 10 History rows fit between the top of the screen and the tab bar"
isDesktop forced true, rebuilt image RED — all three History @phone specs

The first attempt at "adjust stacks on Details" survived: MUI marks a lower dialog aria-hidden, so queryByRole("dialog", { name }) could not see a stacked one and passed either way. The assertion now counts getAllByRole("dialog", { hidden: true }).

Deletions and harness

No CSS class, component or i18n key was deleted, so no deletion grep was needed. Two harness edits follow from the change:

  • phone.spec.ts's overflow walk measures role=list[name="Daily entry history"] at /history instead of role=table — that route renders no table at 390 any more.
  • mutation-check.sh's phone-mui-table-overflow-unclipped expectation lost its /history line for the same reason; /customers still carries the kill.

Verification

Isolated sim stacks on port 8180, never the shared cluckwork-sim project: cw980b built at a5f159c1 for the before frames, cw980a at this head for the after frames and the Playwright run. Both torn down with down -v.

Desktop pixel-identity is argued from the diff plus the suites rather than a byte comparison: the two stacks seed independently, so their Graded column lists grades in a different order and a pixel diff would be noise. The desktop branch's JSX is unchanged except two pure extractions (lossList(e), gradeList(e)) and the gate expressions routed through rowActions(e); the 81 existing desktop cases, ledger-theme.spec.ts, table-cell-first-column-inset.spec.ts and manager.spec.ts all pass untouched, and the 1280 frames are attached for eyes.

Below the 900px switch History renders one two-line button per entry instead of
the ten-column ledger: twelve rows fit a 390x844 screen where five did, and the
row's actions moved into a Details dialog behind a tap rather than sitting off
the right edge. Desktop is unchanged.

Closes #980
@mforce

mforce commented Sep 27, 2026

Copy link
Copy Markdown
Owner Author

Screenshots

Before frames from cw980b built at a5f159c1; after frames from cw980a built at this branch's head. Same farm (default-farm), same route, same viewports, 1:1, no downscaling.

History list at 390x844, scrolled to the end of the page

Before — light After — light
Six History rows at 390px, each three lines tall; the Graded and action columns sit off the right edge Fifteen two-line History rows at 390px, each showing date, flock, status and the totals line
Before — dark After — dark
The same six-row ledger at 390px in dark mode The same fifteen two-line rows at 390px in dark mode

The Details dialog at 390x844 (after only — this is what the change adds)

Submitted row — light Submitted row — dark
Details dialog titled 09/24/2026 · Sim House B on one line, listing Cracked, Dirty, Discarded, Condition, Graded and History, with Audit history, adjust and void at the bottom The same Submitted details dialog in dark mode
Draft row — light Draft row — dark
Details dialog on a Draft row, Condition showing an em dash, offering Audit history and edit and no correction actions The same Draft details dialog in dark mode

Desktop at 1280x800, light — unchanged

Before After
The ten-column History ledger at 1280px The same ten-column History ledger at 1280px

The two stacks were seeded independently, so the Graded column lists the same grades in a different order between these two frames. Nothing else differs.

After frames captured at 9bbdc95.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

web: compact two-line History rows on phones with a tap-to-open details dialog

1 participant