fix(plugin-grid): inline 行动作槽位分配给存活的 primaries (#3762) - #3833
Merged
Conversation
…t render (#3762) `RowActionMenu` allocated its inline slots on the DECLARED row actions, before any `visible` predicate ran: `primaryDefs.slice(0, maxInlineActions)`. So on a row whose LEADING `variant:'primary'` action was suppressed by its own `visible`, that action still held the slot — `RowActionInlineButton` returned `null` into it — while the next primary, the one that did survive the row's predicates, had already been sliced into the overflow list. The row rendered no inline button and a "⋮" hiding its main CTA, though exactly one primary was visible and the budget (default 1) allowed exactly one inline button. The slot decision moves inside `planRowActionMenu`, after visibility: it now takes the capability-gated defs unpartitioned (`actionDefs` + `maxInlineActions` replace the pre-sliced `inlineDefs`/`menuDefs`), filters them once, then partitions the survivors. Survival and placement decided in one function is the point — there is no second place that partitions the defs, so they cannot drift. Cost is unchanged at one `visible` evaluation per def; the partition is array work. `maxInlineActions` keeps its meaning and its default of 1 — it is a width budget for real buttons, and charging it for an invisible action protected no layout. Menu order (folded primaries above secondaries), which items render at all, the ADR-0066 D4 capability gate and the #3562 empty-menu guard are all untouched. PR #3761's status-quo pin `a suppressed primary does NOT promote the next primary into its inline slot` asserted the behavior this issue reverses, so it is REPLACED (its expectations are now the wrong verdicts, not a re-spelling) — along with the code comments that recorded why the slice stayed on declared order. The replacement suite pins the new invariant, the unchanged budget (two survivors still fold the second), and cross-checks the #3562 guard. The ungated fixtures in `RowActionMenu.test.tsx` are deliberately left alone: declared order and surviving order coincide there, so they hold the clipped-column regression this budget exists for. Reverse-verified by restoring the pre-#3762 allocation order under the new signature: exactly the 3 predicted tests went red (the promotion pin plus the two slot-allocation unit cases), 513 others stayed green. Co-authored-by: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Collaborator
Author
|
✅ 验收通过(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt)—— undraft + auto-merge。 核验:分配移入 Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3762
问题
RowActionMenu的 inline 槽位分配跑在声明序上,且先于任何visible求值:于是当一行有 2 个以上
variant: 'primary'、且靠前那个的visible对这一行不成立时:RowActionInlineButton对它return null,槽位空转);menuDefs,只能渲染进「⋮」。结果:这一行明明只有一个可见 primary、
maxInlineActions(默认 1)也允许 1 个 inline,用户看到的却是「没有 inline 按钮 + 一个要点开才看得到主操作的 ⋮」——行的主 CTA 被藏进溢出菜单。修法
槽位分配移进
planRowActionMenu,排在可见性之后。该函数不再接收预先切好的inlineDefs/menuDefs,改为接收未分区的actionDefs(已过 ADR-0066 D4 能力门)加maxInlineActions,自己过滤一遍再分区:存活判定沿用 PR #3816(#3758)的入口:
isCustomRowActionVisible,声明检测按!= null && !== '',所以visible: false同样算「被压掉」、同样不占槽。这次没有新增第二处判定,判定与摆放收在同一个函数里 —— 全仓再没有第二处对 defs 分区,两者结构上无法漂移。求值成本不变:仍是每个 def 一次
visible(改前inlineDefs/menuDefs两次 filter 作用在互斥集合上,总数相同),分区是纯数组操作。前后对照(
maxInlineActions: 1,两个 primary,靠前那个被visible压掉)语义边界(都未变):能进 inline 的数量(默认仍是 1)、菜单内排序(折叠的 primary 仍在 secondary 之上)、哪些项渲染、能力门(仍对声明集只施加一次、在本决定的上游)、#3562 的空菜单守卫(无可渲染项的行仍然不长「⋮」)。全部 primary 都未被门住的行(激发
maxInlineActions的sys_environmentOpen + Upgrade Plan 那个形态)逐位不受影响 —— 声明序与存活序重合。替换的断言(不是并存矛盾断言)
PR #3761 曾把当时的现状正向钉住:
a suppressed primary does NOT promote the next primary into its inline slot(RowActionMenu.emptyGuard.test.tsx)那条钉子断言的正是本单要反转的行为,它的期望(
upgrade不在 inline、存在一个「⋮」)现在是错的裁定,因此按 fixture 三分类里的「整条替换」处理:删除该 case,在原地留下一段注释交代它为何被替换(沿用同文件里 #3758 替换 #3562 fixture 时的写法),新不变量写进新 describe。PR #3761 写在代码里的两处「slice 保持原状的理由」注释(planRowActionMenu的 doc 段 + 组件内 useMemo 上方那段)也一并改写为新不变量;组件内引用旧标识符menuDefs的那句历史引文加了括注,避免留下悬空标识符。新钉子(
RowActionMenu.emptyGuard.test.tsx):maxInlineActions语义与默认值 1 未被顺手改宽);maxInlineActions: 2时每个槽都从存活集填(折叠的 primary 仍在 secondary 之上);maxInlineActions: 0时不发生任何槽位分配。planRowActionMenu整个 describe 的入参从inlineDefs/menuDefs迁到actionDefs(无variant即非 primary,菜单侧各 case 读法不变)。planRowActionMenu不在包 barrel 里(barrel 只导出RowActionMenu/formatActionLabel/RowActionMenuProps),入参换形不外溢;对外类型面零变化,所以下游包无需重编。RowActionMenu.test.tsx的 case 故意一条没动 —— 那里的 fixture 全部未加门,声明序与存活序重合,它们守的是当初maxInlineActions要修的「窄列裁切」回归;只在文件头 doc 补一句说明预算现在按存活集计。消费半径清点
规则的调用方逐一 grep 过:
planRowActionMenu只被本组件与RowActionMenu.emptyGuard.test.tsx引用;RowActionMenu只被同包ObjectGrid(maxInlineActions={schema.maxInlineRowActions ?? 1})消费,app-shell/src/views/ObjectView.tsx里只是一句注释;packages/components的 data-table 半边(PR #3756)没有 inline primary 这条路径,不共享代码。e2e 里只用到row-action-trigger(未门住的 fixture)。全仓无残留的inlineDefs/menuDefs入参写法,仅剩两处明确标注为旧守卫引文的注释。验证
仓根 flock 串行 +
NODE_OPTIONS=--max-old-space-size=4096+--maxWorkers=2(新 worktree 里先pnpm --filter '@object-ui/plugin-grid^...' build)。反向验证(方向先判后跑)
跑之前先写下预判:只把
planRowActionMenu内部的分配顺序退回 #3762 前(先按声明序 slice,再 filter 可见性),保留新签名,这样测试仍能编译、信号纯粹是语义层面的。预判 恰好 3 条红,全在emptyGuard文件:晋升那条 DOM 钉 + 两条槽位分配的纯函数钉;另外「两者都存活」「全部被压」「maxInlineActions: 0」以及整个RowActionMenu.test.tsx应当保持绿——它们是不回归钉,不是本次修复的证据(尤其「全部被压」那条两种语义下都绿,其中一半是「什么都没产生」的空绿,这正是晋升钉写成正向断言的原因)。实测与预判逐条一致:
事后已用 patch 逐字节还原(
diff比对确认与反向验证前的改动完全相同),并在推送前重跑一遍全量 + type-check 全绿。Changeset
.changeset/row-action-inline-slot-survivors-3762.md,@object-ui/plugin-grid: patch—— 用户可见的行为变化(某一项从菜单里移到 inline),正文写明变化面与不变面。可达性说明(承接 issue 的诚实标注)
issue 正文明确「未在真实元数据上复现」:形态(同一
list_item上 2 个以上 primary)确实存在且是既有测试的原始动因(cloudsys_environment的 Open + Upgrade Plan),但靠前那个是否带visible未经核实。本 PR 不改变这一点 —— 代码层面的不对称是确定的且已修,可达性仍按分诊裁定(pm:queue,最坏是 CTA 摆错位置,非数据问题)。Generated by Claude Code