Skip to content

fix(plugin-grid, plugin-detail): a returnType currency formula reads as money in list cells and on the record page - #27689

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-34d66a
Oct 29, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-34d66a

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

Requested by Bill · project thread

Fixes #27494

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:列表网格的三条列构建路径和记录页的字段补全,现在把公式字段声明的 returnType 一并传给单元格;returnType: 'currency' 的公式(如演示应用的「Budget Remaining」)按货币显示 $180,000.00,与旁边的货币列一致。
  • 为什么改:公式单元格本来就会把声明为 currency 的结果交给货币单元格渲染,但列表和记录页在重建字段时只挑了 currencyConfig、scale 等键,漏了 returnType,单元格以为是未声明类型的数字,显示成裸数字 180,000.00。
  • 风险与回滚:只多传一个已有的 spec 键,共 4 行;不新增格式化函数、不改 spec、不改服务端;声明 number 或未声明的公式照旧显示数字。回滚即 revert 本 PR。
  • 先看:ui/packages/plugin-grid/src/objectGridGenerateColumns.tsx(三处 fieldMeta.returnType)→ ui/packages/plugin-detail/src/fieldEnrichment.ts(ENRICHED_FIELD_METADATA_KEYS 加 returnType)→ 新测试 gridFormulaCurrency-27494.test.tsx。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/plugin-grid/src/__tests__/gridFormulaCurrency-27494.test.tsx packages/plugin-detail/src/__tests__/formulaReturnTypeRelay-27494.test.tsx,预期 13/13 通过。
  • 需要你做的:无,席位落地。

What changes

FormulaCellRenderer (the table face) and FormulaField (the form face) already draw a formula declaring returnType: 'currency' through the currency field's own faces (CurrencyCellRenderer / CurrencyField, formatCurrency), reading the formula's own currencyConfig. The renderers were never reached with that key: the hosts that rebuild a field bag from a picked key list carried currencyConfig and scale but not returnType. The cell then saw an undeclared formula holding a JS number and drew the number face at scale: 2, which is the 90,000.00 the card reports beside $150,000.00.

  • plugin-grid, objectGridGenerateColumns.tsx. The three configured-column paths (ListColumn objects, a string column list, inline rows with a fields projection) now copy returnType verbatim beside currencyConfig into the cell's fieldMeta. The auto-generated (object-schema) path already hands the whole def and is unchanged.
  • plugin-detail, fieldEnrichment.ts. ENRICHED_FIELD_METADATA_KEYS, shared by DetailSection, HeaderHighlight and the summary chips, gains returnType, so a section entry naming the field ({ name }) reaches the formula cell with its declared type. A view entry that declares its own returnType still wins (the list's existing fill-the-gaps rule). The list is not exported from the package entry, so no published surface moves.
  • No second money formatter, no spec change, no new key: returnType and currencyConfig are the spec's existing formula keys (spec: a formula field cannot declare a currency result — returnType is number | text | boolean | date, so a formula over money renders as a bare number #22727).

Tests

  • New ui/packages/plugin-grid/src/__tests__/gridFormulaCurrency-27494.test.tsx, under a EUR tenant so the $ can only come from the formula's own fixed currencyConfig: on each of the three configured paths, the currency formula reads $90,000.00 beside the currency field's $150,000.00; controls, a returnType: 'number' formula at scale: 2 reads 1,234.50 and an undeclared formula reads 4,321; every formula cell reads what the whole-def FormulaCellRenderer reads; the auto-generated columns are the reference face.
  • New ui/packages/plugin-detail/src/__tests__/formulaReturnTypeRelay-27494.test.tsx: the fixture is a spec-valid formula def (FieldSchema.safeParse); enrichDetailField copies returnType and a view-entry one wins; DetailSection draws $90,000.00 beside $150,000.00, and a number formula stays 1,234.50.

Acceptance notes

Verification

Live console, Showcase → Projects (fresh boot, 1440×900)

Branch console (ui/apps/console vite) against the branch's objectstack dev --seed-admin --fresh. Rows read from the list's table, columns Budget / Budget Remaining:

  • grid fix ablated (the three fieldMeta.returnType copies renamed through ablation-replace --hold): $600,000.00 / 180,000.00, $50,000.00 / 2,000.00, $200,000.00 / 200,000.00
  • this branch: $600,000.00 / $180,000.00, $50,000.00 / $2,000.00, $200,000.00 / $200,000.00

Restored after the reading: blob == HEAD, git diff HEAD empty.

Ablation (each fix removed, then restored)

@object-ui/* resolves to source in ui vitest, so no rebuild between legs.

  • Grid: node scripts/ablation-replace.mjs --file ui/packages/plugin-grid/src/objectGridGenerateColumns.tsx --anchor "fieldMeta.returnType = " --expect 3 --replacement "fieldMeta.ablated27494 = " -- …gridFormulaCurrency-27494.test.tsx. Landed: anchor 3 → 0, blob 90f02baa3e9c → 6aac6616f1bb. Red: Tests 6 failed | 4 passed (10), the three "reads as money" cases and the three agreement cases, with grid cells ["1Open","Tower","$150,000.00","90,000.00","1,234.50","4,321"]; the four controls and the reference stayed green, as predicted. Restored: blob == HEAD, git diff HEAD empty.
  • Detail: --file ui/packages/plugin-detail/src/fieldEnrichment.ts --anchor " 'returnType'," --replacement " 'ablated27494',". Landed: anchor 1 → 0, blob 910282667aac → 35f03459ed4a. Red: Tests 2 failed | 1 passed (3) (expected undefined to be 'currency'; section text …remaining90,000.00…). Restored: blob == HEAD, git diff HEAD empty.

A first grid leg was refused by the tool (ANCHOR AMBIGUOUS, nothing written) and re-run with --expect 3; the reading above is the second run.

Tests, type-check and gates

All on the merged head 0191a4f9 (origin/main merged once, no file of plugin-grid, plugin-detail or fields moved by it; @objectstack/spec rebuilt after the merge).

  • pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-grid/ packages/plugin-detail/ → Test Files 595 passed | 1 skipped (596), Tests 5347 passed | 18 skipped (5365) (lock VERDICT command-exit 0).
  • pnpm --filter @object-ui/plugin-grid run type-check → exit 0; pnpm --filter @object-ui/plugin-detail run type-check → exit 0 (each runs tsc --noEmit && tsc -p tsconfig.test.json).
  • Derived gates (node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack): 34 derived, 34 run, every one exit 0, reconciled with --ran (0 NOT-MEASURED, 0 UNRUN). node scripts/check-sdui-manifest.mjs and its --self-test are among them. pnpm check:type-check-debt first answered exit 3 (PREREQUISITE NOT MET: its closure build queued behind this branch's own test run on the shared lock) and was re-run alone under the lock: exit 0, 0 ledger entries above their recorded number. pnpm --dir ui exec vitest run scripts/ → Test Files 169 passed | 2 skipped (171).
  • pnpm check:new-line-citations (ui) → 0 new citations.
  • The families CI runs over the whole tree (the type-check lanes, Lint UI, Test UI, Build & E2E UI) are this PR's check-runs.

Generated by Claude Code

The three configured-column paths rebuilt the cell's field bag from a
picked key list that carried currencyConfig and scale but not returnType,
so a returnType 'currency' formula drew the number face.

Claude-Session: https://claude.ai/code/session_01Utp6CYFYwzxE4fR2Vr1sQo
Co-authored-by: Claude <noreply@anthropic.com>
Adds returnType to ENRICHED_FIELD_METADATA_KEYS, with tests for the grid
and the detail section, and a changeset.

Claude-Session: https://claude.ai/code/session_01Utp6CYFYwzxE4fR2Vr1sQo
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Oct 29, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

席位核对

ACCEPT · head 0191a4f9f2d1b670fd98c8334e05cfc1ddb3cd09 · 2026-10-29T18:24Z

  1. Shape: draft → main, Fixes #27494 + Refs #27430 (row 1 only), attribution block on top. The PR has five files: plugin-grid/src/objectGridGenerateColumns.tsx, plugin-detail/src/fieldEnrichment.ts, two new tests and one changeset. It has no assignee and no reviewer.
  2. Premise measured:
    • The dev measured the served metadata, and it carries returnType, currencyConfig and scale. FormulaField / FormulaCellRenderer already draw currency.
    • The defect was upstream: the grid's three configured-column paths and the record page's ENRICHED_FIELD_METADATA_KEYS rebuilt the field from a picked key list without returnType.
    • The seat read the diff: four statements forward returnType verbatim beside currencyConfig. There is no new formatter and no second rule, as triage 6495354739 requires ("uses the currency field's existing currency face").
    • Live: the Projects list read 180,000.00 with the grid fix ablated, and $180,000.00 on the branch.
    • No packages/spec/** path and no server file.
  3. Gates (check-runs on this head): 44 success, 11 skipped, 0 red.
    • Named runs: Lint & Repo Gates 123641034623, TypeScript Type Check 123642012016, Test UI 123645460480, Lint · PM dispatch-gates 123637443180.
    • The dev's derived gates were 34/34 exit 0 and --ran 0 NOT-MEASURED.
    • The full plugin-grid and plugin-detail test directories pass: 595 files, 5347 tests.
    • Ablations went red (grid 6/10, detail 2/3) and were restored.
  4. Contract review: not owed. Clause-②: no: ENRICHED_FIELD_METADATA_KEYS and the grid's column builder are not reachable from either package's entry, so no exported shape changes. Metadata-protocol: none.
  5. Accepted deviations / out of scope:
  6. Landing: not governed (check-governed-merges --pr 27689: NOT governed, 0 of 5 paths), 281 lines < 3000. The seat lands it: ready + auto-merge now.

Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/m tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

1 participant