Skip to content

feat(app-shell): configure a list view's selection-bar actions in Studio (#30089) - #30339

Draft
objectstack-fleet[bot] wants to merge 5 commits into
mainfrom
claude/project-thread-0vx632
Draft

objectstack-fleet[bot] wants to merge 5 commits into
mainfrom
claude/project-thread-0vx632

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Yibo Wang · project thread

Fixes #30089

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:Studio 列表视图属性面板新增「批量操作」区:可从本对象已有的操作(含内置「删除」)中挑选放进选择栏(bulkActions),也可新增、修改、删除「字段更新」(bulkActionDefs:按钮文字、要填写的字段、确认提示)。
  • 为什么改:按裁决 A 执行。动作编辑器一直提示「到列表视图上声明批量操作」,视图面板却无处可填;现在实施和运营在 Studio 里就能配出「批量修改负责人」这类按钮,不用找开发,内核不写死任何业务字段。
  • 风险与回滚:只加界面,spec、服务端、元数据键都不动;不声明这两个键的视图保存结果与之前逐字节一致。回滚即还原本 PR。
  • 先看:ListViewBulkActionsSection.tsx(写入逻辑与「删除是否保留」的判定)、ObjectListViewInspector.tsx(只加了一处挂载)、ObjectListViewInspector.bulkActions-30089.test.tsx。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/ObjectListViewInspector.bulkActions-30089.test.tsx,预期 11 条全部通过;或看截图 30089-4(运行时选择栏出现「批量修改负责人」)与 30089-7(成功 2 / 2)。
  • 需要你做的:无,席位落地。

What changes

A new section in the Studio list-view panel (ListViewBulkActionsSection.tsx), mounted for grid views only, below Sort. It edits exactly the two keys ListViewSchema already declares (packages/spec/src/ui/view.zod.ts, "Row & Bulk Actions"); no spec, server or new metadata key.

  • Selection-bar actions (bulkActions). A picker lists the object's actions by label (read from the draft-overlaid object, the same read the panel's field pickers make) plus the built-in Delete under its reserved name delete. Picked names are listed with a remove button; a name the object does not declare is marked "Not an action of this object".
  • Field updates (bulkActionDefs, operation: 'update'). "Add a field update" opens a form held locally until it has a button label and at least one field; Add then writes one def: name (update_FIELDS, unique among the view's selection actions), label, one required param per field (named for the field so the value is patched there; a select's options and a lookup's object copied from the field; a user field needs no object), and an optional confirmText. Before writing, the def is checked with the spec's BulkActionDefSchema; a refusal is shown and nothing is written. Fields offered: writable fields of a type the bulk dialog can collect (text, number, date, select family, lookup/master-detail with a reference, user), no read-only, formula or platform-injected hidden field.
  • Editing in place. An existing update def's label, fields (the last field cannot be removed) and confirmation are edited in place; a served confirmText arrives as the parsed { dialect, source } envelope, which is shown as its sentence and kept on edit. A def of another kind (delete, aggregate custom) is listed with "Edited in metadata" and a remove button.
  • Empty keys are removed, never written as [], so a view that declares neither key saves byte-for-byte as it was read.
  • Customized view of an installed app. The section writes through the panel's existing writeBody buffer, so on a read-only base the first edit goes through the existing view customization copy (ListViewCustomization.writeTarget): saved as a draft in the .custom pair with overrides: { package, basedOn }. Nothing about that path is rebuilt.
  • i18n: 21 keys each in the studio namespace's en and zh.

The card's "Not measured" items, measured

  • Does the default Delete leave the selection bar when a view declares bulkActionDefs? Yes. Read from ObjectGrid's effectiveBulkActions and confirmed live: with neither key declared the grid shows its built-in Delete; once the view declares either key, Delete stays only if bulkActions names delete. The section states which of the three holds (data-state = default / kept / dropped) and offers "Delete (built-in)" in the action picker so the author can keep it. Live: shots 30089-4 (declared with delete: bar shows 批量修改负责人 + 删除) and 30089-10 (delete removed: bar shows 批量修改负责人 only). Edge: the grid filters an update def out when the caller lacks the edit verdict, and then its implicit Delete comes back; the section describes the author's declaration, not a given user's bar.
  • How a customized view of an installed app merges these keys. It does not merge per key: the customization is the pair's whole copy of the view (overrides declared), and the served effective view is that copy. Live on com.example.crm 4.0.0: after the first edit, GET /meta/view/crm_lead.all?state=draft&package=com.example.crm.custom held bulkActions, bulkActionDefs and overrides: { package: com.example.crm, basedOn: 4.0.0 }; after publish, GET /meta/view/crm_lead.all/layers?package=com.example.crm answered the effective view with both keys.

Tests

  • ObjectListViewInspector.bulkActions-30089.test.tsx (new, 11 cases; the real hook and panel over a real MetadataClient whose transport judges each view PUT with the installed spec's view schema): picking writes bulkActions; adding a field update writes one def BulkActionDefSchema accepts (user / select options / lookup object); add waits for a label and a field; edit label, fields, confirmation and remove round-trip, emptied key removed; served envelope confirmation edited as its sentence; removing the last action removes bulkActions; other-kind def and unknown name; read-only offers no edit; CONTROLS: a view with neither key saves byte-for-byte as read, an edit elsewhere adds neither key, a kanban has no section.
  • InterfacesPillar.customize-28562.test.tsx (shared harness, new top-level describe): on a read-only base, the first field update is written into the pair's copy with the override declared, pinned to "no draft there", the base untouched.
Runs (head d8c1f11)

All under scripts/pm/os-verify-lock.sh, from the ui/ root as ui/AGENTS.md prescribes.

  • pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/InterfacesPillar packages/app-shell/src/views/studio-design/StudioDesignSurface packages/app-shell/src/views/studio-design/ObjectListViewInspector on d8c1f112: Test Files 149 passed (149), Tests 1036 passed (1036), lock VERDICT command-exit 0. Narrowed to the Studio pillar, surface and list-view panel files; the rest of Test UI is CI's.
  • The new file alone on 5baab8fe: 11 passed (11).
  • Census and namespace suites (studio-namespace, studio-namespace-lazy, components clickableNonControlCensus-13461, iconOnlyButtonCensus-12143, app-shell product-neutral-renderer.ratchet, plugin-form affordanceGrantMap-12082): 6 files, 115 passed.
  • pnpm --filter @object-ui/i18n run type-check && pnpm --filter @object-ui/app-shell run type-check: exit 0. npx eslint on the touched files: 0 errors (warnings are the existing react-refresh/only-export-components kind).
  • node scripts/pm/dispatch-gates.mjs --commands on d8c1f112: 35 derived commands, each run, every one exit 0; --ran reconciliation: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. Includes node scripts/check-sdui-manifest.mjs (exit 0).
  • pnpm --dir ui run check:new-line-citations: 0 new citations, exit 0.
Ablation

Each mutation went through scripts/ablation-replace.mjs (anchor hit 1 → 0, blob restored to HEAD, git diff HEAD empty). The test imports resolve app-shell from src (no dist involved), so no rebuild was needed between legs.

  • writeNames (the bulkActions write) made a no-op, on 07a2728e: 2 failed / 8 passed in the new file (the picking pin and the remove-last-action pin).
  • writeDefs (the bulkActionDefs write) made a no-op, on 07a2728e: 4 failed / 32 passed across the new file and the customize harness (add, edit/remove round-trip, other-kind remove, and the pair-copy pin).
  • The served-envelope read (envelope.source) replaced with an empty string, on d8c1f112: 1 failed / 10 passed (the envelope pin).

Acceptance notes

  • The section is shown for grid views only. Non-grid list views (kanban, gallery, …) render their own bulk bar for bulkActions but not bulkActionDefs (ListView.tsx reads only predicates from it), so the section is withheld there rather than offering a field update that would never render. Not filed: a reading, no defect.
  • Each param is written required: true: the executor spreads params straight into the patch, so an empty optional value would clear the field on every selected record. An author who wants an optional field edits the def in metadata.
  • Labels in a def are plain strings (the spec's own note: an authored def is not i18n-resolved); the section writes the label as typed.
  • rowActions (also in the "Row & Bulk Actions" block) is not part of this card's ruling and is untouched.

Verification

Browser, examples/app-crm dev boot from this branch (merged with main), console on Vite, zh-CN, admin. Shots in the project's ui-orders/30089-shots/ folder:

  1. 30089-1-studio-new-field-update.png — 定制 pressed on the read-only 线索 view; the new field-update form filled: 批量修改负责人, field 分配给, confirmation.
  2. 30089-2-studio-section-saved.png — the def saved, 删除(内置) picked; note reads that Delete is kept; header shows the pair override.
  3. 30089-3-studio-reloaded.png — after reload the confirmation reads back as its sentence.
  4. 30089-4-runtime-selection-bar.png — published; two rows selected; bar shows 批量修改负责人 and 删除.
  5. 30089-5 / 30089-6 — the dialog asks 分配给 (person picker), then confirms 「把 2 条线索改派给 Dev Admin?」 with the two records.
  6. 30089-7-runtime-after-run.png — 成功 2 / 2; 30089-8 the list shows Dev Admin on both rows (API read agrees).
  7. 30089-9 / 30089-10 — 删除 removed in Studio (note: not shown), published; the bar shows 批量修改负责人 only.

Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01WGufzhfh9quLdZYWtWEMLK

…panel

The list-view panel gains a section for the grid's selection bar: pick the
object's actions (and the built-in Delete) into `bulkActions`, and add, edit
or remove field updates in `bulkActionDefs` (label, fields to ask,
confirmation), each checked against the spec's BulkActionDefSchema before it
is written. The section says whether the built-in Delete stays.

Claude-Session: https://claude.ai/code/session_01WGufzhfh9quLdZYWtWEMLK
Co-authored-by: Claude <noreply@anthropic.com>
…zation copy they go through

Claude-Session: https://claude.ai/code/session_01WGufzhfh9quLdZYWtWEMLK
Co-authored-by: Claude <noreply@anthropic.com>
… sentence

A saved def comes back with `confirmText` lifted to `{ dialect, source }`;
the section shows its source and keeps the envelope on an edit.

Claude-Session: https://claude.ai/code/session_01WGufzhfh9quLdZYWtWEMLK
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation tooling labels Nov 5, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#4 · os-support-ai · session_01WGufzinedUGSXteN45poyo

维护者速读

  • 改了什么:Studio 列表视图面板(表格视图)新增「批量操作」一节:可勾选对象已声明的动作和内置删除写进 bulkActions,并可新增、编辑、删除「批量修改字段」操作,写进 bulkActionDefs(标题、每个字段一个必填参数、可选确认文字)。
  • 为什么改:选中多行后工具栏能放什么,以前只能手写元数据([Decision] Selection-bar actions cannot be configured in Studio: should the view panel offer them? #30089);规格早已有这两个键,设计器没有入口。
  • 风险与回滚:只是新增一节,写入走面板已有的 writeBody 缓冲,只读基座照旧走定制副本;每个新定义先经规格 BulkActionDefSchema 校验再写。另修了一处实测缺陷:服务端回来的 confirmText 是 {dialect, source} 包,以前读成空。回滚即 revert。
  • 先看:ListViewBulkActionsSection.tsx 的 addDef、bulkDeleteStateOf、FieldUpdateRow 的确认文字读写。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/ObjectListViewInspector.bulkActions-30089.test.tsx(11 条全绿)。
  • 需要你做的:CI 全绿后请 Ready + 加入合并队列(或回复「允许落地」由我代办);须排在 fix(app-shell): a draft-only object's nav entry opens its drafted default list view in Studio Interfaces #30315 之后(同一文件,落地前再合一次 main)。

席位意见:ACCEPT。

席位核对

ACCEPT → PR #30339 @ d8c1f11218dc7d7f2fda9cdd5626b67cc0572038 (card #30089, claim 6650543102, os-dev-report 6651400495).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Decision] Selection-bar actions cannot be configured in Studio: should the view panel offer them?

1 participant