Skip to content

fix: use cached tab title and pageType in mobile RecentsDropdown#375

Merged
2witstudios merged 1 commit intomasterfrom
claude/fix-recent-pages-mobile-NVQjY
Feb 5, 2026
Merged

fix: use cached tab title and pageType in mobile RecentsDropdown#375
2witstudios merged 1 commit intomasterfrom
claude/fix-recent-pages-mobile-NVQjY

Conversation

@2witstudios
Copy link
Owner

@2witstudios 2witstudios commented Feb 4, 2026

The RecentsDropdown (mobile) was showing generic "Page" or "Drive" labels
instead of actual page titles because getTabDisplayInfo() wasn't using
the cached title and pageType properties from the tab object. Now it
properly displays the page names and correct icons.

https://claude.ai/code/session_01RPLsmsjvjB7iEd8RgNJUrF

Summary by CodeRabbit

  • New Features

    • Recents now load from the server with a visible loading state and a “No recent pages” message when empty.
    • Clicking a recent opens the corresponding dashboard page.
  • Refactor

    • Recent items now show icons and titles directly from each page’s type/title for consistent rendering.
    • Replaced tab-driven local state with centralized recent data fetching.
  • Bug Fixes

    • Dashboard layout now renders children by default so page-level effects run reliably.

@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

Replaced local tab-store recents with SWR server fetching; added loading/empty states; adjusted RecentsSection empty handling; changed dashboard layout default to render children; middleware now accepts session bearer tokens prefixed with Bearer ps_sess_ alongside MCP tokens.

Changes

Cohort / File(s) Summary
RecentsDropdown
apps/web/src/components/shared/RecentsDropdown.tsx
Replaced local tab-store logic with SWR fetching from /api/user/recents?limit=10 using fetchWithAuth; removed ICON_MAP and tab-parsing helpers; render items with PageTypeIcon and page.title; navigate to /dashboard/{driveId}/{id} on click; added loading and empty states; updated imports and types (RecentPage, PageType).
Recents UI container
apps/web/src/components/layout/left-sidebar/RecentsSection.tsx
Changed empty-data handling: on empty recents render compact header + “No recent pages” message; on error still return null; loading state preserved via RecentsSkeleton.
Routing/Layout
apps/web/src/app/dashboard/layout.tsx
Adjusted default fallback to render Layout with {children} instead of returning an empty layout, preserving early return for full-page routes.
Middleware auth check
apps/web/middleware.ts
Added SESSION_BEARER_PREFIX = 'Bearer ps_sess_' and updated authorization header checks to accept either MCP or session bearer prefixes; comments updated to reflect broad Bearer token format check.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant UI as RecentsDropdown (UI)
participant SWR as SWR Cache
participant Auth as fetchWithAuth
participant API as /api/user/recents
UI->>SWR: useSWR(key="/api/user/recents?limit=10")
SWR-->>UI: cached data or loading state
SWR->>Auth: perform authenticated fetch
Auth->>API: HTTP request with auth header
API-->>Auth: recent pages payload
Auth-->>SWR: response
SWR-->>UI: data (render list) or error
UI->>Router: navigate to /dashboard/{driveId}/{id} on item click

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped from store to server-side,

Fetching recents, icons by my side,
A loader blink, then titles sing,
Click and off to dashboard spring —
Tiny paws, big routing stride.

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title mentions 'cached tab title and pageType' but the actual changes show a complete refactor from tab-based local state to SWR-based API fetching with no tab caching involved. Update the title to accurately reflect the main change: consider 'refactor: migrate RecentsDropdown to SWR-based data fetching' or similar to match the actual implementation.
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 (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 claude/fix-recent-pages-mobile-NVQjY

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.

@2witstudios 2witstudios force-pushed the claude/fix-recent-pages-mobile-NVQjY branch from 40b1436 to ac4d7b7 Compare February 4, 2026 14:04
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: 1

🤖 Fix all issues with AI agents
In `@apps/web/src/components/shared/RecentsDropdown.tsx`:
- Around line 22-25: The fetcher function should be given an explicit return
type to avoid implicit any from response.json(); update the fetcher signature
(fetcher) to return Promise<{ recents: RecentPage[] }> and ensure the returned
value is typed (e.g., await response.json() cast or typed as { recents:
RecentPage[] }) so it matches the SWR generic parameter and satisfies
TypeScript.
🧹 Nitpick comments (1)
apps/web/src/components/shared/RecentsDropdown.tsx (1)

35-41: Add SWR editing-protection pause for consistency with similar components.

This component should follow the established pattern used in UserDropdown and other navigation/data-fetching components. Add isPaused: () => hasLoadedRef.current && isEditingActive() to pause refreshes during editing, which prevents interruptions when users are actively editing pages elsewhere in the app. This requires importing useEditingStore and tracking load state with a useRef.

Comment on lines +22 to +25
const fetcher = async (url: string) => {
const response = await fetchWithAuth(url);
if (!response.ok) throw new Error('Failed to fetch');
return response.json();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check the file exists and get its content
wc -l apps/web/src/components/shared/RecentsDropdown.tsx

Repository: 2witstudios/PageSpace

Length of output: 118


🏁 Script executed:

# Read the file to see the actual code at lines 22-25 and surrounding context
head -50 apps/web/src/components/shared/RecentsDropdown.tsx | cat -n

Repository: 2witstudios/PageSpace

Length of output: 1829


🏁 Script executed:

# Search for RecentPage type definition in the codebase
rg "type RecentPage|interface RecentPage" -t ts -t tsx

Repository: 2witstudios/PageSpace

Length of output: 92


🏁 Script executed:

# Check for useSWR usage patterns in the file
rg "useSWR" apps/web/src/components/shared/RecentsDropdown.tsx -A 5 -B 2

Repository: 2witstudios/PageSpace

Length of output: 551


🏁 Script executed:

# Check the API route to confirm the response structure
head -50 apps/web/src/app/api/user/recents/route.ts | cat -n

Repository: 2witstudios/PageSpace

Length of output: 1838


🏁 Script executed:

# Also search for RecentPage type to verify the imported type
rg "export.*type RecentPage|export.*interface RecentPage" -A 3

Repository: 2witstudios/PageSpace

Length of output: 310


Type the SWR fetcher to avoid implicit any from response.json().

The fetcher function lacks an explicit return type. response.json() returns any, which violates the TypeScript guideline. Add an explicit return type matching the SWR generic parameter { recents: RecentPage[] }.

🔧 Proposed fix
-const fetcher = async (url: string) => {
+const fetcher = async (url: string): Promise<{ recents: RecentPage[] }> => {
   const response = await fetchWithAuth(url);
   if (!response.ok) throw new Error('Failed to fetch');
   return response.json();
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fetcher = async (url: string) => {
const response = await fetchWithAuth(url);
if (!response.ok) throw new Error('Failed to fetch');
return response.json();
const fetcher = async (url: string): Promise<{ recents: RecentPage[] }> => {
const response = await fetchWithAuth(url);
if (!response.ok) throw new Error('Failed to fetch');
return response.json();
};
🤖 Prompt for AI Agents
In `@apps/web/src/components/shared/RecentsDropdown.tsx` around lines 22 - 25, The
fetcher function should be given an explicit return type to avoid implicit any
from response.json(); update the fetcher signature (fetcher) to return Promise<{
recents: RecentPage[] }> and ensure the returned value is typed (e.g., await
response.json() cast or typed as { recents: RecentPage[] }) so it matches the
SWR generic parameter and satisfies TypeScript.

@2witstudios 2witstudios force-pushed the claude/fix-recent-pages-mobile-NVQjY branch from ac4d7b7 to f76ca16 Compare February 4, 2026 14:16
ROOT CAUSE: The dashboard layout returned `<Layout />` without `{children}`
for page routes, which meant the page.tsx component at [driveId]/[pageId]
never mounted. Since the view recording useEffect was in that component,
page views were never recorded to the database.

Fix: Always render `{children}` so the page component mounts and its
effects run, even though it returns null (visual content is in CenterPanel).

Also:
- Allow Bearer session tokens in middleware (for mobile API access)
- RecentsDropdown uses /api/user/recents API instead of tabs store
- RecentsSection shows "No recent pages" instead of hiding when empty

This fixes:
- Page views not being recorded
- Recents not showing in sidebar or mobile dropdown
- Blue dot not clearing when viewing pages

https://claude.ai/code/session_01RPLsmsjvjB7iEd8RgNJUrF
@2witstudios 2witstudios force-pushed the claude/fix-recent-pages-mobile-NVQjY branch from f76ca16 to 01f46de Compare February 4, 2026 14:30
@2witstudios 2witstudios merged commit 00b80f6 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.

2 participants