fix(plugin-grid): the record-detail date fallback threads the display locale (#4541) - #4552
Merged
Merged
Conversation
… locale (#4541) `renderRecordDetail`'s type-inference fallback called `formatDate(value)` with no options, so `formatDate` handed `Intl` an `undefined` tag — the MACHINE's locale, neither of the repo's two locale channels. On a zh console that one cell rendered `Mar 15, 2024` while every neighbouring date cell rendered `2024年8月15日`. This was the third `formatDate` site in the file; #4272 (PR #4544) ruled its plugin-grid surface to "ONLY the two date-cell call sites" (the two passing `'short'`), so this one was filed rather than fixed there. Pure consumption, not plumbing: the component already reads `useDisplayLocale()` at component level (PR #4544) and `renderRecordDetail` is a plain arrow in the component body that already closes over `tenantCurrency` from the same scope, so the call site simply gains `{ locale: displayLocale }`. Not memoized, so there is no dependency array to keep in step. Red-first: predicted 2 red + 1 green-both-sides, matched exactly. `en` and the runner's `en-US` are byte-identical on this branch, so the en case is a labelled PIN, not evidence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Collaborator
Author
|
PM step-7 复核 — ACCEPT (session_017Qqyix2QcnpUC9XeYVDzx3)
Auto-merge armed (squash) — landing verified per the merge-queue discipline. Generated by Claude Code Generated by Claude Code |
yinlianghui
marked this pull request as ready for review
August 13, 2026 08:23
This was referenced Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4541
ObjectGrid'srenderRecordDetail→renderFieldValueis type-aware first: when the object schema gives a key atypewith a registered cell renderer, that renderer draws the value. Everything else falls through to an inference fallback, whose date branch calledformatDate(value)with no options at all.formatDatethen handedIntlanundefinedtag, andundefinedis not "the user's locale" — it is the machine's, which is neither of the repo's two locale channels. On azhconsole this one cell renderedMar 15, 2024while every neighbouring date cell rendered2024年3月15日.This was the third
formatDatesite in the file. #4272 (PR #4544) ruled its plugin-grid surface to "ONLY the two date-cell call sites" — the two that pass'short'in the mobile card view, which shift by a constant −121 line offset — and this site does not fit that mapping, so #4544 filed it here rather than fixing it.The change
Pure consumption, not plumbing, exactly as the ruling sized it. The component already reads
useDisplayLocale()at component level (landed in PR #4544 for the two'short'cells), andrenderRecordDetailis a plain arrow declared in the component body — it already closes overtenantCurrencyfrom that same scope two branches below. Measured before implementing: the closure sees the hook value, so nothing needed lifting.packages/plugin-grid/src/ObjectGrid.tsxrenderRecordDetail's date-inference fallback — one call gains{ locale: displayLocale }No hook was added, and the function is not memoized, so there is no dependency array to keep in step. One resolver everywhere, unchanged:
useDisplayLocale()(tenant regional default → active UI language →'en').Red-first, and honest direction labelling
Predicted in writing before running anything, then run against unfixed code: 2 red, 1 green-both-sides. Actual matched per case.
Measured on the runner (node v22.22.2, TZ=UTC, machine locale
en-US) forformatDate's default branch:undefinedenzhde2024-03-15T12:00:00Mar 15, 2024Mar 15, 20242024年3月15日15. März 20242024-07-04T09:30:00Jul 4, 2024Jul 4, 20242024年7月4日4. Juli 2024enand the machine'sen-USare identical here, so theencase is a PIN — the byte-identical must-not-change half — and not red evidence that the fix works. It is labelled that way in the file rather than presented as proof. Every expectation spells'en'/'zh'/'de'explicitly; none is computed from a baretoLocale*call against the runner (the #4513 trap).The genuine reds, verbatim:
The tenant-over-UI-language precedence case uses
dedeliberately:15. März 2024matches neither the machine'sMar 15, 2024norzh's2024年3月15日, so it is genuinely red before the fix instead of passing by coincidence.Reverse verification took the fix out with a patch file plus
git checkout(nevergit stash), re-ran, got exactly the same 2 reds, and restored with a sha256-verified match onObjectGrid.tsx.Reaching the branch at all — the #4544 naming lesson, restated
PR #4544's grid suite had to name its columns like dates because the card view's
classify()routes bydateKeyssubstrings. The record-detail path has the same shape of trap in a different place, and both halves matter:data: { provider: 'value', items: ROWS }and nodataSource, soobjectSchemastays null and the field descriptor is undefined for every key. That is what skips the cell-renderer branch and drives the value into the inference fallback where this bug lives. Give the field a schematype: 'date'instead andDateCellRendererdraws it — a different, already-fixed path — and the suite would pin nothing.close_date(matchesdate) andsigned_at(matches_at) cover two of the branch's three spellings; a key such asclosed_onwould fall past the branch to the plainString()tail and render no date at all.Both fixture keys are deliberately non-system, and neither is a grid column, so the value reaches the DOM only through the detail panel. Assertions read
getByTestId('record-detail-panel').textContentrather than the container: the overlay is portaled, and a container-widetoContaincould otherwise be satisfied by an ordinary grid cell rendering the same date through the already-localized renderer — passing for the wrong reason.Verification
packages/plugin-gridsuite: 64 files, 595 tests, all passing — including fix(fields): the date formatter's last three en-US channels thread the display locale (#4272) #4544'smobileCardDateLocale.test.tsx, the fix(plugin-grid): the link column renders a real anchor when the host publishes record URLs (#4490) #4531ObjectGrid.linkCellAnchorpins androwCrudAffordances.type-checkgreen (bothtsc --noEmitandtsconfig.test.json).origin/mainbaseline: identical —ObjectGrid.tsx244 problems (0 errors, 244 warnings) both ways; the new test file adds 0. No new findings.check:control-bytesgreen, re-run after staging so the two new files were actually in the tracked scan (4274 → 4276 files); plus an explicitgrep -naPself-scan of all three touched files.check:phantom-depsandchangeset:check(fixed group + no-major) green.Changeset, by
.d.tsmeasurement@object-ui/plugin-grid— patch. Built both ways withdist/and the tsbuildinfo cleared between builds: all 28.d.tsfiles are byte-identical, aggregate98e66ae4d758494d29d8e0474d8153f568b585b0ced8768607bcb597f3d9eaa8before and after. Module-local, the #4496 precedent. Never major.Scope
Only the one call site plus its explanatory comment. The two #4544-threaded
'short'cells,LinkCell(#4531) and the kebab /rowCrudAffordancescode are untouched — the diff is 6 insertions / 2 deletions in one hunk.packages/fields(#4272, landed), data-objectstack/metadata-admin (#4271), studio inspectors (#4527), DashboardRenderer/ListView (#4528), plugin-kanban (#4254), plugin-gantt (#4542) andcontent/docs/releases/all untouched.No out-of-scope findings: the surrounding fallback's currency branch already threads
tenantCurrency, and the remaining branches are non-locale.Generated by Claude Code