Skip to content

app-shell/DeclaredActionsBar: 服务端声明动作的真值可见性门实证可达 —— visible: false 照样渲染(#3823 消费半径清扫发现的同族第五处) #3835

Description

@yinlianghui

来源

发现自 #3823action:bar 成员动作组件级真值门)的消费半径清扫 —— 按「一个规则改了,它跑到哪里就扫到哪里」枚举 action:button / action:icon 的宿主时,在另一个包里撞到同一形状的第五处门。不在 #3823 的文件面(#3823 只收 packages/components/src/renderers/action/{action-button,action-icon}.tsx),故独立成单,未认领

机理

packages/app-shell/src/views/DeclaredActionsBar.tsx:190:

if ((action as any).visible && !isVisible) return null;

#3492 / #3758 / #3812 / #3823 同一个缺陷:false && … 为假 → 不 return null → 渲染。作者写 visible: false(最明确的「永不显示」)被真值判读成「没声明门」。该文件自己的注释就写着它 "Mirrors action:button (fail-closed visible)" —— 它镜像的正是 #3823 刚修掉的那个门。

可达性不需要论证,是构造性的:DeclaredActionsBar 是一个普通 React 组件(packages/app-shell/src/views/index.ts 导出),由宿主直接以 JSX 挂载 —— apps/console/src/pages/system/ApprovalsInboxPage.tsx:2014:2055。这条路径上没有 packages/reactSchemaRenderer,所以不存在「宿主先按 newSchema.visible !== undefined 求值并隐藏」那层遮挡(那正是 #3823 判定另三处组件级门休眠的依据)。这个门是该路径上唯一的门。

实证(origin/main@c8526825618f86bff6d270f70893a35992243dea,一次性探针,未提交)

探针按求值入口的真实语义打桩(toPredicateInput 原样透传布尔、evaluateCondition 对布尔短路),挂 location: 'record_section' 的两个声明动作,其一 visible: false:

FAIL  PROBE DeclaredActionsBar declared visible:false > visible:false member should NOT render
AssertionError: expected  button type="button" …(2)  /button  to be null

+ Received:
  button
    data-testid="declared-action-ghost"
    type="button"
    variant="outline"
    Ghost
  /button

Tests  1 failed | 1 passed (2)

对照组(无 visible 的同批动作)照常渲染 —— 坏的只是门,不是求值。

与已有覆盖的关系(为什么现有测试全绿)

packages/app-shell/src/views/__tests__/DeclaredActionsBar.test.tsx:26-27 把求值入口整个打桩成常真:

// `visible` predicate: our test actions omit `visible`, so this is unused,
// but keep it truthy so a `visible`-carrying action would still render.
useCondition: () => true,

于是这个门在该套件里从未被行使过 —— 与 #4984 同一族的「fixture 让死掉的规则保持绿色」形态。修的时候这条桩要按真实语义收紧(至少让布尔短路),否则补的钉子会因为「什么也没产生」而空绿。

严重度输入(请分诊裁)

#3812 / #3823 这一族更热的授权面:

  • 这里渲染的是服务端声明的 action def(对象元数据 / 审批请求的 sys_approval_request 动作),不是手写视图 JSON —— ActionSchema.visibleExpressionInputSchema(无 boolean 成员)这条「objectstack build 产不出布尔形状」的缓解在这条路径上不成立:def 来自服务端 metadata 与进程内构造,布尔形状是自然可写的。
  • 宿主是审批收件箱的记录区动作条(Approve / Reject / Reassign)。一个本该被 visible: false 关掉的审批动作渲染成可点按钮,点下去就是一次真实的 approve/reject 调用。

修法(与同族一致,无新决定)

统一到 packages/components/src/renderers/action/visibility-gate.tshasDeclaredVisibilityGate(!= null && !== '',PR #3825 落 main @ b5980f471),verdict 仍交给求值入口。跨包引用方向已经通(app-shell 已依赖 @object-ui/components,同文件已从它 import Button / Separator / cn),但该 helper 目前未从 @object-ui/components 的 barrel 导出 —— 是否导出、还是在 packages/core 立一处共享定义,是实施者要先定的一个小决定(五处同族门分散在 components / plugin-grid / app-shell 三个包,各自抄一份就是 #3142locations 拆过的那种漂移)。

钉子按同族对称性:三形状(false 隐藏 / true 渲染 / 未声明渲染)+ '',并先把上面那条常真桩收紧。

Related: #3823(本单的发现来源)、#3812 / PR #3825#3758 / PR #3816#3492(不变量出处)、#3142(同批文件的 locations 漂移前情)。未认领。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions