Repository navigation
Fix/header rendering - #121
Conversation
Implement comprehensive version history browsing and rollback capabilities for PageSpace, allowing users to restore resources to previous states. ## Schema Changes - Add 'rollback' operation to activity_operation enum - Add rollbackFromActivityId and contentFormat fields to activity_logs - Create retention_policies table for plan-based history retention ## Core Features - RBAC-based rollback permissions (edit access = rollback access) - Resource-specific rollback handlers (pages, drives, agents, etc.) - Plan-based retention limits (7/30/90/unlimited days) - Rollback creates new activity entry (history never erased) ## API Endpoints - GET /api/activities/[activityId] - Single activity with rollback eligibility - POST /api/activities/[activityId]/rollback - Execute rollback - GET /api/pages/[pageId]/history - Page version history - GET /api/drives/[driveId]/history - Drive version history (admin) ## UI Components - VersionHistoryPanel - Slide-out panel with timeline and filters - VersionHistoryItem - Activity item with "Restore" action - RollbackConfirmDialog - Confirmation modal with warnings 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fully implement rollbackPermissionChange for grant/revoke/update operations - Fully implement rollbackMemberChange for add/remove/role change operations - Fully implement rollbackRoleChange for create/delete/update operations - Fix lint errors: remove unused imports, fix useEffect dependencies - Add package exports for @pagespace/lib/permissions and @pagespace/lib/monitoring - Fix useToast import path to use correct hook location 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ability to undo AI changes from a specific message point: - Preview what will be affected before undoing - Two modes: revert conversation only OR revert with all tool changes - Activity logging for audit compliance New files: - ai-undo-service.ts: preview and execute functions - UndoAiChangesDialog.tsx: confirmation dialog with mode selection - /api/ai/chat/messages/[messageId]/undo: GET preview, POST execute Changes: - Add conversation_undo operations to activity schema - Add message rollback handler to rollback-service - Wire undo button to MessageActionButtons and MessageRenderer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Required for UndoAiChangesDialog mode selection. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Required for radio-group UI component used in UndoAiChangesDialog. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous lockfile had a malformed git SSH URL that broke CI: - Before: git+https://git@github.com:electron/node-gyp.git (broken) - After: https://codeload.github.com/electron/node-gyp/tar.gz/... (works) Restored lockfile and re-ran pnpm install to properly resolve dependencies. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CRITICAL rules for package manager (always pnpm, never npm) - Add CRITICAL rules for database migrations (never manually edit) - Fix retention days: founder=90, business=unlimited (was swapped) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Wrap switch case declarations in blocks to prevent variable leakage - Add isActivityEligibleForRollback() helper for DRY rollback checks - Export helper for use in history API routes Addresses PR #118 review issues #5, #13 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add contentFormat field for content type tracking - Add rollbackFromActivityId for rollback chain references - Pass fields as top-level properties to logActivity Addresses PR #118 review issue #3 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add permission check before returning activity details - Implement resourceType query parameter filtering in history routes - Use shared isActivityEligibleForRollback helper - Add case-insensitive resource type matching Addresses PR #118 review issues #6, #7, #13 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use Drizzle count() instead of .length for efficient queries - Add operation validation against known valid operations - Fix unsafe null type assertion in RollbackPreview - Re-export RollbackContext type for API route usage - Wrap AI undo mutations in database transaction - Use switch statement for context determination Addresses PR #118 review issues #2, #16, #18, #19, #23 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use post() with CSRF token for rollback requests - Add error toast for failed preview fetch - Handle non-JSON error responses gracefully - Fix non-existent postWithAuth import to use post - Remove re-throw after toast notification - Fix redundant ternary for buttonSize Addresses PR #118 review issues #1, #8, #11, #17, #22, NEW 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Critical & Major fixes: - Add missing .defaultNow() to retention_policies.updatedAt (fixes schema/migration mismatch that would cause insert failures) - Add contentFormatEnum for type-safe content format validation (prevents invalid values during rollback parsing) - Add CHECK constraint: retentionDays >= -1 (where -1 = unlimited) - Add rollback source snapshot fields for audit trail preservation: - rollbackSourceOperation: captures source activity type - rollbackSourceTimestamp: captures when source change occurred - rollbackSourceTitle: captures resource title at time of change These denormalized fields survive retention policy deletion, ensuring complete audit trails even when source activities are purged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes Major issue #2 from PR #118 review: - Move rollbackFromActivityId from metadata to top-level field - Move contentFormat from metadata to top-level field - Add rollback source snapshot fields to ActivityLogInput interface - Update logRollbackActivity to accept and pass snapshot fields Fields are now stored in dedicated database columns instead of being nested in the metadata JSONB, enabling proper indexing and querying. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enables atomic rollback operations (Issue #7 from PR #118 review): - Add optional transaction parameter to executeRollback() - Update all internal rollback functions to accept database parameter - Pass rollback source snapshot fields to logRollbackActivity When a transaction is provided, all database operations use it instead of the default db connection, enabling atomic rollback + message deletion in AI undo operations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes Issues #5 and #7 from PR #118 review: Context determination (#5): - Align executeAiUndo context logic with previewAiUndo - Use 'ai_tool' context for pages (all activities here are AI-generated) - Simplifies from switch statement to direct assignment with drive check Transaction atomicity (#7): - Wrap rollbacks AND message deletion in single transaction - Pass transaction to executeRollback for atomic operations - If any operation fails, entire undo is rolled back This ensures users don't end up in inconsistent states where messages are deleted but only some changes were reverted. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes Issue #6 from PR #118 review: - Replace manual mode validation with Zod schema - Aligns with codebase patterns (see rollback route, history route) - Provides type-safe body parsing with proper TypeScript inference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CHECK constraint to retentionPolicies schema definition (aligns Drizzle schema with existing migration constraint) - Change AI undo to all-or-nothing transaction semantics (any rollback failure aborts entire operation) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create subscription_tier pgEnum with 'free', 'pro', 'business', 'founder' - Convert retentionPolicies.subscriptionTier from text to enum - Adds DB-level validation to prevent invalid tier values 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comments explaining rollbackFromActivityId intentionally lacks FK (allows provenance to survive source activity deletion for audit) - Add TODO note for contentSnapshot storage considerations - Optimize message fetching: include createdAt in AiUndoPreview to avoid double database query 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PostgreSQL requires explicit cast when converting text column to enum type. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…messages tables and updating permission logic
- Add route tests for /api/activities/[activityId]/rollback (12 tests) - Add route tests for /api/pages/[pageId]/history (21 tests) - Add service tests for ai-undo-service (16 tests) with @scaffold label - Add service tests for rollback-service (28 tests) with @scaffold label - Add permission tests for rollback-permissions (69 tests) - Fix undo route test: remove duplicate test expecting wrong status - Add fake timers to history route tests for deterministic dates Per rubric v2: service tests use @scaffold labels for ORM chain mocks pending repository seam refactoring. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add "Restore this version" action to activity items in: - ActivityDashboard (middle panel for /dashboard/activity and drive activity) - SidebarActivityTab (right sidebar context-aware activity feed) Changes: - ActivityItem: Add hover dropdown menu with rollback action and confirmation dialog - ActivityTimeline: Pass context and onRollback handler to items - ActivityDashboard: Handle rollback with proper context mapping (user→user_dashboard, drive→drive) - SidebarActivityTab: Add rollback UI with context-aware scoping (page/drive/user_dashboard) Rollback is properly scoped by context to prevent unintended changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add compliance tests for: - logRollbackActivity: validates rollback operation logging with source activity reference - logConversationUndo: validates conversation undo logging for both modes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 'create' as rollbackable operation (trash resource to undo creation) - Support both global messages and page chat messages in rollback - Fix AI undo timing to include tool calls from preceding message - Handle message create rollback by deactivating the message 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix build failure: replace dynamic db.query[] bracket notation with explicit conditional to resolve TypeScript union type error - Extract checkUndoPermissions() helper to eliminate 31 lines of duplicated permission logic between GET and POST handlers - Add existingPreview parameter to executeAiUndo() to avoid redundant preview computation (was being called twice per request) - Simplify context determination: remove redundant isAiGenerated check since query already filters for it - Update tests to match new 4-parameter executeAiUndo signature - Add clarifying comment explaining partial failure tests document defensive handling (actual impl uses all-or-nothing transaction) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Caution Review failedThe pull request is closed. WalkthroughThis PR introduces a comprehensive activity rollback and AI conversation undo system. It adds new API endpoints for previewing and executing rollbacks, retrieves version history with retention policies, implements permission-based authorization for rollback operations, introduces database schema extensions for audit tracking and retention configuration, and adds UI components for history viewing, restoration confirmations, and undo dialogs. Changes
Sequence DiagramssequenceDiagram
participant User as User/Client
participant UI as UI Component
participant API as API Route
participant Auth as Auth Service
participant Service as Rollback Service
participant DB as Database
User->>UI: Click "Restore Previous Version"
activate UI
UI->>API: GET /api/activities/[id]?context=page
activate API
API->>Auth: authenticateRequestWithOptions(jwt, no-csrf)
activate Auth
Auth-->>API: ✓ authenticated
deactivate Auth
API->>Service: getActivityById(activityId)
activate Service
Service->>DB: Query activity log
activate DB
DB-->>Service: activity details
deactivate DB
Service->>Service: canUserViewPage(pageId)
Service-->>API: activity + canRollback flag
deactivate Service
API-->>UI: { activity, canRollback, warnings }
deactivate API
UI->>UI: Show RollbackConfirmDialog with preview
deactivate UI
User->>UI: Confirm rollback
activate UI
UI->>API: POST /api/activities/[id]/rollback
activate API
API->>Auth: authenticateRequestWithOptions(jwt, csrf-required)
activate Auth
Auth-->>API: ✓ authenticated
deactivate Auth
API->>Service: executeRollback(activityId, userId, context)
activate Service
Service->>Service: previewRollback (validation)
Service->>Service: canUserRollback (permission check)
Service->>DB: Begin transaction
activate DB
Service->>DB: Restore previous values per resource type
Service->>DB: Log rollback activity
Service->>DB: Commit
DB-->>Service: ✓ committed
deactivate DB
Service-->>API: { rollbackActivityId, restoredValues, message }
deactivate Service
API-->>UI: { success: true, data }
deactivate API
UI->>UI: Show success toast & refresh
deactivate UI
sequenceDiagram
participant User as User/Client
participant UI as UI Component
participant API as API Route
participant Auth as Auth Service
participant Service as AI Undo Service
participant Rollback as Rollback Service
participant DB as Database
User->>UI: Click Undo on AI message
activate UI
UI->>API: GET /api/ai/chat/messages/[id]/undo
activate API
API->>Auth: authenticateRequestWithOptions(jwt)
activate Auth
Auth-->>API: ✓ authenticated
deactivate Auth
API->>Service: previewAiUndo(messageId, userId)
activate Service
Service->>DB: Get message & related AI activities
activate DB
DB-->>Service: message + activities
deactivate DB
Service->>Rollback: isActivityEligibleForRollback (per activity)
activate Rollback
Rollback-->>Service: canRollback flags
deactivate Rollback
Service-->>API: { messages, activities, canRollback array }
deactivate Service
API->>Service: checkUndoPermissions
API-->>UI: preview data
deactivate API
UI->>UI: Show UndoAiChangesDialog with mode selection
deactivate UI
User->>UI: Select mode & confirm undo
activate UI
UI->>API: POST /api/ai/chat/messages/[id]/undo { mode }
activate API
API->>Auth: authenticateRequestWithOptions(jwt, csrf-required)
activate Auth
Auth-->>API: ✓ authenticated
deactivate Auth
API->>Service: executeAiUndo(messageId, userId, mode, preview)
activate Service
Service->>DB: Begin transaction
activate DB
Service->>DB: Soft-delete messages
alt mode includes changes
Service->>Rollback: executeRollback (per activity, reverse order)
activate Rollback
Rollback->>DB: Restore previous values
Rollback-->>Service: results
deactivate Rollback
end
Service->>DB: Log conversation_undo activity
Service->>DB: Commit
DB-->>Service: ✓ committed
deactivate DB
Service-->>API: { messagesDeleted, activitiesRolledBack }
deactivate Service
API-->>UI: { success: true, data }
deactivate API
UI->>UI: Show success toast & refresh
deactivate UI
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (55)
Comment |
Walkthrough - Header Fixes and UI Polish
I have implemented comprehensive fixes and UI improvements for the header area.
The header now loads reliably across all page types and during active editing sessions.
Centralized State Management
Store Sync:
CenterPanel
now automatically syncs the active pageId from the URL to the global store.
Direct Prop Passing:
ViewHeader
and its children now accept pageId as a prop, ensuring immediate and reliable rendering even if the store is lagging.
SWR Hook Improvements
First-Fetch Protection: Hooks for breadcrumbs, permissions, and page tree now ensure the first fetch is never blocked by active AI chat or document editing.
Navigation Resets: The loaded state is reset on every navigation, allowing fresh data to load even if the previous page was already loaded.
2. UI Polish (Truncation)
To ensure a consistent and mobile-friendly UI, I've added truncation to long titles and breadcrumb items.
Breadcrumb Truncation
Each individual item in the breadcrumb path now has a responsive maximum width.
Long folder or page names will be truncated with ... to prevent the breadcrumbs from overflowing the screen.
Full titles are still accessible via browser hover tooltips.
Page Title Truncation
The main page title now truncates if it becomes too long to fit in the header area.
Like breadcrumbs, the full title is available on hover.
Verification Tips
Long Names: Create a page or folder with an extremely long name; verify it truncates cleanly.
Mobile View: Check the header on small screens; breadcrumbs should stay on one line or truncate cleanly.
Hover: Hover over a truncated element to see the full text.
Summary by CodeRabbit
Release Notes
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.