Repository navigation
fix(fields): a formula reads one stored value the same in the form and in the cell (objectui#11748) - #11751
Merged
Conversation
…d in the cell (objectui#11748) FormulaField (the read-only form face) and FormulaCellRenderer (the table cell) each formatted the value themselves. Both now read one rule -- the declared returnType, or with none a JS number as a number and anything else as text -- and draw each type through the calls the matching field type's faces make: formatNumberFieldValue for numbers, the locale's Yes / No word for booleans (only a JS boolean), and formatDate's default face for dates, in both faces. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8
…and text (objectui#11748) FormulaField read `value == null` and printed `String(value)`, so an empty string or empty list drew a blank span with no accessible name, and an expanded record printed `[object Object]`, where the formula cell draws the shared empty affordance and the record's name. The form face now takes the same floor (`isEmptyValue` on the coerced value) and prints the coerced text, as the cell does. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
… (objectui#11748) The patch round the claim amendment added. Prose only; no source or test file changes. - `@object-ui/types`: the doc comments on `FormulaFieldMetadata.returnType` and on the form field's `returnType` member no longer describe the retired two-decimal face. They state the one rule both formula faces read: a number formatted as a `number` field formats it, the UI language's Yes / No word, `formatDate`'s default face, text in monospace, and with no `returnType` a JS number as a number and anything else as text. - `content/docs/fields/formula.mdx`: the Return Types list and the Cell Renderer section, which said two decimal places and monospace. - `content/docs/fields/summary.mdx`: the Cell Renderer comment, false since objectui#11683 (the summary cell reads `15,750.5`, not monospace). - `.changeset/11748-formula-faces.md`: adds `'@object-ui/types': patch` and one sentence on the doc comments; "grouped" becomes "formatted", because a declared `scale: 0` reads ungrouped (`2026`) in both faces. Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
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 #11748
Clause-②: no
A formula's value now reads the same in the read-only record form and in a table cell. Implemented by session
session_01CGZy1BGCjdN5cXqL9cnvB8(seatdomain:ui#3, round 1, claim comment 6027067109).What changed
FormulaField(packages/fields/src/widgets/FormulaField.tsx, the read-only form face) andFormulaCellRenderer(packages/fields/src/index.tsx, the table face) now read one rule. Each type is drawn through the calls the matching field type's faces make. Both edits sit inside the claim's file surface.returnType. With none, a JS number is a number and any other value is text. That is the rule objectui#11683 gave the cell, now read by the form too. No type is inferred from the expression.formatNumberFieldValue, the call the number cell andNumberField's read-only branch make. That gives the locale's grouping and the width a declaredscalesets. The form face no longer callstoFixed(2). The form now reads the value the way the cell does: blank is empty, and a numeric string under a declarednumberis a number.common.yes/common.noword. Only a JS boolean is a boolean, as inBooleanField's read-only branch (objectui#8593) andBooleanCellRenderer(objectui#8582). Any other value drawsEmptyValue. The form face used to read truthiness, so the string'false'said Yes.formatDate's default face (see the next section). A falsy or unparsable value drawsEmptyValue, with the sametoDisplayDateguard asDateField's read-only branch.text-smspan, as the field widgets' read-only branches do. In the cell, the date istabular-nums, the boolean word is a plain span, and the number isNumberCellRendereras before.6865bcd(the patch round the claim amendment added; no source or test file changed). Each statement was measured against this branch's code, which that commit does not change, with a throwaway component probe that was never committed.packages/types/src/field-types.tsandpackages/types/src/form.ts: the doc comments onFormulaFieldMetadata.returnTypeand on the form field'sreturnTypemember said "a number to two decimals, ... anything else as text (the default when it is absent)". They now state the rule above for both faces. Both ship in the@object-ui/typesdeclarations, so the changeset adds'@object-ui/types': patch.content/docs/fields/formula.mdx: the Return Types list said two decimal places, and text as the default with noreturnType. The Cell Renderer section said the cell is monospace. Both now describe this rule.content/docs/fields/summary.mdx: the Cell Renderer comment said the summary cell reads15750.5in monospace, which has been false since objectui#11683. It now says15,750.5(en-US) through the number cell, not monospace. Measured in en-US and zh-CN on this branch..changeset/11748-formula-faces.md: adds'@object-ui/types': patchand one sentence on the doc comments. In the number line, "grouped" becomes "formatted", because a formula declaringreturnType: 'number'andscale: 0reads2026, not grouped, in both faces.summaryOperationscomment inform.ts("countas it arrives, the other four to two decimals") is unchanged. It describes theSummaryFieldwidget, which neither this PR nor objectui#11683 touched, and it is still true there.The rule is written out in both modules. The barrel and the lazily loaded widget may not import each other (the reason
number-format.tsgives). A shared helper module would be a new file outside the claim, so the equality leg of the new pin file keeps the two copies in step.No export, prop or language-pack key is added. The diff adds or removes no
exportline, and both component signatures are unchanged.summaryis still registered toFormulaCellRenderer. It declares noreturnType, so it stays on the no-returnTyperule.The date face: the choice the card left to this PR
Both faces use
formatDate's default face. It readsJul 4in the current year andJul 4, 2020otherwise, or7月4日/2020年7月4日in zh-CN. Neither face uses the date cell's relative default (Today,2 days ago).Why: the
datefield itself has two faces. Its cell defaults to the relative style, and its read-only form face isformatDate's default. Only the default face exists on both surfaces, so it is the only choice where one stored value reads the same in the form and in the cell. It is also the faceFormulaFieldalready drew (objectui#8194), and the date cell's own fallback outside the plus-or-minus seven day window.Cost: within seven days of today, a formula date column reads
Jul 4where a date column beside it reads2 days ago. A pin covers this case ("inside the relative window, the cell keeps the default face").The boolean face
The cell draws the word, not
BooleanCellRenderer's checkbox. The card's Done-when names "the translated Yes / No" for both faces. A checkbox has no text that could match the form's word.Bounded fix inside the claim: the text arm and the empty floor
A component probe on
dd82d4ameasured three more divergences, all on a formula with noreturnType(form face, then cell):—affordance;nameof Ada:[object Object], thenAda.In commit
da0652cthe form face takes the cell's floor (isEmptyValueon the coerced value) and prints the coerced text. All four conditions for a bounded fix hold:Pins (en-US and zh-CN, measured on
textContent)New:
packages/fields/src/__tests__/formulaFaces.returnType-11748.test.tsx, 96 tests. Each session sets both the UI language and the display locale, throughI18nProviderandLocalizationProvider.returnType: 'number'reads200,000, not200000.00;returnType, a JS number reads200,000;scale: 2reads200,000.00, and a fraction reads1,234.5;200.000;200,000, and whitespace draws the affordance, not0;returnTypestays monospace text.Yes/Noand是/否, equal toBooleanField's read-only word, with no monospace;'false','true',0and1draw the affordance;returnType: 'text'overtruereadstrue.Jul 4, 2020/2020年7月4日, equal toformatDate's default and toDateField's read-only face, with no monospace;Jul 4/7月4日while the date cell reads its relative phrase.textover a number stays monospace200000.returnType, value) rows in each of the two sessions. The form's text must equal the cell's text, not a literal, so a change that moves only one face goes red.Updated:
packages/fields/src/widgets/__tests__/formula-summary-spec-reads-11070.test.tsx.'3.00'pin asserted the retiredtoFixed(2)face. It now asserts a numeric string:1,234.5under a declared number,1234.5with none.return_type-retirement control now uses a numeric string. A JS number no longer separates "read" from "ignored", because both read3.Premise check, on
db4cb6bbefore any editThe new pin file ran against unchanged code and failed 51 of 86 tests (35 passed). In the form it read
200000.00,200000and1234.50. In the cell it readtrue(en-US and zh-CN) and2020-07-04, all in monospace. In the form, the string'false'underreturnType: 'boolean'drew a word, not the affordance.Measured, on head
da0652cpnpm exec vitest run --maxWorkers=2 packages/fields/src/widgets/Test Files 112 passed (112),Tests 1051 passed (1051)pnpm exec vitest run --maxWorkers=2 packages/fields/src/__tests__/plus the 9 test files directly underpackages/fields/src/Test Files 127 passed, 1 skipped (128),Tests 2768 passed, 7 skipped (2775)pnpm --filter @object-ui/fields type-checktsc --noEmit && tsc -p tsconfig.test.json;--listFilesOnlyon the test program lists both changed test filespnpm exec vitest run --maxWorkers=2over 49 consumer files (below)Test Files 49 passed (49),Tests 1030 passed (1030)pnpm exec eslinton the 4 changed source filespnpm check:control-bytes/check:test-path-roots/check:changeset-claims/check:pending-changeset-literals/check:new-line-citations/check:vi-mock-specifiers/check:comment-mask-corpus/check:esm-specifiers/check:self-import/check:phantom-deps/check:unreferenced-sourcescheck:changeset-claims: "No pending changeset names a file this change touches."check:new-line-citations: 0 new citationsnode scripts/check-changeset-presence.mjs/-no-major/-fixed/-overwritepnpm --workspace-concurrency=2 --filter '@object-ui/fields^...' builddd82d4a; no dependency changed after itThe two package-suite halves together cover all 240 test files under
packages/fields(119 + 112 + 9). The suite was split because a single run held the lock for 9 minutes 5 seconds ondd82d4a(exit 0, 239 passed and 1 skipped), too close to the foreground cap.Consumer selection: every test file under
apps/console,packages/app-shell,packages/components,packages/reactandpackages/plugin-*that contains the wordformula(agit grep -l -i), less metadata-admin and plugin-designer. That is a declared narrowing: the public surface is byte-unchanged, so the rest of the farm is left to CI. Heavy runs went throughos-verify-lock.sh, and the times above are shared-box times.NOT MEASURED:
check:eager-closure: PREREQUISITE NOT MET, because it needs a builtapps/consolebundle. The barrel's imports are unchanged.FormulaFieldnow also importsnumber-format.js,coerceToSafeValue.jsand core'sisEmptyValue, and all three are already in the barrel's eager closure.check:readme-exports: exit 1 with "404 self-import(s) could not be judged", because nodisttype entries are built. This gate is only owed when exports change, and none did.Ablation (one-time proof; no permanent test added)
Each mutation was made from a committed head through
ablation-replace.mjs, which ran the new pin file and then restored the file. Every restore was proven: blob equal toHEAD, and an emptygit diff HEAD. The pins import the units by relative path (../index,../widgets/FormulaField), so the ablations readsrc, anddistis not involved.DateCellRenderer(the relative face)dd82d4aformatNumberFieldValue(num, field, locale)becomesnum.toFixed(2)dd82d4aString(value)dd82d4aisEmptyValue(safe)becomesvalue == nullda0652cEach direction was predicted before its run. Past-year dates stay green under the first mutation because the relative face falls back to the default face outside its window.
Acceptance notes
content/docs/fields/summary.mdx, in its "Cell Renderer" section, said the summary cell renders "monospace text: 15750.5", which has been false since objectui#11683. It was corrected in commit6865bcd(see What changed). The summary field's own two faces still disagree (the form widget printstoFixed(2)). That is filed as objectui#11752. (Edited bydomain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, after the patch round.).changeset/11683-formula-datetime-cell-text.mdsays any other declaredreturnType"is drawn as before". This PR makes that untrue forbooleananddate. Rather than edit another card's entry, this PR's changeset says so in its last paragraph.FormulaCellRendererunder "the floor exactly", with a note about its number arm. Past the floor, the new boolean and date arms also draw the affordance for a non-boolean or unparsable value. The table is now incomplete but not false. It sits outsideFormulaCellRenderer, so it was left alone.NumberField's read-only branch prints it as it arrives, andNumberCellRendererformats it. A formula declarednumberfollows the cell's reading in both faces, so the formula's two faces agree. The number field's own split belongs to that field, not to this card.returnTypehas no currency member.Generated by Claude Code