发现于 framework#5016 的实施过程(objectstack-ai/objectstack#6235),与那单的修复无关(那单开放的是作者写在 param 上的内联选项,走的是另一条分支),按 Prime Directive #10 单独立单,未认领。
事实
packages/app-shell/src/utils/resolveActionParams.ts:228 的 normaliseOptions 把每个条目重建成 { label, value }:
return options.map((o) => {
const raw = typeof o === 'string' ? { label: o, value: o } : o;
const label = optionLabel ? optionLabel(objectName, fieldName, raw.value, raw.label) : raw.label;
return { label, value: raw.value }; // 其余键在这里消失
});
它出现在 resolveActionParam 的这一行(同文件 :331):
const resolvedOptions = param.options ?? normaliseOptions(field.options, ownerName, param.field, ctx.fieldOptionLabel);
所以只有从字段继承的列表被重建。作者显式写在 param 上的 options 走左半,逐字下沉。
后果(今天就能撞上)
一个对象字段声明了逐选项 visibleWhen(@objectstack/spec 的 SelectOptionSchema 早已声明,ADR-0058 / #2284),在对象表单里正常按谓词收窄;同一个字段被 action param 以 { field: 'xxx' } 继承后,visibleWhen 在 normaliseOptions 里被丢掉,对话框把所有选项都列出来 —— 包括那些谓词本该藏起来的。同一份字段元数据,两个 surface 两种行为,没有任何提示。
color 同理(虽然影响面小得多:对话框只建输入控件,本来也不渲染 color)。
修法方向(不要猜,值得先定一次)
normaliseOptions 真正需要做的只有两件事:把裸字符串规格化成 { label, value },以及经 fieldOptionLabel 翻译 label。保留其余键是一行的事:
- return { label, value: raw.value };
+ return { ...raw, label, value: raw.value };
但连带要动两处类型(这是需要一并想清楚的部分,不是纯粹一行):
RawActionParam.options?: Array<{ label: string; value: string }>(同文件 :52)
ActionParamDef.options?: Array<{ label: string; value: string }>(packages/core/src/actions/ActionRunner.ts:436)
两者都比它们承载的东西窄。目标词汇是 @object-ui/types 的 SelectOptionMetadata(packages/types/src/field-types.ts:289),也是 paramToField 下游控件真正读的形状 —— 收敛到它、还是只加 visibleWhen?: FieldRulePredicate,值得定一次再动。
顺带:framework 侧 objectstack-ai/objectstack#6235 落地后,ActionParamSchema.options[] 会接受 visibleWhen,所以上面两个 TS 类型也会成为「服务端接受、TS 作者写不出来」的那种不对称 —— 两件事一起修比较划算。
参考
发现于 framework#5016 的实施过程(objectstack-ai/objectstack#6235),与那单的修复无关(那单开放的是作者写在 param 上的内联选项,走的是另一条分支),按 Prime Directive #10 单独立单,未认领。
事实
packages/app-shell/src/utils/resolveActionParams.ts:228的normaliseOptions把每个条目重建成{ label, value }:它出现在
resolveActionParam的这一行(同文件:331):所以只有从字段继承的列表被重建。作者显式写在 param 上的
options走左半,逐字下沉。后果(今天就能撞上)
一个对象字段声明了逐选项
visibleWhen(@objectstack/spec的SelectOptionSchema早已声明,ADR-0058 / #2284),在对象表单里正常按谓词收窄;同一个字段被 action param 以{ field: 'xxx' }继承后,visibleWhen在normaliseOptions里被丢掉,对话框把所有选项都列出来 —— 包括那些谓词本该藏起来的。同一份字段元数据,两个 surface 两种行为,没有任何提示。color同理(虽然影响面小得多:对话框只建输入控件,本来也不渲染 color)。修法方向(不要猜,值得先定一次)
normaliseOptions真正需要做的只有两件事:把裸字符串规格化成{ label, value },以及经fieldOptionLabel翻译 label。保留其余键是一行的事:但连带要动两处类型(这是需要一并想清楚的部分,不是纯粹一行):
RawActionParam.options?: Array<{ label: string; value: string }>(同文件:52)ActionParamDef.options?: Array<{ label: string; value: string }>(packages/core/src/actions/ActionRunner.ts:436)两者都比它们承载的东西窄。目标词汇是
@object-ui/types的SelectOptionMetadata(packages/types/src/field-types.ts:289),也是paramToField下游控件真正读的形状 —— 收敛到它、还是只加visibleWhen?: FieldRulePredicate,值得定一次再动。顺带:framework 侧 objectstack-ai/objectstack#6235 落地后,
ActionParamSchema.options[]会接受visibleWhen,所以上面两个 TS 类型也会成为「服务端接受、TS 作者写不出来」的那种不对称 —— 两件事一起修比较划算。参考
options[]该不该讲字段级的逐选项词汇(color/visibleWhen)? —— 三处形状,三种拼法 objectstack#5016(裁决与逐键 liveness 审计)、feat(spec): action param 的 options[] 声明逐选项 visibleWhen (#5016) objectstack#6235(framework 侧实施,含完整消费链证据)resolveCascadingOptions(packages/core/src/evaluator/optionRules.ts:101)—— 读visibleWhen的那一处