fix(app-shell): keep a field's own option keys when an action param inherits them (#3559) - #3764
Merged
Merged
Conversation
…nherits them (#3559) `normaliseOptions()` rebuilt every field-inherited option entry as a fresh `{ label, value }`, dropping the rest of the vocabulary the field declared — above all the per-option `visibleWhen` predicate (ADR-0058 / #2284). A select field whose options narrow by predicate in an object form offered the FULL list once an action param inherited it via `{ field: '...' }`, predicate-hidden entries included, with no diagnostic anywhere. Options authored inline on the param were never affected (they skip this function entirely), so the same authored key behaved two ways on two surfaces. The resolver now preserves each entry and keeps to its two real jobs: expanding bare strings and translating the label through `fieldOptionLabel`. The option widgets already read `visibleWhen` (`resolveVisibleOptions` in `@object-ui/core`, wrapped by `useCascadingOptions`), so the narrowing now actually applies in the dialog — verified end to end through `paramToField()` into a real `<SelectField>`. Types: `ActionParamOption` (`@object-ui/core`) names the two keys the param layer reads and carries the rest through, following `BulkActionParam`'s catch-all idiom rather than binding to `SelectOptionMetadata` — `ActionParamDef.options` and the resolver's `RawActionParam.options` / `RuntimeField.options` all speak it. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
The `ActionParamOption` type landed BETWEEN `ActionParamDef`'s doc block and the interface, so two block comments sat back to back and the interface's own prose — the objectui#3201 record of why `validation` is not declared there — attached to nothing. Move the new type above it; both declarations now carry their own documentation. No type or runtime change. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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 free
to 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 #3559
事实核对(前提复核于
origin/main@b1204af0a)正文的三处定位全部成立,仅行号有漂移,按内容锚定:
packages/app-shell/src/utils/resolveActionParams.ts—normaliseOptions在:228,调用点在:330-331(param.options ?? normaliseOptions(field.options, …));RawActionParam.options在同文件:50(正文写:52);ActionParamDef.options在packages/core/src/actions/ActionRunner.ts:436(与正文一致)。另外一条正文没提、但修法必须一并动的:同文件
RuntimeField.options(:180)是继承来源的类型,同样写死成{ label, value } | string。不放宽它,连"字段声明了visibleWhen"这件事都在 TS 里写不出来(测试 fixture 会被 excess-property check 打回),运行时展开也在类型层丢光。消费链逐段核实过,只有
normaliseOptions一处在剥键:useConsoleActionRuntime.tsx:198p.options.map((o) => ({ ...o, label: … }))— 展开保留ActionParamDialog.tsx:224rawParam.options?.map((o) => ({ ...o, label: … }))— 展开保留paramToField.tsoptions: param.options— 直接透传SelectField→useCascadingOptions→resolveCascadingOptions→resolveVisibleOptionsvisibleWhen并逐项过滤改动
运行时(一行):
normaliseOptions保留原条目,只做它真正的两件事 —— 裸字符串展开成{ label, value }、经fieldOptionLabel翻译 label:类型(按分诊预裁的小路线):
@object-ui/core新增ActionParamOption={ label: string; value: string; [key: string]: unknown },循BulkActionParam已有的 catch-all 惯用形;⛔ 未绑定、未改动SelectOptionMetadata(packages/types一字未动,#3309 照同一答案自行跟进)。ActionParamDef.options、RawActionParam.options、RuntimeField.options、normaliseOptions的入参/返回一律说这门词汇,两个站点因此是同一个类型而不是两处一致的复述。端到端验证(裁决 3:不止验 map)
ActionParamDialog渲染 select param 的路径是field={paramToField(param)}+getLazyFieldWidget('select')→SelectField。新增resolveActionParams.optionVisibleWhen.test.tsx就按这套线接:字段元数据 →resolveActionParams()→paramToField()→ 真的SelectField组件,断言谓词收窄确实发生:select-empty-tier空状态,不再渲染一个装着被挡选项的下拉;standard留下(仍有 combobox),admin_only不在可选集里,widget 的 cascade-clear 把预填值清掉;消费方已经会算
visibleWhen,所以这个修法是完整的一半加另一半:键送到 + 消费方读它。没有过度声称的部分。一处如实测量(不是主张,预测被推翻后按实测记录)
对话框不传
dependentValues(param 值在它自己的 local state 里),所以 record 相关谓词看到的是SchemaRendererContext的formValues/data,不是对话框自己在填的值。进去前的预测是"record为{}→record.country == 'cn'为假 → 选项被藏";实测相反:{}下该谓词不可解,按resolveVisibleOptions()既有的 fail-open 默认保留该选项(同一列表在{ country: 'us' }下照常过滤成[])。即残留缺口窄且默认安全 —— 对话框无法拿自己在途的 param 收窄继承来的列表,而不可解谓词是全给不是全藏。测量写进测试注释,另行报告,本 PR 不擅自设计它的语义。反向验证(先定方向,再跑)
预测:去掉展开 → 新钉子里 5 条转红(unit 3 条 + widget 2 条),而"作者内联 options 逐字下沉"这条回归钉、裸字符串钉、fail-open 测量条保持绿。实跑完全一致:
恢复后 41/41 绿。
测试与门禁
pnpm exec vitest run packages/core packages/app-shell --maxWorkers=2→ 363 文件 / 4122 通过,0 失败;SelectField.cascade、core 的optionRules)→ 34/34 绿;type-check(core / app-shell / components,含 app-shell 的tsconfig.typetests.json)→ 全过。类型钉子放在真的会被编译的那个文件里:resolveActionParams.test.ts已在 typetests 名单内,两条@ts-expect-error钉住label/value仍是必填(未用的 suppression 会 TS2578 报错,所以这钉子是活的)。core 自己的测试被它的tsc排除(TEST_DEBT),所以 core 那支测试只声称行为一致,类型半件明写在文件头说明放在何处;eslint触及文件 → 0 error;check-control-bytes→ OK(3700 tracked);check-changeset-no-major→ OK;@object-ui/app-shell/@object-ui/core各 patch。未越界
只动 issue 指定的两个文件面 + 两包测试 + 一个 changeset。
packages/types/、content/docs/releases/一字未动;SelectOptionMetadata未碰。Generated by Claude Code