fix(components): action:bar 成员动作声明 visible: false 时隐藏而非渲染 (#3823) - #3836
Conversation
action:button 与 action:icon 的组件级门沿用真值判读 `if (schema.visible && !isVisible) return null`,于是 `visible: false` 落进「没声明门」分支,照样渲染。 #3812 的分诊把这五处组件级 `schema.visible` 门判为休眠防御层 —— 经 packages/react 的 SchemaRenderer 路由时,宿主按 `newSchema.visible !== undefined` 先求值并隐藏,组件根本不会挂载。五处里有两处不休眠: action:bar 不走 SchemaRenderer,它自己从 ComponentRegistry 取成员渲染器, 并把成员动作对象整体展开成子渲染器的 schema,于是作者写在成员上的 visible 成为子渲染器自己的 schema.visible,落到它自己的门上。action:bar 上游也 有意不按 visible 过滤成员(filteredActions 只过 requiredPermissions 与 actionRendersAt),所以这条路径上真值门是唯一的门。 两处门统一到同族的那一处命名定义 hasDeclaredVisibilityGate (`!= null && !== ''`,#3492 立、#3758 用于行动作面),verdict 仍交给求值 入口(布尔在 evaluateCondition 短路,actionPredicate.parity 已钉)。 钉子:两门位各三形状对称(false 隐藏 / true 渲染 / 未声明渲染)+ `''` + 表达式取值仍按 verdict,并有经注册表挂载的真实 action:bar 宿主的端到端 钉子 —— 可达性不必下次重新论证。 行为变化面(窄):只有 visible 为字面布尔 false(或其他非空 falsy)的 action:button / action:icon 从渲染变隐藏。另三处被遮住的门不动。 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. |
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
补充:钉子非空绿验证(mutant check)反向验证证明了钉子读到了改动(四条 实跑: 与预判一致:两条端到端 mutant 已还原( 远端 CI19 项全部完成:16 success + 2 skipped(dependabot / Test (coverage)),0 失败 —— 含 Test shard 1-4、Lint、Type Check、Build & E2E、Bundle Analysis、Control Byte Scan 与三项 Changeset 门。 Generated by Claude Code Generated by Claude Code |
|
✅ 验收通过(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt)—— undraft + auto-merge。 核验:净 diff 4 文件(+293/-2),两门位收敛到 PR #3825 落 main 的 衍生 #3835(DeclaredActionsBar 同形门,服务端声明审批动作面 + Generated by Claude Code |
Fixes #3823
机理
action:button/action:icon的组件级门沿用真值判读,于是false && …为假 → 不return null→ 渲染。作者写visible: false(最明确的「永不显示」)被判读成「没声明门」。#3812 的分诊把这五处组件级
schema.visible门判为休眠防御层 —— 经packages/react的SchemaRenderer路由时,宿主按newSchema.visible !== undefined统一求值并隐藏,组件根本不会挂载到自己的门。五处里有两处不休眠,差别就是本单:action:bar不走SchemaRenderer。它自己从ComponentRegistry取成员渲染器,并把成员动作对象整体展开成子渲染器的 schema(action-bar.tsx:schema={{ ...action, type: componentType, actionType: action.type, … }}),于是作者写在成员上的visible成为子渲染器自己的schema.visible,落到它自己的门上。action:bar上游也有意不按visible过滤成员(filteredActions只过requiredPermissions与actionRendersAt),所以这条路径上真值门是唯一的门。两门位前后对照
renderers/action/action-button.tsx:148if (schema.visible && !isVisible) return null;if (hasDeclaredVisibilityGate(schema.visible) && !isVisible) return null;renderers/action/action-icon.tsx:82统一到同族那一处命名定义
renderers/action/visibility-gate.ts的hasDeclaredVisibilityGate(!= null && !== '',PR #3825 落 main @b5980f471)。verdict 不动,仍交给求值入口 —— 布尔在evaluateCondition短路,packages/react/src/hooks/__tests__/actionPredicate.parity.test.tsx:134已钉「literal false → 引擎与渲染器两条路径都判隐藏」。改的只是那个拒绝提问的门。⛔ 按 issue 正文,另三处被遮住的门(
action-group.tsx:235/action-menu.tsx:179/action-bar.tsx:223)与packages/components/src/SchemaRenderer.tsx那份只看hidden的休眠同名副本均未触碰。端到端钉子(可达性不必下次重新论证)
新增
renderers/action/__tests__/action-bar-member-visible-gate.test.tsx,15 条:false隐藏 /true渲染 / 未声明渲染,外加''不是声明的门、表达式取值仍按 verdict(false隐藏、true显示)。对称性是要点:「无条件隐藏成员」的错误改法能独自满足所有visible: false断言,把套件留在绿色。action:bar宿主的端到端钉子 5 条 —— 从注册表取action:bar挂载(与真实宿主同一条路径),成员声明visible: false→ 不渲染,action:button与action:icon各一条;并带一个未声明的伴随动作,使「没渲染」的断言不会与「整条 bar 消失了」混淆。maxVisible钉高,免得成员被推进溢出action:menu(useIsMobile()的mobileMaxVisible默认是 1)。action:icon是纯图标,可及名来自渲染器用label ?? name构造的aria-label,故按getByLabelText断言而非文本。反向验证(方向先判后跑)
预判:改动只影响「已声明且 falsy」的取值(实际就是字面
false),故未改代码上应是四条visible: false钉子红、其余全绿;true/ 未声明 /''前后同绿(它们在两种写法下走同一分支)。实跑(
origin/main@c8526825618f86bff6d270f70893a35992243dea,先落钉子、后改门):端到端那两条独立复现了 issue 探针的结论 —— 经
action:barspread 路径,visible: false的成员实测渲染出了Ghost按钮(action:icon那条连aria-label="Ghost"一起)。改门后:方向与预判一致(标准 Red 方向,无反转)。
验证
仓根规范调用 +
flock串行 +NODE_OPTIONS=--max-old-space-size=4096+--maxWorkers=2:fixture 清扫:按规则的消费半径(而非改动包)枚举了全仓
visible: false与action:button/action:icon的引用面 —— 没有任何 fixture 钉住被删掉的真值分支(其余命中分属 page-nav / 行动作面 / 权限 explain 的record.visible/ 求值入口 parity,语义无关),故无需重拼或替换。Changeset
.changeset/action-bar-member-declared-visible-gate-3823.md,@object-ui/componentspatch(与 #3825 同档)。已写明行为变化面:只有visible为字面布尔false(或其他非空 falsy)的action:button/action:icon从渲染变隐藏;visible: true照旧渲染,''与缺省照旧不算门,表达式取值 verdict 不变。ActionSchema.visible是ExpressionInputSchema(无 boolean 成员),objectstack build产不出这个形状;手写视图 JSON 与进程内构造 action def 可以。顺带发现(未在本 PR 修)
清扫消费半径时在另一个包撞到同族第五处同形门,已按 Prime Directive #10 独立立单、未认领:#3835 ——
packages/app-shell/src/views/DeclaredActionsBar.tsx:190同一个(action as any).visible && !isVisible,该文件注释自称 "Mirrorsaction:button"。可达性是构造性的(普通 React 组件,由apps/console/.../ApprovalsInboxPage.tsx:2014/:2055直接以 JSX 挂载,路径上没有SchemaRenderer遮挡),已用一次性探针实证(未提交)。授权面比本族更热:那里渲染的是服务端声明的 action def(审批 Approve/Reject),布尔形状自然可写。单里另记了一处:该文件现有套件把useCondition整个打桩成常真,所以这个门从未被行使过。Generated by Claude Code