Skip to content

feat(pages): add page deletion with safe subpage reparenting - #49

Open
Pioneer113 wants to merge 4 commits into
CopilotKit:mainfrom
Pioneer113:feat/page-deletion
Open

Pioneer113 wants to merge 4 commits into
CopilotKit:mainfrom
Pioneer113:feat/page-deletion

Conversation

@Pioneer113

@Pioneer113 Pioneer113 commented Oct 3, 2026 •

Copy link
Copy Markdown

User workflow

Users can create pages, save AI drafts, organize subpages, and move pages within Spaces, but there was previously no way to delete unwanted or temporary pages.

This PR adds page deletion to the document workspace. When a user deletes a page, any nested subpages are reparented to the deleted page's parent (or moved to the root level if the deleted page was at the top level), so no child documents are lost.

Changes

  • Core (src/server/pages.ts): Pages.delete(spaceId, id) runs in one BEGIN IMMEDIATE transaction. It reparents children (bumping their revision so clients resync the new parent), removes the page's page_threads binding, deletes the page, and validates the Space. It returns false for a missing page. New Pages.exists(spaceId, id) helper.
  • API (src/server/page-routes.ts): DELETE /spaces/:spaceId/pages/:id returns { ok: true } or 404 for a missing page or Space. The review receipt endpoint (GET /conversations/:id/reviewed-page/:toolCallId) now returns { deleted: true, pageId, spaceId } when the reviewed page was deleted, instead of a 404.
  • Client: Delete page in the document menu with a confirmation dialog and an error notice. On success the page leaves the library immediately: SpaceWorkspace removes it, re-parents its children locally and keeps a tombstone so a stale poll cannot bring it back (mergePageSnapshot otherwise never removes pages). It also drops the pending autosave and the dirty flag before navigating home, so the "Leave your unsaved page draft?" prompt does not appear for a page that no longer exists. PageReviewCard shows "Saved, then deleted" for such a review and lets the conversation continue (the agent is told not to link the page).
  • Docs: docs/SETUP.md lists page deletion.

Design decisions

  • page_reviews rows are kept on delete. createReviewed uses them for idempotent retries ("retries recover the same saved page"). Deleting them would let a retried approval silently recreate a deleted page. A retry after deletion now fails with 404 instead.
  • Conversation history is not deleted. Only the local page_threads binding is removed. The page's conversation thread stays in the configured Intelligence project; no Intelligence deletion call is made.
  • Deletion is not exposed to agents as a tool. It is an owner-only UI/API action.

Known limitations

  • A concurrent PageService.conversation() call racing with a delete could leave an orphaned page_threads row (no foreign keys in the schema). The window is small and the row is unreachable because lookups join against pages.
  • Review cards that were already completed (outcome.approved) still show an "Open page" link; it leads to a missing page if that page was deleted later. This predates this PR's receipt handling.
  • A page deleted from another tab, or by an agent, is not removed from an already open tab until that tab reloads: the library merge never treats absence as deletion, and only deletions made in this tab are tombstoned.
  • The delete-menu flow and the dirty-draft behaviour have no automated UI test (the repo has no DOM test setup); they were checked manually, see below.

Verification

  • npm test — 170/170 passed (also under Node 24.21).
  • npm run typecheck, npm run lint, npm run check-format — passed.
  • npm run build — succeeded.
  • New tests: reparenting, thread-binding cleanup, retried-review-does-not-recreate (tests/pages.test.ts); DELETE route and deleted-review receipt (tests/page-routes.test.ts); deleted-review recognition (tests/page-review.test.tsx). The new regression tests fail on the code before the fix.

Manual UI check (dev server, local)

  • Deleting a page that has a subpage: the library goes from 3 to 2 pages and the subpage now shows its new parent.
  • Deleting while the editor shows "Unsaved changes": the only confirmation is the delete one; no "Leave your unsaved page draft?" prompt.
  • 375 px wide viewport: the actions menu fits the screen and the page has no horizontal scroll.
  • Keyboard: ArrowUp in the open menu focuses "Delete page" with a visible focus ring; Escape closes the menu and returns focus to "Page actions".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant