背景
这是 #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.
背景
这是 #2579(详情页相关子表 tab)里明确 defer 的 follow-up —— 见该 issue 的「相关 follow-up」一节。
PageComponentSchema已有visibility: ExpressionInputSchema(CEL 谓词,packages/spec/src/ui/page.zod.tsL109),所以页面组件可按记录状态条件显隐。但page:tabs的 item 本身没有visibility—— 形状只有{ label, icon?, children }(packages/spec/src/ui/component.zod.tsPageTabsProps)。后果:你能用组件级
visibility隐藏一个 tab 的内容,但 tab 头(标签)还在,点进去是空的。无法真正「整条 tab 按记录状态显隐」。典型企业需求:
record.status == 'customer'显示;提案
给
PageTabsProps.items[]加一个可选visibility,复用与组件级visibility/ actionvisible相同的ExpressionInputSchema(CEL):语义:
visibility求值为 false → 整条 tab(头 + 面板)从 tab 条移除,而不是留一个空头。求值上下文与组件级visibility一致(record + page 变量;page 变量变化时响应式重算)。渲染器(objectui):
page:tabs渲染时过滤掉visibility为 false 的 item;若当前激活的 tab 被隐藏 → 自动回落到第一个可见 tab(避免空白)。设计边界(与 #2579 一致)
PageTabsProps,不碰ObjectSchema。ExpressionInputSchema),不引入新表达式机制;与PageComponentSchema.visibility、actionvisible/disabled、nav 可见条件同源。改动范围
packages/spec/src/ui/component.zod.ts的PageTabsProps.items加visibility;补测试。page:tabs渲染器按visibility过滤 item + 激活 tab 回落;补测试。验收
visibility: 'record.status == "customer"':非 customer 记录看不到该 tab 头,customer 记录看得到。visibility的 item 行为完全不变。Refs #2579.