Skip to content

feat(studio): New similar on a flow in the Automations pillar, opening the copy where the clone door landed it - #28668

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-la2x0b
Nov 1, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-la2x0b

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #28567

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:Studio 自动化页里,打开的流程的 ⋯ 菜单新增「新建类似」:只读软件包和可写软件包的流程都有。它要求填写新的机器名和标签,调用流程克隆门;只读基础包不带目标包(由服务器选配对的 <base>.custom),可写包以当前包为目标。副本在服务器回答的那个包里打开,并原样显示服务器“副本已关闭”的那句话。
  • 为什么改:管理员想要一条和 HotCRM 某流程相似、规则不同的流程,又不改动 HotCRM 本身(ADR-0146 D4 / Q6)。以前只有 Setup 的克隆,Studio 里没有复制入口。
  • 风险与回滚:纯前端改动,只调用已上线的克隆门(Flow clone door → "new similar": the copy lands in a writable target package, by default the paired <base>.custom, never package-less #28149 / f23e0512)。只读包的流程现在也显示 ⋯ 菜单,但其中没有“删除”。纯 revert 即可回滚。
  • 先看:ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx 的 onFlowCopied(副本在哪打开)与菜单调用处的 target;FlowItemMoreMenu.tsx 的 requestFlowNewSimilar。
  • 两分钟验证:cd ui && pnpm exec vitest run packages/app-shell/src/views/studio-design/AutomationsPillar.newSimilar-28567.test.tsx,预期 7 例全绿。
  • 需要你做的:无,席位落地。

What changes

  • New similar in the flow's ⋯ menu (FlowItemMoreMenu.tsx). Drawn on a read-only package's flow and on a writable package's flow. It opens a dialog with a new machine name and a label, both mandatory, prefilled <name>_copy and <label> (copy) as Setup's clone dialog is. It posts to POST /api/v1/automation/:name/clone with exactly { name, label } on a read-only base, so the door picks the paired <base>.custom, and { name, label, package: <open package> } on a writable package.
  • Refusals verbatim. Any refusal, a 409 for a taken name included, is the server's sentence through actionErrorDetail (the reader the toggle door uses). The dialog stays open on the names typed.
  • The copy opens where the answer says (onFlowCopied in AutomationsPillar). The answer's data.packageId decides. Another package (the pair) opens on that package's Automations pillar on the copy (studioPillarItemPath(…, 'automations', { type: 'flow', name })), and the landing rides the navigation's state into the remounted pillar. The open package re-reads the rail and opens the copy in place. Either way a strip shows "Saved the copy NAME in package PKG." and the door's data.notice (the copy is switched off) as sent. An answer that names no package says so and opens nothing. Nothing says what the copy was made from (ADR-0126 §9).
  • Gates. A caller without manage_metadata sees the item disabled, titled with the console's engine.edit.capabilityReadOnly sentence. A held edit is asked about before the dialog opens, as New is. Delete stays a writable package's flow only. The package-less scope draws no menu: it has no pair and no package to name.
  • Wanted 5 (Setup's "Open the clone in Studio"): already re-pointed by f23e0512 (PackagedAutomationPage.tsx reads data.packageId into artifactStudioPath). Checked, not touched.
  • Strings in @object-ui/i18n's studio namespace (en + zh), engine.studio.auto.newSimilar.*. zh uses 新建类似, the word the permission-set card (Studio: "New similar" on a base permission set — the copy lands where the clone door puts it (<base>.custom) and opens in Studio; Setup's clone button reads the same #28573) uses for the same gesture.

Tests

  • New AutomationsPillar.newSimilar-28567.test.tsx (7 cases), the pillar mounted under the Studio's package route and keyed by package as the surface mounts it, the clone door doubled at fetch:
    • read-only base: no Delete; body is exactly { name, label }; the router lands on /studio/com.acme.crm.custom/automations?surface=flow:approval_copy; the copy's caption opens; the strip names the package and shows the notice byte-for-byte;
    • writable package: body carries package: <open package>; the rail re-reads and opens the copy in place; Delete still offered (control);
    • 409 verbatim, dialog open on the typed names, nothing opens; a 422 verbatim too;
    • an answer with no packageId opens nothing and says so;
    • without manage_metadata the item is disabled with the reason, and nothing is sent;
    • the package-less scope draws no menu.
  • AutomationsPillar.deleteFlow-27356.test.tsx: the read-only case now pins "the menu offers no Delete" (it used to pin "no menu").
  • Ablations (each through scripts/ablation-replace.mjs on the committed tree, restored, git diff HEAD empty after): target always omitted → 1 red (writable); target always sent → 1 red (read-only); never navigate → 1 red; refusal replaced by the fallback → 2 red; notice dropped → 3 red; disabled reason ignored → 1 red; no-package arm removed → 1 red; Delete drawn on read-only → 1 red; menu drawn in the package-less scope → 1 red.

Acceptance notes

Verification

At head ea00d7d3 (main merged at 9da2f4b0; no incoming commit touches these files):

  • cd ui && vitest run over the 36 app-shell test files that name AutomationsPillar or FlowItemMoreMenu, plus packages/i18n/: 130/130 files, 1733 passed / 13 skipped (os-verify-lock VERDICT command-exit 0). The full app-shell suite is left to CI's Test UI shards (a declared narrowing).
  • turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/i18n (both tsc --noEmit and tsc -p tsconfig.test.json): 66/66 tasks, VERDICT command-exit 0.
  • dispatch-gates --commands --repo objectstack-ai/objectstack: 34 derived gates, every one exit 0; --ran reconciliation 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. The PR-body gates (check-closing-keyword-parity, check-adr-0087-registration, check-changeset-no-major, check-empty-changeset) ran against this body through GITHUB_EVENT_PATH, re-run at the final head, plus check-sdui-manifest (exit 0, no registry source moved).
  • Scoped eslint over the touched files: 0 errors; no new warning on a changed line.
  • Not run locally: full dogfood (no ! in the title, no (narrowing) arm), repo-wide pnpm lint (CI's).

🤖 Generated with Claude Code

https://claude.ai/code/session_01QsR2jSCZAioSyympShqoHq

The flow's more menu offers New similar on a read-only package's flow and
on a writable package's flow. It asks for a new machine name and label and
calls the flow clone door: no target on a read-only base (the door picks
the paired .custom package), the open package on a writable one. The copy
opens where the answer says it landed, with the door's switched-off
sentence shown as sent; refusals stay in the dialog verbatim.

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

Copy link
Copy Markdown
Contributor Author

domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

席位核对 · ACCEPT · 2026-11-01T13:06Z

Head-sha: ea00d7d3e4b74e0085040485b68cb5a7eb1a4e2e

  • Shape: draft → main, first content line Fixes #28567, no other card number beside a closing keyword. 7 files, +741 / −47 (788 lines ≤ 3000), no governed path (check-governed-merges --pr 28668: 0 of 7 paths hit the register). Author objectstack-fleet[bot]. Clause-②: no / Metadata-protocol: none line-initial in body and changeset, as claimed. The new strings are 14 keys in @object-ui/i18n's studio namespace (Record<string, string>, en + zh), so they widen no literal type and no locales/* pack key moved: Clause-② no holds and no contract review is owed.
  • File surface: FlowItemMoreMenu.tsx, its call site in StudioDesignSurface.tsx (AutomationsPillar), the two pillar tests, the studio en/zh packs and the changeset. Inside the claimed surface. PackagedAutomationPage.tsx was not touched: f23e0512 already reads data.packageId into the Setup link (wanted 5, checked by the dev).
  • Wanted, item by item, read in the diff:
    1. The open flow's ⋯ menu offers New similar on a read-only package's flow and on a writable one's. Delete stays a writable package's flow only (onDelete={readOnly ? undefined : …}). The package-less scope draws no menu (packageId !== null).
    2. The dialog asks for a new machine name and a label, both mandatory (submit disabled on a blank trimmed field), prefilled <name>_copy and <label> (copy).
    3. requestFlowNewSimilar posts exactly { name, label } on a read-only base, so the door picks the pair, and { name, label, package: <open package> } on a writable package.
    4. A refusal, a 409 included, is actionErrorDetail's reading of the server's answer, and the dialog stays open on the typed names.
    5. The copy opens where data.packageId says. Another package navigates to studioPillarItemPath(pkg, 'automations', { type: 'flow', name }) with the landing in navigation state, read only when it names that package. The open package re-reads the rail and opens the copy. data.notice is shown as sent. An answer naming no package opens nothing and says so. No lineage is drawn.
    6. Without manage_metadata the item is disabled, titled with engine.edit.capabilityReadOnly. A held edit is asked about before the dialog opens.
  • Gates (check-runs on this head): 44 success, 11 skipped, 0 failed or pending. All ten required contexts are included; Build Core is skipped by its path filter on a ui-only diff. The head merges main at 9da2f4b0, and no incoming commit touches these files.
  • Tests: new AutomationsPillar.newSimilar-28567 (7 cases: the read-only base body and its landing route on the pair; the writable package body and its in-place open; 409 and 422 verbatim with the dialog open; no packageId; no manage_metadata; the package-less scope). deleteFlow-27356 now pins "no Delete" on a read-only flow. Nine ablations, each red as reported.
  • Observations, not blocking:
    • The network catch shows a thrown error's own message (a browser "Failed to fetch"), not the localized newSimilar.failed. The localized string appears only when the message is empty.
    • The landing strip rides history state, so it shows again if the admin goes back to that history entry.
    • Neither touches the card's wanted.
  • Out of scope / NOT MEASURED: no live probe against a running clone door; the door itself landed with Flow clone door → "new similar": the copy lands in a writable target package, by default the paired <base>.custom, never package-less #28149 (f23e0512) and is doubled at fetch here. Other languages fall back to en for the 14 new keys, as the whole studio namespace does. Skills-docs: not owed.
  • Landing: ordinary queue landing, pr_ready then automerge_enable. Fixes #28567 closes the card on merge. Serial neighbour PR feat(studio): New similar on a read-only base's permission set, opening the copy where the clone door landed it #28669 (Studio: "New similar" on a base permission set — the copy lands where the clone door puts it (<base>.custom) and opens in Studio; Setup's clone button reads the same #28573) also edits StudioDesignSurface.tsx (the Access pillar, another region) and the studio packs. The queue rebuilds whichever lands second, and a textual conflict means the later one merges main.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 1, 2026 13:08
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 1, 2026 13:08
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 1, 2026
Merged via the queue into main with commit 1404938 Nov 1, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-la2x0b branch November 1, 2026 13:25
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 tooling

Projects

None yet

1 participant