Uh oh!
There was an error while loading. Please reload this page.
refactor(plugin-grid,core): the bulk dialog's data-source rule derives from core, not a fourth private copy - #5314
Merged
os-support-ai merged 1 commit intoAug 19, 2026
Conversation
…s from core, not a fourth copy (#4815) `bulkParamToField` held a private `DATA_SOURCE_WIDGET_TYPES` — the fourth hand-maintained answer to "which widget must be handed a DataSource", and the only one matching none of the other three. It now reads `@object-ui/core`'s `EXPANDABLE_FIELD_TYPES` through one predicate, feeding all three consumers of the rule. No reachable behaviour change: `tree` (the one cell the two tables differed on) can never be a widget key here — it is absent from the fields widget map and resolves to `lookup` — and the form-only widget-hint pickers are deliberately NOT absorbed, since pulling them in would change which widgets get a DataSource. Pinned by identity, not membership: a spy on the `has` of core's exported Set, so a member-identical private copy fails the test.
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
os-support-ai
marked this pull request as ready for review
August 19, 2026 13:20
Uh oh!
There was an error while loading. Please reload this page.
os-support-ai
deleted the
claude/issue-4815-data-source-widget-types-convergence
branch
August 19, 2026 13:22
This was referenced Aug 19, 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 freeto 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#4815
packages/plugin-grid/src/components/bulkParamToField.tsheld its ownDATA_SOURCE_WIDGET_TYPES— the fourth hand-maintained answer to one question ("which widget has to query records, so it must be handed a DataSource and a reference target"), and the only one whose member set matched none of the other three. Nothing anywhere could detect the drift. Same shape as the convergences #4770 and #4790 each landed on another surface.Verified on current
origin/main(de4e29a) rather than taken from the card: theownercell is already gone (#4814 / PR #4915 —USER_WIDGET_TYPESreadsnew Set(['user'])with a tombstone above it), so the remaining ask was exactly the convergence.What changed
One definition. The reference half is no longer restated here:
widgetNeedsDataSource()readsEXPANDABLE_FIELD_TYPESfrom@object-ui/core— the same object the$expandbuilder, the predicate-record projection and the object form'sneedsDataSourceWiringalready read. All three consumers of the rule now go through that one predicate:isLookupishParamBulkActionDialogfieldNeedsDataSourcedataSourceprop threaded into the widget (BulkActionDialog.tsx:600)bulkParamToFieldreference_to/display_fieldbranch of the field shapepackages/core/src/utils/expand-fields.tsgains the fourth consumer in its "one family, N consumers" TSDoc, so the shared table names every surface that reads it.No reachable behaviour change — which is why the changeset is
patch, and it is the roll-back clause taken seriously rather than assumed:treeis the one cell where the two tables differed, and it can never be a widget key on this path: it is absent from the fields widget map andmapFieldTypeToFormTypesends it tofield:lookup, so atreeparam reaches the rule aslookup. Counter-probed (0 hits fortreeinfieldWidgetMapwhilelookup/master_detail/usergive 3 from the same extraction) and pinned by a test, so if someone ever registers a realtreewidget this flips loudly instead of silently.object-ref/filter-condition/recipient-picker— widget hints no object schema can declare and no bulk param produces. Absorbing them would change which widgets receive a DataSource here: a behaviour change, not a convergence. finding(plugin-grid):DATA_SOURCE_WIDGET_TYPES是「哪些 widget 要 DataSource」的第四份私有副本 —— 与表单规则不同集、零 gate #4815's own analysis is the spec for that cell, and a test pins it shut.The pin is an identity pin
expect(...).toEqual([...])on the members would have passed against exactly the defect this PR removes — four copies that happen to agree today — so it would have been worse than no test. The pin instead spies on thehasof the Set object core exports and asserts this module called that object.Proved to discriminate, not assumed. Reverse verification ran two legs, each predicted before running and matched exactly:
Tests 2 failed | 13 passed—expected [] to include 'lookup'new Set([...EXPANDABLE_FIELD_TYPES]), members equal by construction)Tests 2 failed | 13 passed— same twoLeg B is the one that matters: every membership-shaped assertion in the file stayed green against that copy, which is the empirical version of "a value-equality assertion reports a convergence that isn't there".
Stated rather than counted: the other 3 new assertions are green on both legs by design. They pin the normalization contract (every core member is closed under
resolveBulkParamWidgetType) and the two deliberate boundaries above — they guard a future widening, not this convergence.Rebuild question, per leg: no build artifact sits between any edit and the runner. The canonical invocation (
pnpm exec vitest run ...from the repo root, which is what CI shards) loads the rootvitest.config.mts, whoseresolve.aliasmaps@object-ui/coretopackages/core/src; the test importsbulkParamToFieldby a relative specifier. Proved directly rather than read off the config: withpackages/core/distmoved aside entirely the run is still 15/15 green. Both red legs above are therefore self-proving — they could not have gone red unless the edit reached the runner. The pin also holds under the other resolution regime (a package-cwd run, where@object-ui/coreresolves through package exports todist): 15/15.Verification
All at
455a274f6, after the final commit:pnpm exec vitest runover the 8 affected files (bulk param + dialog params/record/multiple/fanout, core expand-fields + unmaterialized-fields, the form's data-source wiring): 8 files / 80 tests passedpnpm --filter @object-ui/plugin-grid --filter @object-ui/core type-check: bothDone(script name echoed, so it is not a zero-match silent pass)eslinton the three changed files: 0 errors (5 pre-existingno-explicit-anywarnings on untouched lines)check:control-bytes,check:phantom-deps,check:self-import,check:esm-specifiers: pass; plus a direct control-byte scan of the changed filesOut of scope, filed not fixed
paramToFieldis now the LAST private copy of the reference-bearing rule — and its "moves in lockstep with plugin-grid" comment stopped being true #5312 —app-shell'sparamToFieldis now the last private copy of this rule, and its "moves in lockstep with plugin-grid's twin" comment stopped being mechanically true the moment this PR landed the twin on core. Asymptomatic today, same reason as here. Outside this PR's file surface.assertCanonicalVitestInvocationdoes not cover the 11 packages that own avitest.config.ts— measured: a package-cwd run inplugin-gridis NOT refused #5313 —assertCanonicalVitestInvocationdoes not cover the 11 packages that own avitest.config.ts; measured, a package-cwd run inplugin-gridis not refused, contradicting the guard's own coverage claim.Generated by Claude Code
Generated by Claude Code