Skip to content

Commit 58b277c

Browse files
fix(app-shell): package sheet asks in-app before Delete, Discard and Duplicate; Studio returns to its landing after a delete (objectui#11784) (#11831)
Fixes #11784 Clause-②: no The package sheet (`PackageDetailSheet`, `packages/app-shell/src/views/metadata-admin/PackagesPage.tsx`) no longer uses a browser dialog for *Delete app*, *Discard changes* or *Duplicate*. After a delete, Studio now returns to its landing instead of opening another package. Implemented by the os-dev agent dispatched by the `domain:ui#3` seat, session `https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8`. This PR supersedes draft objectui#11829. The sheet change is the same: its net diff was applied to a fresh branch cut from `main`, so that no commit here names a model in a trailer. The seat retires objectui#11829. ## What changed ### The package sheet - **Delete app** opens one in-app `AlertDialog`: - a radio between "Delete the structure, keep the records" and "Delete the structure and the data", with nothing preselected; - the package name (the one the sheet's title shows) typed to arm the destructive button; - a Cancel that sends nothing. "Keep the records" sends `DELETE /api/v1/packages/ID?keepData=true`; the other choice sends no query (the spec's `keepData` in `package-api.zod.ts`: preserve object tables, remove metadata only). Before, two `window.confirm` calls ran in a row, and the second one's Cancel sent `?keepData=true`, so Cancel still deleted the structure. - **Discard changes (N)** asks first, naming the count. Only its confirm calls `/discard-drafts`. - **Duplicate** replaces `window.prompt` with an inline form built from the Studio landing's own pieces, imported rather than copied: `PackageIdInput` (same sanitizer and format hint), `PACKAGE_ID_RE` (one id rule) and `duplicatePackage` from `studio-design/packages-io.ts`. `BuilderLanding.tsx` is not edited. Because the call is now `duplicatePackage`, a 200 whose duplicate verdict is `success: false` shows as an error, not as "Package duplicated": the sheet's old reader looked only at the envelope's `success`. - Rows: `deleteConfirm`, `deleteKeepData` and `duplicatePrompt` are removed from both `en` and `zh` designer tables (nothing else read them). The new `engine.packages.detail.*` rows are paired. The duplicate form reuses the landing's `engine.studio.landing.dup*` placeholders and default name, so the sheet's default copy name is now "NAME copy" (it was "NAME (copy)"). ### Studio after a delete (the host) Where Studio goes after a delete is the host's decision, not the sheet's: `PackageSwitcher`'s `onManageChanged` in `views/studio-design/StudioDesignSurface.tsx`. Only its eviction target changes: - **Other packages remain:** Studio now goes to the Studio landing, `/studio` (the console's index route in `StudioRoute.tsx`; `HomePage` spells it the same way). It used to open `list[0]`, whichever package the list started with, which is the card's "Studio lands on another package (showcase)". - **No package left at all:** unchanged. Studio still goes to `useHomePath()`'s declared home. That arm is a recovery exit governed by objectui#7373, and the source scan `homeRecoveryRedirectsFollowDeclaration-7373.test.ts` pins `const homePath = useHomePath()` at this site. The two "nothing left" deletion pins stay unchanged, as controls. No sheet prop or callback was added. The console's Packages page hosts the same sheet with `onChanged` set to a list reload, so the host change cannot reach it. A new pin drives a delete there and shows it reloads in place and never navigates to `/studio`. No new export, prop, type member or language-pack key. `PackageDetailSheet` keeps its props, and the rows live in app-shell's module-local designer table, which the package root does not re-export. ## Tests `PackagesPage.confirmFlows-11784.test.tsx` drives the real sheet through a fetch stub that records every request. - **Delete:** - Cancel sends no DELETE, however the question is asked. - Cancel after choosing a mode and typing the name sends none. - The button stays disabled until a mode is chosen and the name matches. The package id is not accepted as the name. - "Structure only" sends `?keepData=true`; "structure and data" sends no query. - A refused DELETE keeps the sheet open and shows the refusal. - Reopening the dialog starts over. - **Discard:** the dialog names the count, Cancel sends nothing, and confirm discards once. - **Duplicate:** - The typed id and name are sent. - An id that `PACKAGE_ID_RE` refuses never reaches the server. - Cancel sends nothing. - A false verdict on a 200 is shown as an error. - **No native dialogs:** spies show no `window.confirm` or `window.prompt` call on the three paths. - **Console Packages page:** a delete reloads the list, closes the sheet, and stays on the page (it never goes to `/studio`). In `StudioDesignSurface.packageDeletionInference.test.tsx`, the case "REAL deletion, a sibling survives" now asserts the Studio landing. It cites this card and triage comment 6041966855 ("return to `/studio` after a delete"). Every other case is unchanged: two failed-refresh cases, two "nothing left" cases and "package still there". **Ablations** (one-time checks, not kept). Each was run with the fix committed, through objectstack's `scripts/ablation-replace.mjs`. In both, the anchor hit once and the blob moved; afterwards the restored blob equals HEAD and `git diff HEAD` is empty. 1. **Sheet.** The old two-confirm delete was put back in place of the dialog opener. The "Cancel deletes nothing" pin went red on the defect itself: it received `DELETE /api/v1/packages/com.acme.crm?keepData=true` after the spy answered OK, then Cancel. 7 of 12 pins went red; the Discard and Duplicate pins, which the mutation does not reach, stayed green. This was measured on the old branch, with the same sheet bytes. 2. **Host.** The old `list[0]` target was put back. The restated sibling pin went red: the location was `/studio/app.other/interfaces`, the sibling package. The other 5 cases stayed green (1 failed, 5 passed). ## Gates All on head `e896089`: - `turbo run build --filter=@object-ui/app-shell^... --concurrency=2` (28 tasks), then `pnpm --filter @object-ui/app-shell type-check` (`tsc --noEmit && tsc -p tsconfig.test.json`): exit 0. - `pnpm exec vitest run` on 11 files: `Test Files 11 passed (11)`, `Tests 297 passed (297)`. The files: - both pin files above; - `homeRecoveryRedirectsFollowDeclaration-7373`; - `StudioDesignSurface.manageSnapshotRefresh` and `StudioDesignSurface.packageUserMessage`; - `PackagesPage.envelopeUserMessage`; - `PackageIdInput` and `BuilderLanding.orgScope-11553`; - the three i18n gate suites (`check-i18n-designer-table-parity`, `check-i18n-dead-keys`, `check-i18n-en-drift`). - The whole `packages/app-shell/src/views/studio-design/` directory: `Test Files 94 passed (94)`, `Tests 553 passed (553)`. - `eslint` on the five touched source and test files, with the repo's own config: 0 errors. - `StudioDesignSurface.tsx` has 14 warnings at base and at head. - `PackagesPage.tsx` has 18 warnings at base and 17 at head. - No type-aware rules are configured, so the diff cannot move a verdict on an untouched file. - `check:control-bytes`, `check:test-path-roots`, `check:changeset-claims`, `check:pending-changeset-literals`, `check:i18n-keys`, `check:i18n-drift`, `check:i18n-designer-parity`, `check:new-line-citations`, `check-changeset-presence`, `check-changeset-no-major`: exit 0 each. - `check:i18n-dead-keys` (a report) lists no `engine.packages.detail.*` key. - The full `vitest run packages/app-shell/` was not re-run on this branch; CI runs it. It last ran green on objectui#11829's branch with the same sheet diff: `Test Files 1059 passed | 1 skipped (1060)`. ## Acceptance notes - Not this card: the other native `confirm` / `prompt` / `alert` calls under `app-shell/src/views` stay as they are. That includes `adoptOrphans` on this same sheet (`engine.packages.detail.adoptConfirm`). A `git grep` for `window.confirm(` / `confirm(` style calls under `packages/app-shell/src/views` (tests excluded) also finds: - `RuntimeDraftBar.tsx` - `MetadataTypeActions.tsx` - `ResourceEditPage.tsx` (three) - `ResourceHistoryPage.tsx` - `datasource/DatasourceResourcePage.tsx` - `StudioDesignSurface.tsx` (two) That grep is not exhaustive; the card counts by its own reading. - objectstack-ai/objectstack#22090 (package *Revert* 404) and its wording are untouched. - Already there before this PR, not changed here: rendering the sheet with pending drafts logs React's "div cannot be a descendant of p" warning (the `Badge` inside the *Pending changes* paragraph). --- _Generated by [Claude Code](https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8aebc6f commit 58b277c

6 files changed

Lines changed: 742 additions & 40 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
The package sheet's Delete, Discard changes and Duplicate ask in-app before they act, Cancel on Delete deletes nothing, and Studio returns to its landing after the open package is deleted (objectui#11784).
6+
7+
Delete app used to ask two browser confirms in a row, and the second one's Cancel still deleted the
8+
package's structure, keeping only its records. It now opens one dialog: the author picks "Delete the
9+
structure, keep the records" or "Delete the structure and the data" (nothing is preselected), types
10+
the package's name, and only then is the delete button enabled. Cancel, at any point, sends no
11+
request. "Keep the records" sends the delete with `?keepData=true`, as before; the other choice
12+
also drops the object tables.
13+
14+
After deleting the package that is open in Studio, Studio now returns to its landing (`/studio`),
15+
where the next package can be picked or a new one created. It used to open whichever package the
16+
list started with. With no package left at all it still goes to the home page, as before. The
17+
console's Packages page is unchanged: a delete there reloads the list in place.
18+
19+
Discard changes (N) used to discard every pending draft at once. It now asks first, naming the count.
20+
21+
Duplicate used to ask for the new package id in a browser prompt. It now opens the same inline form
22+
the Studio landing uses: a name and a package id, checked by the same package-id rule, with the
23+
Create copy button disabled until the id is valid. A duplicate that the server reports as not done is
24+
now shown as an error rather than as "Package duplicated".
25+
26+
None of the three uses a browser dialog any more, so they also work inside an embedded frame, where
27+
those dialogs are blocked or answered automatically.

0 commit comments

Comments
 (0)