Skip to content

[web] Fix recents tracking and mobile dropdown#378

Merged
2witstudios merged 4 commits intomasterfrom
codex/fix-recents-sidebar-mobile-dropdown
Feb 5, 2026
Merged

[web] Fix recents tracking and mobile dropdown#378
2witstudios merged 4 commits intomasterfrom
codex/fix-recents-sidebar-mobile-dropdown

Conversation

@2witstudios
Copy link
Owner

@2witstudios 2witstudios commented Feb 4, 2026

What changed

  • move page-view tracking into CenterPanel so recents are recorded on real dashboard page routes
  • simplify app/dashboard/[driveId]/[pageId]/page.tsx to route-shell only (no dead side effects)
  • switch mobile RecentsDropdown from tab-store data to /api/user/recents API data
  • render real page title/type/time in the mobile dropdown instead of generic tab fallbacks

Why

  • left-sidebar Recents never rendered because page-view tracking lived in a route component that does not run for these routes
  • mobile recents dropdown showed generic entries ("Page"/"Dashboard") because it relied on tab metadata

Verification

  • manual: open a page and confirm POST /api/pages/{pageId}/view fires
  • manual: open dashboard sidebar Recents and mobile navbar Recents to confirm real page entries appear
  • note: automated typecheck/lint were not run here because apps/web dependencies are not installed in this workspace (node_modules missing)

Summary by CodeRabbit

  • Improvements

    • Recents dropdown now loads live recent pages from the server with loading and retry states.
    • Recent items show concise relative timestamps (e.g., "just now", "5m ago", "yesterday") and clearer page-type icons.
    • More reliable recent-items listing and safer handling of result limits.
  • New Features

    • Page view events are recorded on page switches to improve analytics and syncing.

@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

Route-driven side effects were removed from the dashboard Page component and consolidated into CenterPanel. CenterPanel now derives activeDriveId, syncs activePageId to the store, posts page-view events and clears hasChanges. RecentsDropdown now fetches recents via SWR and the Recents API types page.type as PageType.

Changes

Cohort / File(s) Summary
Dashboard Page
apps/web/src/app/dashboard/[driveId]/[pageId]/page.tsx
Implementation stripped: removed hooks and side-effect logic; component now returns null.
CenterPanel (route-driven effects)
apps/web/src/components/layout/middle-content/CenterPanel.tsx
Added activeDriveId derivation, sync of activePageId to global store, a persistent updateNodeRef to call usePageTree.updateNode, and a POST to /api/pages/{activePageId}/view that clears hasChanges; includes cancellation handling.
Recents UI
apps/web/src/components/shared/RecentsDropdown.tsx, apps/web/src/components/layout/left-sidebar/RecentsSection.tsx
RecentsDropdown now uses SWR + fetchWithAuth for /api/user/recents?limit=8, renders items with PageTypeIcon and a relative-time formatter, navigates to /dashboard/{driveId}/{id}; RecentsSection removed an explicit PageType cast.
Recents API types
apps/web/src/app/api/user/recents/route.ts
Added PageType mapping/validation, hardened limit parsing, filtered out non-mapped types, and changed RecentPage.type from string to PageType.

Sequence Diagram(s)

sequenceDiagram
  participant Router as Router
  participant Center as CenterPanel
  participant Store as Global Store / PageTree
  participant API as /api/pages/:id/view
  participant Update as updateNode (usePageTree)

  Router->>Center: route change (driveId, pageId)
  Center->>Store: set activeDriveId(activeDriveId)
  Center->>Store: set activePageId(activePageId)
  Center->>Update: clear hasChanges for pageId (via updateNodeRef)
  Center->>API: POST /api/pages/{activePageId}/view
  API-->>Center: 200 OK
  Center->>Update: confirm clear hasChanges (on success)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰
I hopped from Page into the Pane,
Counting views like gentle rain.
Recents fetched, the list grows bright,
hasChanges gone — the tree sleeps tight.
Tiny whiskers tap a happy bite 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the two main changes: moving recents tracking (implied by 'Fix recents tracking') and updating the mobile dropdown component ('mobile dropdown').

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-recents-sidebar-mobile-dropdown

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/web/src/components/shared/RecentsDropdown.tsx`:
- Around line 80-87: The component RecentsDropdown currently treats any
fetch/auth error the same as an empty recents list; update the render branch
that checks error || !data?.recents || data.recents.length === 0 to separate the
error case: if error is truthy, render a distinct error UI (e.g., "Failed to
load recent pages" with optional retry control) and only fall back to "No recent
pages" when data.recents exists but is empty; locate the conditional using
isLoading, error, and data?.recents in RecentsDropdown to implement this change.
- Around line 96-103: The RecentPage.type is currently typed as string but
should use the PageType enum; update the RecentPage definition in
apps/web/src/app/api/user/recents/route.ts to declare type: PageType (and import
PageType there), then in components like RecentsDropdown.tsx remove the
unnecessary "as PageType" assertion (e.g., where PageTypeIcon is used) and run
TS checks to update any other usages of RecentPage to the new PageType-typed
field.
🧹 Nitpick comments (1)
apps/web/src/components/shared/RecentsDropdown.tsx (1)

52-59: Add SWR editing-protection pause to prevent revalidation interruptions during editing.

The fetch has a 5-minute refresh interval that will continue during user editing. Add isPaused with editing state protection, consistent with patterns used elsewhere in the codebase. The coding guidelines specify: use isPaused: () => hasLoadedRef.current && isEditingActive() to allow the initial fetch, then pause revalidation after load.

Pattern example from InboxCenterList.tsx
const hasLoadedRef = useRef(false);

const { data, isLoading, error } = useSWR(/* ... */, {
  // ... other options
  isPaused: () => hasLoadedRef.current && isEditingActive(),
  onSuccess: () => { hasLoadedRef.current = true; },
});

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/app/api/user/recents/route.ts (1)

23-26: ⚠️ Potential issue | 🟡 Minor

Guard against invalid limit values producing NaN.
parseInt can return NaN, which will propagate through Math.min/Math.max and can break the DB query. Use a safe fallback when parsing fails.

Suggested fix
-  const limit = Math.min(Math.max(parseInt(limitParam || '8', 10), 1), 50);
+  const parsedLimit = Number.parseInt(limitParam ?? '8', 10);
+  const safeLimit = Number.isFinite(parsedLimit) ? parsedLimit : 8;
+  const limit = Math.min(Math.max(safeLimit, 1), 50);

…idebar-mobile-dropdown

# Conflicts:
#	apps/web/src/app/dashboard/[driveId]/[pageId]/page.tsx
#	apps/web/src/components/shared/RecentsDropdown.tsx
@2witstudios 2witstudios merged commit 3d6d8db into master Feb 5, 2026
3 checks passed
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