Skip to content

条件 tab:给 page:tabs 的 item 加 visibility(CEL)—— #2579 follow-up #2606

Closed

Description

@os-zhuang

背景

这是 #2579(详情页相关子表 tab)里明确 defer 的 follow-up —— 见该 issue 的「相关 follow-up」一节。

PageComponentSchema 已有 visibility: ExpressionInputSchema(CEL 谓词,packages/spec/src/ui/page.zod.ts L109),所以页面组件可按记录状态条件显隐。但 page:tabs 的 item 本身没有 visibility —— 形状只有 { label, icon?, children }(packages/spec/src/ui/component.zod.ts PageTabsProps)。

后果:你能用组件级 visibility 隐藏一个 tab 的内容,但 tab 头(标签)还在,点进去是空的。无法真正「整条 tab 按记录状态显隐」。

典型企业需求:

  • "Contracts" tab 仅当 record.status == 'customer' 显示;
  • 按记录阶段 / 角色显隐的 tab。

提案

给 PageTabsProps.items[] 加一个可选 visibility,复用与组件级 visibility / action visible 相同的 ExpressionInputSchema(CEL):

items: z.array(z.object({
  label: I18nLabelSchema,
  icon: z.string().optional(),
  visibility: ExpressionInputSchema.optional()
    .describe('Visibility predicate (CEL). When false, the whole tab (header + panel) is omitted.'),
  children: z.array(z.unknown()).describe('Child components'),
})),

语义:visibility 求值为 false → 整条 tab(头 + 面板)从 tab 条移除,而不是留一个空头。求值上下文与组件级 visibility 一致(record + page 变量;page 变量变化时响应式重算)。

渲染器(objectui):page:tabs 渲染时过滤掉 visibility 为 false 的 item;若当前激活的 tab 被隐藏 → 自动回落到第一个可见 tab(避免空白)。

设计边界(与 #2579 一致)

  • 这是 Tier 2(page 层) 能力 —— 条件 / 排布归 page,不进对象层(ADR-0085 准入测试:对象层只放跨表面业务意图,不放「隐藏 / 重排」)。所以只加在 PageTabsProps,不碰 ObjectSchema。
  • 复用现有 CEL(ExpressionInputSchema),不引入新表达式机制;与 PageComponentSchema.visibility、action visible / disabled、nav 可见条件同源。
  • 加性、向后兼容(可选字段)→ minor。

改动范围

  • framework(spec):packages/spec/src/ui/component.zod.ts 的 PageTabsProps.items 加 visibility;补测试。
  • objectui(渲染):page:tabs 渲染器按 visibility 过滤 item + 激活 tab 回落;补测试。

验收

  • page:tabs 某 item 带 visibility: 'record.status == "customer"':非 customer 记录看不到该 tab 头,customer 记录看得到。
  • 激活的 tab 被隐藏时自动落到第一个可见 tab,无空白面板。
  • 不带 visibility 的 item 行为完全不变。

Refs #2579.

Activity

  1. self-assigned this
    on Jul 15, 2026
  2. os-zhuang commented on Jul 15, 2026

    @os-zhuang
    ContributorAuthor

    基于 ADR-0089 的重新评估结论

    本 issue(2026-07-05)早于 ADR-0089(2026-07-14 接受),重新评估如下:

    提案本身依然成立,不需要重新设计。 Tier 2(page 层)定位、复用 ExpressionInputSchema(CEL)、不进对象层、整条 tab(头 + 面板)移除的语义、激活 tab 回落 —— 这些都不受 ADR-0089 影响,照原样落地。

    唯一修正:字段名从 visibility 改为 visibleWhen。 ADR-0089 D1 已把条件显隐谓词统一为规范名 visibleWhen(与 readonlyWhen/requiredWhen 家族对齐),visibility/visibleOn 降级为 @deprecated alias。给一个全新表面按提案原文加 visibility 等于在 alias 废弃窗口内新增该 alias 的使用面,方向相反。

    新表面不接受 alias。 ADR-0089 D2 的 alias 机制服务于已有键的存量元数据;tab item 此前没有任何 visibility 键,不存在存量 → 只声明 visibleWhen,visibility/visibleOn 在 tab item 上不被接受(spec 测试已固化;渲染器也不做防御性 alias 读取,Prime Directive #12)。注意:PageTabsProps 目前是 strip 模式(非 .strict()),写错键会被静默丢弃 —— ADR-0089 D3b 的 lint(标记新写源码中的 deprecated alias)可以兜住 visibility 这个具体拼法。

    已按此落地(均为 draft):

    顺带发现(不在本 issue 范围内):渲染器实际消费的 item 级 value(?tab= URL 同步的稳定标识,objectui#2257)和 count(徽标数)在 PageTabsProps.items[] 里未声明 —— 若未来对 items 翻 .strict(),这两个键会先被误伤;需要时可另开 issue 补声明。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions