Skip to content

fix(web): scope file search recents by revision#1392

Open
DivyamTalwar wants to merge 4 commits into
sourcebot-dev:mainfrom
DivyamTalwar:divyam/fix-file-search-recent-revisions
Open

fix(web): scope file search recents by revision#1392
DivyamTalwar wants to merge 4 commits into
sourcebot-dev:mainfrom
DivyamTalwar:divyam/fix-file-search-recent-revisions

Conversation

@DivyamTalwar

@DivyamTalwar DivyamTalwar commented Jun 29, 2026

Copy link
Copy Markdown

Fixes #1387

Problem

Browse file-search recents were stored per repository, so switching branches or revisions could show stale file paths from another revision.

Root cause

The localStorage key used only repoName, while selected recents navigate using the current revisionName.

Solution

Scope the recents key by repository and revision, encode key segments to avoid delimiter collisions, and migrate legacy repo-scoped recents only into the default/HEAD revision context so existing default-branch recents are preserved.

Tests

  • node .yarn/releases/yarn-4.7.0.cjs workspace @sourcebot/web test src/app/(app)/browse/components/fileSearchRecents.test.ts
  • node .yarn/releases/yarn-4.7.0.cjs workspace @sourcebot/web exec eslint src/app/(app)/browse/components/fileSearchCommandDialog.tsx src/app/(app)/browse/components/fileSearchRecents.ts src/app/(app)/browse/components/fileSearchRecents.test.ts

Risk

Low to moderate. Recents become revision-scoped; legacy repo-scoped recents are migrated only for the default revision to avoid reintroducing stale branch-specific paths.

Summary by CodeRabbit

  • New Features
    • Recently opened files are now remembered separately for each repository revision, improving accuracy when switching branches or commits.
    • Existing recent-file history can be automatically carried over from the older storage format when appropriate.
  • Bug Fixes
    • Prevents stale “recently opened” files from appearing in the wrong revision context.
  • Tests
    • Added automated test coverage for recent-file storage key generation and legacy migration rules.

Store file-search recents per repository revision and migrate legacy repo-scoped recents only into the default revision context.\n\nConstraint: Recently opened files are stored in browser localStorage and can point at paths missing on other revisions.\nRejected: Change the key without migration | existing users would silently lose default-branch recents.\nConfidence: high\nScope-risk: narrow\nDirective: Keep persisted browse state scoped to the navigation context that can safely resolve it.\nTested: node .yarn/releases/yarn-4.7.0.cjs workspace @sourcebot/web test src/app/(app)/browse/components/fileSearchRecents.test.ts; node .yarn/releases/yarn-4.7.0.cjs workspace @sourcebot/web exec eslint src/app/(app)/browse/components/fileSearchCommandDialog.tsx src/app/(app)/browse/components/fileSearchRecents.ts src/app/(app)/browse/components/fileSearchRecents.test.ts\nNot-tested: Browser E2E over live revision switching
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1a819a78-9939-4260-a826-6094dd539294

📥 Commits

Reviewing files that changed from the base of the PR and between 669264a and 22c7935.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx
  • packages/web/src/app/(app)/browse/components/fileSearchRecents.test.ts
  • packages/web/src/app/(app)/browse/components/fileSearchRecents.ts
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/web/src/app/(app)/browse/components/fileSearchRecents.test.ts
  • packages/web/src/app/(app)/browse/components/fileSearchRecents.ts
  • packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx

Walkthrough

Adds revision-scoped recently opened file storage keys, tests the key and migration helpers, and updates the file-search dialog to migrate legacy repo-scoped recents when appropriate.

Changes

Revision-scoped recently opened files

Layer / File(s) Summary
fileSearchRecents helpers and tests
packages/web/src/app/(app)/browse/components/fileSearchRecents.ts, packages/web/src/app/(app)/browse/components/fileSearchRecents.test.ts
Defines the legacy repo-only key, the revision-scoped key format, the migration predicate, and tests key construction plus migration gating.
Dialog adopts new recents storage
packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx, CHANGELOG.md
Switches the dialog to the revision-scoped localStorage key, adds one-time legacy seeding from the old key, and records the fix in the changelog.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • sourcebot-dev/sourcebot#341: Introduced the file search dialog and its original recently opened files storage behavior that this PR updates.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: scoping file search recents by revision.
Linked Issues check ✅ Passed The changes scope recents to repo+revision and migrate legacy data only for the default revision, matching #1387.
Out of Scope Changes check ✅ Passed The changelog, tests, and helper extraction are all directly related to the revision-scoping fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Document the file-search recents revision scoping fix in the Unreleased changelog after the PR number was assigned.\n\nConstraint: Sourcebot requires every PR to include a changelog entry with the PR link.\nConfidence: high\nScope-risk: narrow\nDirective: Keep changelog entries as follow-up commits once PR numbers exist.\nTested: not run; changelog-only change\nNot-tested: Runtime behavior

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/web/src/app/(app)/browse/components/fileSearchRecents.ts (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Export this sentinel as a camelCase constant.

DEFAULT_REVISION_NAME breaks the TS naming rule here, and keeping "HEAD" private forces other files to duplicate the same contract. Renaming/exporting it would fix both problems at once.

Suggested cleanup
-const DEFAULT_REVISION_NAME = 'HEAD';
+export const defaultRevisionName = 'HEAD';
@@
-    const encodedRevisionName = encodeURIComponent(revisionName ?? DEFAULT_REVISION_NAME);
+    const encodedRevisionName = encodeURIComponent(revisionName ?? defaultRevisionName);
@@
-    return revisionName === undefined || revisionName === null || revisionName === DEFAULT_REVISION_NAME;
+    return revisionName === undefined || revisionName === null || revisionName === defaultRevisionName;

As per coding guidelines, **/*.{ts,tsx,js,jsx} files should use camelCase starting with a lowercase letter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/app/`(app)/browse/components/fileSearchRecents.ts at line 1,
The sentinel in fileSearchRecents should be exposed as a camelCase export
instead of a private SCREAMING_SNAKE_CASE constant. Rename DEFAULT_REVISION_NAME
to a lowercase camelCase identifier and export it so other modules can reuse the
same HEAD contract without duplicating the literal, while keeping the existing
behavior in fileSearchRecents intact.

Source: Coding guidelines

packages/web/src/app/(app)/browse/components/fileSearchRecents.test.ts (1)

42-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the missing null migration assertion.

shouldMigrateLegacyRecentlyOpenedFiles treats null as part of the default-revision path, but this suite never locks that branch down.

Suggested assertion
     test('only migrates legacy recents into the default revision context', () => {
         expect(shouldMigrateLegacyRecentlyOpenedFiles({ revisionName: undefined })).toBe(true);
+        expect(shouldMigrateLegacyRecentlyOpenedFiles({ revisionName: null })).toBe(true);
         expect(shouldMigrateLegacyRecentlyOpenedFiles({ revisionName: 'HEAD' })).toBe(true);
         expect(shouldMigrateLegacyRecentlyOpenedFiles({ revisionName: 'main' })).toBe(false);
         expect(shouldMigrateLegacyRecentlyOpenedFiles({ revisionName: 'feature/file-search' })).toBe(false);
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/app/`(app)/browse/components/fileSearchRecents.test.ts
around lines 42 - 46, Add the missing null-case assertion in the
shouldMigrateLegacyRecentlyOpenedFiles test so the default-revision migration
behavior is locked down for both undefined and null. Update the
fileSearchRecents.test suite alongside the existing
shouldMigrateLegacyRecentlyOpenedFiles checks to include an expectation that
revisionName: null returns true, matching the current legacy-recents migration
path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/web/src/app/`(app)/browse/components/fileSearchCommandDialog.tsx:
- Around line 48-66: The legacy recently-opened migration in
fileSearchCommandDialog should clear the old repo-scoped localStorage entry
after successfully copying its data into the new state. Update the useEffect
that reads getLegacyRecentlyOpenedFilesStorageKey and calls setRecentlyOpened so
it removes the legacy key once a valid parsed array is applied, preventing the
one-time migration from replaying whenever the HEAD-scoped list becomes empty.

---

Nitpick comments:
In `@packages/web/src/app/`(app)/browse/components/fileSearchRecents.test.ts:
- Around line 42-46: Add the missing null-case assertion in the
shouldMigrateLegacyRecentlyOpenedFiles test so the default-revision migration
behavior is locked down for both undefined and null. Update the
fileSearchRecents.test suite alongside the existing
shouldMigrateLegacyRecentlyOpenedFiles checks to include an expectation that
revisionName: null returns true, matching the current legacy-recents migration
path.

In `@packages/web/src/app/`(app)/browse/components/fileSearchRecents.ts:
- Line 1: The sentinel in fileSearchRecents should be exposed as a camelCase
export instead of a private SCREAMING_SNAKE_CASE constant. Rename
DEFAULT_REVISION_NAME to a lowercase camelCase identifier and export it so other
modules can reuse the same HEAD contract without duplicating the literal, while
keeping the existing behavior in fileSearchRecents intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3babb738-ef24-40bd-9dee-963dbff77d89

📥 Commits

Reviewing files that changed from the base of the PR and between 82b5c1f and 669264a.

📒 Files selected for processing (3)
  • packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx
  • packages/web/src/app/(app)/browse/components/fileSearchRecents.test.ts
  • packages/web/src/app/(app)/browse/components/fileSearchRecents.ts

Apply CodeRabbit feedback by clearing migrated legacy recents, exporting the default revision sentinel, and covering null migration input.\n\nConstraint: Review feedback identified one replay risk and two small coverage/style gaps in the recents migration.\nConfidence: high\nScope-risk: narrow\nDirective: Keep legacy localStorage migrations one-time and explicitly covered.\nTested: node .yarn/releases/yarn-4.7.0.cjs workspace @sourcebot/web test src/app/(app)/browse/components/fileSearchRecents.test.ts; node .yarn/releases/yarn-4.7.0.cjs workspace @sourcebot/web exec eslint src/app/(app)/browse/components/fileSearchCommandDialog.tsx src/app/(app)/browse/components/fileSearchRecents.ts src/app/(app)/browse/components/fileSearchRecents.test.ts\nNot-tested: Browser E2E over live revision switching
…h-recent-revisions

# Conflicts:
#	CHANGELOG.md
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.

File search recents are shared across browse revisions

1 participant