Skip to content

Commit 784e3f0

Browse files
committed
docs(spec): the bulk path now carries a promoted lookup param's picker settings
The bulk adapter's toBulkParam forwards lookupFilters, lookupColumns, lookupPageSize and descriptionField since the plugin-grid fix landed, so the BULK_PARAM_WIDGET_CONFIG_KEYS JSDoc, its refusal prescription, the list.bulkActionDefs liveness row and the v18 migration entry stop saying they are dropped. idField / titleFormat still do not travel. Prose only; the accept set does not change. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzh5MQsqK7dBe3KZ9Aa
1 parent d745bb5 commit 784e3f0

4 files changed

Lines changed: 29 additions & 24 deletions

File tree

‎packages/spec/liveness/view.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@
195195
"bulkActionDefs": {
196196
"status": "live",
197197
"evidence": "packages/spec/src/ui/bulk-action.zod.ts",
198-
"note": "objectui: ListView.tsx:1343 forwards rich defs to ObjectGrid (BulkActionDialog). Dispatch: useBulkExecutor.ts run() — per-record fan-out by default; execution:'aggregate' defs go through the ONE-call bulkCall branch injecting params._selectedIds (ObjectGrid.runBulkActionAggregate, objectui#3139). Verified objectui@4bf612c. #4457 gave the def a SHAPE (it was z.record(z.any())): the entry schema is BulkActionDefSchema, strict, and it refuses the combinations that parse but the executor never reads — so this row's liveness now covers the keys inside a def, not just the array. A PROMOTED def's field-backed params (packages/spec/src/ui/bulk-action.zod.ts; moved out of spec source, #23434): resolved when the dialog opens by objectui main @dca25aff2 packages/plugin-grid/src/resolveBulkActions.ts#resolvePromotedBulkParams through `resolveActionParams` (objectui 29b99490), then renamed onto the bulk vocabulary by the same file's #toBulkParam, which carries the field's type, translated label, options, required, description, placeholder, defaultValue, multiple, `dependsOn`, `accept` and `maxSize` (plus a reference-bearing field's reference and display field) and drops the lookup settings. An authored param's `options[]` entries (packages/spec/src/ui/bulk-action.zod.ts, the `.passthrough()` rationale; moved out of spec source, #23434): objectui @b9814b334 packages/plugin-grid/src/components/bulkParamToField.ts#bulkParamToField spreads each entry into the field metadata (`options?.map(o => ({ ...o, value: String(o.value) }))`), so every extra key reaches the widget, whose option vocabulary is objectui @b9814b334 packages/types/src/field-types.ts#SelectOptionMetadata, extending objectui @b9814b334 packages/types/src/select-option.ts#SelectOptionBase (`color`, `visibleWhen`, `disabled` and `icon` beyond the pair); the select cell reads `option?.color` in objectui @b9814b334 packages/fields/src/index.tsx#SelectCellRenderer. The renderer's own param type now agrees: objectui @b9814b334 packages/types/src/objectql.ts#BulkActionParam types an `options` entry open (an index signature, citing objectstack#4001), where the source's sha-less reading had it closed (`Array<{ label; value }>`). Re-read 2026-10-15, first cited by line, sha-less."
198+
"note": "objectui: ListView.tsx:1343 forwards rich defs to ObjectGrid (BulkActionDialog). Dispatch: useBulkExecutor.ts run() — per-record fan-out by default; execution:'aggregate' defs go through the ONE-call bulkCall branch injecting params._selectedIds (ObjectGrid.runBulkActionAggregate, objectui#3139). Verified objectui@4bf612c. #4457 gave the def a SHAPE (it was z.record(z.any())): the entry schema is BulkActionDefSchema, strict, and it refuses the combinations that parse but the executor never reads — so this row's liveness now covers the keys inside a def, not just the array. A PROMOTED def's field-backed params (packages/spec/src/ui/bulk-action.zod.ts; moved out of spec source, #23434): resolved when the dialog opens by objectui main @dca25aff2 packages/plugin-grid/src/resolveBulkActions.ts#resolvePromotedBulkParams through `resolveActionParams` (objectui 29b99490), then renamed onto the bulk vocabulary by the same file's #toBulkParam, which carries the field's type, translated label, options, required, description, placeholder, defaultValue, multiple, `dependsOn`, `accept` and `maxSize` (plus a reference-bearing field's reference and display field) and that field's lookup settings `lookupFilters`, `lookupColumns`, `lookupPageSize` and `descriptionField`, which reach the selection bar's picker as they reach the single-record dialog's (objectstack#26951); `idField` / `titleFormat` are still not carried. An authored param's `options[]` entries (packages/spec/src/ui/bulk-action.zod.ts, the `.passthrough()` rationale; moved out of spec source, #23434): objectui @b9814b334 packages/plugin-grid/src/components/bulkParamToField.ts#bulkParamToField spreads each entry into the field metadata (`options?.map(o => ({ ...o, value: String(o.value) }))`), so every extra key reaches the widget, whose option vocabulary is objectui @b9814b334 packages/types/src/field-types.ts#SelectOptionMetadata, extending objectui @b9814b334 packages/types/src/select-option.ts#SelectOptionBase (`color`, `visibleWhen`, `disabled` and `icon` beyond the pair); the select cell reads `option?.color` in objectui @b9814b334 packages/fields/src/index.tsx#SelectCellRenderer. The renderer's own param type now agrees: objectui @b9814b334 packages/types/src/objectql.ts#BulkActionParam types an `options` entry open (an index signature, citing objectstack#4001), where the source's sha-less reading had it closed (`Array<{ label; value }>`). Re-read 2026-10-15, first cited by line, sha-less."
199199
},
200200
"conditionalFormatting": {
201201
"status": "live",

‎packages/spec/src/migrations/entries/semantic/18.ui-bulk-action-param-unknown-keys-refused.ts‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ export const entry: SemanticMigration = {
3434
+ 'the picker knobs `lookupFilters` / `lookupColumns` / `lookupPageSize` / '
3535
+ '`descriptionField` / `picker` / `subtitle` / `avatarField` / `idField` / `allowCreate`) '
3636
+ 'is answered with one prescription naming `FieldSchema` as the shape those keys are real '
37-
+ 'on, and saying that of them only `accept` / `maxSize` declared there reach this dialog, '
38-
+ 'through a promoted action. `dependsOn` needs NO edit — it is declared, in the same '
37+
+ 'on, and saying that of them only `accept` / `maxSize` and the picker settings '
38+
+ '`lookupFilters` / `lookupColumns` / `lookupPageSize` / `descriptionField` declared there '
39+
+ 'reach this dialog, through a promoted action. `dependsOn` needs NO edit — it is declared, in the same '
3940
+ 'shape the field-level key takes (`[\'parent\']`, or `[{ field, param }]` when the remote '
4041
+ 'filter key differs).',
4142
reason:
@@ -64,9 +65,10 @@ export const entry: SemanticMigration = {
6465
+ 'does not reach this dialog either. The one route that consults the field is a PROMOTED '
6566
+ 'action — an action the object declares, named in the view\'s `bulkActions`, whose '
6667
+ 'field-backed params (`{ field }`) are resolved through the single-record dialog\'s '
67-
+ 'resolver when the bulk dialog opens — and of these keys only `accept` / `maxSize` arrive '
68-
+ 'that way: `lookupFilters` / `lookupColumns` / `lookupPageSize` / `descriptionField` are '
69-
+ 'resolved and then dropped on the bulk path, and the rest are never read off the field. '
68+
+ 'resolver when the bulk dialog opens — and of these keys only `accept` / `maxSize` and '
69+
+ 'the picker settings `lookupFilters` / `lookupColumns` / `lookupPageSize` / '
70+
+ '`descriptionField` arrive that way, reaching the selection bar\'s picker as they reach '
71+
+ 'the single-record dialog\'s; the rest are never read off the field. '
7072
+ 'A census of authored bulk params taken at registration time over the two repositories '
7173
+ 'reachable from that session found ZERO carrying an undeclared key '
7274
+ '(objectstack@176b03582e: 7 param literals; objectui@3e4f6324f7: 3), so no in-corpus '

‎packages/spec/src/ui/bulk-action.test.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ describe('BulkActionDefSchema — the def shape is typed, not `z.any()`', () =>
7777
expect(issues).toContain('FieldSchema');
7878
// ⛔ The prescription must NOT send this author to the field: a key
7979
// declared there reaches the bulk dialog only through a PROMOTED action
80-
// (`bulkActions`), and of this family only `accept` / `maxSize` make that
81-
// trip. Both are named by subject, so the rejection says which route and
82-
// which keys rather than implying `min` would follow.
80+
// (`bulkActions`), and of this family only `accept` / `maxSize` and the
81+
// four lookup picker settings make that trip. They are named by subject,
82+
// so the rejection says which route and which keys rather than implying
83+
// `min` would follow.
8384
expect(issues).toContain('`bulkActions`');
8485
expect(issues).toContain('`accept` / `maxSize`');
8586
});

‎packages/spec/src/ui/bulk-action.zod.ts‎

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export type BulkActionExecution = z.input<typeof BulkActionExecutionSchema>;
144144
* to name it beside min/max/step, and the sweep found no FORM widget reading it
145145
* at all.
146146
*
147-
* ⚠️ The prescription refuses the obvious-sounding remedy for all but two of
147+
* ⚠️ The prescription refuses the obvious-sounding remedy for all but six of
148148
* these keys. An AUTHORED def's params reach the dialog as written: nothing on
149149
* that path consults the object's field definitions. The bulk surface's
150150
* field-backed route is the PROMOTED def, an action the object declares, named
@@ -157,15 +157,16 @@ export type BulkActionExecution = z.input<typeof BulkActionExecutionSchema>;
157157
* carries the field's `type`, translated `label`, `options`, `required`,
158158
* `description` (as the help text), `placeholder`, `defaultValue`, `multiple`,
159159
* `accept` and `maxSize`, plus a reference-bearing field's `reference`,
160-
* `displayField` and `dependsOn`. From THIS list only `accept` and `maxSize`
161-
* make the trip. The lookup settings `lookupFilters` / `lookupColumns` /
162-
* `lookupPageSize` / `descriptionField` are resolved and then dropped by the
163-
* bulk adapter, and the rest are never read off the field (`idField` has no
160+
* `displayField` and `dependsOn`, and that field's lookup settings
161+
* `lookupFilters` / `lookupColumns` / `lookupPageSize` / `descriptionField`,
162+
* which reach the selection bar's picker as they reach the single-record
163+
* dialog's. From THIS list only those four and `accept` / `maxSize` make the
164+
* trip, and the rest are never read off the field (`idField` has no
164165
* `FieldSchema` spelling to declare; the resolver's snake `id_field` read is
165-
* dropped with the lookup settings). So
166-
* "declare it on the field and let the dialog inherit" is right for `accept` /
167-
* `maxSize` on a promoted def, and a confidently wrong answer for every other
168-
* key here, the shape this campaign has already shipped more than once.
166+
* still not carried onto the bulk param). So
167+
* "declare it on the field and let the dialog inherit" is right for those six
168+
* keys on a promoted def, and a confidently wrong answer for every other key
169+
* here, the shape this campaign has already shipped more than once.
169170
*/
170171
const BULK_PARAM_WIDGET_CONFIG_KEYS = [
171172
'min', 'max', 'step', 'precision', 'scale', 'rows',
@@ -257,12 +258,13 @@ export const BulkActionParamSchema = lazySchema(() => strictObject(
257258
+ 'field-backed param (`{ field }`), named in the view\'s `bulkActions`. That route '
258259
+ 'carries the field\'s `type`, `label`, `options`, `required`, `description` (as the help '
259260
+ 'text), `placeholder`, `defaultValue`, `multiple`, `accept` and `maxSize`, plus a '
260-
+ 'reference field\'s `reference`, `displayField` and `dependsOn`. ⛔ So of these keys only '
261-
+ '`accept` / `maxSize` arrive that way: the picker settings `lookupFilters` / '
262-
+ '`lookupColumns` / `lookupPageSize` / `descriptionField` are dropped on the bulk path, '
263-
+ 'and the rest are never read off the field. Remove the key, or for `accept` / '
264-
+ '`maxSize` move the param onto a promoted action; open an issue if a bulk param '
265-
+ 'genuinely needs a key declared here.',
261+
+ 'reference field\'s `reference`, `displayField` and `dependsOn` and its picker settings '
262+
+ '`lookupFilters` / `lookupColumns` / `lookupPageSize` / `descriptionField`, which reach '
263+
+ 'the selection bar\'s picker as they reach the single-record dialog\'s. ⛔ So of these '
264+
+ 'keys only `accept` / `maxSize` and those four picker settings arrive that way, and the '
265+
+ 'rest are never read off the field. Remove the key, or for one of those six move the '
266+
+ 'param onto a promoted action; open an issue if a bulk param genuinely needs a key '
267+
+ 'declared here.',
266268
}],
267269
history:
268270
'Until this shape was closed, `params[]` was `.passthrough()` — every unknown key rode through '

0 commit comments

Comments
 (0)