Skip to content

feat(studio): Restore package original moves onto the override mark, in a popover that names what it overrides and its version - #29842

Merged
objectstack-fleet[bot] merged 18 commits into
mainfrom
claude/project-thread-rvb9lz
Nov 3, 2026
Merged

objectstack-fleet[bot] merged 18 commits into
mainfrom
claude/project-thread-rvb9lz

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #29692

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:Studio 里「覆盖 XX」标记变成按钮,点开小气泡:写明覆盖了哪个包、基于哪个版本,底部是「恢复包原版」,仍走原来的确认框。各条目 ⋯ 菜单里的「恢复包原版」去掉,只剩这一个入口;「自定义」保留标题行主按钮位。
  • 为什么改:ADR-0146 D2 要求恢复入口放在点名定制的地方;原来要在 ⋯ 菜单里找,且标记本身不说明基于哪个版本。
  • 风险与回滚:只动 app-shell 前端;恢复请求与原来逐字节相同(先删草稿,再删行,都带 package= 配对包),无元数据、接口和 i18n 键变化。回滚即 revert 本 PR。
  • 先看:StudioCustomizeControls.tsx(StudioOverrideChip 气泡)、StudioItemHeader.tsx(折进 ⋯ 菜单后,恢复时关掉菜单)、StudioDesignSurface.tsx / StudioBundleItemEditor.tsx(去掉菜单项、接上 onRestore)。
  • 两分钟验证:窗口 1024 px、右侧面板打开,在 Studio 打开一个已定制的视图:⋯ → 点「覆盖 …」→ 气泡里有版本句和「恢复包原版」→ 弹出确认框,菜单已关。键盘:⋯ 上 Enter,再 Enter 打开气泡,焦点在「恢复包原版」。
  • 需要你做的:无,席位落地。

What changes

  • The override mark is the door. StudioOverrideChip ("Overrides HotCRM") is now a popover trigger. The popover (studio-override-popover) names the package it overrides and the version it was taken from (the existing overridesTitle sentence, which was the chip's tooltip), and holds Restore package original (studio-override-restore). Restore goes through the existing confirmation dialog, and confirming sends the same two deletes at the pair as before: its draft, then its row. Without onRestore (a declaration served while the item is not in the pair) the popover shows the facts only.
  • Every type that draws the mark gets it: Interfaces views, dashboards and reports (the item header), an object leaf's list view, flows (Automations), and the All-metadata form editor (StudioBundleItemEditor). Customize keeps the header's primary slot; Restore is never a header button of its own.
  • One door. The ⋯-menu Restore entries (studio-restore-original) come out of the Interfaces item menu, FlowItemMoreMenu (its restore prop is gone) and the bundle editor's menu. Each host's inPair is declaration !== null, so everywhere Restore was reachable the mark is drawn and carries it.
  • Folded into the ⋯ menu (Studio: an item header keeps the item name readable; chips and tools collapse first #29693's header fold): the mark sits in the one studio-item-header-folded-chips entry. Its popover is a child of that menu item in React's tree, so pointer, click and key events inside it stop at the popover. Otherwise a pointer moving over the popover focused the menu item and closed the popover. Restore there closes the ⋯ menu before the confirmation opens (useStudioFoldedMenuClose), so no hidden menu is left behind the dialog to take the next Enter.
  • content/docs/build-without-code.mdx: the sentence that sent the reader to the ⋯ menu now points at the mark.
  • No new i18n keys and no changed en values.

Tests

  • StudioCustomizeControls.customize-28562.test.tsx: the chip's facts are on the popover; Restore asks once and closes; a disabled Restore asks nothing; without onRestore the popover is facts only.
  • StudioItemHeader.titleRowFold-12897.test.tsx, new describe for the folded mark: one press opens one popover and the menu stays, a second press closes it; Enter on the folded entry opens it; Restore asks once and closes both the popover and the menu; a pointer moving and pressing inside the popover neither focuses the entry nor closes the popover.
  • InterfacesPillar.customize-28562.test.tsx, AutomationsPillar.customizeFlow-28570.test.tsx, StudioBundleItemEditor.customize-28569.test.tsx: Restore is driven from the mark and the existing resets assertions (same two requests at the pair) still hold; the ⋯ menus carry no studio-restore-original; the dialog's item label equals the rail row's label (Interfaces "Pipeline", flow "Notify owner").
  • ui/e2e/live/studio-customize-journey.spec.ts: the Restore step presses the mark in the row, or in the folded ⋯ entry when the row has folded, then the popover's Restore.
Readings
  • At head 9403cae: the five touched test files plus itemTools-28239 and oneSurface-28572, 7 files, 112 tests passed.
  • Ablation of the two folded-menu fixes, one at a time, restored to the committed blob: dropping the popover's event stops reds the pointer pin (1 failed, 20 passed); dropping the menu close reds the Restore pin (1 failed, 20 passed).
  • app-shell type-check (src and tests) exit 0; type-check:e2e exit 0; eslint on the touched files 0 errors.
  • pnpm --dir ui exec vitest run scripts/: 170 files passed, 2 skipped. check:type-check-debt exit 0. check-i18n-en-drift: no en value changed.
  • Derived gates (dispatch-gates --commands): 67 derived, 67 run, all exit 0; --ran reconciles 0 NOT-MEASURED. check-sdui-manifest exit 0.
  • Merged main right before opening (14 incoming commits, none touching these files; no parallel fix found).

Acceptance notes

  • Dialog label (任务清单 vs "Task List"): not reproducible on this tree. In zh the view leaf's dialog says 「任务清单」, as its header and rail row do; in en it says "Task List". The dashboard reads 「图表画廊」, the object leaf's list view 「全部任务」, and the flow "Notify on Task Completed", matching its zh rail row (the flow has no translation). Pinned in tests against the rail label.
  • At about 1024 px with the right panel open every header folds, so the folded state was measured there and the row state at 1440 px with the panel open (object leaf list view).
  • The live journey spec passes with --timeout=180000 (41.6 s); under the default 30 s test timeout it runs out in the later "Add region__c" step on a Vite dev Console, after Restore has passed.

Verification

Live on the showcase app (objectstack dev --seed-admin --fresh) with the Console on Vite, Chromium, right panel open, overrides drafted in the pair for a view, a dashboard, a flow and an object's list view. For each, by mouse and by keyboard, at 1024 px (folded) and 1440 px:

Item Header Mouse Keyboard
View (Task List) folded at 1024 and 1440 popover stays open under the pointer, exactly one, menu stays under it; Restore opens the dialog and the menu is gone Enter on ⋯ focuses the folded entry, Enter opens the popover with focus on Restore, Enter opens the dialog
Dashboard (Chart Gallery) folded at 1024 and 1440 same same
Flow (Notify on Task Completed) folded at 1024 and 1440 same same
Object list view (All Tasks) folded at 1024, row at 1440 same same

Screenshots (en and zh) are with the seat.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QsR2jUNJci3hxdpiN6RFQ1

claude added 15 commits November 3, 2026 02:01
The title keeps its first twelve characters readable; on a narrower row the
identity chips and the item tools fold into the item's more menu (the
pillar's own, or one the header draws), so the menu trigger stays inside the
column. The pillar rails draw the customization mark as its glyph alone.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jUYXmZ6DQBWc6piyyF
… actions icon-only

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jUYXmZ6DQBWc6piyyF
…r in the item's folded menu

At the live job's 1280 px window with the Interfaces inspector open, the
item header folds its identity chips into the item's more menu so the
item's name stays readable, so the published pair's override chip is
looked for in the row first, then in the menu's chips entry, and the
menu is closed again before the next step.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jUYXmZ6DQBWc6piyyF
…s, its version and Restore package original

Restore leaves the item's more menu (Interfaces, flow, bundle editor) for
the mark that names the customization; it still asks through the existing
confirmation dialog. Folded into the header's menu, the mark is pressed by
the keys through the folded entry.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jUNJci3hxdpiN6RFQ1
…abel and one-door pins

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jUNJci3hxdpiN6RFQ1
…-rvb9lz

# Conflicts:
#	ui/packages/app-shell/src/views/studio-design/StudioItemHeader.titleRowFold-12897.test.tsx
#	ui/packages/app-shell/src/views/studio-design/StudioItemHeader.tsx
…estore closes the folded menu

Folded into the header's more menu, the popover is a child of a menu item in
React's tree: a pointer moving over it focused the item and closed it, and
after Restore the menu stayed open behind the confirmation. Events inside the
popover now stop at it, and Restore closes the folded menu before it asks.

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

Copy link
Copy Markdown
Contributor Author

domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

席位核对 · ACCEPT · 2026-11-03T07:22Z

Head-sha: 9403cae28e45542e6fb73d9010e5af53e7c06b1e

  • Shape: draft → main, Fixes #29692 in the body only. 13 files, +378 / −109 (487 lines ≤ 3000). No governed path (check-governed-merges --pr 29842 on the final file list: 0 of 13 hit the register). Clause-②: no and Metadata-protocol: none are line-initial in the body and the changeset, so no review face applies and no contract review is owed.
  • Premise, measured: it holds. On main before this change, studio-restore-original was reachable only from the item's more menu (if-item-more, FlowItemMoreMenu, the bundle editor menu), and studio-override-chip carried no action. The report lists each of those doors.
  • Read in the diff:
    • StudioOverrideChip is a popover trigger that keeps its test id. The popover names the overridden package and the version the customization was taken from (the existing overridesTitle sentence) and holds Restore package original. Restore goes through each host's existing confirmation and sends the same two deletes at the pair.
    • The more-menu Restore entries are removed from all three menus. Each was gated on inPair = declaration !== null, and every one of those headers draws the chip on that same declaration, so no restorable type loses its door. One-door asserts in the three pillar tests pin this.
    • Customize keeps the primary slot. Restore never enters the actions row.
    • Folded case: inside Studio: an item header keeps the item name readable; chips and tools collapse first #29693's studio-item-header-folded-chips entry, events inside the popover stop at it. Before this, a pointer move focused the menu item and closed the popover. Restore now closes the folded menu first (useStudioFoldedMenuClose), so no hidden menu stays open behind the dialog. Both bugs were found live and pinned, and each pin goes red under ablation.
  • Measured live (screenshots under /mnt/project-files/issue-29692/shots/, en and zh):
    • Mouse and keyboard, through the popover and the dialog, for view, dashboard, flow and the object-leaf list view, at 1024 px with the panel open, where every header folds.
    • The row state at 1440 px. The seat read the zh dashboard popover at 1024 px (folded) and the en flow popover at 1440 px.
    • The dialog's item label equals the rail's label: pinned for one view and one flow. The card's 任务清单 vs "Task List" did not reproduce on this tree.
  • Accepted deviations:
    • The row state was measured at 1440 px, because every header folds at 1024 px with the panel open.
    • content/docs/build-without-code.mdx: one sentence changed, because it sent the reader to the ⋯ menu for Restore. Not a governed path.
    • No new i18n keys: the popover reuses overrides, overridesTitle and restore.
    • The pushes used the documented OS_ALLOW_CARD_TRAILER_PUSH override. The check refused only over feat(app-shell): a Studio item header keeps the item name readable; chips, tools and labels give way first #29765's pre-squash commits that came in with the base. The seat read this card's own four commits (10d0e0a3, 2aac8138, 5de32e80, 25aaa060): each carries only the model-free trailer pair, with no card number. The squash message is the PR body.
    • Locally, the live journey spec needed a longer test timeout on a Vite dev Console. Its timeout is not raised in the file, and CI ran it in 12.6 s under the default (below).
  • Out of scope: the report lists none. Skills-docs: is not owed (Metadata-protocol: none, no narrowing arm).
  • Tests: 7 files, 112 tests green. 67 of 67 derived gates exit 0, and --ran reconciles with 0 NOT-MEASURED.
  • Gates (check-runs on this head): 51 success, 8 skipped (opt-in or matrix placeholders), 0 failed or pending, including all 16 Test UI shards and Live E2E UI (job 125776711209: studio-customize-journey.spec.ts:121 passed in 12.6 s under the default 30 s timeout, 17 of 17 live specs). Every required context succeeded.
  • Landing: ordinary queue landing, pr_ready then automerge_enable. Fixes #29692 closes the card on merge.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 3, 2026 07:23
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 3, 2026 07:23
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Nov 3, 2026
…-rvb9lz

# Conflicts:
#	ui/packages/app-shell/src/views/studio-design/StudioItemHeader.titleRowFold-12897.test.tsx
@github-actions github-actions Bot added the size/l label Nov 3, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

席位核对 · ACCEPT (re-armed after a merge of main) · 2026-11-03T09:00Z

This replaces ACCEPT 6597850058 at 9403cae2. That head left the merge queue at 07:40:05Z with no group run: it conflicted with #29843 (97f8f6f6, the header note slot) in StudioItemHeader.titleRowFold-12897.test.tsx. The dev merged main (01872ad2), kept both sides' pins, and added 42a3115d, which pins the folded override mark working next to the note line. Nothing else in the card's diff changed. git merge-tree --write-tree origin/main on this head is clean.

Head-sha: 01872ad2ae554113c800db203f2723dd338e2a29

  • Shape: draft → main, Fixes #29692 in the body only. 13 files, +399 / −109 (508 lines ≤ 3000; the +21 is pin 42a3115d). No governed path (check-governed-merges --pr 29842 on the final file list: 0 of 13 hit the register). Clause-②: no and Metadata-protocol: none are line-initial in the body and the changeset, so no review face applies and no contract review is owed.
  • Premise, measured: it holds. On main before this change, studio-restore-original was reachable only from the item's more menu (if-item-more, FlowItemMoreMenu, the bundle editor menu), and studio-override-chip carried no action. The report lists each of those doors.
  • Read in the diff:
    • StudioOverrideChip is a popover trigger that keeps its test id. The popover names the overridden package and the version the customization was taken from (the existing overridesTitle sentence) and holds Restore package original. Restore goes through each host's existing confirmation and sends the same two deletes at the pair.
    • The more-menu Restore entries are removed from all three menus. Each was gated on inPair = declaration !== null, and every one of those headers draws the chip on that same declaration, so no restorable type loses its door. One-door asserts in the three pillar tests pin this.
    • Customize keeps the primary slot. Restore never enters the actions row.
    • Folded case: inside Studio: an item header keeps the item name readable; chips and tools collapse first #29693's studio-item-header-folded-chips entry, events inside the popover stop at it. Before this, a pointer move focused the menu item and closed the popover. Restore now closes the folded menu first (useStudioFoldedMenuClose), so no hidden menu stays open behind the dialog. Both bugs were found live and pinned, and each pin goes red under ablation.
  • Measured live (screenshots under /mnt/project-files/issue-29692/shots/, en and zh):
    • Mouse and keyboard, through the popover and the dialog, for view, dashboard, flow and the object-leaf list view, at 1024 px with the panel open, where every header folds.
    • The row state at 1440 px. The seat read the zh dashboard popover at 1024 px (folded) and the en flow popover at 1440 px.
    • The dialog's item label equals the rail's label: pinned for one view and one flow. The card's 任务清单 vs "Task List" did not reproduce on this tree.
  • Accepted deviations:
    • The row state was measured at 1440 px, because every header folds at 1024 px with the panel open.
    • content/docs/build-without-code.mdx: one sentence changed, because it sent the reader to the ⋯ menu for Restore. Not a governed path.
    • No new i18n keys: the popover reuses overrides, overridesTitle and restore.
    • The pushes used the documented OS_ALLOW_CARD_TRAILER_PUSH override. The check refused only over feat(app-shell): a Studio item header keeps the item name readable; chips, tools and labels give way first #29765's pre-squash commits that came in with the base. The seat read this card's own four commits (10d0e0a3, 2aac8138, 5de32e80, 25aaa060): each carries only the model-free trailer pair, with no card number. The same holds for 42a3115d. The squash message is the PR body.
    • Locally, the live journey spec needed a longer test timeout on a Vite dev Console. Its timeout is not raised in the file, and CI ran it in 12.4 s under the default (below).
  • Out of scope: the report lists none. Skills-docs: is not owed (Metadata-protocol: none, no narrowing arm).
  • Tests: 7 files, 112 tests green. 67 of 67 derived gates exit 0, and --ran reconciles with 0 NOT-MEASURED.
  • Gates (check-runs on this head): 51 success, 8 skipped (opt-in or matrix placeholders), 0 failed or pending, including all 16 Test UI shards and Live E2E UI (job 125815089554: studio-customize-journey.spec.ts:121 passed in 12.4 s under the default 30 s timeout, 17 of 17 live specs). Every required context succeeded. The red rows on 42a3115d were cancelled by the push of 01872ad2; they did not fail. mergeable_state is clean and the PR is not a draft.
  • Landing: ordinary queue landing, pr_ready then automerge_enable. Fixes #29692 closes the card on merge.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 592845b Nov 3, 2026
59 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-rvb9lz branch November 3, 2026 09:16
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/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Studio: put Restore package original on the override mark, where the customization is named

1 participant