Repository navigation
Commit 5a311a3
fix(plugin-form): merge
Fixes #9778
Clause-②: no
`object-form.customFields` now MERGES over the metadata-generated field
set, per the director-seat ruling on the card (batch #161 item 5, summon
#24, maintainer 「其他同意」 2026-09-18T12:07Z). The registration description
is the contract and is **unchanged**.
Clause-② tested against this diff, not inherited: the diff adds **0**
lines containing `export ` (lit control on the same corpus: 18 added
lines contain `customFields`) and no new key on any published payload —
an existing branch is made reachable. Answer stands at `no`.
## What changed
`ObjectForm.tsx`, three sites:
1. **The replace path is gone.** A non-empty `customFields` used to run
`setFormFields(schema.customFields.map(normalizeVisibility))` and return
above the metadata branch, so the object's schema was never even
fetched.
2. **The metadata is now fetched whenever an `objectName` and a data
source are present**, inline members or not — without the generated set
there is nothing to merge over, and the merge lookup
`schema.customFields?.find((f) => f.name === name)` stays the dead code
objectui#8071 measured. The members-only schema (an object with no
fields) became the **fallback** rather than the inline path's fixed
answer: it is what the registration's second sentence describes, "with
inline definitions and no data source, this becomes the only field
source".
3. **Members naming nothing in the generated set are appended** after
it, in authored order, right before `setFormFields(generatedFields)`.
Two smaller consequences, both deliberate:
- The loading flag no longer drops unconditionally on the inline path —
it drops when nothing is going to be fetched, otherwise the metadata
branch's own `willFetchData` tail clears it. Without this an empty
`form` sat on screen for the duration of `getObjectSchema`.
- A `getObjectSchema` that throws (or returns nothing) now falls back to
the members-only source **when inline members are present**, instead of
replacing a form that used to render with an error panel. The metadata
is an overlay on this path, not a prerequisite.
## The pins, one row per direction
`objectFormCustomFieldsMembers-8071.test.tsx` flips from pinning the
replace behaviour to pinning the merge:
| row | direction | asserts |
| --- | --- | --- |
| 1 | shape + merge | members are whole field definitions keyed by
`name`; the merged set is `customer, note, amount, zz` |
| 2 | **override** | a member takes the declared field's position,
supplies its whole definition, **and the metadata IS fetched** —
`getObjectSchema` inverted from `toBe(0)` to `toBe(1)` |
| 3 | **keep** | `customer` / `amount`, which no member names, still
render with the object's own labels |
| 4 | **append** | members naming nothing declared come after the
generated set, in authored order |
| 5 | (unchanged) | an EMPTY `customFields` is UNAUTHORED — the read is
`.length > 0`, not truthiness |
| 6 | (unchanged) | the same member count exempts the block from the
no-adapter panel; doubles as the control for the no-data-source sentence
|
One collateral red, repaired in place and called out here:
`ObjectForm.mobileFullscreen.test.tsx`'s "commits a fullscreen edit back
into the form state" mounts a `customFields` member named `summary`
against an object that also declares `changelog`, so the merge draws two
expand affordances and an unscoped `findByTestId` found both. The lookup
is now scoped to the field the case is about; nothing else in the file
moved.
## Reverse verification (ablation)
The fix was committed first, then `ObjectForm.tsx` alone was reverted to
this branch's base commit and the flipped pins re-run:
- mutation landed on disk: the `objectui#9778` markers went 5 to 0 and
the replace path
`setFormFields(schema.customFields.map(normalizeVisibility))` came back
(1 occurrence); blob `85d6c1c4` against HEAD's `cd4bd869`
- result: **4 failed | 2 passed (6)** — rows 1-4 red, each for its own
reason (`expected [ 'zz', 'note' ] to deeply equal [ 'customer', 'note',
'amount', 'zz' ]`; `expected +0 to be 1`; `expected null to be
'Customer'`; `expected [ 'zz', 'yy' ] to deeply equal [ 'customer',
'note', 'amount', …(2) ]`), rows 5-6 green as they should be, since
neither is about the merge
- restored by `git checkout HEAD -- ObjectForm.tsx` (trap-guarded,
absolute path): blob back to `cd4bd869`, `git diff HEAD` empty, markers
back to 5
## Tests
Run at `096496e052`:
- `pnpm --filter @object-ui/plugin-form test` — **100 files passed, 940
passed | 1 skipped (941)**
- `pnpm --filter @object-ui/plugin-form type-check` — exit 0 (`tsc
--noEmit` plus `tsconfig.test.json`), after `pnpm --filter
'@object-ui/plugin-form^...' build` — without that dependency-closure
build it reports `TS2307 Cannot find module '@object-ui/*'` on every
workspace import, which is a missing `dist`, not a type error
- consumers that pass `customFields` through: `packages/plugin-view/` +
`packages/plugin-designer/` + `registry-inputs-spec-parity.test.ts` +
`public-block-binding-reach.test.tsx` — **66 files, 757 passed**. The
fenced ledger's counts do not move, exactly as the dispatch predicted,
so it was **not edited**.
- gates, each exit code captured before any pipe: `check:control-bytes`,
`check:new-line-citations`, `check:changeset-claims`,
`check:pending-changeset-literals`, `check:test-path-roots`,
`check:vi-mock-specifiers`, `check:vi-mock-inherit`,
`check:vi-mock-override-shape`, `check:element-data-source-declaration`,
`check-changeset-presence.mjs`, `check-changeset-no-major.mjs` — all
exit 0. `eslint` on the three changed files: 0 errors (64 pre-existing
`no-explicit-any` warnings).
- `check:sdui-registration-pins` — **NOT MEASURED**: exit 2 is its own
prerequisite refusal ("No console build to weigh at
apps/console/dist/assets"), not a red. This diff adds and removes no
registration; CI builds the console and runs it.
## Acceptance notes
Out-of-scope findings, neither touched here:
1. **To file (class b).** The same registered description still
describes the drawer and modal presentations of this block, and both
still replace. `ObjectForm` spreads the schema — `customFields` included
— into `DrawerForm` / `ModalForm` for `formType: 'drawer' | 'modal'`,
and each of those runs its own `if (schema.customFields?.length) {
setFormFields(schema.customFields); }`. So an author who takes the
registration at its word gets a merge on the flat presentation and a
replacement on the other two, from one declared key. Out of this card's
file surface (the ruling names `ObjectForm.tsx`) and it needs its own
pins. Dedupe words: `DrawerForm customFields replace` · `ModalForm
customFields replace` · `presentation arms merge parity` · `formType
drawer inline fields` · `customFields merge unreachable`.
2. **Noted, not filed.** The console ledger entry for
`object-form.customFields` still describes the replace behaviour in
prose ("they REPLACE the metadata-generated set … `getObjectSchema`
asserted at zero calls … handed back as a finding rather than
repaired"). It is reviewed prose, not a computed assertion — its counts
do not move and its test stays green (measured above) — and the file is
held by open PR objectui#9924, so it was not edited. Successor: whoever
lands objectui#9924, or the next objectui#8071 slice that edits that
ledger.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01UanLVj6xvbS6puBCewLr8L
---
_Generated by [Claude
Code](https://claude.ai/code/session_01UanLVj6xvbS6puBCewLr8L)_
---------
Co-authored-by: Claude <noreply@anthropic.com>object-form.customFields over the metadata-generated field set (#9948)1 parent d6a8444 commit 5a311a3
5 files changed
Lines changed: 210 additions & 68 deletions
File tree
- .changeset
- packages/plugin-form/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
7 | | - | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | | - | |
| 15 | + | |
15 | 16 | | |
16 | | - | |
17 | | - | |
18 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
636 | 636 | | |
637 | 637 | | |
638 | 638 | | |
639 | | - | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
640 | 647 | | |
641 | | - | |
| 648 | + | |
642 | 649 | | |
643 | | - | |
| 650 | + | |
644 | 651 | | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
645 | 659 | | |
646 | 660 | | |
647 | 661 | | |
| |||
653 | 667 | | |
654 | 668 | | |
655 | 669 | | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
656 | 680 | | |
657 | 681 | | |
658 | 682 | | |
659 | 683 | | |
660 | 684 | | |
661 | | - | |
662 | | - | |
663 | | - | |
664 | | - | |
665 | | - | |
666 | | - | |
667 | | - | |
668 | | - | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
669 | 694 | | |
670 | | - | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
671 | 698 | | |
672 | 699 | | |
673 | 700 | | |
| |||
718 | 745 | | |
719 | 746 | | |
720 | 747 | | |
721 | | - | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
722 | 767 | | |
723 | | - | |
724 | | - | |
725 | | - | |
726 | | - | |
727 | | - | |
728 | | - | |
729 | | - | |
730 | 768 | | |
731 | 769 | | |
732 | 770 | | |
| |||
973 | 1011 | | |
974 | 1012 | | |
975 | 1013 | | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
976 | 1028 | | |
977 | 1029 | | |
978 | 1030 | | |
| |||
Lines changed: 9 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
49 | | - | |
| 49 | + | |
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| |||
239 | 239 | | |
240 | 240 | | |
241 | 241 | | |
242 | | - | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
243 | 250 | | |
244 | 251 | | |
245 | 252 | | |
| |||
0 commit comments