Skip to content

action param 的 options[] 该不该讲字段级的逐选项词汇(color / visibleWhen)? —— 三处形状,三种拼法 #5016

Description

@xuyushun441-sys

#4001 批 14 把 ActionParamSchema.options[] 收成了 strictObject({ label, value }) —— 它一直以来的契约,只是从「靠删除来执行」变成了说出口。收紧本身不删任何能用的东西(见下面的实测),但测量过程暴露出一个独立的能力问题,这里存档,不在批 14 里猜。

现状:同一个概念,仓里有三种拼法

位置 形状 posture
data/field.zod.ts SelectOptionSchema label / value / color / default / visibleWhen strictObject(已关)
ui/action.zod.ts ActionParamSchema.options[] label / value strictObject(批 14 关的)
ui/bulk-action.zod.ts BulkActionParamSchema.options[] label / value + 开放 .passthrough()(#4909)

objectui 那侧还有第四份:SelectOptionMetadata(packages/types/src/field-types.ts)—— label / value / color / icon / disabled / visibleWhen。注意 icon / disabled 在 spec 里任何一处都没有声明,只活在 objectui 自己的接口里。

实测(2026-08-03)

1. action 的门今天就在剥。 一个 action 是注册 metadata type,所以作者写的 param 是经 getMetadataTypeSchema('action') 到达 objectui 的。拿真实 payload 过这道门:

options: [{ label: 'Overload', value: 'overload',
            color: 'red', visibleWhen: "record.status == 'open'", icon: 'x', disabled: false }]

parse 成功,出来的是:

{"label":"Overload","value":"overload"}

四个键在任何 renderer 看到它们之前就没了,而且报告成功。所以批 14 的收紧没有拿走任何在工作的东西,只是把静默变成了响亮。

2. 但渲染侧其实读得懂其中两个。 dialog 走 paramToField -> field.options -> getLazyFieldWidget('select') -> SelectField,而 SelectField 通过 useCascadingOptions -> resolveCascadingOptions 解析逐选项 visibleWhen(ADR-0058 / #2284);color 则被 grid/detail 的展示渲染器读(packages/fields/src/index.tsxoption?.color)。也就是说:唯一挡在作者和一个能工作的逐选项门控之间的,就是 spec 的这道剥离。

3. 字段回退那条路也不通。 直觉上的处方「把 param 写成 field-backed,继承字段自己的选项」对这两个键是假的 —— resolveActionParamsnormaliseOptions 把每个条目重建成 { label, value }。两个方向都丢。批 14 的 guidance 因此刻意没有给出这条建议(账本 finding 18:错误里的文案是行为,自信而错的处方比没有更糟)。

要判的事

action param 的选项列表该不该讲 SelectOptionSchema 已经声明、对象表单已经兑现的那套逐选项词汇?

  • A. 维持 { label, value }(批 14 的落点)。契约最小、最诚实。代价:一个已经接好线的门控能力被合约挡着,而且这个不对称本身就是 AI 作者会踩的坑。
  • B. 让它复用 SelectOptionSchema(.extend() 覆写 labelI18nLabelSchemavaluez.string(),.extend() 会继承 strict)。一套词汇,N 个面。代价:normaliseOptions 必须同步停止重建条目,否则声明了却不兑现 —— 又是一次 declared != enforced;且要判 color / default 在这条路上是否真被读,否则是声明惰性键。
  • C. B 再加上把 icon / disabled 补进 SelectOptionSchema,让 spec 和 objectui 的选项词汇彻底对齐。代价最大,但这是唯一让「四份拼法」收敛成一份的选项。

个人倾向 B,并且必须normaliseOptions 的修改同一个 PR 落地 —— 单独放开 spec 会造出一个声明了、门也过了、渲染器却收不到的键,正好是 ADR-0078 要消灭的那种。但这跨 framework + objectui 两个仓,且要先做一次 color / default 的逐键 liveness 审计,不适合塞进一个收紧批次。

另注:批 14 之所以没跟 bulk-action.passthrough(),是因为 #4909 的两条理由在这里都不成立 —— 那边的 def 是「left as-authored」逐字到达 grid(没有这道 spec 门),且 objectui 的 BulkActionParam 声明了显式的 [key: string]: unknown 兜底;这边的目标类型 SelectOptionMetadata封闭接口。目标词汇封闭,正是「声明」胜过「容忍」的场合。

发现于 #4001 批 14,未指派。

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions