Repository navigation
Commit f5aaa0b
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4Uu9k2t4srZBGSUnXnWt5NrsY)_
Fixes #30260
Clause-②: yes (widening) — `@object-ui/core`'s exported `ActionParamDef`
gains one optional member, `widget?: string`, and `@object-ui/fields`'
`RawActionParam` gains the same optional member (measured on the built
`ui/packages/core/dist/actions/ActionRunner.d.ts` and
`ui/packages/fields/dist/resolveActionParams.d.ts`). No accepted key,
value or answer is taken away.
Metadata-protocol: semantic
Skills-docs: follow-up owed — skills/objectui/rules/protocol.md,
skills/objectstack-ui/rules/actions.md
## 维护者速读
- 改了什么:动作参数上写的 `widget` 现在真的生效。参数写 `widget: 'permission-ref'`
时,动作对话框画权限集选择器(列出标签与机器名,提交机器名);未注册的名字退回 `type` 控件。
- 为什么改:spec 半边(#30259)已声明这个键,但控制台没人读,Create User 的权限集只能手敲名字;本卡是读者半边,之后
#30117 的服务端切换才有意义。
- 风险与回滚:只影响写了 `widget` 的参数(或继承字段 widget 的字段型参数);未写的参数渲染逐字节不变。回滚即 revert
本 PR。
-
先看:`ui/packages/app-shell/src/utils/paramToField.ts`(`authoredWidgetKey`
与降级判断)、`ui/packages/fields/src/resolveActionParams.ts`(`inheritedWidget`)、`packages/spec/liveness/action.json`(`widget`
行翻 live)。
- 两分钟验证:`pnpm --dir ui exec vitest run -t 30260
packages/app-shell/src/views/ActionParamDialog.test.tsx`,预期 3 条通过(选择器提交
`support_agent`、无 widget 的对照是文本框、未注册名退回 textarea)。
- 需要你做的:无,席位落地。
## What changes
- **`ActionParamDef.widget`**
(`ui/packages/core/src/actions/ActionRunner.ts`, the type only): the
resolved param carries the spec's `ActionParamSchema.widget`.
- **`resolveActionParam`**
(`ui/packages/fields/src/resolveActionParams.ts`): copies the param's
`widget` on the inline branch and the unresolved-field branch. On the
field-backed branch the param's own `widget` wins; otherwise it inherits
the field's `FieldSchema.widget`, but only while the param also inherits
the field's `type` (or restates it). A param that overrides `type` asks
for a different value, so a widget chosen for the field's value is not
carried onto it (`inheritedWidget`).
- **`paramToField`**
(`ui/packages/app-shell/src/utils/paramToField.ts`): a `widget` that
names a registered field widget replaces the `type` widget key the
dialog mounts through `getLazyFieldWidget`; a name nothing registers
keeps the `type` widget. The test is the shared resolver's own answer
(`resolveFormWidgetType`, read for its documented `text` fallback), the
same reading the console's `FormPage` makes of a field's `widget`.
`paramDegradesWithoutTarget` answers false when a registered widget is
drawn, so a targetless lookup param with such a widget gets neither the
text fallback nor the paste-an-id hints, and the predicate/adapter
equivalence still holds.
- **Spec seam** (comment 6652583019):
`packages/spec/liveness/action.json`'s `params.widget` row is `live`,
citing both readers, with `authorWarn` / `authorHint` dropped;
`packages/spec/src/ui/action.zod.ts` loses the describe's "Not read yet"
sentence, the `//` pointer comment and the JSDoc "Planned" sentence.
Generated with them: `content/docs/references/ui/action.mdx`
(`gen:schema && gen:docs`) and
`packages/spec/liveness/state-counts/action.md` (`gen:liveness-counts`).
- One root changeset (`minor` on `@object-ui/core`, `@object-ui/fields`,
`@object-ui/app-shell`, `@objectstack/spec`).
## Why
`ActionParamSchema.widget` was accepted and stored but read by nothing,
so a param that asked for the `permission-ref` picker drew a text box.
This is the console half of #30117's split; Create User's param switch
stays with #30117 (`packages/platform-objects/**` untouched).
## Tests
New pins, each a top-level `describe` in the existing harness file:
- `resolveActionParams.test.ts` — inline copy, field-backed inheritance,
restated type inherits, overridden type does not, param beats field,
no-widget control, unresolved branch keeps it, the public `ActionParam`
type accepts it (8).
- `paramToField.test.ts` — registered widget drawn, no-widget control,
unregistered falls back to the param's own type widget (`text` /
`select` / `textarea`), an authored `text` honoured, a targetless lookup
with a registered widget is drawn and does not degrade, with the
unregistered control still degrading (5).
- `ActionParamDialog.test.tsx` — mounted inside `SchemaRendererProvider`
with a catalog: the picker lists `Support Agent (support_agent)`,
submits `{ permissionSet: 'support_agent' }`, and the emitted value
matches `expectedParamShape` (`string`); CONTROL without `widget` is an
input that lists nothing; an unregistered name on a `textarea` param is
the textarea (3).
## Acceptance notes
- **Bulk dialog not covered.** The selection bar's bulk dialog maps
resolved params through plugin-grid's `toBulkParam` /
`bulkParamToField`, whose `BulkActionParam` shape has no `widget`, so a
promoted bulk action's param still draws its `type` widget. Outside this
card's file surface; recorded in the liveness note. carrier: seat.
- **A private copy of the "names a registered widget" test.**
`authoredWidgetKey` restates `FormPage`'s `namesRegisteredWidget` (one
line over `resolveFormWidgetType`). A shared export would mean editing
`@object-ui/fields`' barrel and `ui/apps/console`, both outside the
surface. carrier: seat.
- **Field-widget inheritance rule** (a field-backed param inherits the
field's `widget` only while it inherits or restates the field's `type`,
a restated type matched through the param-type fold; a param that
overrides `type` does not) is this PR's reading of the spec's "widget
mapping from object metadata"; the seat accepted it at ACCEPT, and the
spec JSDoc says the same.
- Contract-review should-fixes (review 6661565862) landed in ae7e6fa:
paramDegradesWithoutTarget judges the widget the param draws,
inheritedWidget matches a restated type through the param-type fold, and
the spec JSDoc says inherits or restates; 57e88ed turns the lint pin of
the planned params.widget warning into its inverse. Delta review PASS
6662404259.
- Branch is the card thread's harness branch
`claude/project-thread-ijgrij` (claim amendment 6659791806), not
`claude/issue-30260-*`.
- `paramValueShape.ts` needed no edit: `expectedParamShape` resolves
through `paramToField`, so a `permission-ref` param already reads its
`string` contract row.
## Verification
Ablations (each with `scripts/ablation-replace.mjs`, mutation proven on
disk, restored to the HEAD blob; the ui suites alias `@object-ui/*` to
source, so no build leg):
- `paramToField`: authored widget leg removed ⇒ 5 of the 16 new tests
red (the picker render, registered widget drawn, `text` honoured,
targetless lookup, public type); controls green.
- `resolveActionParam` inline `widget: param.widget` ⇒ `widget:
undefined` ⇒ 2 red.
- field-backed `widget: inheritedWidget(param, field)` deleted ⇒ 3 red.
Local gates on `4d88bf5a` (the head after merging `origin/main`): `node
scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 105 families, all 105 run, each exit
code captured before any pipe; `--ran` reconciliation: **105 derived,
105 run, 0 NOT-MEASURED, 0 UNRUN**. Plus the order's extras: `pnpm --dir
ui run check:spec-symbols` exit 0 and `node
scripts/check-sdui-manifest.mjs` exit 0 (in the derived set).
`check:dual-build-cjs-loads` read built output after a full `turbo run
build` (131 packages, exit 0).
Type-check: `pnpm --filter @object-ui/core run type-check`,
`@object-ui/fields`, `@object-ui/app-shell` (the last re-run after the
merge), all exit 0. Tests after the merge:
`resolveActionParams.test.ts`, `paramToField.test.ts`,
`ActionParamDialog.test.tsx`, `paramValueShape.test.ts` exit 0.
Dogfood battery: n/a — no `!` in the title and no `(narrowing)` arm.
<details><summary>Gate run record (105 derived + 1 extra)</summary>
```text
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-adr-links.mjs :: exit 0
node scripts/check-adr-links.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-adoption.mjs :: exit 0
node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-dev-prereqs.mjs --self-test :: exit 0
node scripts/check-doc-route-spelling.mjs --advisory :: exit 0
node scripts/check-doc-route-spelling.mjs --self-test :: exit 0
node scripts/check-docs-section-name.mjs :: exit 0
node scripts/check-docs-section-name.mjs --self-test :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-issue-citations.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/check-section-landing-index.mjs :: exit 0
node scripts/check-section-landing-index.mjs --self-test :: exit 0
node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0
node scripts/docs-audit/check-affected-docs.mjs :: exit 0
node scripts/docs-audit/check-drift-comment.mjs :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0
pnpm --filter @objectstack/spec run check:api-surface :: exit 0
pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0
pnpm --filter @objectstack/spec run check:browser-reachable-entries :: exit 0
pnpm --filter @objectstack/spec run check:docs :: exit 0
pnpm --filter @objectstack/spec run check:dual-source-exports :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm --filter @objectstack/spec run check:empty-state :: exit 0
pnpm --filter @objectstack/spec run check:entry-nameability :: exit 0
pnpm --filter @objectstack/spec run check:export-origins :: exit 0
pnpm --filter @objectstack/spec run check:exported-any :: exit 0
pnpm --filter @objectstack/spec run check:generated :: exit 0
pnpm --filter @objectstack/spec run check:liveness :: exit 0
pnpm --filter @objectstack/spec run check:llms-txt :: exit 0
pnpm --filter @objectstack/spec run check:skill-examples :: exit 0
pnpm --filter @objectstack/spec run check:skill-refs :: exit 0
pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0
pnpm --filter @objectstack/spec run check:variant-docs :: exit 0
pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:corpus-claim-drift :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:doc-anchors :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:doc-frontmatter :: exit 0
pnpm check:docs-audit-scope :: exit 0
pnpm check:docs-redirects :: exit 0
pnpm check:docs-single-h1 :: exit 0
pnpm check:docs-spec-enumerations :: exit 0
pnpm check:docs-transcript-drift :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 0
pnpm check:dual-build-cjs-loads :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:issue-citations :: exit 0
pnpm check:keyed-text-bounds :: exit 0
pnpm check:lean-entry-closure :: exit 0
pnpm check:logger-receiver-detach :: exit 0
pnpm check:merge-driver :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:org-identifier :: exit 0
pnpm check:page-declaration-shape :: exit 0
pnpm check:platform-checklist :: exit 0
pnpm check:platform-object-tenancy-census :: exit 0
pnpm check:pm-prior-rulings :: exit 0
pnpm check:published-files :: exit 0
pnpm check:published-readme-links :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:react-page-adapter-contract :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:registry-log-declared :: exit 0
pnpm check:rest-log-spy-declared :: exit 0
pnpm check:role-word :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:slot-lookup :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 0
pnpm check:spec-docblock-symbol-anchors :: exit 0
pnpm check:spec-parsed-alias :: exit 0
pnpm check:system-context-census :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:vendor-version-stamps :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
pnpm --dir ui run check:spec-symbols :: exit 0
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L6bhgXcNPmrQhpwYYn7fEq)_
<!-- signed: domain:ui#4 · os-sales · session_01L6bhgVfPeFZkN1FP93imKU
-->
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5d0904c commit f5aaa0b
12 files changed
Lines changed: 369 additions & 32 deletions
File tree
- .changeset
- content/docs/references/ui
- packages
- lint/src
- spec
- liveness
- state-counts
- src/ui
- ui/packages
- app-shell/src
- utils
- views
- core/src/actions
- fields/src
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
142 | 142 | | |
143 | 143 | | |
144 | 144 | | |
145 | | - | |
| 145 | + | |
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
| |||
236 | 236 | | |
237 | 237 | | |
238 | 238 | | |
239 | | - | |
| 239 | + | |
240 | 240 | | |
241 | 241 | | |
242 | 242 | | |
| |||
374 | 374 | | |
375 | 375 | | |
376 | 376 | | |
377 | | - | |
| 377 | + | |
378 | 378 | | |
379 | 379 | | |
380 | 380 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
190 | | - | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
195 | 196 | | |
196 | 197 | | |
197 | 198 | | |
| |||
201 | 202 | | |
202 | 203 | | |
203 | 204 | | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
209 | 208 | | |
210 | 209 | | |
211 | 210 | | |
212 | | - | |
213 | | - | |
214 | | - | |
215 | | - | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
216 | 222 | | |
217 | 223 | | |
218 | 224 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
98 | | - | |
| 98 | + | |
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
| |||
129 | 129 | | |
130 | 130 | | |
131 | 131 | | |
132 | | - | |
| 132 | + | |
133 | 133 | | |
134 | 134 | | |
135 | | - | |
136 | | - | |
137 | | - | |
| 135 | + | |
| 136 | + | |
138 | 137 | | |
139 | 138 | | |
140 | 139 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
253 | 253 | | |
254 | 254 | | |
255 | 255 | | |
256 | | - | |
257 | | - | |
258 | | - | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
259 | 260 | | |
260 | | - | |
261 | 261 | | |
262 | 262 | | |
263 | 263 | | |
264 | 264 | | |
265 | | - | |
266 | | - | |
| 265 | + | |
267 | 266 | | |
268 | 267 | | |
269 | 268 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
380 | 380 | | |
381 | 381 | | |
382 | 382 | | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
0 commit comments