Preserve Pages when trashing database collections - #4605
Draft
3mdistal wants to merge 3 commits into
Draft
Conversation
This comment has been minimized.
This comment has been minimized.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A Content Page can belong to several Databases. Moving one Database to Trash previously followed membership edges and trashed its member Pages, including Pages used elsewhere. Row menus also lacked a clear canonical Page Trash command alongside membership removal.
Change
Trash now follows Page hierarchy, locks and rechecks the affected resources and permissions in its transaction, and preserves membership-only Pages. New rows keep their own hierarchy position instead of inheriting the Database as their parent. Creation and moves coordinate with Trash so a live child cannot arrive under a trashed parent.
Table, List, Gallery and selection controls expose explicit Page Trash separately from membership removal. Batch results distinguish successful, already-trashed, ancestor-covered and failed requests. Confirmation freezes the selected Pages; Undo restores only roots actually changed. Success counts include affected descendants. Dialogs restore keyboard focus and use localized labels in all configured locales. Reference blocks say Remove reference and retain editor-local removal; View deletion remains a presentation operation. Favorites preview uses an explicit unpin mutation.
Legacy Database-parent edges do not record whether they originally meant membership or deliberate hierarchy. They return DATABASE_CHILD_OWNERSHIP_AMBIGUOUS before any mutation. This accepted limitation does not infer ownership or migrate old rows. Ordinary Page hierarchy remains supported.
Verification
Current pushed implementation has 129 passing lifecycle/row/source/form action tests, 45 focused parent/move assertions, 16 UI tests, and 13 toolkit tests. Content TypeScript check and toolkit build pass. An independent bounded review found and then verified repairs for post-commit false failures, concurrent child writes, and sibling-position races.
Real local browser checks cover row Trash/Undo, membership removal with the same Page URL, selected parent/child recovery, separate List/View operations, keyboard focus, and dialog bounds at 390, 768 and 1280 pixels. A Page owned by another local fixture identity and explicitly shared as viewer exposes no Trash command. A legacy ambiguity fixture reports its reason and remains live. Reference removal was exercised on a real unresolved Reference atom; SQL Page reference navigation is not supported by that renderer and is not claimed here.
Additional verification and integration
Human QA caught an additional read-side bug after Database A was trashed: the surviving member remains visible in B, but direct reads and Files still infer deletion from the deleted membership. The shared read filters are repaired: the same browser fixture now preserves direct URL/body/sidebar access while A is trashed, and restoring A restores its membership. Canonically trashed Pages still reject property reads. Final bulk Undo restores both selected parent and child and reports two affected Pages. Two ordinary memberships were seeded in the authorized local fixture harness because adding an existing Page to a second ordinary Database has no public Action/UI; this setup does not claim that creation capability.
The Windows aggregate guard runner fails with spawn EINVAL before execution. Eight relevant individually invoked guards pass. Localization catalogs report 2,537 existing repository issues; product docs report 1,002 issues; untracked-import checks produce verified Windows path-separator false positives. Changed-copy reports zero recognized surfaces and is not counted as localization coverage. The unscoped-query guard likewise inspected no tables. No baseline suppressions were added.
This draft is one part of the coordinated deletion work. Full read-only Trash behavior and viewer unpin belong to the adjacent lifecycle change; restore/purge controls and attribution belong to the recovery change. Duplicate ownership belongs to the sidebar change. Integration must retain their final shared helper and recovery hunks. No merge or deployment is requested.
Final read-boundary lifecycle suite: 46 passed; parity: 51 passed; CI recovery UI/move/Slack suites: 26 passed. Final Content typecheck passed. PostgreSQL locking fixtures now distinguish hierarchy from membership; real PostgreSQL and Linux security verification will run in CI. No local PostgreSQL service was available.
Follow-up PostgreSQL CI ran 15 tests: 14 passed; the restore-wins fixture hit the live-member preflight before exercising its race. Commit 057638a removes that fixture membership and requires both lock waiters before releasing the gate. The original restored-root rejection assertion is retained. Typecheck and formatting pass; CI run 34379663038 is pending for this test-only correction.