You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
SPA: render audit detailsJson as a readable per-key table instead of a raw tooltip #745
Follow-up named in #722's own mockup comment and recorded as unowned in that slice's design; filed late — #722 closed without it, caught by the owner.
What
web/src/routes/AuditPage.tsx:409 renders the audit payload as the row's raw title attribute:
<trkey={e.id}title={e.detailsJson??undefined}>
So a payload arrives as a single unformatted JSON blob in a hover tooltip — unselectable, unwrappable, unfilterable, and identical in all three locales because none of its keys are translated.
Why it matters now
#722 (merged, 97c866f) made these payloads worth reading. A SalesOrder.AddItem row now carries salesOrderItemId, productId, quantity, unitPriceMinorUnits, listUnitPriceMinorUnits, listPriceBasis, currencyCode and currencyMinorUnit; SalesOrder.UpdateItem adds a before/after pair. That is the data an investigator needs for the incident that opened #719 — and today the only way to read it in-app is to hover a row and squint at raw JSON.
The mockup on #722 (docs/images/discount-mockups/AuditRow.png) draws the intended readable table. #722's comment explicitly scoped it out: "today the SPA shows detailsJson as a raw JSON tooltip with no per-key renderer, so the readable table in the mockup needs a small follow-up."
Scope
Render detailsJson as a per-key table or definition list in the audit row's expanded state, not a title tooltip.
Money values need their denomination applied — the payload carries currencyCode and currencyMinorUnit precisely so a renderer does not have to guess.
Key names are currently English identifiers. Rendering them as labels makes them user-visible strings, which pulls in web/src/i18n and catalog parity for en/es/tl — that is the bulk of the work, and it is why Sales: record list/old/new price in the order-line audit payload #722 did not do it.
AuditPage.test.tsx already fixtures detailsJson: '{"count":5}', so there is a seam to build on.
Not in scope
The payload's shape. #722 fixed it and it is covered by mutation rows; a renderer reads it and does not change it.
Related: #747 — the payload this renderer consumes carries productId but no product name, while this mockup's Details column renders "Medium Eggs". Resolving the id live gives today's name, so a renamed product would make historical audit rows render a name the seller never saw. #747 adds the snapshot. This issue is not blocked on it — the renderer can show the id until the name exists.
Activity
mforce commentedon Sep 10, 2026
Related: #747 — the payload this renderer consumes carries
productIdbut no product name, while this mockup's Details column renders "Medium Eggs". Resolving the id live gives today's name, so a renamed product would make historical audit rows render a name the seller never saw. #747 adds the snapshot. This issue is not blocked on it — the renderer can show the id until the name exists.docs(audit): attach the 1:1 before/after capture for the Details colu…
feat(audit): show the sales-line audit payload as a readable Details …
docs(plans): commit the #722 and #745 design records
docs(plans): commit the #722 and #745 design records (#754)
feat(audit): carry the discount reason on the confirm audit row
fix(audit): show the price a line sold for, not its list price (#759)
chore(main): release 0.1.0 (#542)
feat(web): redesign Audit onto Concept C "Focus panels", expandable e…
feat(web): redesign Audit onto Concept C "Focus panels", expandable e…