Repository navigation
fix(app-shell): format currency, number and percent values in the record history Changes entry - #27638
Conversation
…ord history Changes entry Route numeric field types in auditHistoryDisplay formatScalar through the field renderer's own formatters (formatCurrency + resolveFieldCurrency, formatNumberFieldValue, formatPercent + percentCellScale), so the History tab reads a stored amount the way the record page does. Claude-Session: https://claude.ai/code/session_01Utp6CXcn7RbCYknff87Ke1 Co-authored-by: Claude <noreply@anthropic.com>
…geset Claude-Session: https://claude.ai/code/session_01Utp6CXcn7RbCYknff87Ke1 Co-authored-by: Claude <noreply@anthropic.com>
…llers Claude-Session: https://claude.ai/code/session_01Utp6CXcn7RbCYknff87Ke1 Co-authored-by: Claude <noreply@anthropic.com>
…i/fields Claude-Session: https://claude.ai/code/session_01Utp6CXcn7RbCYknff87Ke1 Co-authored-by: Claude <noreply@anthropic.com>
|
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh |
|
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh Contract reviewServed-tier: Face: declaration only ( ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh 席位核对ACCEPT · head
Generated by Claude Code |
Requested by Bill · project thread
维护者速读
4321000),改为与记录页同样的格式(如$4,321,000.00)。ui/packages/app-shell/src/utils/auditHistoryDisplay.ts的formatNumericAmount;ui/packages/fields/src/index.tsx新增的formatNumberFieldValue导出。pnpm --dir ui exec vitest run packages/app-shell/src/utils/__tests__/auditHistoryDisplay.numericAmounts-27486.test.ts,预期 12 passed。Fixes #27486
Clause-②: no
Metadata-protocol: none
What changes
auditHistoryDisplay.tsformatScalar()gains an arm forcurrency,numberandpercentfields. A finite stored value (a JS number, or a decimal column's numeric string) is formatted by the calls the record page's cells make, by reference:currency:formatCurrency(value, resolveFieldCurrency(def, ctx.tenantCurrency), ctx.locale), the pairCurrencyCellRendereruses.number:formatNumberFieldValue(value, field, ctx.locale), the callNumberCellRendererandNumberField's read-only branch make (declaredscale,useGrouping).percent:formatPercent(value, percentCellScale(def), resolveFieldScale(...), ctx.locale), the pairPercentCellRendereruses (declared storage and width).A value that is not a number keeps the existing
String(value)face.AuditFieldDefdeclares the members those formatters read (scale,max,useGrouping,currencyConfig), so the arm needs no cast.AuditValueFormatContextgains an optionaltenantCurrency, the last step ofresolveFieldCurrency's precedence.@object-ui/fields:formatNumberFieldValueis exported from the package entry (it was module-internal), and itslocaleparameter is optional likeformatCurrency's andformatPercent's. No rendering change there.ui/scripts/__tests__/percent-storage-callers-11475.test.ts: the repo-wide pin over everyformatPercentcaller gains the new call's row (storagepercentCellScale(def), field in hand). The pin went red on the first gate run because the population on disk grew by this file, which is its job.patchfor@object-ui/app-shelland@object-ui/fields.Currency modes, measured against
resolveFieldCurrencyfixed: the declared code. The card'sshowcase_account.annual_revenueisfixedUSD, so its repro now reads$4,321,000.00.dynamic: the tenant default when the caller passestenantCurrency; without it, the formatter's no-code face (a plain grouped number at width 2), never a guessed symbol.record(ADR-0144 D2): the code lives in a sibling field of the row.formatAuditValueis called once per side with no row, so the resolver answers no code, and the amount reads as a plain grouped number. The tenant default is never substituted (the resolver's own rule). No hard-coded code, no second formatter.Tests
ui/packages/app-shell/src/utils/__tests__/auditHistoryDisplay.numericAmounts-27486.test.ts, 12 cases: currency (fixed USD both sides, JPY width, de-DE locale, numeric string, dynamic with and without a tenant default, record mode), number (declared scale, scale-0 year ungrouped, de-DE, non-numeric value), percent (fraction storage, whole storage viamax, de-DE). Each states the record page's text as a literal and checks the shared formatter returns the same.Acceptance notes
RecordDetailView's History effect builds the format context as{ t, locale: displayLocale, lookupLabels }. It does not passtenantCurrency, so adynamic-mode currency field still reads as a plain number in history while the record page shows the tenant symbol. The one-line fix (tenantCurrencyfromuseLocalization().currency) is inRecordDetailView.tsx, which this card's order puts out of bounds (the record-page chain). Listed for the seat in the report.old_value/new_value) handed to the formatter; that is a caller change too. Not attempted.auditHistoryDisplay.tsand its tests, the@object-ui/fieldsexport, the changeset); it is the registration that pin requires of any newformatPercentcaller, and is declared as a deviation in the report.String(value)); they pin that the arm keeps those faces, not that it fires.Verification
Local runs, head fded0c5
pnpm --dir ui exec vitest run packages/app-shell/src/utils/__tests__/: Test Files 28 passed, 1 skipped; Tests 433 passed, 8 skipped.pnpm --filter @object-ui/app-shell run type-check(both tsconfigs) andpnpm --filter @object-ui/fields run type-check: exit 0.scripts/ablation-replace.mjs): the arm'sreturn formatNumericAmount(...)disabled, the new file reads 10 failed, 2 passed; restored, blob equals HEAD andgit diff HEADis empty.dispatch-gates --commands, 34 commands,check-sdui-manifestincluded) run on fded0c5, each exit 0, includingpnpm --dir ui exec vitest run scripts/(Test Files 169 passed, 2 skipped; Tests 4902 passed, 2 skipped).dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED.pnpm --dir ui run check:new-line-citations: 0 new citations.Generated by Claude Code