Skip to content

Harden Content workspace navigation and Trash lifecycle#2262

Merged
3mdistal merged 81 commits into
mainfrom
codex/content-global-workspace-model
Jul 20, 2026
Merged

Harden Content workspace navigation and Trash lifecycle#2262
3mdistal merged 81 commits into
mainfrom
codex/content-global-workspace-model

Conversation

@3mdistal

@3mdistal 3mdistal commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

This follow-up to #2206 closes the remaining production and deploy-preview regressions in Content's database-backed global workspace model.

  • restore the framework organization picker while keeping it independent from Content workspace selection
  • keep Personal and organization workspaces simultaneously visible and independently expandable, with serialized persisted expansion state
  • render sidebar nesting from page parent relationships, preserve selected-page emphasis, truncate long workspace names, and restore page hover actions
  • use one shared Add workspace source chooser from both the sidebar and Workspaces database, carrying active filter/group property values into blank or local-folder-backed workspaces
  • restore reversible Trash for pages and databases, including subtree restore, original row ordering, independent nested Trash roots, and legacy archived-database migration
  • enforce scoped Trash reads and atomic permanent deletion; exclude trashed content from normal reads, search, duplication, public document surfaces, and agent context
  • filter Workspaces catalog rows by current authorization before pagination so stale references cannot expose inaccessible workspace titles
  • restore Favorites/workspace disclosure icon behavior and hide generic creation controls that cannot create valid workspace records

Safety and data integrity

  • preserves existing document IDs, bodies, ownership, visibility, database membership, and source identity
  • requires document-level admin authority before archiving an inline database page
  • revalidates the selected Trash root atomically before permanent deletion
  • preserves independently trashed descendants when an ancestor is deleted
  • migrates legacy archived database trees into explicit Trash roots without orphaning their page descendants
  • keeps auto-merge disabled; merging remains a separate explicit decision

Validation

  • 1,832 Content tests passed across 147 files; 3 expected failures and 5 skips
  • Content typecheck passed
  • Content production build passed
  • migration, unscoped-query, localization-catalog, security, parity, and Content DB guards passed
  • all 48 GitHub checks passed on bc41d4e94fc95d9bd40e7c49628ceffe4899c82d
  • independent exact-head code review passed, including an executed nested legacy Trash migration fixture
  • authenticated deploy-preview QA passed for independent workspace toggles, reload persistence, hierarchy/breadcrumbs, selected-page state, the shared Add Workspace menu, closed-by-default Trash behavior, responsive sidebar layout, and a clean browser console

QA focus

  • Personal and organization workspaces can remain open at the same time and retain their expansion state across reloads
  • the bottom organization picker changes framework organization context without collapsing or replacing Content workspace navigation
  • nested pages align under their parent and open with the correct workspace breadcrumb
  • Add Workspace exposes the same blank-workspace and Local folder choices from the sidebar and Workspaces database
  • Trash remains closed by default, opens without disturbing workspace expansion, and safely restores or permanently deletes only the selected authorized root
  • inaccessible or trashed pages never leak titles or bodies through sidebar, database, search, public, or agent read paths

Governing brief: Agent-Native Content global workspace data model 2026-07-16.md.

3mdistal added 30 commits July 16, 2026 15:49
…workspace-model

# Conflicts:
#	packages/core/src/client/index.ts
#	packages/core/src/server/action-routes.spec.ts
…workspace-model

# Conflicts:
#	templates/content/actions/_content-space-access.ts
#	templates/content/actions/blocks-seeding.db.test.ts
#	templates/content/actions/create-content-database.ts
@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

# Conflicts:
#	templates/content/actions/_database-utils.ts
#	templates/content/actions/list-documents.ts
#	templates/content/app/components/sidebar/DocumentSidebar.layout.test.ts
#	templates/content/app/components/sidebar/DocumentSidebar.tsx
#	templates/content/app/hooks/use-documents.ts
#	templates/content/parity/matrix.md
#	templates/content/server/plugins/db.ts
@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

builder-io-integration[bot]

This comment was marked as outdated.

@netlify

This comment has been minimized.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Here's a visual recap of what changed:

Visual recap

Open the full interactive recap

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 5 potential issues 🔴

Review Details

Code Review Summary

This incremental review covers PR #2262's latest Content changes: organization picker restoration, sidebar Trash for pages and databases, soft-delete/restore lifecycle actions, and filtering of trashed documents from normal discovery paths. The overall architecture is sound: the migration is additive, destructive operations are transaction-wrapped, and the new Trash list and mutations use scoped access checks. The test additions also cover subtree round-trips, independent trash state, permanent deletion, and foreign-owner visibility.

Risk assessment: High, because this changes deletion semantics, durable data lifecycle, and access-controlled read surfaces.

Key Findings

  • 🔴 HIGH — Permanent deletion is not constrained to the selected Trash root and can irreversibly remove descendants belonging to another Trash item.
  • 🟡 MEDIUM — Trashed pages remain readable through direct pull/export actions.
  • 🟡 MEDIUM — Restoring a deleted database row can reintroduce duplicate positions.
  • 🟡 MEDIUM — Trashed documents can still be updated through the mutation path.
  • 🟡 MEDIUM — Known trashed database item IDs can be duplicated into active documents.

Please address these lifecycle and visibility gaps before relying on Trash as the sole reversible deletion boundary. Browser testing will run after this review because the PR changes user-facing Content sidebar flows.

Comment thread templates/content/actions/permanently-delete-document.ts Outdated
Comment thread templates/content/actions/delete-document.ts
Comment thread templates/content/actions/delete-database-items.ts
Comment thread templates/content/actions/get-document.ts Outdated
Comment thread templates/content/actions/delete-database-items.ts

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 3 potential issues 🔴

Review Details

Code Review Summary

This update moves page deletion from recursive hard-delete to a reversible, subtree-scoped Trash lifecycle, adds restore/permanent-delete actions, filters trashed content from normal reads, and restores the organization picker plus sidebar Trash/Favorites/workspace affordances. The overall model is directionally sound: the schema migration is additive, normal listing/search/public-context paths consistently exclude trashed documents, and the UI invalidates the new lifecycle queries.

Risk assessment: High, because this change introduces data deletion, restoration, and authorization-sensitive state transitions.

Key Findings

  • 🔴 HIGH — Permanent deletion checks Trash state outside the destructive transaction, allowing a concurrent restore to be followed by deletion of the restored subtree.
  • 🔴 HIGH — Restoring an inline database descendant can clear its database deletedAt flag without restoring its still-trashed backing document, making the database disappear from both active and Trash views.
  • 🟡 MEDIUM — An editor-authorized inline database deletion now recursively trashes backing pages and row subtrees without requiring document-admin access.

The focused lifecycle tests cover important round trips and ownership filtering, but do not cover these concurrency and inline-database authorization paths.

🧪 Browser testing: Skipped — dev server is available, but browser automation tools were unavailable; all planned UI cases were reported as environment-blocked.

Comment thread templates/content/actions/permanently-delete-document.ts Outdated
Comment thread templates/content/actions/restore-content-database.ts Outdated
Comment thread templates/content/actions/delete-content-database.ts

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 3 potential issues 🔴

Review Details

Code Review Summary

This update broadens the PR from sidebar-only changes to a shared WorkspaceSourceMenu used by the Content sidebar and Workspace catalog database creation surfaces. The extraction removes duplicated workspace creation dialogs and adds blank/local-folder choices, while preserving the Trash lifecycle and sidebar filtering work. The shared menu is a good direction, and the new workspace-source tests cover the common menu contract.

Risk assessment: High, because the PR still changes destructive lifecycle behavior and also affects creation flows across multiple database view types.

Key Findings

  • 🔴 HIGH — The new trashed-page guard covers get-document, but the public-agent pull-document read path still returns trashed document content to callers with existing access.
  • 🟡 MEDIUM — Workspace catalog creation controls in non-table views remain visible but call a callback that now returns early, so they silently do nothing.
  • 🟡 MEDIUM — New workspace creation no longer receives active filter/group property values, so a workspace created in a constrained view can immediately disappear from that view.

The existing unresolved comments were not reposted. The shared menu and query invalidation patterns are otherwise well-factored.

🧪 Browser testing: Skipped — dev server is running, but browser automation remained unavailable after the allowed retry; all 20 planned cases were environment-blocked.

Comment thread templates/content/actions/get-document.ts
Comment thread templates/content/app/components/editor/database/DatabaseView.tsx
Comment thread templates/content/app/components/editor/database/DatabaseView.tsx Outdated
@3mdistal
3mdistal requested a review from steve8708 July 20, 2026 18:41
@3mdistal 3mdistal changed the title Restore Content organization and Trash navigation Harden Content workspace navigation and Trash lifecycle Jul 20, 2026
@3mdistal
3mdistal merged commit 701e1a3 into main Jul 20, 2026
90 checks passed
@3mdistal
3mdistal deleted the codex/content-global-workspace-model branch July 20, 2026 20:03
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.

2 participants