feat(grid): aggregate single-call mode for bulk actions — execution: 'aggregate' (#3139) - #3141
Merged
Merged
Conversation
…'aggregate' (#3139) A custom bulkActionDefs entry could only fan out one action-runner dispatch per selected record; "select N rows → ONE call with every id" (single zip download, merged PDF, batch print) was inexpressible. BulkActionDef now carries execution?: 'perRecord' | 'aggregate' (default 'perRecord'). An aggregate def dispatches its action exactly once for the whole eligible selection, injecting params._selectedIds: string[] and publishing the rows as context.selectedRecords. The authored form names a declared object action ({ name, operation: 'custom', execution: 'aggregate' }) and resolveBulkActions attaches the declaration. - executor: the aggregate call rides executeBulkBatch's existing bulkCall slot (one batch, batchSize ignored, single-row selections still aggregate); the perRow fallback only re-throws the captured error for per-id attribution — never N re-dispatches against a single-call endpoint, and a def with no wired dispatcher fails loudly instead of degrading to fan-out - results are all-or-nothing; per-row Retry is hidden (total failure keeps the selection, re-running the action is the retry) - console serverActionHandler recognizes _selectedIds and skips the single-record multi-select guard; posts no synthesized recordId - url/api target interpolation exposes ${ctx.selection.ids} / ${ctx.selection.count} so plain list_toolbar actions can carry the selection; ${param._selectedIds} works in aggregate dispatches - pins for both semantics side by side (one-call aggregate vs one-request-per-record), resolver merge scoping, guard skip, interpolation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S9aiswZBzoVYsyLKRuGByE
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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.
Closes #3139.
问题
批量选择条的
bulkActionDefs中,operation: 'custom'只有逐行语义:runner 对每个选中记录各调一次runAction(actionDef, row, params)(注入_rowRecord)。「勾选 N 行 → 一次调用拿到全部选中 id → 服务端产出单一聚合产物」(多台设备二维码打包成一个 zip、批量打印、合并导出 PDF)无法表达。现状还很不对称:
operation: 'update'/'delete'早有聚合通道(executeBulkBatch的bulkCall,一次带全部 ids),未解析的字符串批量动作也已有一条executeAction({ type, params: { records } })单次全量通道 —— 把动作正确声明为对象动作反而丢失聚合语义。方案
BulkActionDef新增execution?: 'perRecord' | 'aggregate'(缺省'perRecord',存量视图零影响)。作者书写形态就是命名一个已声明的对象动作:聚合模式下 runner 恰好调用一次,注入
params._selectedIds: string[],整记录走已类型化的context.selectedRecords通道(5000 行上限时 POST body 只带 ids,不背整记录)。能力放在视图侧 def 而非ActionSchema—— spec 17 的action.bulkEnabled墓碑明示多选工具栏只由视图bulkActions/bulkActionDefs驱动,本方案不重开该退役决定,也不需要新的服务端路由。改动
useBulkExecutor.ts):聚合调用复用executeBulkBatch现有的bulkCall槽位 ——bulkFastPath.ts一字未改。整批一次调用(忽略batchSize,maxRecords仍生效),单行选择也走聚合(服务端契约不同)。失败为 all-or-nothing:真实错误归因到每个 id 供结果面板/错误 CSV 使用,perRow分支只重抛不重放 —— 绝不对单次调用契约的端点扇出 N 次;未接线 dispatcher 时响亮报错而非静默降级为逐行。ObjectGrid.tsx):新增runBulkActionAggregate,与runBulkActionRecord共用剥离 helper(防两个分发器漂移)。聚合模式保留resultDialog(逐行「N 个弹窗阻塞」的理由不成立,一次性揭示下载链接正是该场景)。runAggregate;逐行 Retry 对聚合隐藏(整批失败保留选中集,重跑动作即重试)。resolveBulkActions.ts):仅当 def 显式execution: 'aggregate'且无内联actionDef时才解析同名对象动作并附上(authored 键胜出,丢弃逐行并发上限batchSize: 25)。普通 custom def 与对象动作同名时保持历史 no-op 语义(有回归守卫)。serverActionHandler识别_selectedIds,跳过「select exactly one row」多选拦截、不合成recordId(服务端读 id 数组)。flow 动作维持拦截 —— flow 只有单recordId输入变量,多选歧义。${ctx.selection.ids}/${ctx.selection.count}(逗号拼接,沿用现有String(array)行为)—— issue 建议方案 3 的低成本切片,普通list_toolbarurl/api 动作也能拿到当前选中集;聚合模式下${param._selectedIds}天然可用。配套的服务端契约(
_selectedIds进入 ADR-0104 参数白名单 + spec describe + showcase specimen)在 objectstack-ai/objectstack#4461。防 AI 犯错措施
executeBulkBatch决策树内,不开并行代码路径。execution在类型、executor 分支、resolver 合并、两个分发器四处都写了决策注释。demo/bulk-actions.tsx)双语义并示:Mark Done 每行一行日志,Export Zip 一行带[t1,t2,t3]。测试
新增覆盖:恰好一次调用带全部行与参数;单行选择仍走聚合;
batchSize: 2对 5 行仍一次调用;失败 → N 条带真实错误的 per-id 记录且零次逐行分发;未接线 → 响亮失败;retry()返回 false;execution缺省时即便接线了runAggregate仍走逐行(模式由 def 决定,不由能力决定);resolver 合并的四种边界;${ctx.selection.ids}空/非空;console 多选守卫放行。验证:plugin-grid 全量 409 测试通过、core actions 211 通过、app-shell console runtime 套件通过;lint 0 error;types/core/plugin-grid/app-shell 构建通过。
🤖 Generated with Claude Code
https://claude.ai/code/session_01S9aiswZBzoVYsyLKRuGByE