Skip to content

Code navigation #315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 49 commits into from
May 28, 2025
Merged

Code navigation #315

merged 49 commits into from
May 28, 2025

Conversation

brendan-kellam
Copy link
Contributor

@brendan-kellam brendan-kellam commented May 26, 2025

This PR introduces code navigation, along with a host of performance improvements to how we render search results.

Summary by CodeRabbit

  • New Features

    • Introduced code navigation ("code-nav") capabilities, including symbol hover popups, go-to-definition, and find references features in the code browser and search panels.
    • Added a lightweight syntax highlighter for code snippets with improved styling and line number support.
    • Implemented resizable and collapsible bottom and side panels for enhanced navigation and UI flexibility.
    • Added animated resizable handles and loading button components for improved user interaction.
  • Enhancements

    • Improved search and file browsing panels with direct file preview, better error handling, and external code host links.
    • Enhanced filter panels with bidirectional filtering between repositories and languages.
    • Updated editor theming and code highlighting with new color schemes and refined visual styles.
    • Improved scroll state restoration and persistent panel collapse state in the search UI.
    • Updated entitlement plans to include code navigation features.
  • Bug Fixes

    • Fixed query caching and fetching to scope suggestions and secrets per domain.
    • Improved handling of missing or invalid query parameters with clearer error responses.
  • Documentation

    • Added README documentation for the file browser feature and updated style guidelines.
  • Chores

    • Updated dependencies and ESLint configuration for improved code quality and maintainability.
  • Refactor

    • Streamlined code preview and navigation logic, replaced deprecated components, and restructured panel state management for clarity and performance.
  • Style

    • Refined editor and search match highlighting styles, hover effects, and font settings for a more polished appearance.
  • Tests

    • No user-facing test changes included.

Copy link

coderabbitai bot commented May 26, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update introduces a comprehensive code navigation feature set, including symbol references and definitions, hover popups, and a bottom explore panel. It refactors code preview and search result panels, enhances editor theming, and restructures the filter panel logic for bidirectional filtering. New hooks, UI components, and backend APIs support these features, with significant improvements to code highlighting, navigation, and user interface consistency.

Changes

Files / Groups Change Summary
.cursor/rules/style.mdc Added style rules for indentation and filename casing.
packages/web/.eslintrc.json Added recommended Tanstack Query ESLint plugin.
packages/web/package.json Added dependencies: @codemirror/language-data, @uidotdev/usehooks, and devDependency @tanstack/eslint-plugin-query.
packages/web/src/app/[domain]/browse/README.md Added documentation for file browser URL structure.
packages/web/src/app/[domain]/browse/[...path]/codePreview.tsx
packages/web/src/app/[domain]/components/keyboardShortcutHint.tsx
packages/web/src/app/[domain]/search/components/searchResultsPanel/codePreview.tsx
packages/web/src/app/[domain]/search/components/searchResultsPanel/lightweightCodeMirror.tsx
packages/web/src/hooks/useTailwind.ts
Deleted deprecated code preview, keyboard shortcut hint, and lightweight CodeMirror components, and Tailwind hook.
packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx Added new CodePreviewPanel component with integrated code navigation and highlighting.
packages/web/src/app/[domain]/browse/[...path]/components/rangeHighlightingExtension.ts Added CodeMirror extension for range highlighting.
packages/web/src/app/[domain]/browse/[...path]/page.tsx Refactored file preview logic, improved error handling, and integrated new code preview panel and code host link.
packages/web/src/app/[domain]/browse/browseStateProvider.tsx Added browse state context provider and state management.
packages/web/src/app/[domain]/browse/components/bottomPanel.tsx Added resizable, collapsible bottom panel with code navigation integration and entitlement checks.
packages/web/src/app/[domain]/browse/hooks/useBrowseNavigation.ts Added navigation hook for path, highlight range, and state management.
packages/web/src/app/[domain]/browse/hooks/useBrowseState.ts Added hook for accessing browse state context.
packages/web/src/app/[domain]/browse/layout.tsx Added layout with resizable panels and browse state provider.
packages/web/src/app/[domain]/components/connectionCreationForms/secretCombobox.tsx Updated query key to include domain for secrets fetching.
packages/web/src/app/[domain]/components/editorContextMenu.tsx Replaced hardcoded query param with imported constant.
packages/web/src/app/[domain]/components/fileHeader.tsx Made file name clickable for navigation, improved branch display.
packages/web/src/app/[domain]/components/lightweightCodeHighlighter.tsx Added lightweight code highlighter component for syntax highlighting and range highlighting.
packages/web/src/app/[domain]/components/searchBar/searchBar.tsx
packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx
Updated imports and wrapped keyboard shortcut hint in tooltip.
packages/web/src/app/[domain]/components/searchBar/useSuggestionsData.ts Updated query keys to include domain for suggestions data.
packages/web/src/app/[domain]/search/components/codePreviewPanel/codePreview.tsx Refactored code preview to integrate navigation, symbol hover, and internalize match selection state.
packages/web/src/app/[domain]/search/components/codePreviewPanel/index.tsx Refactored code preview panel to use new API, props, and state handling.
packages/web/src/app/[domain]/search/components/filterPanel/entry.tsx Added isHidden and isDisabled properties to entry type and UI.
packages/web/src/app/[domain]/search/components/filterPanel/index.tsx Refactored filter panel for bidirectional filtering and dynamic disabling/hiding.
packages/web/src/app/[domain]/search/components/filterPanel/useFilterMatches.ts
packages/web/src/app/[domain]/search/components/filterPanel/useGetSelectedFromQuery.ts
Added hooks for filtered matches and selected query parameters.
packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatch.tsx Refactored to use lightweight code highlighter and navigation hook.
packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatchContainer.tsx Updated to use preview button and removed match index handling.
packages/web/src/app/[domain]/search/components/searchResultsPanel/index.tsx Simplified scroll state, unified open file preview callback, and improved state restoration.
packages/web/src/app/[domain]/search/page.tsx Refactored panel state, search parameter handling, and UI responsiveness.
packages/web/src/app/api/(server)/references/route.ts Added API route for symbol references lookup.
packages/web/src/app/components/keyboardShortcutHint.tsx Updated styling for keyboard shortcut hint.
packages/web/src/app/globals.css Overhauled editor theming, color variables, and search match highlighting styles.
packages/web/src/components/ui/animatedResizableHandle.tsx Added animated resizable handle component.
packages/web/src/components/ui/loading-button.tsx Added loading button component with spinner.
packages/web/src/ee/features/codeNav/components/exploreMenu/index.tsx
packages/web/src/ee/features/codeNav/components/exploreMenu/referenceList.tsx
Added explore menu and reference list components for symbol navigation.
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/index.tsx
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolDefinitionPreview.tsx
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolHoverTargetsExtension.ts
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/useHoveredOverSymbolInfo.ts
Added symbol hover popup, definition preview, hover target extension, and hover info hook.
packages/web/src/features/codeNav/actions.ts
packages/web/src/features/codeNav/schemas.ts
packages/web/src/features/codeNav/types.ts
Added code navigation actions, schemas, and types for symbol references/definitions.
packages/web/src/features/entitlements/constants.ts Added "code-nav" entitlement to relevant plans.
packages/web/src/features/search/fileSourceApi.ts
packages/web/src/features/search/schemas.ts
packages/web/src/features/search/searchApi.ts
packages/web/src/features/search/types.ts
Added file webUrl, match count stats, refactored types, and improved search response structure.
packages/web/src/hooks/useCodeMirrorHighlighter.ts
packages/web/src/hooks/useCodeMirrorLanguageExtension.ts
packages/web/src/hooks/useCodeMirrorTheme.ts
Added/renamed hooks for CodeMirror language, theming, and highlighting.
packages/web/src/lib/errorCodes.ts Added new error code for missing query parameter.
packages/web/src/lib/extensions/searchResultHighlightExtension.ts Updated types and class names for search result highlighting.
packages/web/src/lib/utils.ts Added query param guard, updated measure functions, and minor string change.
packages/web/src/tailwind.ts Added module exporting resolved Tailwind config.
packages/web/tailwind.config.ts Expanded Tailwind config with editor and sidebar themes, fonts, and colors.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant UI
  participant CodeEditor
  participant API
  participant CodeNavActions
  participant SearchAPI

  User->>UI: Open file or search for symbol
  UI->>CodeEditor: Render code preview panel
  CodeEditor->>API: Request symbol references/definitions (if code-nav enabled)
  API->>CodeNavActions: findSearchBasedSymbolReferences/Definitions
  CodeNavActions->>SearchAPI: search (with symbol query)
  SearchAPI-->>CodeNavActions: Search results (files, matches)
  CodeNavActions-->>API: Parsed symbol references/definitions
  API-->>CodeEditor: Symbol data
  CodeEditor->>UI: Show hover popup, explore menu, highlight ranges
  User->>UI: Click reference/definition or navigate
  UI->>CodeEditor: Highlight and scroll to symbol location
Loading

Possibly related PRs

  • sourcebot-dev/sourcebot#259: Updates repository display name handling and git config sync, directly related to repository metadata and sync logic.
  • sourcebot-dev/sourcebot#273: Implements search contexts, including schema and UI integration, related to search context features and scoping.

Poem

In fields of code, a rabbit hops,
Through lines and symbols, never stops.
With hover popups, panels slide,
References and definitions side by side.
Colors bloom, the search runs deep,
Navigation magic—no secrets to keep!
🐇✨


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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@brendan-kellam brendan-kellam marked this pull request as ready for review May 28, 2025 05:42
@brendan-kellam brendan-kellam requested a review from msukkari May 28, 2025 05:42
@brendan-kellam
Copy link
Contributor Author

@coderabbitai review

Copy link

coderabbitai bot commented May 28, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@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: 14

🧹 Nitpick comments (26)
packages/web/src/app/components/keyboardShortcutHint.tsx (1)

11-17: Consider maintaining consistency with Tailwind utility classes.

The change from Tailwind's text-xs class to inline styles reduces consistency with the rest of the codebase. Inline styles have higher specificity and can be harder to maintain.

Consider using Tailwind's arbitrary value syntax or custom utility classes instead:

-      <kbd
-        className="px-2 py-1 font-semibold font-sans border rounded-md"
-        style={{
-          fontSize: "0.65rem",
-          lineHeight: "0.875rem",
-        }}
-      >
+      <kbd className="px-2 py-1 font-semibold font-sans border rounded-md text-[0.65rem] leading-[0.875rem]">

This maintains consistency with Tailwind's approach while achieving the same visual result.

packages/web/src/app/[domain]/search/components/filterPanel/entry.tsx (1)

11-11: Consider documenting the usage of isHidden property.

The isHidden property is added to the Entry type but not used within this component. If this property is intended for parent components to conditionally render entries, consider adding a comment to clarify its purpose.

packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolHoverTargetsExtension.ts (3)

13-48: Remove duplicate node types from the array.

The NODE_TYPES array contains duplicate entries:

  • "Identifier" appears on lines 22 and 32
  • "PropertyName" appears on lines 19 and 26

This could lead to unnecessary iterations during the tree traversal.

const NODE_TYPES = [
    // Typescript + Python
    "VariableName",
    "VariableDefinition", 
    "TypeDefinition",
    "TypeName",
    "PropertyName",
-   "PropertyDefinition",
    "JSXIdentifier",
    "Identifier",
    // C#
    "VarName",
    "TypeIdentifier",
-   "PropertyName",
    "MethodName",
    "Ident",
    "ParamName",
    "AttrsNamedArg",
    // C/C++
-   "Identifier",
    "NamespaceIdentifier",
    "FieldIdentifier",
    // Objective-C
    "variableName",
    "variableName.definition",
    // Java
    "Definition",
    // Rust
    "BoundIdentifier",
    // Go
    "DefName",
    "FieldName",
    // PHP
    "ClassMemberName",
    "Name"
]

58-62: Consider removing commented debug code.

The commented debug helper function should be removed for production code or moved to a development-only conditional block.

-        // @note: useful for debugging
-        // const getTextAt = (from: number, to: number) => {
-        //     const doc = state.doc;
-        //     return doc.sliceString(from, to);
-        // }

64-71: Performance consideration for large files.

The tree iteration processes the entire document synchronously, which could cause UI blocking for very large files. Consider implementing a threshold or debouncing mechanism for files above a certain size.

        tree?.iterate({
            enter: (node) => {
-               // console.log(node.type.name, getTextAt(node.from, node.to));
                if (NODE_TYPES.includes(node.type.name)) {
                    decorations.push(decoration.range(node.from, node.to));
                }
            },
        });
packages/web/src/hooks/useCodeMirrorHighlighter.ts (1)

13-13: Consider grouping related tags for better maintainability.

The tag mappings could be better organized by grouping related functionality. For example, all variable-related tags could be grouped together.

            // Names, identifiers, properties
-           { tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName, t.variableName], class: 'text-editor-tag-name' },
+           { tag: [t.name, t.propertyName, t.macroName, t.variableName], class: 'text-editor-tag-name' },
+           { tag: [t.deleted, t.character], class: 'text-editor-tag-name' },
packages/web/src/app/[domain]/browse/[...path]/components/rangeHighlightingExtension.ts (1)

28-30: Consider adding bounds checking for line numbers.

The loop assumes start.lineNumber and end.lineNumber are valid. Consider adding bounds checking to prevent errors if invalid line numbers are provided.

            const decorations: Range<Decoration>[] = [];
+           const maxLine = state.doc.lines;
            for (let line = start.lineNumber; line <= end.lineNumber; line++) {
+               if (line > 0 && line <= maxLine) {
                    decorations.push(lineDecoration.range(state.doc.line(line).from));
+               }
            }
packages/web/src/app/[domain]/browse/components/bottomPanel.tsx (1)

36-43: Consider removing enableOnFormTags and enableOnContentEditable options.

These options allow the keyboard shortcut to trigger while users are typing in forms or content-editable areas, which could be disruptive. Also, the description "Open Explore Panel" is slightly misleading since the shortcut toggles the panel state.

     useHotkeys("shift+mod+e", (event) => {
         event.preventDefault();
         updateBrowseState({ isBottomPanelCollapsed: !isBottomPanelCollapsed });
     }, {
-        enableOnFormTags: true,
-        enableOnContentEditable: true,
-        description: "Open Explore Panel",
+        description: "Toggle Explore Panel",
     });
packages/web/src/app/[domain]/search/components/filterPanel/useFilterMatches.ts (2)

10-10: Remove unnecessary empty line.

-
 export const useFilteredMatches = (

24-31: Consider adding a default case to the switch statement.

While TypeScript ensures all cases are covered, adding a default case improves robustness and satisfies exhaustiveness checking.

         switch (filterBy) {
             case 'repository':
                 return matches.filter((match) => isInRepoSet(match.repository));
             case 'language':
                 return matches.filter((match) => isInLanguageSet(match.language));
             case 'all':
                 return matches.filter((match) => isInRepoSet(match.repository) && isInLanguageSet(match.language));
+            default:
+                return matches;
         }
packages/web/src/app/[domain]/browse/browseStateProvider.tsx (1)

47-61: Consider adding validation for parsed state structure.

While the JSON parsing has error handling, there's no validation that the parsed state conforms to the BrowseState interface structure. Malformed state could lead to runtime issues.

Consider adding state validation:

 useEffect(() => {
     if (hydratedBrowseState) {
         try {
             const parsedState = JSON.parse(hydratedBrowseState) as Partial<BrowseState>;
+            // Validate parsed state structure
+            if (typeof parsedState === 'object' && parsedState !== null) {
                 onUpdateState(parsedState);
+            } else {
+                console.warn("Invalid browse state structure in URL parameter");
+            }
         } catch (error) {
             console.error("Error parsing hydratedBrowseState", error);
         }
packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx (2)

50-89: Consider extracting highlight range parsing into a separate utility function.

The highlight range parsing logic is complex and could benefit from being extracted into a reusable utility function for better testability and maintainability.

Consider extracting this logic:

// utils/parseHighlightRange.ts
export const parseHighlightRange = (highlightRangeQuery: string): BrowseHighlightRange | undefined => {
    const rangeRegex = /^(\d+:\d+,\d+:\d+|\d+,\d+)$/;
    if (!rangeRegex.test(highlightRangeQuery)) {
        return;
    }

    const [start, end] = highlightRangeQuery.split(',').map((range) => {
        if (range.includes(':')) {
            return range.split(':').map((val) => parseInt(val, 10));
        }
        const line = parseInt(range, 10);
        return [line];
    });

    if (start.length === 1 || end.length === 1) {
        return {
            start: { lineNumber: start[0] },
            end: { lineNumber: end[0] }
        };
    } else {
        return {
            start: { lineNumber: start[0], column: start[1] },
            end: { lineNumber: end[0], column: end[1] }
        };
    }
};

196-196: Apply optional chaining suggestion from static analysis.

The static analysis tool correctly identified that this can be simplified using optional chaining.

- {editorRef && editorRef.view && currentSelection && (
+ {editorRef?.view && currentSelection && (
🧰 Tools
🪛 Biome (1.9.4)

[error] 196-196: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

packages/web/src/ee/features/codeNav/components/symbolHoverPopup/useHoveredOverSymbolInfo.ts (4)

33-34: Consider making timeout values configurable.

The hardcoded timeout values work well but could benefit from being configurable, especially for accessibility or user preference customization.

Consider extracting to a configuration object:

const HOVER_CONFIG = {
    MOUSE_OVER_TIMEOUT_MS: 500,
    MOUSE_OUT_TIMEOUT_MS: 100,
} as const;

51-51: Apply optional chaining suggestion from static analysis.

The static analysis tool correctly identified that this can be simplified using optional chaining.

- return (symbolElement && symbolElement.textContent) ?? undefined;
+ return symbolElement?.textContent ?? undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 51-51: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


54-80: Optimize query configuration for better performance.

The query configuration is well-structured, but consider adding error handling and optimizing the select function.

 const { data: symbolDefinitions, isLoading: isSymbolDefinitionsLoading } = useQuery({
     queryKey: ["definitions", symbolName, repoName, revisionName, language, domain],
     queryFn: () => unwrapServiceError(
         findSearchBasedSymbolDefinitions({
             symbolName: symbolName!,
             repoName,
             language,
             revisionName,
         }, domain)
     ),
-    select: ((data) => {
+    select: useCallback((data) => {
         return data.files.flatMap((file) => {
             return file.matches.map((match) => {
                 return {
                     lineContent: match.lineContent,
                     language: file.language,
                     fileName: file.fileName,
                     repoName: file.repository,
                     range: match.range,
                 }
             })
         })
-
-    }),
+    }, []),
     enabled: !!symbolName,
     staleTime: Infinity,
+    retry: 1,
 })

98-109: Improve event handling robustness.

The mouse event handling could be more robust by checking for null targets and handling edge cases.

 const handleMouseOver = (event: MouseEvent) => {
+    if (!event.target) return;
+    
     const target = (event.target as HTMLElement).closest(`[${SYMBOL_HOVER_TARGET_DATA_ATTRIBUTE}="true"]`) as HTMLElement;
     if (!target) {
         return;
     }
     clearTimers();
     setSymbolElement(target);

     mouseOverTimerRef.current = setTimeout(() => {
         setIsVisible(true);
     }, SYMBOL_HOVER_POPUP_MOUSE_OVER_TIMEOUT_MS);
 };
packages/web/src/ee/features/codeNav/components/exploreMenu/index.tsx (2)

84-90: Enhance error messaging for better user experience.

The error message could be more descriptive to help users understand what went wrong.

 if (isError) {
     return (
         <div className="flex flex-row items-center justify-center h-full">
-            <p>Error loading {activeExploreMenuTab}</p>
+            <p className="text-sm text-muted-foreground">Failed to load {activeExploreMenuTab} for symbol "{selectedSymbolInfo.symbolName}"</p>
         </div>
     )
 }

105-125: Remove or fix the disabled tooltip.

The tooltip is disabled but still has content defined. This adds unnecessary code and confusion.

Either enable the tooltip by removing the disabled attribute:

 <TooltipTrigger
-    disabled={true}
     className="mr-auto"
 >

Or remove the tooltip entirely if it's not needed:

-<Tooltip
-    delayDuration={100}
->
-    <TooltipTrigger
-        disabled={true}
-        className="mr-auto"
-    >
-        <Badge
-            variant="outline"
-            className="w-fit h-fit flex-shrink-0 select-none"
-        >
-            Search Based
-        </Badge>
-    </TooltipTrigger>
-    <TooltipContent
-        side="top"
-        align="start"
-    >
-        Symbol references and definitions found using a best-guess search heuristic.
-    </TooltipContent>
-</Tooltip>
+<Badge
+    variant="outline"
+    className="w-fit h-fit flex-shrink-0 select-none mr-auto"
+>
+    Search Based
+</Badge>
packages/web/src/app/[domain]/search/components/codePreviewPanel/index.tsx (1)

60-64: Enhance error message for better user feedback.

The error message could be more descriptive to help users understand the issue.

 if (isError) {
     return (
-        <p>Failed to load file source</p>
+        <div className="flex flex-col items-center justify-center h-full text-muted-foreground">
+            <p className="text-sm">Failed to load file source</p>
+            <p className="text-xs mt-1">Please try again or check if the file exists</p>
+        </div>
     )
 }
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/index.tsx (2)

83-85: Address the TODO: Implement modifier key behavior for navigation.

The comment indicates that the ctrl/cmd key behavior for navigation needs to be implemented. This is a common UX pattern where users hold a modifier key to enable click-to-navigate functionality.

Would you like me to implement the modifier key detection logic or open an issue to track this enhancement?


86-95: Consider adding element reference check in cleanup.

The event listener management is correct, but could be made more robust by storing a reference to the element.

 useEffect(() => {
     if (!symbolInfo || !symbolInfo.symbolDefinitions) {
         return;
     }
 
+    const element = symbolInfo.element;
-    symbolInfo.element.addEventListener("click", onGotoDefinition);
+    element.addEventListener("click", onGotoDefinition);
     return () => {
-        symbolInfo.element.removeEventListener("click", onGotoDefinition);
+        element.removeEventListener("click", onGotoDefinition);
     }
 }, [symbolInfo, onGotoDefinition]);
packages/web/src/features/codeNav/actions.ts (2)

33-33: Consider the limitations of word boundary regex for symbol matching.

The \b word boundary may not work correctly for symbols containing special characters (e.g., operators like ++, ->, or symbols starting/ending with underscores). This could lead to missed matches or incorrect results depending on the programming language.

Consider using language-specific symbol matching patterns or a more flexible regex approach:

-const query = `\\b${symbolName}\\b repo:^${escapeStringRegexp(repoName)}$ rev:${revisionName} lang:${language}`
+// For more accurate symbol matching, consider escaping the symbol and using lookaround assertions
+const escapedSymbol = escapeStringRegexp(symbolName);
+const query = `(?<![\\w_])${escapedSymbol}(?![\\w_]) repo:^${escapeStringRegexp(repoName)}$ rev:${revisionName} lang:${language}`

Alternatively, consider implementing language-specific patterns based on the language parameter.


85-109: Remove unnecessary async from the transform function.

The transform function is marked as async but doesn't contain any await statements, making it unnecessarily return a Promise.

-const parser = searchResponseSchema.transform(async ({ files }) => ({
+const parser = searchResponseSchema.transform(({ files }) => ({
packages/web/src/app/[domain]/components/lightweightCodeHighlighter.tsx (2)

63-69: Address the TODO: Handle multi-line highlight ranges.

The current implementation only checks if a range starts or ends on a line, but doesn't handle ranges that span across multiple lines. This could lead to incorrect highlighting in the middle lines of a multi-line range.

Would you like me to implement the logic to handle multi-line ranges correctly?


157-172: Consider simplifying the nested async logic.

The nested async IIFE makes the code harder to read. Consider extracting it to a separate function or simplifying the flow.

Here's a cleaner approach:

-        const parser = await (async () => {
-            const found = LanguageDescription.matchLanguageName(
-                builtinLanguages,
-                languageName,
-                true
-            );
-
-            if (!found) {
-                return null;
-            }
-
-            if (!found.support) { 
-                await found.load();
-            }
-            return found.support ? found.support.language.parser : null;
-        })();
+        const found = LanguageDescription.matchLanguageName(
+            builtinLanguages,
+            languageName,
+            true
+        );
+
+        if (!found) {
+            return plainTextLanguage.parser;
+        }
+
+        if (!found.support) { 
+            await found.load();
+        }
+        
+        const parser = found.support?.language.parser;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50f2f36 and 0ca6ba6.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (61)
  • .cursor/rules/style.mdc (1 hunks)
  • packages/web/.eslintrc.json (1 hunks)
  • packages/web/package.json (3 hunks)
  • packages/web/src/app/[domain]/browse/README.md (1 hunks)
  • packages/web/src/app/[domain]/browse/[...path]/codePreview.tsx (0 hunks)
  • packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx (1 hunks)
  • packages/web/src/app/[domain]/browse/[...path]/components/rangeHighlightingExtension.ts (1 hunks)
  • packages/web/src/app/[domain]/browse/[...path]/page.tsx (4 hunks)
  • packages/web/src/app/[domain]/browse/browseStateProvider.tsx (1 hunks)
  • packages/web/src/app/[domain]/browse/components/bottomPanel.tsx (1 hunks)
  • packages/web/src/app/[domain]/browse/hooks/useBrowseNavigation.ts (1 hunks)
  • packages/web/src/app/[domain]/browse/hooks/useBrowseState.ts (1 hunks)
  • packages/web/src/app/[domain]/browse/layout.tsx (1 hunks)
  • packages/web/src/app/[domain]/components/connectionCreationForms/secretCombobox.tsx (1 hunks)
  • packages/web/src/app/[domain]/components/editorContextMenu.tsx (2 hunks)
  • packages/web/src/app/[domain]/components/fileHeader.tsx (3 hunks)
  • packages/web/src/app/[domain]/components/keyboardShortcutHint.tsx (0 hunks)
  • packages/web/src/app/[domain]/components/lightweightCodeHighlighter.tsx (1 hunks)
  • packages/web/src/app/[domain]/components/searchBar/searchBar.tsx (3 hunks)
  • packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx (1 hunks)
  • packages/web/src/app/[domain]/components/searchBar/useSuggestionsData.ts (4 hunks)
  • packages/web/src/app/[domain]/search/components/codePreviewPanel/codePreview.tsx (7 hunks)
  • packages/web/src/app/[domain]/search/components/codePreviewPanel/index.tsx (1 hunks)
  • packages/web/src/app/[domain]/search/components/filterPanel/entry.tsx (3 hunks)
  • packages/web/src/app/[domain]/search/components/filterPanel/index.tsx (5 hunks)
  • packages/web/src/app/[domain]/search/components/filterPanel/useFilterMatches.ts (1 hunks)
  • packages/web/src/app/[domain]/search/components/filterPanel/useGetSelectedFromQuery.ts (1 hunks)
  • packages/web/src/app/[domain]/search/components/searchResultsPanel/codePreview.tsx (0 hunks)
  • packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatch.tsx (3 hunks)
  • packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatchContainer.tsx (6 hunks)
  • packages/web/src/app/[domain]/search/components/searchResultsPanel/index.tsx (4 hunks)
  • packages/web/src/app/[domain]/search/components/searchResultsPanel/lightweightCodeMirror.tsx (0 hunks)
  • packages/web/src/app/[domain]/search/page.tsx (10 hunks)
  • packages/web/src/app/api/(server)/references/route.ts (1 hunks)
  • packages/web/src/app/components/keyboardShortcutHint.tsx (1 hunks)
  • packages/web/src/app/globals.css (4 hunks)
  • packages/web/src/components/ui/animatedResizableHandle.tsx (1 hunks)
  • packages/web/src/components/ui/loading-button.tsx (1 hunks)
  • packages/web/src/ee/features/codeNav/components/exploreMenu/index.tsx (1 hunks)
  • packages/web/src/ee/features/codeNav/components/exploreMenu/referenceList.tsx (1 hunks)
  • packages/web/src/ee/features/codeNav/components/symbolHoverPopup/index.tsx (1 hunks)
  • packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolDefinitionPreview.tsx (1 hunks)
  • packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolHoverTargetsExtension.ts (1 hunks)
  • packages/web/src/ee/features/codeNav/components/symbolHoverPopup/useHoveredOverSymbolInfo.ts (1 hunks)
  • packages/web/src/features/codeNav/actions.ts (1 hunks)
  • packages/web/src/features/codeNav/schemas.ts (1 hunks)
  • packages/web/src/features/codeNav/types.ts (1 hunks)
  • packages/web/src/features/entitlements/constants.ts (2 hunks)
  • packages/web/src/features/search/fileSourceApi.ts (2 hunks)
  • packages/web/src/features/search/schemas.ts (2 hunks)
  • packages/web/src/features/search/searchApi.ts (4 hunks)
  • packages/web/src/features/search/types.ts (1 hunks)
  • packages/web/src/hooks/useCodeMirrorHighlighter.ts (1 hunks)
  • packages/web/src/hooks/useCodeMirrorLanguageExtension.ts (1 hunks)
  • packages/web/src/hooks/useCodeMirrorTheme.ts (1 hunks)
  • packages/web/src/hooks/useTailwind.ts (0 hunks)
  • packages/web/src/lib/errorCodes.ts (1 hunks)
  • packages/web/src/lib/extensions/searchResultHighlightExtension.ts (2 hunks)
  • packages/web/src/lib/utils.ts (6 hunks)
  • packages/web/src/tailwind.ts (1 hunks)
  • packages/web/tailwind.config.ts (1 hunks)
💤 Files with no reviewable changes (5)
  • packages/web/src/hooks/useTailwind.ts
  • packages/web/src/app/[domain]/components/keyboardShortcutHint.tsx
  • packages/web/src/app/[domain]/search/components/searchResultsPanel/codePreview.tsx
  • packages/web/src/app/[domain]/browse/[...path]/codePreview.tsx
  • packages/web/src/app/[domain]/search/components/searchResultsPanel/lightweightCodeMirror.tsx
🧰 Additional context used
🧬 Code Graph Analysis (20)
packages/web/src/app/[domain]/components/editorContextMenu.tsx (1)
packages/web/src/app/[domain]/browse/hooks/useBrowseNavigation.ts (1)
  • HIGHLIGHT_RANGE_QUERY_PARAM (14-14)
packages/web/src/features/codeNav/types.ts (1)
packages/web/src/features/codeNav/schemas.ts (1)
  • findRelatedSymbolsResponseSchema (4-20)
packages/web/src/components/ui/loading-button.tsx (1)
packages/web/src/components/ui/button.tsx (2)
  • ButtonProps (36-40)
  • Button (56-56)
packages/web/src/features/search/types.ts (1)
packages/web/src/features/search/schemas.ts (2)
  • repositoryInfoSchema (34-40)
  • rangeSchema (13-16)
packages/web/src/app/[domain]/components/searchBar/searchBar.tsx (2)
packages/web/src/components/ui/tooltip.tsx (3)
  • Tooltip (30-30)
  • TooltipTrigger (30-30)
  • TooltipContent (30-30)
packages/web/src/app/components/keyboardShortcutHint.tsx (1)
  • KeyboardShortcutHint (8-22)
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolHoverTargetsExtension.ts (1)
packages/web/src/lib/utils.ts (1)
  • measureSync (241-259)
packages/web/src/app/[domain]/components/fileHeader.tsx (1)
packages/web/src/app/[domain]/browse/hooks/useBrowseNavigation.ts (1)
  • useBrowseNavigation (25-59)
packages/web/src/ee/features/codeNav/components/exploreMenu/referenceList.tsx (7)
packages/web/src/features/codeNav/types.ts (1)
  • FindRelatedSymbolsResponse (4-4)
packages/web/src/features/search/types.ts (2)
  • RepositoryInfo (28-28)
  • SourceRange (29-29)
packages/web/src/app/[domain]/browse/hooks/useBrowseNavigation.ts (1)
  • useBrowseNavigation (25-59)
packages/web/src/components/ui/scroll-area.tsx (1)
  • ScrollArea (48-48)
packages/web/src/app/[domain]/components/fileHeader.tsx (1)
  • FileHeader (26-103)
packages/web/src/lib/utils.ts (1)
  • base64Decode (202-205)
packages/web/src/app/[domain]/components/lightweightCodeHighlighter.tsx (1)
  • LightweightCodeHighlighter (38-149)
packages/web/src/app/[domain]/browse/[...path]/components/rangeHighlightingExtension.ts (1)
packages/web/src/app/[domain]/browse/hooks/useBrowseNavigation.ts (1)
  • BrowseHighlightRange (6-12)
packages/web/src/lib/extensions/searchResultHighlightExtension.ts (1)
packages/web/src/features/search/types.ts (1)
  • SourceRange (29-29)
packages/web/src/ee/features/codeNav/components/exploreMenu/index.tsx (7)
packages/web/src/app/[domain]/browse/hooks/useBrowseState.ts (1)
  • useBrowseState (6-12)
packages/web/src/lib/utils.ts (1)
  • unwrapServiceError (289-296)
packages/web/src/features/codeNav/actions.ts (2)
  • findSearchBasedSymbolReferences (15-47)
  • findSearchBasedSymbolDefinitions (50-82)
packages/web/src/components/ui/resizable.tsx (2)
  • ResizablePanelGroup (48-48)
  • ResizablePanel (48-48)
packages/web/src/components/ui/tooltip.tsx (3)
  • Tooltip (30-30)
  • TooltipTrigger (30-30)
  • TooltipContent (30-30)
packages/web/src/components/ui/animatedResizableHandle.tsx (1)
  • AnimatedResizableHandle (5-11)
packages/web/src/ee/features/codeNav/components/exploreMenu/referenceList.tsx (1)
  • ReferenceList (17-75)
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/index.tsx (5)
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/useHoveredOverSymbolInfo.ts (2)
  • SymbolDefinition (18-24)
  • useHoveredOverSymbolInfo (36-142)
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolDefinitionPreview.tsx (1)
  • SymbolDefinitionPreview (18-62)
packages/web/src/components/ui/separator.tsx (1)
  • Separator (31-31)
packages/web/src/components/ui/loading-button.tsx (1)
  • LoadingButton (30-30)
packages/web/src/components/ui/button.tsx (1)
  • Button (56-56)
packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatchContainer.tsx (2)
packages/web/src/features/search/types.ts (1)
  • SearchResultFile (18-18)
packages/web/src/components/ui/button.tsx (1)
  • Button (56-56)
packages/web/src/app/[domain]/browse/browseStateProvider.tsx (2)
packages/web/src/app/[domain]/browse/components/bottomPanel.tsx (1)
  • BOTTOM_PANEL_MIN_SIZE (16-16)
packages/web/src/hooks/useNonEmptyQueryParam.ts (1)
  • useNonEmptyQueryParam (18-25)
packages/web/src/app/[domain]/browse/hooks/useBrowseNavigation.ts (1)
packages/web/src/app/[domain]/browse/browseStateProvider.tsx (2)
  • BrowseState (7-17)
  • SET_BROWSE_STATE_QUERY_PARAM (26-26)
packages/web/src/features/search/searchApi.ts (1)
packages/web/src/features/search/types.ts (1)
  • SourceRange (29-29)
packages/web/src/app/[domain]/search/components/filterPanel/useFilterMatches.ts (1)
packages/web/src/app/[domain]/search/components/filterPanel/useGetSelectedFromQuery.ts (1)
  • useGetSelectedFromQuery (7-17)
packages/web/src/app/[domain]/components/lightweightCodeHighlighter.tsx (3)
packages/web/src/features/search/types.ts (1)
  • SourceRange (29-29)
packages/web/src/hooks/useCodeMirrorHighlighter.ts (1)
  • useCodeMirrorHighlighter (6-86)
packages/web/src/lib/utils.ts (1)
  • measure (261-279)
packages/web/src/app/[domain]/search/components/searchResultsPanel/index.tsx (1)
packages/web/src/features/search/types.ts (1)
  • SearchResultFile (18-18)
packages/web/src/app/[domain]/search/page.tsx (10)
packages/web/src/hooks/useNonEmptyQueryParam.ts (1)
  • useNonEmptyQueryParam (18-25)
packages/web/src/lib/utils.ts (2)
  • unwrapServiceError (289-296)
  • createPathWithQueryParams (25-36)
packages/web/src/app/api/(client)/client.ts (1)
  • search (20-35)
packages/web/src/features/search/types.ts (1)
  • SearchResultFile (18-18)
packages/web/src/app/[domain]/search/components/filterPanel/useFilterMatches.ts (1)
  • useFilteredMatches (11-36)
packages/web/src/components/ui/tooltip.tsx (3)
  • Tooltip (30-30)
  • TooltipTrigger (30-30)
  • TooltipContent (30-30)
packages/web/src/components/ui/button.tsx (1)
  • Button (56-56)
packages/web/src/app/components/keyboardShortcutHint.tsx (1)
  • KeyboardShortcutHint (8-22)
packages/web/src/components/ui/animatedResizableHandle.tsx (1)
  • AnimatedResizableHandle (5-11)
packages/web/src/app/[domain]/search/components/codePreviewPanel/index.tsx (1)
  • CodePreviewPanel (18-73)
🪛 Biome (1.9.4)
packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx

[error] 196-196: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

packages/web/src/ee/features/codeNav/components/symbolHoverPopup/useHoveredOverSymbolInfo.ts

[error] 51-51: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (87)
.cursor/rules/style.mdc (1)

6-7: Style rules are clear.
The bullets correctly mandate 4-space indentation and camelCase filenames (with an exception for existing formats), which aligns with the project’s consistency goals.

packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx (1)

18-18: Use of absolute import aligns with project conventions
The import path for KeyboardShortcutHint now uses the alias @/app/..., improving consistency and readability across the codebase.

packages/web/.eslintrc.json (1)

10-11: Ensure ESLint plugin is correctly applied
Extending plugin:@tanstack/query/recommended aligns linting with new React Query usage. Confirm that @tanstack/eslint-plugin-query is installed and that plugin rules are activated.

packages/web/src/app/[domain]/components/editorContextMenu.tsx (2)

12-12: Appropriate use of named constant for query parameter
Importing HIGHLIGHT_RANGE_QUERY_PARAM centralizes the query key and prevents hardcoded strings. This improves maintainability and consistency across navigation logic.


110-113: Use constant instead of hardcoded string in URL builder
Replacing the literal 'highlightRange' with HIGHLIGHT_RANGE_QUERY_PARAM in createPathWithQueryParams reduces risk of typos and keeps URL param logic in sync with useBrowseNavigation.

packages/web/package.json (2)

149-149: Add ESLint plugin for React Query
Adding @tanstack/eslint-plugin-query in devDependencies supports the newly extended query linting rules.


37-37:

✅ Verification successful

Verify usage of @codemirror/language-data
A new dependency has been added—ensure it’s actually imported and utilized (for example, in language data extensions) to avoid unnecessary bundle size increase.


🏁 Script executed:

#!/bin/bash
# Verify that @codemirror/language-data is imported in the codebase
rg "@codemirror/language-data"

Length of output: 413


🏁 Script executed:

#!/bin/bash
# Locate lightweightCodeHighlighter.tsx and verify usage of the imported `builtinLanguages`
fd lightweightCodeHighlighter.tsx -t f -x rg -n "builtinLanguages" -A2 {}

Length of output: 390


Dependency usage confirmed for @codemirror/language-data
The languages export is imported as builtinLanguages in
packages/web/src/app/[domain]/components/lightweightCodeHighlighter.tsx
and is actively passed (lines 159–161) into the useCodeMirrorHighlighter hook. No unused dependency.

packages/web/src/hooks/useCodeMirrorLanguageExtension.ts (1)

7-7: LGTM! Function rename improves semantic clarity.

The rename from useSyntaxHighlightingExtension to useCodeMirrorLanguageExtension better reflects the function's broader purpose of providing language extension support, not just syntax highlighting.

packages/web/src/features/search/types.ts (1)

28-29: LGTM! Type additions follow established patterns.

The new RepositoryInfo and SourceRange types are properly inferred from their corresponding zod schemas. The SourceRange type provides better naming consistency across the codebase compared to the previous SearchResultRange.

packages/web/src/features/codeNav/types.ts (1)

1-4: LGTM! Clean type definition following established patterns.

The file follows the standard pattern of inferring types from zod schemas. The FindRelatedSymbolsResponse type name is descriptive and aligns with the code navigation feature's purpose.

packages/web/src/app/[domain]/browse/README.md (1)

1-12: Excellent documentation for file browser URL structure.

The README provides clear documentation of the URL path template with a practical example. This will help developers understand the routing structure for the file browser feature.

packages/web/src/app/[domain]/components/connectionCreationForms/secretCombobox.tsx (1)

43-43: LGTM! Improved caching strategy with domain scoping.

Adding the domain to the query key ensures secrets are cached separately per domain, preventing cross-domain data issues and enabling proper cache invalidation per domain context.

packages/web/src/app/[domain]/browse/hooks/useBrowseState.ts (1)

1-12: LGTM! Clean React hook implementation.

This hook follows React best practices perfectly:

  • Proper context usage with error boundary checking
  • Clear error message for developer guidance
  • Clean, minimal implementation that serves its purpose well

The pattern ensures components can safely access the browse state context while providing helpful debugging information if used incorrectly.

packages/web/src/features/search/fileSourceApi.ts (2)

1-1: Good addition of server directive.

The 'use server' directive correctly indicates this code runs in a server-side context, which is appropriate for this API function.


46-46: LGTM! webUrl addition enhances navigation capabilities.

Adding the webUrl property to the response enables direct linking to external code hosts, which aligns perfectly with the code navigation features being introduced. The property is sourced from the existing file metadata, maintaining consistency with the search API.

packages/web/src/features/search/schemas.ts (2)

66-68: Good addition of stats object with match count.

Adding the stats object with matchCount provides valuable aggregate information about search results. This enhances the search functionality by giving users insights into the total number of matches found.


117-117: LGTM! webUrl property supports external navigation.

Adding the optional webUrl property to the file source response schema enables direct linking to external code hosts, which is essential for the code navigation features. The optional nature maintains backward compatibility.

packages/web/src/tailwind.ts (1)

1-5: Excellent refactoring to centralize Tailwind config resolution.

This approach is much better than the previous hook-based solution:

  • Eliminates redundant config resolution across components
  • Provides a single source of truth for the resolved Tailwind configuration
  • Improves performance by resolving once rather than memoizing in each component
  • Simplifies imports for components that need Tailwind config access

Clean and effective architectural improvement!

packages/web/src/app/api/(server)/references/route.ts (1)

1-37: Well-structured API route with proper error handling.

The implementation correctly validates required headers and query parameters, uses appropriate error codes, and follows consistent error handling patterns.

Minor suggestions for enhanced robustness:

  1. Consider adding input sanitization for the query parameters
  2. Add rate limiting if this endpoint will be heavily used
  3. Consider adding request logging for debugging purposes

The current implementation is solid and follows good API design practices.

packages/web/src/app/[domain]/search/components/filterPanel/useGetSelectedFromQuery.ts (1)

6-17: Clean and well-structured custom hook implementation.

The hook properly uses useCallback for memoization and handles missing query parameters gracefully by returning an empty Set.

Consider adding JSDoc documentation to improve developer experience:

+/**
+ * Custom hook to parse comma-separated query parameter values into Sets
+ * @returns Object containing getSelectedFromQuery function
+ */
 export const useGetSelectedFromQuery = () => {
     const searchParams = useSearchParams();
+    /**
+     * Parses a query parameter into a Set of strings
+     * @param param - The query parameter name to parse
+     * @returns Set of comma-separated values or empty Set if parameter doesn't exist
+     */
     const getSelectedFromQuery = useCallback((param: string): Set<string> => {
packages/web/src/components/ui/animatedResizableHandle.tsx (1)

5-11: Excellent implementation of animated resize handle.

The component effectively uses data attribute selectors for state-based styling and provides smooth transitions. The use of data-[resize-handle-state=drag] and data-[resize-handle-state=hover] is a clean approach for handling different interaction states.

The implementation follows good practices:

  • Proper separation of concerns
  • Consistent theming with accent colors
  • Smooth transition effects with appropriate delay
  • Clean and maintainable code structure
packages/web/src/app/[domain]/search/components/filterPanel/entry.tsx (1)

27-27: Well implemented disabled state functionality.

The isDisabled property is properly destructured and correctly applied to the component styling with the opacity-50 class. This provides clear visual feedback for disabled entries.

Also applies to: 42-42

packages/web/src/components/ui/loading-button.tsx (2)

9-26: Excellent implementation of LoadingButton component.

This component follows React best practices:

  • Properly extends ButtonProps with additional loading prop
  • Correctly forwards refs using React.forwardRef
  • Appropriately merges the disabled state (loading || props.disabled)
  • Clean conditional rendering of the loading spinner
  • Proper TypeScript typing throughout

The implementation is clean, reusable, and maintains accessibility by disabling the button during loading state.


28-28: Good practice setting displayName for debugging.

Setting the displayName helps with React DevTools debugging and is a good practice for forwardRef components.

packages/web/src/app/[domain]/components/searchBar/searchBar.tsx (4)

46-46: Improved import strategy for Tailwind configuration.

The change from using the useTailwind hook to directly importing the resolved Tailwind configuration is cleaner and more efficient. This aligns with the broader refactoring mentioned in the AI summary.


163-163: Correctly updated useMemo dependency array.

Good catch removing the tailwind dependency from the useMemo dependency array since tailwind is now a static import rather than a hook value that could change.


269-280: Enhanced user experience with tooltip for keyboard shortcut.

The addition of a Tooltip wrapper around the KeyboardShortcutHint with a 100ms delay provides helpful context for users about the "/" keyboard shortcut functionality. The tooltip positioning and content are appropriate.


45-45: Import path change from relative to absolute.

The import path for KeyboardShortcutHint changed from a relative import to an absolute import. This is consistent with the broader component reorganization mentioned in the AI summary.

packages/web/src/app/[domain]/components/searchBar/useSuggestionsData.ts (1)

40-40: LGTM! Good practice for multi-tenant caching.

The addition of domain to all query keys ensures proper data isolation and cache scoping per domain context. This is excellent for preventing cross-domain data leakage and maintaining correct caching behavior in a multi-tenant application.

Also applies to: 53-53, 73-73, 103-103

packages/web/src/lib/extensions/searchResultHighlightExtension.ts (1)

3-3: LGTM! Consistent with broader type and styling refactoring.

The changes correctly update:

  1. Type imports from SearchResultRange to SourceRange - aligns with the type definition in packages/web/src/features/search/types.ts
  2. CSS class names from cm-searchMatch to searchMatch - removes CodeMirror-specific prefixes for more generic styling

These updates maintain consistency with the broader codebase refactoring while preserving the extension's functionality.

Also applies to: 7-7, 10-10, 49-49, 52-52, 55-55

packages/web/src/features/entitlements/constants.ts (1)

20-20: LGTM! Proper entitlement setup for code navigation feature.

The addition of the "code-nav" entitlement is correctly implemented:

  • Added to the main entitlements array for type safety
  • Appropriately granted to enterprise self-hosted plans only
  • Follows existing patterns and maintains consistency with the entitlement system

This properly gates the new code navigation features behind enterprise plans.

Also applies to: 31-32

packages/web/src/app/[domain]/components/fileHeader.tsx (3)

1-1: LGTM! Proper setup for client-side navigation.

The addition of 'use client' directive and useBrowseNavigation hook correctly enables client-side navigation functionality for the file header component.

Also applies to: 8-8, 40-40


65-69: Minor styling improvements applied.

The spacing adjustments using inline styles and className-based margins improve the visual layout of the branch information display.


77-87:

❌ Incorrect review comment

Verify revision name usage in navigation.

The clickable file name implementation looks good, but using branchDisplayName as revisionName might not always be correct. Branch display names could be formatted for UI purposes and may not match the actual revision identifiers expected by the navigation system.

Consider verifying that branchDisplayName always contains the correct revision identifier, or if a separate revision prop should be passed to the component.


🏁 Script executed:

#!/bin/bash
# Description: Check how branchDisplayName is used in other navigation contexts
# Expected: Find other usages to verify if branchDisplayName is appropriate for navigation

rg -A 5 -B 5 "branchDisplayName.*revision|revision.*branchDisplayName"

Length of output: 3790


🏁 Script executed:

#!/bin/bash
# Find the exact path of fileHeader.tsx
fd fileHeader.tsx -t f

# Display the top of the file to inspect prop definitions
sed -n '1,200p' packages/web/src/app/*/components/fileHeader.tsx

Length of output: 3565


🏁 Script executed:

#!/bin/bash
# Locate the useBrowseNavigation hook
fd useBrowseNavigation -t f

# Inspect its implementation to see what revisionName it provides
sed -n '1,200p' packages/web/src/app/[domain]/browse/hooks/useBrowseNavigation.ts

Length of output: 1980


No action needed: branchDisplayName is the actual revision identifier
The branchDisplayName prop is sourced directly from the actual revisionName (e.g. in your browse page you pass branchDisplayName={revisionName}), and branchDisplayTitle exists for any UI‐specific formatting or tooltip. This means using branchDisplayName for navigation is correct, and no additional prop is required.

Likely an incorrect or invalid review comment.

packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolHoverTargetsExtension.ts (1)

50-78: Excellent use of performance measurement and proper StateField patterns.

The implementation correctly uses ensureSyntaxTree to parse the entire document and follows CodeMirror StateField best practices. The performance measurement with measureSync is a good practice for monitoring expensive operations.

packages/web/src/hooks/useCodeMirrorHighlighter.ts (1)

6-86: Well-structured syntax highlighting configuration.

The hook provides comprehensive coverage of syntax highlighting tags with a consistent CSS class naming convention. The use of useMemo ensures the highlighter is created only once, which is good for performance.

packages/web/src/features/codeNav/schemas.ts (2)

4-20: Clean and well-structured schema definition.

The schema properly reuses existing schemas through imports and provides a clear structure for the API response. The use of z.array() and nested objects follows Zod best practices.


12-12:

✅ Verification successful

Consider making webUrl required if it's always expected.

The webUrl field is marked as optional with .optional(). Verify if this field should always be present or if there are legitimate cases where it might be missing.


🏁 Script executed:

#!/bin/bash
# Search for usage of webUrl field to understand if it's always expected
rg -A 3 -B 3 "webUrl" --type ts

Length of output: 30721


🏁 Script executed:

#!/bin/bash
echo "----- packages/web/src/features/codeNav/schemas.ts (first 50 lines) -----"
sed -n '1,50p' packages/web/src/features/codeNav/schemas.ts
echo
echo "----- packages/web/src/features/codeNav/actions.ts (first 50 lines) -----"
sed -n '1,50p' packages/web/src/features/codeNav/actions.ts

Length of output: 2693


🏁 Script executed:

#!/bin/bash
echo "----- packages/web/src/features/codeNav/actions.ts (lines 50-150) -----"
sed -n '50,150p' packages/web/src/features/codeNav/actions.ts

Length of output: 2249


No change needed: webUrl can be legitimately absent
The search API returns webUrl only when a repository URL template is available (otherwise it’s undefined), and downstream components guard on its presence before rendering links. Keeping webUrl optional in findRelatedSymbolsResponseSchema aligns with those cases.

packages/web/src/app/[domain]/browse/[...path]/components/rangeHighlightingExtension.ts (1)

15-39: Solid implementation of range highlighting extension.

The extension correctly handles both column-specific and line-only highlighting scenarios. The column position calculations properly convert from 1-indexed to 0-indexed positions, and the StateField implementation follows CodeMirror patterns.

packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatch.tsx (1)

62-70: LGTM! Clean transition to LightweightCodeHighlighter.

The replacement of CodePreview with LightweightCodeHighlighter is well-implemented with appropriate props for syntax highlighting, line numbers, and match highlighting.

packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolDefinitionPreview.tsx (1)

18-62: LGTM! Well-structured component with proper optimization.

The component follows React best practices with:

  • Proper memoization of computed values (highlightRanges and decodedLineContent)
  • Clean integration with LightweightCodeHighlighter
  • Informative tooltip explaining the "Search Based" nature of the definition
  • Appropriate prop destructuring and usage
packages/web/src/ee/features/codeNav/components/exploreMenu/referenceList.tsx (4)

21-26: LGTM! Efficient repository lookup optimization.

The memoized repoInfoMap provides O(1) repository lookups instead of O(n) searches, which will improve performance when rendering multiple files with references.


50-51: LGTM! Good UX with sorted matches.

Sorting matches by line number ensures a logical reading order for users navigating through references in a file.


58-66: LGTM! Clean navigation integration.

The navigation logic properly uses the useBrowseNavigation hook with all required parameters including the highlight range for precise positioning.


91-95: LGTM! Proper memoization in nested component.

Both decodedLineContent and highlightRanges are correctly memoized to prevent unnecessary re-computations and re-renders.

packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatchContainer.tsx (3)

106-114: LGTM! Clean Preview button implementation.

The Preview button provides clear user interaction for file preview functionality, with appropriate styling and click handling.


122-125: LGTM! Consistent with FileMatch refactoring.

Removing the onOpen prop aligns with the FileMatch component's new internal navigation handling using the useBrowseNavigation hook.


136-136: LGTM! Improved accessibility with focus styles.

The addition of focus ring styles enhances keyboard navigation accessibility for the "Show more matches" functionality.

Also applies to: 146-146

packages/web/src/app/[domain]/browse/components/bottomPanel.tsx (1)

19-114: Well-structured component implementation!

The component demonstrates good React practices with proper use of refs, effects, and state management. The conditional rendering logic is clear and the UI states are well-handled.

packages/web/tailwind.config.ts (2)

79-108: Excellent editor theme configuration!

The comprehensive syntax tag color definitions provide great flexibility for editor theming. The consistent naming convention and CSS variable usage make it easy to customize themes.


4-150: Great improvements to the Tailwind configuration!

The migration from HSL function calls to direct CSS variable references simplifies the configuration and improves maintainability. The addition of editor and sidebar themes provides excellent customization capabilities.

packages/web/src/app/[domain]/search/components/filterPanel/useFilterMatches.ts (1)

26-30:

✅ Verification successful

Verify that SearchResultFile type guarantees repository and language fields.

The filtering logic directly accesses match.repository and match.language without null checks. Please ensure the type definition guarantees these fields are always present.


🏁 Script executed:

#!/bin/bash
# Description: Check SearchResultFile type definition to ensure repository and language fields are required

# Search for SearchResultFile type definition
ast-grep --pattern 'type SearchResultFile = {
  $$$
}'

# Also check with interface syntax
ast-grep --pattern 'interface SearchResultFile {
  $$$
}'

# Use ripgrep as fallback to find the type definition
rg -A 10 "type SearchResultFile|interface SearchResultFile" --type ts

Length of output: 2054


🏁 Script executed:

#!/bin/bash
# Inspect SearchResponse definition and its Zod schema to verify required fields
rg -n "type SearchResponse" -A 30 --type ts packages/web/src/features/search/types.ts
rg -n "interface SearchResponse" -A 30 --type ts packages/web/src/features/search/types.ts
rg -n "searchResponseSchema" -A 30 --type ts packages/web/src/features/search/types.ts

Length of output: 2104


🏁 Script executed:

#!/bin/bash
# Display the definition of searchResponseSchema to verify required fields
rg -n "export const searchResponseSchema" -A 200 --type ts packages/web/src/features/search/schemas.ts

Length of output: 2754


Filtering logic is safe—no null checks needed
The searchResponseSchema (packages/web/src/features/search/schemas.ts:69–79) defines both repository and language as required z.string() fields on each file entry, so match.repository and match.language are guaranteed to be present at runtime. You can leave the filter calls as-is.

packages/web/src/app/[domain]/browse/browseStateProvider.tsx (1)

1-24: LGTM! Well-structured state interface and imports.

The BrowseState interface is well-defined with clear types, and the default state configuration is appropriate. The import structure follows good practices.

packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx (1)

150-178:

❓ Verification inconclusive

Verify navigation behavior for edge cases.

The onGotoDefinition function handles single vs multiple definitions well, but consider edge cases where symbolDefinitions might contain invalid data.


🏁 Script executed:

#!/bin/bash
# Description: Check if SymbolDefinition type validation is handled in the backend API
# Expected: Backend should validate symbol definition structure

ast-grep --pattern 'interface SymbolDefinition {
  $$$
}'

# Also check if there are any validation utilities for symbol definitions
rg -A 5 "SymbolDefinition.*validate|validate.*SymbolDefinition"

Length of output: 125


Verify SymbolDefinition edge cases in onGotoDefinition

Ensure that onGotoDefinition can safely handle unexpected or malformed SymbolDefinition entries before navigating:

  • Location: packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx
    Function: onGotoDefinition
  • Action items:
    1. Confirm that the backend always returns valid fileName, repoName, and range for each SymbolDefinition.
    2. Add runtime guards in the single-definition branch, for example:
       if (symbolDefinitions.length === 1) {
           const symbolDefinition = symbolDefinitions[0];
      -    const { fileName, repoName } = symbolDefinition;
      +    const { fileName, repoName, range } = symbolDefinition;
      +    if (!fileName || !repoName || !range) {
      +      return;
      +    }
           navigateToPath({
               repoName,
               revisionName,
               path: fileName,
               pathType: 'blob',
               highlightRange: range,
           })
       }
    3. Optionally, add logging or error reporting for any skipped definitions to aid debugging.
packages/web/src/app/[domain]/browse/hooks/useBrowseNavigation.ts (1)

6-12: Well-designed union type for flexible highlight ranges.

The BrowseHighlightRange type elegantly handles both line-only and line-column highlight formats using discriminated unions. This provides good type safety while maintaining flexibility.

packages/web/src/ee/features/codeNav/components/exploreMenu/index.tsx (1)

172-206: Well-implemented Entry component.

The component properly handles edge cases with count display and uses appropriate memoization.

packages/web/src/app/[domain]/browse/[...path]/page.tsx (3)

53-66: Good error handling for repository not found.

The explicit handling of repository not found errors with a user-friendly UI is a great improvement over throwing exceptions.


77-81: Good default value for revision.

Defaulting to 'HEAD' when no revision is specified ensures consistent behavior.


98-103: Well-implemented external link feature.

The external link to the code host is properly implemented with:

  • Security attributes (noopener noreferrer)
  • Conditional rendering
  • Proper icon with alt text
  • Good UX with code host name display

Also applies to: 124-138

packages/web/src/app/[domain]/search/components/codePreviewPanel/index.tsx (2)

24-28: Good branch selection logic with clear documentation.

The memoized branch selection with a clear explanatory comment makes the code easy to understand.


53-58: Comprehensive loading state handling.

Checking both isLoading and isPending ensures all loading scenarios are covered.

packages/web/src/hooks/useCodeMirrorTheme.ts (2)

14-55: Excellent theme generation with Tailwind integration.

The dynamic theme generation using Tailwind tokens is well-implemented with:

  • Proper memoization
  • Clean destructuring of theme properties
  • Correct dependency array
  • Integration with syntax highlighting

59-133: Well-structured theme extension creator.

The createThemeExtension function is excellently implemented with:

  • Conditional application of styles to avoid unnecessary properties
  • Proper handling of all theme settings
  • Good reference to the source pattern
  • Clean code structure
packages/web/src/ee/features/codeNav/components/symbolHoverPopup/index.tsx (1)

40-73: LGTM! Well-implemented positioning logic.

The floating-ui integration is properly configured with appropriate middleware for offset, flipping, and shifting. The boundary constraint using the editor's DOM element ensures the popup stays within the editor viewport.

packages/web/src/lib/utils.ts (3)

137-137: LGTM! Improved naming consistency.

The change from "Generic Git Host" to "Git Host" is more concise and consistent with other code host names.


241-279: LGTM! Useful enhancement to timing utilities.

The addition of the optional outputLog parameter provides flexibility to suppress console output when needed, while maintaining backwards compatibility with the default value of true.


298-308: LGTM! Well-implemented parameter validation utility.

The requiredQueryParamGuard function provides a clean and consistent way to validate required query parameters in API routes, with proper error handling and clear error messages.

packages/web/src/app/[domain]/search/components/codePreviewPanel/codePreview.tsx (3)

111-164: LGTM! Well-designed navigation logic.

The navigation callbacks handle different scenarios appropriately:

  • Single definition navigates directly for better UX
  • Multiple definitions and references open the explore panel
  • Browse state is properly configured for each scenario

260-269: LGTM! Proper feature gating with entitlements.

The symbol hover popup is correctly gated behind the "code-nav" entitlement check, ensuring the feature is only available to authorized users.


35-36:

✅ Verification successful

Verify all component usages have been updated.

Making file and repoName required props is a breaking change. Ensure all usages of this component have been updated to provide these props.


🏁 Script executed:

#!/bin/bash
# Description: Find all usages of CodePreview component to verify they provide required props

# Search for CodePreview component usage
rg -A 5 '<CodePreview' --type tsx --type jsx

Length of output: 74


I’ll search without relying on file-type filters to locate all <CodePreview usages:


🏁 Script executed:

#!/bin/bash
# Find all usages of CodePreview in .tsx and .jsx files
rg --glob '*.tsx' --glob '*.jsx' -n '<CodePreview'

Length of output: 333


I’ll pull the surrounding lines for each usage to confirm both file and repoName props are provided:


🏁 Script executed:

#!/bin/bash
echo "Context in search/page.tsx:"
sed -n '330,360p' 'packages/web/src/app/[domain]/search/page.tsx'

echo -e "\nContext in codePreviewPanel/index.tsx:"
sed -n '60,80p' 'packages/web/src/app/[domain]/search/components/codePreviewPanel/index.tsx'

echo -e "\nContext in browse/page.tsx:"
sed -n '130,160p' 'packages/web/src/app/[domain]/browse/[...path]/page.tsx'

Length of output: 2320


All <CodePreview> usages updated

A search across the repo shows the only direct <CodePreview> invocation (in codePreviewPanel/index.tsx) now supplies both required props:

  • packages/web/src/app/[domain]/search/components/codePreviewPanel/index.tsx:
    <CodePreview file={file} repoName={previewedFile.repository} onClose={onClose} />

No other direct <CodePreview> usages exist. No further changes are needed.

packages/web/src/features/search/searchApi.ts (3)

9-9: Type rename looks good.

The change from SearchResultRange to SourceRange aligns with the updated type definitions and improves naming consistency across the codebase.


216-301: Good refactoring of the files array construction.

Extracting the files mapping logic into a separate constant improves code readability and follows the Single Responsibility Principle. The logic remains unchanged while making the code structure cleaner.


334-343: Useful addition of aggregated match statistics.

The new stats property with matchCount provides valuable aggregate information that can be displayed in the UI, eliminating the need for manual summation in consuming components.

packages/web/src/app/[domain]/search/components/filterPanel/index.tsx (3)

20-34: Excellent documentation for the bidirectional filtering feature.

The comprehensive JSDoc clearly explains the component's behavior and provides helpful examples. This will greatly aid future maintainability.


42-91: Well-implemented bidirectional filtering logic.

The implementation correctly handles the interdependency between repository and language filters, preventing users from selecting combinations that yield no results. The use of custom hooks (useGetSelectedFromQuery and useFilteredMatches) promotes code reusability.


125-129: Consider performance optimization for large datasets.

For repositories with many files, filtering visible entries on every render might impact performance. Consider memoizing these computations only when the relevant dependencies change.

-    const visibleRepos = useMemo(() => Object.values(repos).filter((entry) => !entry.isHidden), [repos]);
-    const visibleLanguages = useMemo(() => Object.values(languages).filter((entry) => !entry.isHidden), [languages]);
+    const visibleRepos = useMemo(() => {
+        return Object.values(repos).filter((entry) => !entry.isHidden);
+    }, [repos]);
+    
+    const visibleLanguages = useMemo(() => {
+        return Object.values(languages).filter((entry) => !entry.isHidden);
+    }, [languages]);

Note: The current implementation is already using useMemo, so this is just a formatting suggestion. The performance consideration is already addressed.

packages/web/src/app/[domain]/search/components/searchResultsPanel/index.tsx (3)

22-46: Excellent implementation of scroll state restoration.

The use of browser history state to preserve scroll position, measurements cache, and UI state provides a seamless experience when users navigate back to search results. The implementation correctly handles all necessary state elements.


90-101: Smart use of debouncing for history state updates.

Debouncing the scroll offset updates (100ms) prevents excessive history replacements while still capturing the user's scroll position effectively. This is a good performance optimization.


103-116: Thoughtful UX improvement for the show/hide matches toggle.

Scrolling to the top of the file match when collapsing ensures the "show fewer matches" button remains visible. This attention to detail improves the user experience.

packages/web/src/app/globals.css (3)

7-163: Excellent improvements to CSS variable organization and theming!

The changes enhance maintainability by:

  • Using consistent hsl() function syntax for all color variables
  • Adding comprehensive editor-specific variables for better theme customization
  • Maintaining clear separation between light and dark themes

242-254: Well-designed hover styles for improved code navigation UX!

The hover underline effect with smooth transitions provides excellent visual feedback for interactive code elements.


187-199:

✅ Verification successful

Verify the search match class name changes are applied consistently.

The class names have been changed from .cm-searchMatch to .searchMatch. Ensure all components using these classes have been updated.


🏁 Script executed:

#!/bin/bash
# Description: Verify that old class names are not used anywhere in the codebase

# Search for any remaining usage of the old class names
echo "Searching for old .cm-searchMatch class usage..."
rg "cm-searchMatch" --type ts --type tsx --type js --type jsx

# Search for usage of new class names to ensure they're being applied
echo -e "\nSearching for new .searchMatch class usage..."
rg "searchMatch(?!-selected)" --type ts --type tsx --type js --type jsx -A 2

Length of output: 621


🏁 Script executed:

#!/bin/bash
# Verify no residual usage of the old .cm-searchMatch class
echo "🔍 Searching for old .cm-searchMatch usage in code and markup files..."
rg -F "cm-searchMatch" -g "*.{js,jsx,ts,tsx,html}" -n || echo "✅ No occurrences of .cm-searchMatch found."

echo
# Verify that the new .searchMatch class is actually referenced in code
echo "🔍 Searching for .searchMatch usage in code and markup files..."
rg -F "searchMatch" -g "*.{js,jsx,ts,tsx,html}" -n || echo "⚠️ No occurrences of .searchMatch found."

Length of output: 996


Consistency Verified for Search Match Classes

  • No remaining occurrences of the old .cm-searchMatch selector.
  • New .searchMatch / .searchMatch-selected classes are referenced in:
    • packages/web/src/app/[domain]/browse/[...path]/components/rangeHighlightingExtension.ts
    • packages/web/src/lib/extensions/searchResultHighlightExtension.ts
    • packages/web/src/app/[domain]/components/lightweightCodeHighlighter.tsx

All relevant files have been updated—no further action required.

packages/web/src/app/[domain]/search/page.tsx (5)

25-35: Good improvements to imports and naming clarity!

The renamed constant DEFAULT_MAX_MATCH_COUNT better describes its purpose, and the new imports support the enhanced UI functionality.


56-58: Robust handling of query parameter parsing!

The improved parsing logic with NaN checking ensures the application handles invalid input gracefully.


228-238: Consider potential keyboard shortcut conflicts.

The Cmd+B (Mac) / Ctrl+B (Windows/Linux) shortcut might conflict with the browser's bookmark shortcut, which could confuse users.

Consider using a different shortcut combination or documenting this override clearly in the UI. Alternative suggestions:

  • Cmd/Ctrl+Shift+F for filter panel
  • Cmd/Ctrl+\ (backslash)
  • Cmd/Ctrl+[ (left bracket)

222-222: Excellent simplification of state management!

The refactoring from separate file/match indices to a single previewedFile state makes the code more intuitive and maintainable. The conditional rendering of the preview panel is clean and efficient.

Also applies to: 316-318, 331-348


226-226:

❓ Verification inconclusive

Add error handling for localStorage operations.

The useLocalStorage hook might throw exceptions in private browsing mode or when storage quota is exceeded.

Consider wrapping localStorage operations in a try-catch or ensuring the useLocalStorage hook handles errors gracefully:

// If the hook doesn't handle errors internally, consider creating a wrapper:
const [isFilterPanelCollapsed, setIsFilterPanelCollapsed] = useSafeLocalStorage('isFilterPanelCollapsed', false);

// Where useSafeLocalStorage wraps the operations in try-catch

🏁 Script executed:

#!/bin/bash
# Description: Check if useLocalStorage hook has error handling

# Search for the useLocalStorage implementation
echo "Searching for useLocalStorage implementation..."
fd -e ts -e tsx -e js -e jsx | xargs rg -l "useLocalStorage" | xargs rg -A 10 "export.*useLocalStorage"

Length of output: 208


🏁 Script executed:

#!/bin/bash
# Enhanced search for useLocalStorage implementation

echo "Searching for export patterns..."
rg -nE 'export (function|const) useLocalStorage' -t js -t jsx -t ts -t tsx

echo "Searching for function definitions..."
rg -n 'function useLocalStorage' -t js -t jsx -t ts -t tsx

echo "Searching for any usage of useLocalStorage..."
rg -n 'useLocalStorage' -t js -t jsx -t ts -t tsx

echo "Searching for files with 'localStorage' in their names..."
fd -e ts -e tsx -e js -e jsx -i localstorage

Length of output: 1079


#!/bin/bash
echo "1. All occurrences of useLocalStorage:"
rg "useLocalStorage" -n .

echo "2. Import statements referencing useLocalStorage:"
rg "import.*useLocalStorage" -n .

echo "3. Definitions of useLocalStorage in the repo:"
rg "function useLocalStorage" -n .
rg "const useLocalStorage" -n .

Verify error handling for localStorage usage
The call on line 226 persists UI state via useLocalStorage('isFilterPanelCollapsed', false), which can throw (e.g. in private mode or when storage is full). Confirm whether your useLocalStorage hook already wraps all localStorage operations in a try/catch. If it does not, consider one of the following:

  • Add error handling directly inside the existing hook
  • Introduce a useSafeLocalStorage wrapper that catches and silences/storage-quota errors

Location:

  • packages/web/src/app/[domain]/search/page.tsx, line 226

@brendan-kellam brendan-kellam merged commit cf5ecec into v4 May 28, 2025
2 checks passed
@brendan-kellam brendan-kellam deleted the bkellam/code_nav branch May 28, 2025 18:53
@coderabbitai coderabbitai bot mentioned this pull request May 28, 2025
Merged
brendan-kellam pushed a commit that referenced this pull request May 28, 2025
Sourcebot V4 introduces authentication, performance improvements and code navigation. Checkout the [migration guide](https://docs.sourcebot.dev/self-hosting/upgrade/v3-to-v4-guide) for information on upgrading your instance to v4.

### Changed
- [**Breaking Change**] Authentication is now required by default. Notes:
  - When setting up your instance, email / password login will be the default authentication provider.
  - The first user that logs into the instance is given the `owner` role. ([docs](https://docs.sourcebot.dev/docs/more/roles-and-permissions)).
  - Subsequent users can request to join the instance. The `owner` can approve / deny requests to join the instance via `Settings` > `Members` > `Pending Requests`.
  - If a user is approved to join the instance, they are given the `member` role.
  - Additional login providers, including email links and SSO, can be configured with additional environment variables. ([docs](https://docs.sourcebot.dev/self-hosting/configuration/authentication)).
- Clicking on a search result now takes you to the `/browse` view. Files can still be previewed by clicking the "Preview" button or holding `Cmd` / `Ctrl` when clicking on a search result. [#315](#315)

### Added
- [Sourcebot EE] Added search-based code navigation, allowing you to jump between symbol definition and references when viewing source files. [Read the documentation](https://docs.sourcebot.dev/docs/search/code-navigation). [#315](#315)
- Added collapsible filter panel. [#315](#315)

### Fixed
- Improved scroll performance for large numbers of search results. [#315](#315)
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