Skip to content

feat(dashboard): Overview V2 - Codebase Intelligence#218

Merged
DevanshuNEU merged 9 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:feature/dashboard-v2
Jan 25, 2026
Merged

feat(dashboard): Overview V2 - Codebase Intelligence#218
DevanshuNEU merged 9 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:feature/dashboard-v2

Conversation

@DevanshuNEU

@DevanshuNEU DevanshuNEU commented Jan 24, 2026

Copy link
Copy Markdown
Collaborator

🧠 Overview V2: Codebase Intelligence

What Changed

Completely redesigned the Overview tab to provide actionable codebase intelligence instead of basic stats.

Why

Competitive Differentiation from DeepWiki:

DeepWiki CodeIntel
Static documentation Live dependency analysis
"Here's what this code does" "Here's where to start and what's critical"
Read about code Work with code

New Features

🧠 Intelligence Hero Card

  • Smart summary with function count, language detection
  • Auto-detects architecture patterns (middleware/plugin, hooks-based)
  • Identifies core file automatically
  • Quick action buttons: "Start Here", "Search Code", "View Architecture"

⚠️ High-Impact Files

  • Shows files with most dependents
  • Computed from dependency graph edges
  • Helps developers know what to handle with care

📁 Architecture Overview

  • Directory structure with file counts
  • "Core" badge for directories containing critical files

⚡ Entry Points

  • Most-imported files (API surface)
  • Shows import count for each

📊 Code Health

  • Type coverage percentage
  • Naming consistency score
  • Async adoption rate
  • Branch indicator

Technical Details

  • New Component: CodebaseIntelligence.tsx
  • Updated: RepoOverview.tsx - uses new intelligence component
  • Updated: DashboardHome.tsx - passes onTabChange for cross-tab navigation
  • No backend changes - derives all data from existing /dependencies and /style-analysis APIs

Screenshots

The Overview tab now shows:

  1. Gradient hero card with codebase summary
  2. High-impact files with dependency counts
  3. Architecture tree with annotations
  4. Entry points with import counts
  5. Code health metrics

Testing

  • ✅ Build passes
  • ✅ Dark mode verified
  • ✅ Light mode verified
  • ✅ Data correctly computed from dependency graph

Commits

  • c195280 - feat(dashboard): Overview V2 - Codebase Intelligence
  • 1cbf10a - fix(overview): compute critical files from edge data

Summary by CodeRabbit

  • New Features

    • AI-driven Codebase Intelligence panel and Repository Summary card.
    • Cached repo insights hook for richer, faster repository analytics.
  • Improvements

    • Unified design system: componentized UI (buttons, inputs, cards), refreshed colors, spinners, and skeletons.
    • Theming, layout and UX refinements across dashboard, search, command palette, sidebar, and repo views; persisted sidebar collapse.
  • Public API additions

    • New optional props exposed (e.g., loading, defaultBranch, onTabChange).

✏️ Tip: You can customize this high-level summary in your review settings.

- DashboardLayout: Added theme-aware Toaster, sidebar state persistence
- Sidebar: Migrated to theme tokens, lucide-react icons
- TopNav: Theme toggle button, shadcn Button, proper theme tokens
- DashboardStats: Theme tokens for stat cards with indigo accent
- DashboardHome: Full theme migration, lucide-react icons
- RepoList: Theme tokens, lucide-react icons for repo cards
- AddRepoForm: Migrated to shadcn Input, Label, Button components

All hardcoded colors (bg-[#09090b], text-gray-400, border-white/5)
replaced with theme tokens (bg-background, text-muted-foreground, border-border)
… mode support

Components migrated:
- RepoOverview: bg-muted, text-foreground, text-muted-foreground, border-border
- StyleInsights: all cards and text now use theme tokens
- ImpactAnalyzer: form inputs, cards, risk badges migrated
- DependencyGraph: cards, controls, legend use theme tokens
- SearchBox: input styling, focus states, badges
- ResultCard: code blocks adapt to light/dark, all text themed
- SearchPanel: cards, badges, empty state

Replaced hardcoded colors:
- bg-[#0a0a0c] → bg-muted/bg-card
- border-white/5 → border-border
- text-zinc-500/text-gray-400 → text-muted-foreground
- text-white → text-foreground
- text-blue-400 → text-primary

All repo detail tabs now properly support light and dark modes.
- Created RepoSummaryCard component with auto-generated insights
- Fetches data from /insights and /style-analysis endpoints
- Shows: main summary, quick stats pills, critical files warning
- Added useRepoInsights hook with caching support
- Card only shows when repo status is 'indexed'
- Gradient background with primary color theming
- Loading skeleton while data fetches

Phase 2.5a complete - the 'aha moment' is here!
WHAT:
- Replace basic stats with intelligent codebase analysis
- Auto-detect entry points from dependency graph
- Show high-impact files with dependency counts
- Architecture tree with core annotations
- Code health indicators (type coverage, naming consistency)
- Quick actions to navigate between tabs

WHY:
- Competitive differentiation from DeepWiki
- DeepWiki = static documentation
- CodeIntel = actionable intelligence
- Help developers START WORKING, not just READ

COMPONENTS:
- CodebaseIntelligence.tsx: Main intelligence card
- Updated RepoOverview.tsx: Uses new component
- onTabChange prop for cross-tab navigation

Data derived from existing APIs:
- /dependencies: entry points, architecture
- /style-analysis: health metrics
- No backend changes needed
Bug: High-Impact Files section was empty
Cause: Relying on deps.metrics.most_critical_files from backend
       but Entry Points (which worked) computed from edges directly

Fix: Compute critical files locally from same edge data
     - Sort by in-degree (most dependents first)
     - Consistent with Entry Points calculation
     - No backend dependency for this data
@vercel

vercel Bot commented Jan 24, 2026

Copy link
Copy Markdown

@DevanshuNEU is attempting to deploy a commit to the Dev's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jan 24, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Migrates many UI surfaces to design-token classes and shared UI primitives, adds theme support and persisted sidebar state, introduces CodebaseIntelligence and RepoSummaryCard components, and adds a useRepoInsights hook plus related cache invalidation. Several components gained optional props (onTabChange, defaultBranch, loading).

Changes

Cohort / File(s) Summary
Design tokens & Theming
frontend/src/App.tsx, frontend/src/components/StyleInsights.tsx, frontend/src/components/search/ResultCard.tsx, frontend/src/components/search/SearchBox.tsx, frontend/src/components/search/SearchPanel.tsx
Replaced hardcoded colors with token classes (bg-, text-, border-*, primary, etc.), added theme-aware code styling and adjusted UI color tokens across components.
New intelligence components
frontend/src/components/CodebaseIntelligence.tsx, frontend/src/components/RepoSummaryCard.tsx
Added CodebaseIntelligence (fetches dep graph & style, computes metrics, renders intelligence UI) and RepoSummaryCard (fetches insights/style, generates AI summary and skeleton).
Forms & UI primitives
frontend/src/components/AddRepoForm.tsx, frontend/src/components/ImpactAnalyzer.tsx, frontend/src/components/search/SearchBox.tsx, frontend/src/components/search/ResultCard.tsx
Replaced inline inputs/buttons with shared UI primitives (Button, Input, Label, Loader2), updated loading states and action areas. AddRepoForm now accepts a loading prop.
Dependency graph & analysis
frontend/src/components/DependencyGraph.tsx, frontend/src/components/ImpactAnalyzer.tsx
Inlined useDependencyGraph usage, simplified data processing and highlight/reset logic, and switched node/edge colors/markers to theme tokens.
Repo UI surface changes
frontend/src/components/RepoOverview.tsx, frontend/src/components/RepoList.tsx, frontend/src/components/RepoSummaryCard.tsx, frontend/src/components/SearchPanel.tsx
RepoOverview now accepts optional onTabChange; SearchPanel/ResultCard accept defaultBranch; replaced many repo UIs with token-driven styling and surfaced indexing flows.
Dashboard & navigation
frontend/src/components/dashboard/*, frontend/src/components/dashboard/DashboardLayout.tsx, frontend/src/components/dashboard/DashboardStats.tsx, frontend/src/components/dashboard/Sidebar.tsx, frontend/src/components/dashboard/TopNav.tsx, frontend/src/components/dashboard/DashboardHome.tsx
Replaced custom SVGs with lucide-react icons, added theme toggle (next-themes), persisted sidebarCollapsed to localStorage, unified nav styling, and made stats rendering data-driven.
Search UX
frontend/src/components/search/ResultCard.tsx, frontend/src/components/SearchPanel.tsx, frontend/src/components/search/SearchBox.tsx
Theme-aware syntax highlighting, consolidated request shaping, restyled badges/empty states, and replaced native buttons with shared Button component.
Hooks & caching
frontend/src/hooks/useCachedQuery.ts
Added useRepoInsights({ repoId, apiKey, enabled }) hook and extended useInvalidateRepoCache to invalidate insights cache key.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant RepoOverview
    participant CodeIntel as CodebaseIntelligence
    participant API as BackendAPI
    participant Cache as LocalStorage

    User->>RepoOverview: Open repository page
    RepoOverview->>CodeIntel: Render intelligence (if repo indexed)
    CodeIntel->>Cache: Check cached insights/style
    alt Cache hit
        Cache-->>CodeIntel: Return cached data
    else Cache miss
        CodeIntel->>API: GET /dependency-graph
        API-->>CodeIntel: Return graph
        CodeIntel->>API: GET /style-analysis
        API-->>CodeIntel: Return style data
        CodeIntel->>Cache: Store insights/style
    end
    CodeIntel->>CodeIntel: Compute metrics (degrees, entry points, health)
    CodeIntel-->>User: Render intelligence UI
    User->>CodeIntel: Click tab/action
    CodeIntel->>RepoOverview: onTabChange(tab)
    RepoOverview->>RepoOverview: Update active tab
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰
Tokens hop where colors used to hide,
Buttons nestle cozy, icons at my side.
Graphs whisper maps of files and light,
Summaries bloom, the dashboard feels right.
I nibble a carrot and skip into the night. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(dashboard): Overview V2 - Codebase Intelligence' accurately captures the main changes: introducing a redesigned Overview dashboard with codebase intelligence features.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 11

Caution

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

⚠️ Outside diff range comments (4)
frontend/src/components/dashboard/DashboardStats.tsx (1)

10-24: Add RAF cleanup to avoid state updates after unmount.

Without cancelling the scheduled animation frame, React can attempt setCount after unmount. Add a cleanup to cancel the frame and guard the callback.

🛠️ Suggested fix
 useEffect(() => {
   if (end === 0) { setCount(0); return }
   let startTime: number | null = null
+  let frameId: number | null = null
+  let cancelled = false
   const animate = (timestamp: number) => {
+    if (cancelled) return
     if (!startTime) startTime = timestamp
     const progress = Math.min((timestamp - startTime) / duration, 1)
     const easeOut = 1 - Math.pow(1 - progress, 3)
     setCount(Math.floor(easeOut * end))
-    if (progress < 1) requestAnimationFrame(animate)
+    if (progress < 1) frameId = requestAnimationFrame(animate)
   }
-  requestAnimationFrame(animate)
+  frameId = requestAnimationFrame(animate)
+  return () => {
+    cancelled = true
+    if (frameId !== null) cancelAnimationFrame(frameId)
+  }
 }, [end, duration])
frontend/src/components/dashboard/CommandPalette.tsx (1)

49-76: Stale closure: filteredItems and onClose missing from dependency array.

The keyboard handler references filteredItems and onClose, but the effect only re-runs when isOpen, selectedIndex, or query change. If repos loads after the palette opens (while query remains empty), the handler will reference an outdated filteredItems array, potentially invoking the wrong action or causing an index-out-of-bounds issue.

🐛 Proposed fix
     window.addEventListener('keydown', handleKeyDown)
     return () => window.removeEventListener('keydown', handleKeyDown)
-  }, [isOpen, selectedIndex, query])
+  }, [isOpen, selectedIndex, filteredItems, onClose])

Alternatively, remove query since filteredItems already captures query changes. Including filteredItems ensures the handler always sees the current list.

frontend/src/components/DependencyGraph.tsx (1)

65-82: Filter threshold is bypassed for nodes with any edge.
allEdges.some(...) makes any single edge pass the filter, so minDeps/critical thresholds are effectively ignored for those nodes. Consider counting edges and comparing to the threshold.

🐛 Suggested fix
-      filteredNodes = allNodes.filter((node: any) => 
-        (node.data.imports || 0) >= threshold || allEdges.some(e => e.target === node.id)
-      )
+      filteredNodes = allNodes.filter((node: any) => {
+        const inCount = allEdges.filter(e => e.target === node.id).length
+        const depCount = Math.max(node.data.imports || 0, inCount)
+        return depCount >= threshold
+      })
frontend/src/components/search/ResultCard.tsx (1)

10-18: Make GitHub links branch-aware.

Hardcoding main breaks repos whose default branch isn’t main. Consider passing the repo branch into this component and using it when building the URL.

🔧 Suggested change
 interface ResultCardProps {
   result: SearchResult;
   rank: number;
   isExpanded?: boolean;
   aiSummary?: string;
   repoUrl?: string;
+  repoBranch?: string;
 }
 
-export function ResultCard({ result, rank, isExpanded: initialExpanded = false, aiSummary, repoUrl }: ResultCardProps) {
+export function ResultCard({ result, rank, isExpanded: initialExpanded = false, aiSummary, repoUrl, repoBranch = 'main' }: ResultCardProps) {
 ...
-  const githubUrl = repoUrl ? `${repoUrl}/blob/main/${cleanFilePath}#L${result.line_start}-L${result.line_end}` : null;
+  const githubUrl = repoUrl ? `${repoUrl}/blob/${repoBranch}/${cleanFilePath}#L${result.line_start}-L${result.line_end}` : null;

Also applies to: 29-29

🤖 Fix all issues with AI agents
In `@frontend/src/components/CodebaseIntelligence.tsx`:
- Around line 96-102: The component currently uses repo.file_count as a fallback
for totalFunctions and then derives sizeDesc from that, which misreports
functions; update the logic so totalFunctions is only taken from
style?.summary?.total_functions (do not fall back to repo.file_count or
deps.total_files), display "N/A" in the UI when total_functions is
undefined/null, and compute sizeDesc strictly from the real totalFunctions value
(e.g. 'compact'/'medium-sized'/'large' only when totalFunctions is a number and
meets thresholds); adjust the equivalent logic referenced around the other block
(the usage at lines ~170-173) to follow the same rule and symbols
(totalFunctions, sizeDesc, repo.file_count).
- Around line 92-93: The current startHere picks criticalFiles[0] but the
comment asks for the most critical file that is also an entry point; change the
logic so startHere first searches criticalFiles for an item whose file is
present in entryPoints (e.g., use criticalFiles.find(cf => entryPoints.some(ep
=> ep.file === cf.file))). If none found, fall back to entryPoints[0]?.file or
null; update the variable startHere accordingly and reference the arrays
criticalFiles and entryPoints and the variable startHere in your change.
- Around line 370-381: The HealthIndicator component currently treats 0 as falsy
and shows "N/A"; change the prop type from { label: string, value: string |
null, threshold: number } to { label: string, value: string | number | null,
threshold: number }, replace the falsy check `if (!value)` with `if (value ==
null)` to only treat null/undefined as missing, and compute the numeric value
safely in HealthIndicator (e.g., if typeof value === 'number' use it, otherwise
parseFloat(value)) before comparing to threshold.
- Around line 34-36: The current guard in the useMemo that computes intelligence
is checking deps?.metrics, which hides the panel when metrics are missing even
if graph data exists; update the guard to gate on deps existence or graph data
instead (e.g., check deps != null or nodes.length > 0) so the intelligence
computation (inside the intelligence constant / useMemo) runs when deps is
present or when nodes/edges (extracted earlier with empty-array fallbacks)
contain data; adjust the conditional that returns null accordingly to reference
deps or nodes.length rather than deps?.metrics.

In `@frontend/src/components/dashboard/DashboardLayout.tsx`:
- Around line 19-27: The localStorage reads/writes around SIDEBAR_STORAGE_KEY
can throw and currently call JSON.parse directly; update the sidebarCollapsed
state initializer and the useEffect to guard against errors by wrapping
localStorage.getItem + JSON.parse in a try/catch and returning false on any
failure, and likewise wrap localStorage.setItem in a try/catch so failures are
no-ops; specifically modify the useState initializer for sidebarCollapsed and
the useEffect that calls localStorage.setItem(SIDEBAR_STORAGE_KEY,
JSON.stringify(sidebarCollapsed)) to handle exceptions safely.

In `@frontend/src/components/dashboard/DashboardStats.tsx`:
- Around line 39-64: The "Functions Indexed" stat in DashboardStats is using
totalFunctions (which sums repo.file_count from the Repository interface) so it
shows file count rather than function count; update DashboardStats to either
rename the stat to "Files Indexed" (change the label for the object with icon
Code2 / value animatedFunctions) or change the source to use the real function
count (pull style?.summary?.total_functions or the detailed insights source used
elsewhere and feed it into the animatedFunctions/totalFunctions calc), and
ensure any formatting/format flag remains consistent with the new metric name.

In `@frontend/src/components/dashboard/TopNav.tsx`:
- Around line 80-90: The theme toggle Button in TopNav is icon-only and lacks an
accessible name; update the Button (where toggleTheme is used and theme
determines Sun/Moon) to include a dynamic aria-label (or aria-labelledby) such
as aria-label={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark
mode'} (or a localized equivalent) so screen readers announce the purpose; keep
existing props (variant, size, onClick, className) and ensure the label changes
with the theme.

In `@frontend/src/components/RepoList.tsx`:
- Around line 83-88: The UI label "Functions" is misleading because the
component uses repo.file_count; either change the displayed label to "Files" or
replace repo.file_count with the correct function-count metric (e.g.,
repo.function_count or repo.metrics.functions) if one exists on the Repository
object; update Repository type/props and any callers to pass the correct field
so RepoList.tsx renders the intended metric (look for the repo.file_count usage
in RepoList component and the Repository type/interface to locate and fix).

In `@frontend/src/components/RepoSummaryCard.tsx`:
- Around line 128-136: The label generation uses literal markdown (the variable
main in RepoSummaryCard.tsx) so `**${repo.name}**` will render asterisks; change
this to render plain text or a proper HTML element by removing the markdown and
using a <strong> element (e.g., build the summary as JSX or concatenate strings
with repo.name without asterisks) so the repository name is bolded properly in
the UI; update the code paths that produce main and any consumers that expect a
string to accept JSX if needed.
- Around line 101-103: The primaryLang selection uses Object.keys(languages)[0]
which may not be the dominant language; update the logic that sets primaryLang
to inspect the values in languages (handle both numeric values and objects with
percentage/count fields), sort the language entries by their numeric share
descending, and pick the top key as primaryLang (falling back to 'Unknown' if
languages is empty); locate and modify the constants languages and primaryLang
in RepoSummaryCard.tsx (referencing insights, style, and
style.language_distribution) to implement this deterministic selection.

In `@frontend/src/components/search/ResultCard.tsx`:
- Line 6: The theme check in ResultCard is using the raw theme value from
useTheme which can be "system", so change the hook usage to destructure
resolvedTheme (const { resolvedTheme } = useTheme()) and replace any checks like
theme === 'dark' with resolvedTheme === 'dark' (or a defensive fallback like
(resolvedTheme || theme) === 'dark') so the Prism theme selection respects the
OS preference; update all occurrences in the ResultCard component that compare
theme to 'dark'.
🧹 Nitpick comments (2)
frontend/src/components/dashboard/CommandPalette.tsx (2)

78-88: Consider checking response.ok before parsing JSON.

If the API returns a 4xx/5xx status, the response body may not contain the expected repositories field, silently falling back to an empty list without surfacing the error to the user.

♻️ Proposed improvement
   const fetchRepos = async () => {
     try {
       const response = await fetch(`${API_URL}/repos`, {
         headers: { 'Authorization': `Bearer ${session?.access_token}` }
       })
+      if (!response.ok) {
+        console.error('Failed to fetch repos:', response.status)
+        return
+      }
       const data = await response.json()
       setRepos(data.repositories || [])
     } catch (error) {
       console.error('Error fetching repos:', error)
     }
   }

102-107: Consider breaking long item definitions across multiple lines for readability.

These single-line item definitions are dense and harder to scan during review. Multi-line formatting would improve maintainability.

♻️ Example formatting
-    items.push({ id: 'action-add-repo', type: 'action', title: 'Add Repository', subtitle: 'Clone and index a new repository', icon: '➕', action: () => { window.dispatchEvent(new CustomEvent('openAddRepo')); navigate('/dashboard') } })
+    items.push({
+      id: 'action-add-repo',
+      type: 'action',
+      title: 'Add Repository',
+      subtitle: 'Clone and index a new repository',
+      icon: '➕',
+      action: () => {
+        window.dispatchEvent(new CustomEvent('openAddRepo'))
+        navigate('/dashboard')
+      }
+    })

Comment thread frontend/src/components/CodebaseIntelligence.tsx Outdated
Comment thread frontend/src/components/CodebaseIntelligence.tsx Outdated
Comment thread frontend/src/components/CodebaseIntelligence.tsx Outdated
Comment thread frontend/src/components/CodebaseIntelligence.tsx Outdated
Comment thread frontend/src/components/dashboard/DashboardLayout.tsx
Comment thread frontend/src/components/dashboard/TopNav.tsx
Comment thread frontend/src/components/RepoList.tsx
Comment thread frontend/src/components/RepoSummaryCard.tsx
Comment thread frontend/src/components/RepoSummaryCard.tsx Outdated
Comment thread frontend/src/components/search/ResultCard.tsx
CodebaseIntelligence.tsx:
- Fix guard to work with deps/nodes instead of requiring metrics
- Fix startHere to find critical file that's also entry point
- Fix totalFunctions to only use real data, show N/A when missing
- Fix HealthIndicator to handle 0 values (not treat as falsy)

DashboardLayout.tsx:
- Wrap localStorage operations in try/catch

DashboardStats.tsx:
- Rename 'Functions Indexed' to 'Files Indexed' (correct metric)

TopNav.tsx:
- Add aria-label to theme toggle for accessibility

RepoList.tsx:
- Change 'Functions' label to 'Files' (matches file_count)

RepoSummaryCard.tsx:
- Fix markdown asterisks - use JSX <strong> for repo name
- Fix primaryLang to sort by dominant language value

ResultCard.tsx:
- Use resolvedTheme instead of theme for system theme support

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@frontend/src/components/RepoSummaryCard.tsx`:
- Around line 122-124: The sort assumes every namingConventions entry has a
percentage and uses parseFloat directly, which can produce NaN; update the sort
comparator used when building primaryNaming to defensively read percentage
(e.g., a[1]?.percentage or a[1]?.percentage ?? '0') and convert with a safe
parse that falls back to 0 for missing/invalid values, and when selecting
primaryNaming ensure you handle the case of an empty array before indexing so
namingStyle is null if none found; locate the sort and assignment around
primaryNaming, namingConventions, and namingStyle and apply these defensive
fallbacks.

In `@frontend/src/components/search/ResultCard.tsx`:
- Around line 92-101: The language badge can show "undefined" while
SyntaxHighlighter falls back to 'text'; update the badge in the ResultCard
component to use the same fallback as the highlighter (use result.language ||
'text') so the span that displays language uses the identical value as the
SyntaxHighlighter's language prop; locate the SyntaxHighlighter usage and the
adjacent span (the badge) and change the span's content to the same fallback
expression.
- Line 29: The GitHub URL is hardcoded to "main"; update the types and props to
carry the repository default branch and use it when constructing the URL: add
default_branch (string) to the SearchResult interface, update wherever
SearchResult instances are created so they include repository.default_branch,
and update ResultCard's props (and any callers) to accept and use
result.default_branch (or a prop named defaultBranch) in place of the literal
"main" when building githubUrl (the variable in ResultCard.tsx) so links work
for repos with master/develop/trunk, etc.
♻️ Duplicate comments (8)
frontend/src/components/dashboard/TopNav.tsx (1)

80-92: Past issue addressed: Accessible label added to theme toggle.

The aria-label has been correctly added to the icon-only button, addressing the previous accessibility concern.

frontend/src/components/dashboard/DashboardLayout.tsx (1)

19-35: Past issue addressed: localStorage operations properly guarded.

The try/catch blocks have been correctly added around both localStorage.getItem and localStorage.setItem operations, preventing potential crashes from storage errors or quota limits.

frontend/src/components/RepoSummaryCard.tsx (2)

106-115: Past issue addressed: Primary language selection now sorts by value.

The language selection logic correctly handles both numeric values and objects with percentage/count properties, sorting descending to pick the dominant language.


56-58: Past issue addressed: Repository name rendered with JSX <strong> element.

The markdown bold syntax has been replaced with proper JSX rendering using <strong>{repo.name}</strong>.

frontend/src/components/CodebaseIntelligence.tsx (4)

34-39: Past issue addressed: Guard now checks deps existence instead of metrics.

The guard correctly checks !deps && nodes.length === 0 to allow the component to work when graph data exists but metrics are missing.


93-97: Past issue addressed: startHere now properly intersects critical files with entry points.

The logic correctly finds a critical file that is also an entry point before falling back to the first entry point.


99-108: Past issue addressed: Function count no longer uses file_count as proxy.

totalFunctions is now strictly derived from style?.summary?.total_functions with proper null handling, and the UI conditionally renders "N/A" when unavailable.

Also applies to: 177-182


379-391: Past issue addressed: Numeric 0 now handled correctly in HealthIndicator.

The check value == null properly distinguishes between missing data and a valid zero value, and the type signature includes number | null.

🧹 Nitpick comments (3)
frontend/src/components/dashboard/TopNav.tsx (1)

32-34: Handle system theme value in toggle and aria-label.

The useTheme hook from next-themes can return 'system' as the theme value. When theme === 'system', the toggle will set it to 'light' (since it's not 'dark'), and the aria-label will say "Switch to dark mode" even though the system might already be in dark mode. Consider using resolvedTheme instead for accurate display, or explicitly handling the system case.

♻️ Suggested improvement
 export function TopNav({ onToggleSidebar, sidebarCollapsed, onOpenCommandPalette }: TopNavProps) {
   const { session, signOut } = useAuth()
-  const { theme, setTheme } = useTheme()
+  const { theme, setTheme, resolvedTheme } = useTheme()
   const [showUserMenu, setShowUserMenu] = useState(false)

   const userEmail = session?.user?.email || 'User'
   const userInitial = userEmail.charAt(0).toUpperCase()

   const toggleTheme = () => {
-    setTheme(theme === 'dark' ? 'light' : 'dark')
+    setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')
   }

And for the aria-label and icon:

-            aria-label={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'}
+            aria-label={resolvedTheme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'}
           >
-            {theme === 'dark' ? (
+            {resolvedTheme === 'dark' ? (

Also applies to: 85-85

frontend/src/components/dashboard/DashboardLayout.tsx (1)

75-77: Toaster theme may not reflect system preference.

Similar to TopNav, when theme is 'system', the Toaster receives 'light' instead of the actual resolved theme. Consider using resolvedTheme for accurate theming.

♻️ Suggested fix
 export function DashboardLayout({ children }: DashboardLayoutProps) {
-  const { theme } = useTheme()
+  const { resolvedTheme } = useTheme()
   
   // ... rest of component
   
   <Toaster 
-    theme={theme === 'dark' ? 'dark' : 'light'}
+    theme={resolvedTheme === 'dark' ? 'dark' : 'light'}
     position="bottom-right"
   />
frontend/src/components/search/ResultCard.tsx (1)

52-76: Add ARIA wiring for the expandable header.
The toggle button expands/collapses content but doesn’t expose state or control linkage to assistive tech.

♿ Proposed accessibility fix
-import { useState, useRef, useEffect } from 'react';
+import { useState, useRef, useEffect, useId } from 'react';

 export function ResultCard({ result, rank, isExpanded: initialExpanded = false, aiSummary, repoUrl }: ResultCardProps) {
   const [expanded, setExpanded] = useState(initialExpanded);
   const contentRef = useRef<HTMLDivElement>(null);
   const [contentHeight, setContentHeight] = useState<number | undefined>(initialExpanded ? undefined : 0);
+  const contentId = useId();
   const { resolvedTheme } = useTheme();
@@
-      <button onClick={() => setExpanded(!expanded)} className="w-full p-4 flex items-start justify-between text-left hover:bg-muted/50 transition-colors">
+      <button
+        onClick={() => setExpanded(!expanded)}
+        aria-expanded={expanded}
+        aria-controls={contentId}
+        className="w-full p-4 flex items-start justify-between text-left hover:bg-muted/50 transition-colors"
+      >
@@
-      <div ref={contentRef} className="overflow-hidden transition-all duration-200 ease-out" style={{ height: contentHeight !== undefined ? contentHeight : 'auto' }}>
+      <div
+        id={contentId}
+        ref={contentRef}
+        className="overflow-hidden transition-all duration-200 ease-out"
+        style={{ height: contentHeight !== undefined ? contentHeight : 'auto' }}
+      >

Comment thread frontend/src/components/RepoSummaryCard.tsx Outdated
Comment thread frontend/src/components/search/ResultCard.tsx Outdated
Comment thread frontend/src/components/search/ResultCard.tsx Outdated
- RepoSummaryCard: defensive namingConventions sort (handle NaN, empty array)
- ResultCard: language badge uses same fallback as SyntaxHighlighter
- ResultCard: use defaultBranch prop instead of hardcoded 'main'
- SearchPanel: pass defaultBranch to ResultCard
- DashboardHome: pass repo.branch to SearchPanel

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@frontend/src/components/RepoSummaryCard.tsx`:
- Around line 159-161: The code appends `(X consistency)` using
`(primaryNaming[1] as any).percentage` which can be undefined; update the block
in RepoSummaryCard.tsx that references primaryNaming to safely read percentage
(e.g., use nullish coalescing or a fallback like `?? '0'` or convert with
`parseFloat(... ?? '0')`) before both the >80 check and the string interpolation
so the displayed consistency never shows "undefined" and uses the same defensive
logic used in the sort code.
🧹 Nitpick comments (2)
frontend/src/components/RepoSummaryCard.tsx (2)

11-16: Consider handling query error states.

The component handles loading but not errors. If either query fails, the component will render the summary with potentially missing data, which might lead to a confusing UI or incomplete information display.

♻️ Suggested enhancement
 export function RepoSummaryCard({ repo, apiKey }: RepoSummaryCardProps) {
-  const { data: insights, isLoading: insightsLoading } = useRepoInsights({ repoId: repo.id, apiKey })
-  const { data: style, isLoading: styleLoading } = useStyleAnalysis({ repoId: repo.id, apiKey })
+  const { data: insights, isLoading: insightsLoading, isError: insightsError } = useRepoInsights({ repoId: repo.id, apiKey })
+  const { data: style, isLoading: styleLoading, isError: styleError } = useStyleAnalysis({ repoId: repo.id, apiKey })

   const isLoading = insightsLoading || styleLoading
+  const hasError = insightsError || styleError

Then optionally render an error state or a minimal fallback when hasError is true.


155-155: Inconsistent number formatting.

functionCount uses toLocaleString() but fileCount is interpolated directly. For consistency across the summary text, both should use the same formatting.

♻️ Suggested fix
-  main += `${primaryLang} codebase with ${functionCount.toLocaleString()} functions across ${fileCount} files. `
+  main += `${primaryLang} codebase with ${functionCount.toLocaleString()} functions across ${fileCount.toLocaleString()} files. `

Comment thread frontend/src/components/RepoSummaryCard.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@frontend/src/components/RepoSummaryCard.tsx`:
- Around line 133-136: The code assumes insights.most_critical_files is an array
and f.file is a string; change the block that builds criticalFiles so it first
verifies Array.isArray(insights?.most_critical_files) before calling .slice(0,
3), then in the forEach callback guard f and f.file (e.g., if (!f || typeof
f.file !== 'string') continue or use a fallback string) before calling
.split('/').pop(); update the logic around insights, most_critical_files, the
.slice(0, 3) call and the forEach callback to avoid throwing when data is
missing or malformed.
♻️ Duplicate comments (1)
frontend/src/components/RepoSummaryCard.tsx (1)

106-112: Primary language sorting can mis-rank percentage strings.
Line 110–112 uses Number(...), which turns "12%" into NaN, so the sort can become unstable. Prefer parseFloat (with fallback) to support percent strings.

🔧 Suggested fix
-    const sorted = langEntries.sort((a, b) => {
-      const valA = typeof a[1] === 'number' ? a[1] : (a[1] as any)?.percentage ?? (a[1] as any)?.count ?? 0
-      const valB = typeof b[1] === 'number' ? b[1] : (b[1] as any)?.percentage ?? (b[1] as any)?.count ?? 0
-      return Number(valB) - Number(valA)
-    })
+    const sorted = langEntries.sort((a, b) => {
+      const valA =
+        typeof a[1] === 'number'
+          ? a[1]
+          : parseFloat((a[1] as any)?.percentage ?? (a[1] as any)?.count ?? a[1] ?? '0') || 0
+      const valB =
+        typeof b[1] === 'number'
+          ? b[1]
+          : parseFloat((b[1] as any)?.percentage ?? (b[1] as any)?.count ?? b[1] ?? '0') || 0
+      return valB - valA
+    })

Comment thread frontend/src/components/RepoSummaryCard.tsx Outdated
@vercel

vercel Bot commented Jan 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
opencodeintel Ready Ready Preview, Comment Jan 25, 2026 0:33am

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant