Skip to content

feat(app-shell): Studio item toolbar — layers, references, history with rollback, audit and source on every pillar item - #28296

Merged
objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/project-thread-v8ndrp
Oct 31, 2026
Merged

objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/project-thread-v8ndrp

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Fixes #28239

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:Studio 的 Data、Interfaces、Automations 三个支柱,打开任一项时,项头部多出一组工具:分层、引用关系、历史(可回滚)、审计日志、源码,与 Setup 项页面右侧那套是同一批组件;这些组件搬到共享目录 views/item-tools/,Setup 改为从那里引用,行为不变。
  • 为什么改:维护者裁决 D-5 / D-7(「setup 右侧这套界面,包括看版本历史的,本身就应该属于 studio」):作者在 Studio 改了东西,要撤销还得跑去 Setup;后续定制卡都要在编辑处看历史和回滚。
  • 风险与回滚:Setup 页面只换了引用路径、引用面板的加载搬进同语义的 hook,Setup 原有测试全部不改语义照绿;Studio 只在头部加按钮组。整个 PR 可单独回退。
  • 先看:ui/packages/app-shell/src/views/item-tools/StudioItemTools.tsx(工具栏与回滚门槛)、StudioDesignSurface.tsx 三处头部接线、ResourceEditPage.tsx 引用面板换 hook 的那几处。
  • 两分钟验证:Studio 打开任一对象 / 页面 / 流程,点头部「历史」→ 选一个旧版本点回滚 → 出现应用内确认框,确认后该项重新读取;只读包里同一入口没有回滚按钮、源码只读。
  • 需要你做的:无,席位落地。

What changes

  • Shared directory. LayeredDiff, ResourceHistoryPage (HistoryPanel and the history route page), AuditPanel and JsonSourceEditor move, with their own tests, to ui/packages/app-shell/src/views/item-tools/ (git mv, so history follows). The references panel and its lazy scan leave ResourceEditPage.tsx as item-tools/ReferencesPanel.tsx (ReferencesPanel + useReferencesScan, the same idle / loading / loaded / error union and re-entry guard). Setup's item page imports all five from there; its behaviour is unchanged.
  • Studio item toolbar. New item-tools/StudioItemTools.tsx: five icon buttons in each pillar's item-header actions slot, each opening the panel Setup's sheet holds.
    • History and Audit are offered only when useCanReadAuthoringTrail admits the caller, as on Setup.
    • Rollback is offered on Setup's Save gate (an authoring caller on an item that is not read-only), asks the same in-app confirm, writes through the same client.rollback, and bumps the pillar's own reload nonce (objReloadNonce / leafReloadNonce / flowReloadNonce) so the item is re-read.
    • Source edits the pillar's own draft buffer (Data's object draft, an Interfaces leaf's draft, the open flow's draft) and the pillar's autosave sends it; it is read-only on a read-only package, where the pillar has no designer for the item, and on an Interfaces object entry (the object is edited in Data), where it shows the served body.
    • Layers and Source-without-a-buffer read client.layered(type, name, { packageId }) lazily, with an error arm and a retry.
  • Not carried over (card item 3): Setup's autosave toggle and DraftReviewPanel.
  • i18n. One contiguous engine.studio.itemTools.* block per pack (en, zh); every tool label reuses Setup's existing engine.edit.* keys.

Move map (old path → new path)

Under ui/packages/app-shell/src/views/:

Old New
metadata-admin/LayeredDiff.tsx item-tools/LayeredDiff.tsx
metadata-admin/LayeredDiff.overlayScope.test.tsx item-tools/LayeredDiff.overlayScope.test.tsx
metadata-admin/ResourceHistoryPage.tsx item-tools/ResourceHistoryPage.tsx
metadata-admin/AuditPanel.tsx item-tools/AuditPanel.tsx
metadata-admin/AuditPanel.emptyPlaceholderAffordance-8504.test.tsx item-tools/AuditPanel.emptyPlaceholderAffordance-8504.test.tsx
metadata-admin/AuditPanel.loadFailure.test.tsx item-tools/AuditPanel.loadFailure.test.tsx
metadata-admin/AuditPanel.lockState.test.tsx item-tools/AuditPanel.lockState.test.tsx
metadata-admin/JsonSourceEditor.tsx item-tools/JsonSourceEditor.tsx
metadata-admin/JsonSourceEditor.fallback.test.tsx item-tools/JsonSourceEditor.fallback.test.tsx
metadata-admin/JsonSourceEditor.monaco-export.test.tsx item-tools/JsonSourceEditor.monaco-export.test.tsx
metadata-admin/ResourceEditPage.tsx (ReferencesState, ReferencesPanel, the references loader) item-tools/ReferencesPanel.tsx (ReferencesState, ReferencesPanel, useReferencesScan)

Import re-paths only: src/index.ts (the LayeredDiff and MetadataResourceHistoryPage exports keep their names), metadata-admin/index.ts, ResourceRouter.tsx, PermissionMatrixEditor.tsx, DraftReviewPanel.tsx, and the tests metadataAdminFaces.displayLocale-9909, useMonacoFallback.fastfail, useMonacoFallback.loaderRejection-11800, ResourceHistoryPage.rollbackConfirm-13333 (stays in metadata-admin/; its native-confirm file list re-pathed), and i18n's ariaLabelLiteralCensus-12145 path row.

Size note

Rename-aware (git diff -M --numstat): +900 / −186 = 1,086 lines, under the order's ~1,500 split line, so move and wiring ship as one PR. dispatch-gates.mjs counts without rename detection (+3,033 / −2,319 = 5,352) and reports it over the 3,000 human-merge line; the seat reads GitHub's own additions/deletions on this PR for the landing class.

Tests

  • New studio-design/StudioDesignSurface.itemTools-28239.test.tsx (8 tests, real pillars and real Setup page, the metadata client doubled):
    • each of Data (object), Interfaces (page) and Automations (flow) shows the five buttons in order and opens all five, each reading its own door for that item (layered with the package, references, history, audit), Source holding the item's JSON, editable;
    • rollback from Studio: the in-app confirm names object/showcase_account and version 1, accepting calls client.rollback('object', 'showcase_account', 1) once, and the pillar re-reads the object;
    • a read-only package: history without rollback, Source read-only with its sentence; CONTROL: the writable package offers the two rollbacks;
    • a setup.access-only caller gets Layers, References and Source, not History or Audit;
    • CONTROL: Setup's item page still opens Layers, References, History, Audit and the Source tab.
  • Changed: DataPillar.headerActions-12511 — the header's control set on every tab is now the rail toggle plus the five tools (was the rail toggle alone); its docblock says why (rulings D-5 / D-7).
  • Moved tests keep their bodies; only relative imports were re-pathed.

Acceptance notes

  • Interfaces keeps its existing ⋯ → View definition sheet (a source page's code editor, other items read-only JSON) beside the new Source tool, which edits the leaf's JSON. Folding the two is a follow-up for the Studio customization cards, not done here.
  • docs/adr/0005-metadata-customization-overlay.md still names metadata-admin/LayeredDiff.tsx; that file is Tier H and left untouched (the claim's file surface excludes docs/adr/**).
  • The references count badge appears after the References sheet has been opened once (the scan is lazy, as on Setup); Layers carries no overlay-count badge in Studio because Studio does not read the layers until the sheet opens.
  • views/setup/PackagedAutomationPage.tsx, the object pickers and ResourceEditPage.tsx's validation region are untouched.

Verification

Head b0fe67bc, local, under scripts/pm/os-verify-lock.sh.

Tests
  • pnpm --dir ui exec vitest run over item-tools/, the new test, DataPillar.headerActions-12511, every metadata-admin/ResourceEditPage*, ResourceHistoryPage.rollbackConfirm-13333, metadataAdminFaces.displayLocale-9909, useMonacoFallback*, trailDoorsGate-12475, PermissionMatrixEditor*, DraftReviewPanel.test.tsx: Test Files 99 passed (99), Tests 539 passed (539).
  • Every DataPillar.*, AutomationsPillar.*, InterfacesPillar.*, StudioItemHeader.* test (head 0754547f, before two type-only commits to StudioItemTools.tsx): Test Files 55 passed (55), Tests 244 passed (244).
  • packages/i18n/: Test Files 93 passed (93), Tests 1433 passed, 13 skipped.
  • The full studio-design/ directory was not run locally (over the foreground limit); CI's Test UI shards run it.
Type-check
  • pnpm --filter @object-ui/app-shell run type-check (both programs, after env -u OS_SKIP_DTS pnpm turbo run build --filter='@object-ui/app-shell^...'): exit 0.
  • pnpm --filter @object-ui/i18n run type-check: exit 0.
Derived gates

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack → 34 families, each run with stdin closed, every one exit 0 (including node scripts/check-sdui-manifest.mjs, pnpm check:cross-package-test-inputs, pnpm check:type-check-coverage, pnpm check:type-check-debt, pnpm check:test-source-alias, and pnpm --dir ui exec vitest run scripts/: Test Files 169 passed, 2 skipped). --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Tier: no path-derived mandate.


Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01L9qiby6kg33hPqfAa7kpc5

…ools directory

LayeredDiff, ResourceHistoryPage (HistoryPanel), AuditPanel and
JsonSourceEditor move with their own tests; the references panel and its
lazy scan leave ResourceEditPage as ReferencesPanel + useReferencesScan.
Setup's item page imports them from the new directory, behaviour unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qiby6kg33hPqfAa7kpc5
… rollback, trail gate, Setup control

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qiby6kg33hPqfAa7kpc5
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · os-tesla · session_01L9qibz8HEj53Wx2uphTo2o

维护者速读

席位意见:组件是搬家不是复制,Setup 与 Studio 共用一份;回滚的放行条件与 Setup 保存一致,可直接落地。

席位核对

ACCEPT · seat domain:ui#3 · head 571a4967 · 2026-10-31T04:32Z

  1. Shape: Fixes #28239, draft, base main; 29 files, +900/−186 (GitHub's count; the moves are renames): LayeredDiff, ResourceHistoryPage, AuditPanel, JsonSourceEditor and their tests git mv'd to views/item-tools/; new ReferencesPanel.tsx + useReferencesScan (taken out of ResourceEditPage.tsx, same idle/loading/loaded/error semantics) and StudioItemTools.tsx (five buttons + sheets, keyed per item; History/Audit behind useCanReadAuthoringTrail; rollback only when !readOnly && useCanAuthorMetadata(); Source edits the pillar buffer when editable, else read-only effective body); the three header actions slots in StudioDesignSurface.tsx (Interfaces, Data, Automations) + per-pillar reload nonce on rollback; import re-paths in the files the seat approved; Studio i18n keys en/zh; DataPillar.headerActions-12511 pin extended to the five tools; changeset. Seat read of the diff.
  2. Premise measured: on main views/studio-design/** imported none of the five (card measurement at d6c0a75f1a, re-checked by the dev at 6285203d).
  3. Gates / check-runs: on head 571a4967 (merge of origin/main with fix(console): a served form row marked required holds Save when left empty #28293) every latest check-run is success or skipped (44 / 11, 0 failure), mergeable_state clean; the post-merge re-run passed 58 files / 259 tests incl. fix(console): a served form row marked required holds Save when left empty #28293's suites. Dev on b0fe67bc: 99 files / 539 tests, app-shell + i18n type-check green, 34/34 derived gates exit 0, --ran 0 NOT-MEASURED (os-dev-report 6538584259); writes relay 2, MCP 0.
  4. Accepted deviations: dispatch-gates' rename-blind size reads 5352 and prints OVER 3000; the platform count check-governed-merges uses is 1086 (renames counted as moves), both named in the PR body. docs/adr/0005-* still names LayeredDiff's old path: Tier H, left for the maintainer's ADR work (N-01).
  5. Out of scope: Setup's autosave toggle and draft review stay Setup-only (Studio keeps its own draft → publish). Skills-docs: none — Metadata-protocol: none.
  6. Landing: check-governed-merges --pr 28296 NOT governed, 1086 changed lines ≤ 3000; no contract review owed (Clause-②: no, no packages/spec path); changeset present. The seat readies it and arms auto-merge under the maintainer's 「按 pm-dispatch 审过的pr你可以自主落地」.

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 tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Studio: one item toolbar — layers, references, history with rollback, audit, source — on every pillar item

1 participant