Repository navigation
console: 平台内置「审批请求」(sys_approval_request) 行「更多操作」菜单展开后 0 个菜单项——渲染成 128×10 的空白方块 #3562
Description
Activity
Triage:
pm:queue. Nodomain:*label — objectui is a whole-repo seat and routes byrepo:*, not by domain lanes. Kept in objectui rather than transferred to the objectstack backlog: the landing site is objectui-only (see below), it touches nopackages/specsurface and is not cross-repo, so it is repo-local work.Landing site — and a correction to the issue's own analysis, so nobody starts from the wrong hypothesis. The body reads the symptom as "this platform object's row-action set resolves to empty but the button renders unconditionally". The button is not unconditional; the guard is just counting the wrong thing.
packages/components/src/renderers/complex/data-table.tsxonorigin/main@7dfbeb7:1973: const customActions = Array.isArray(schema.rowActionDefs) && schema.onRowActionDef ? schema.rowActionDefs : []; 1976: if (!schema.onRowEdit && !schema.onRowDelete && customActions.length === 0) return null;That predicate asks whether handlers were passed. The menu's items are then filtered a second time, per item, by
DataTableBuiltinRowActionItemagainstschema.rowEditPredicates(and the equivalent for custom defs). So the empty-box state is reachable exactly when handlers are present but every item is predicate-suppressed — the trigger survives its guard, then renders nothing. That also explains the reporter's control case cleanly: a business object whose predicates pass keeps its two items,sys_approval_requestloses all of them, same component, same version.Consequence for the fix: the issue's option 2 ("don't render the trigger when there are no actions") is the right shape and is a one-place change — make the guard count items that will actually render rather than handlers that were supplied. It is object-agnostic, so it fixes every future instance of this rather than just
sys_approval_request, which is why it is queued as the scope here. Option 1 (give the platform object a row-action set) is a separate product question aboutsys_approval_requestitself and is not in this scope — if someone wants it, it is an objectstackplatform-objectsissue.Repro quality is good enough to dispatch as-is: named object and view, DOM measurements (
data-state=open,z-index: 50, 128×10,[role=menu]children0), an explicit ruling-out of the z-index misdiagnosis, and confirmation that rc.3 → rc.5 changed nothing.Dedup. No open issue or PR in the three repos covers this render guard. objectui#3055 (
pm:queue) also concernssys_approval_requestbut is a different defect — approval entry points and declared actions diverging across two implementations, which is about which actions exist, not about a trigger that renders with zero items. Cross-link, not duplicate; whoever claims both should note the shared object in "Serial constraints cleared" even though the files differ.本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
认领:PM 循环批 180(objectui 整仓席位,登记表 objectstack#4604)
按分诊裁定范围执行:方案 2(对象无关)——data-table 行菜单触发器的守卫从「数传入的 handler」改为「数真正会渲染的菜单项」(谓词过滤后),空则不渲染 ⋮ 按钮;方案 1(给 sys_approval_request 补行动作集)明确出界,属 objectstack platform-objects 议题。与在飞 #3717/#3742/#3613/#3614 文件面零相交(本单在 packages/components)。#3055 同对象不同缺陷,交叉引用不并卡。
会话:
session_01GTRjn8xBqp75dk7kFupVRt
分支:claude/issue-3562-row-menu-empty-guard
Worktree:objectui-3562
文件面:packages/components/(data-table.tsx 行菜单守卫 + 该包测试)(越界即停)
Generated by Claude Code
登陆点更正 + 本次交付范围(会话
session_01GTRjn8xBqp75dk7kFupVRt,分支claude/issue-3562-row-menu-empty-guard,PR #3756 draft)分诊裁定的缺陷机理是对的(守卫数 handler、菜单项按记录谓词二次过滤,两者不一致就出空菜单),但落点文件对报告人那一屏不成立。按
origin/main@b7b05da7f逐条核过:packages/plugin-grid/src/ObjectGrid.tsx:2194——rowActions: !!(schema.editable && hasActions),注释写明「RowActionMenu column (from columnsWithActions) already handles edit/delete … Only enable DataTable's built-in action column for inline-editing save/cancel」。console 对象列表非 editable 时,data-table 的操作单元格根本不渲染。ObjectGrid.tsx:1624-1660—— 列表自己注入操作列,cell 渲染 plugin-grid 的RowActionMenu。grep -c 'onRowEdit\|onRowDelete' packages/plugin-grid/src/ObjectGrid.tsx= 0 —— ObjectGrid 从不把onRowEdit/onRowDelete/rowEditPredicates传给 data-table,那条下拉分支在列表路径上拿不出任何项。ObjectGrid.tsx:1448:「ObjectGrid is the single convergence point of all three list callers」—— Setup 的系统对象列表也汇到这里。- 孪生缺陷(报告人的真实落点):
packages/plugin-grid/src/components/RowActionMenu.tsx:273-278
hasMenu = (canEdit && onEdit) || (canDelete && onDelete) || menuDefs.length > 0 || rowActions.length > 0
—— 同样在数 handler / 声明数;项一级过滤在:130、:179、:219。sys_approval_request在list_item声明的 approve / reject / recall 等动作,其visible是写给审批人的,admin 在「全部」视图逐行都不满足 →hasMenu为真、0 项。 - 旁证:报告实测
[role=menu]的children.length === 0。data-table 那条路径在onRowEdit与onRowDelete同时在场时会无条件渲染一条DropdownMenuSeparator,那种状态 children 至少为 1;RowActionMenu一条分隔线都没有,全压掉恰好是 0。
已交付(PR #3756,draft):
packages/components里 data-table 行菜单守卫改为数「真正会渲染的项」——行级决策(谓词按记录求值),守卫与两个 item 组件共用同一个可见性函数,含新测试(含反向验证:换回旧守卫 3 红 30 绿,与事先预测逐条一致)与 changeset。这条路径的真实消费者是packages/plugin-detail/src/RelatedList.tsx:1004-1042(详情页关联列表),缺陷在那里真实可达 —— 但不是本单报告人的那一屏。需要后续:修
plugin-grid的RowActionMenu.hasMenu(同一裁定方案 2、同一形状,文件面packages/plugin-grid/)才能真正关闭本单。本次派发的文件面限定packages/components/only,越界即停,故未动,请 PM 重新派发;PR #3756 建议以Refs而非Fixes合并,或与孪生修复一并关闭。
Generated by Claude Code
裁定 + 半件验收(PM 循环批 180,会话
session_01GTRjn8xBqp75dk7kFupVRt):裁定:方案 A。 PR #3756(data-table 半件)ACCEPT,正文已改 Part-of 不关本单;报告人那一屏的真实落点
plugin-grid/src/components/RowActionMenu.tsx:273-278的hasMenu(同样在数 handler/声明数)按同一裁定(数谓词过滤后真正渲染的项,零则不渲染触发器,含 :219 的 inline primary 按钮路径)继续本认领另派孪生 dev,其 PR 以 Fixes 关闭本单。C(直接关)不可取——会把仍坏着的用户报告标记已修;B 违反文件面边界。公开确认前提订正:分诊(含我的派发)把落点定在 data-table 是错的——dev 以七条实证推翻(ObjectGrid 不传 onRowEdit/onRowDelete、自注入 RowActionMenu 列、分隔线旁证与 0-children 实测吻合等,见 PR #3756 正文「登陆点更正」)。data-table 侧缺陷同类且真实可达(生产者=详情页关联列表 RelatedList),修复有效不白做。后续读者以 PR 正文的登陆点更正为准。
#3756 验收记录:守卫行级化(谓词按记录求值,表级守卫表达不了)、单一谓词求值源(守卫与 item 组件结构性不可分歧)、孤立分隔线顺带修、混合行列对齐钉住;13 新测试,逆向验证预测 3 红逐字命中;type-check/lint/控制字节全绿。
visible: false真值门刻意逐字保留并立 #3758(改它会改变哪些项渲染,越出本单)。孪生半件派发:分支
claude/issue-3562-rowactionmenu-guard,worktreeobjectui-3562b,文件面packages/plugin-grid/(RowActionMenu.tsx + 该包测试)。
Generated by Claude Code
孪生半件已交付(PR #3761,draft) —— 会话
session_01GTRjn8xBqp75dk7kFupVRt(同一认领的延续),分支claude/issue-3562-rowactionmenu-guard,worktreeobjectui-3562b,文件面packages/plugin-grid/only。本 PR 以Fixes关闭本单。前提复核:裁定的落点(
RowActionMenu.tsx的hasMenu,数 handler / 声明数)在origin/main@e473b6c29上逐字成立,行号 273-278 未漂移;:130/:179/:219三处项级过滤也如描述。premise 有效。按裁定五条逐条落地:
- 守卫改为数谓词过滤后真正会渲染的菜单项(
plan.menuCount),零则整个 ⋮ 不渲染;决策落在行级(RowActionMenu本就由_actions列的 cell 逐行实例化,无需像 data-table 那样新抽 per-row 组件)。 :219的 inline primary 路径:核实结果是它本来就在谓词失败时return null,所以行为不变;按裁定「align 到同一可见性源」办 —— 改为读共享函数,不再自带一份useRowPredicate+ 真值判断。- 单一可见性源:
isBuiltinRowActionVisible/isCustomRowActionVisible,经planRowActionMenu被守卫与三个 item 渲染器共读,与 PR fix(data-table): 行「更多操作」触发器改为数「真正会渲染的项」,空则不渲染 #3756 结构平行(同名、同 plan 形状),不跨包 import。 visible: false真值门逐字保留并加了正向钉子(行动作声明visible: false仍然渲染该菜单项——可见性门用真值判断(#3492 在行菜单上的未收口部分) #3758 仍成立)。- 列对齐:操作列是
ObjectGrid表级注入的,本次只改单元格内部;空行渲染空单元格,并用真实 ObjectGrid 钉住混合行td数量一致。
验证:新增 23 例;
packages/plugin-grid/全量 55 文件 / 479 例全绿;type-check 0、lint 0 error、控制字节 OK。反向验证先写预测后运行,预测 4 红 19 绿(并明确预测 inline 套件那两条不会红 —— 单个 primary 占掉 inline 槽时旧守卫同样为 false,那两条结构上察觉不到守卫被换回去),实测逐条命中。顺带发现,未在本 PR 修:已立 #3762(unassigned)——
maxInlineActions槽位按声明序分配,被visible压掉的 primary 白占槽位,把存活的下一个 primary 挤进溢出菜单。属「某一项渲染在哪里」,越出本单裁定第 4 条;注意修它需替换 PR #3761 里那条正向钉住现状的测试,而非新增矛盾断言。
Generated by Claude Code
Generated by Claude Code
- 守卫改为数谓词过滤后真正会渲染的菜单项(
孪生半件验收:PR #3761 ACCEPT(会话
session_01GTRjn8xBqp75dk7kFupVRt,PM 循环批 180/181)——报告人那一屏的真实落点已修,本 PR 以 Fixes 关闭本单;两半件合计:data-table(PR #3756,已合)+ plugin-grid(本 PR)。交付内容:
hasMenu换为planRowActionMenu的menuCount > 0——触发器只数本行谓词过滤后存活的项,零存活即不渲染 ⋮;可见性单一来源(isBuiltinRowActionVisible/isCustomRowActionVisible)同时供 plan 与全部三个 item 渲染器读,含 :219 inline primary(该处行为本已正确,按裁定完成的是对齐到共享来源——如实定界);与 #3756 结构平行(同名函数、同 plan 形)但不跨包 import;visible: false真值门与 maxInlineActions 切片按裁定第 4 条逐字保留并正向钉住;列对齐无需动 ObjectGrid(表级注入,压掉的行渲染空单元格)。证据:23 新测试含报告人形状/对照组/真实 ObjectGrid 列对齐;逆向验证预测 4 红 19 绿且显式预测两条 inline 用例结构上无法探测该回退(模板式"全红"预测在此本会是错的)——实测恰 4 红逐字命中;plugin-grid 全包 479 测试绿;CI 报告时 14/18 零失败,余下 shard 由 merge queue 兜底。
新立 #3762(maxInlineActions 槽位在 visible 求值前分配,被压 primary 浪费槽位把幸存 CTA 挤进溢出菜单;可达性如实标注未验证,并预警修它需替换本 PR 的正向钉而非加矛盾断言)入分诊池。
Generated by Claude Code
现象
平台内置对象
sys_approval_request(com.objectstack.account)的列表,每行都渲染了「更多操作」(⋮) 按钮,但点开后菜单里一个菜单项都没有 —— 视觉上就是「点了没反应 + 操作列旁边多出一小块空白」。一开始很容易误判成 z-index 被表格遮挡,不是 —— 层级完全正常,菜单也确实打开了,就是没有内容。
复现
sys_approval_request有数据DOM 实测
17.0.0-rc.5,admin 账号,1440×900:对照
同库、同版本、同一套行菜单组件,业务侧自有对象(我们的设备台账)的行「更多操作」正常展开「编辑 / 删除」两项。所以问题限于这个平台内置对象 —— 像是它的行动作集合解析出来是空的,但按钮仍然无条件渲染了。
期望
二选一:
版本
@objectstack/*17.0.0-rc.517.0.0-rc.3升到 rc.5 后逐条复验,此条无任何变化(rc.3 上的 DOM 量测与上面逐字一致)