1- import { useState , useEffect } from 'react'
1+ import { useState , useEffect , useRef } from 'react'
22import { toast } from 'sonner'
33import { Progress } from '@/components/ui/progress'
44import type { Repository } from '../types'
5+ import { WS_URL } from '../config/api'
56
67interface RepoOverviewProps {
78 repo : Repository
@@ -10,38 +11,112 @@ interface RepoOverviewProps {
1011 apiKey : string
1112}
1213
14+ interface IndexProgress {
15+ files_processed : number
16+ functions_indexed : number
17+ total_files : number
18+ progress_pct : number
19+ }
20+
1321export function RepoOverview ( { repo, onReindex, apiUrl, apiKey } : RepoOverviewProps ) {
1422 const [ indexing , setIndexing ] = useState ( false )
15- const [ progress , setProgress ] = useState ( 0 )
23+ const [ progress , setProgress ] = useState < IndexProgress | null > ( null )
24+ const wsRef = useRef < WebSocket | null > ( null )
25+ const completedRef = useRef ( false ) // Track if indexing completed successfully
26+
27+ // Cleanup WebSocket on unmount
28+ useEffect ( ( ) => {
29+ return ( ) => {
30+ if ( wsRef . current ) {
31+ wsRef . current . close ( )
32+ }
33+ }
34+ } , [ ] )
1635
1736 const handleReindex = async ( ) => {
1837 setIndexing ( true )
19- setProgress ( 10 )
20- toast . loading ( 'Starting re-index...' , { id : 'reindex' } )
38+ setProgress ( { files_processed : 0 , functions_indexed : 0 , total_files : 0 , progress_pct : 0 } )
39+ completedRef . current = false
40+
41+ // Connect to WebSocket for real-time progress
42+ const wsUrl = `${ WS_URL } /ws/index/${ repo . id } ?token=${ apiKey } `
43+
44+ try {
45+ const ws = new WebSocket ( wsUrl )
46+ wsRef . current = ws
47+
48+ ws . onopen = ( ) => {
49+ toast . loading ( 'Indexing started...' , { id : 'reindex' } )
50+ }
51+
52+ ws . onmessage = ( event ) => {
53+ const data = JSON . parse ( event . data )
54+
55+ if ( data . type === 'progress' ) {
56+ setProgress ( {
57+ files_processed : data . files_processed ,
58+ functions_indexed : data . functions_indexed ,
59+ total_files : data . total_files ,
60+ progress_pct : data . progress_pct
61+ } )
62+ } else if ( data . type === 'complete' ) {
63+ completedRef . current = true
64+ toast . success ( `Indexing complete! ${ data . total_functions } functions indexed.` , { id : 'reindex' } )
65+ setIndexing ( false )
66+ setProgress ( null )
67+ onReindex ( )
68+ } else if ( data . type === 'error' ) {
69+ completedRef . current = true
70+ toast . error ( `Indexing failed: ${ data . message } ` , { id : 'reindex' } )
71+ setIndexing ( false )
72+ setProgress ( null )
73+ }
74+ }
75+
76+ ws . onerror = ( ) => {
77+ if ( ! completedRef . current ) {
78+ toast . dismiss ( 'reindex' )
79+ fallbackToHttp ( )
80+ }
81+ }
82+
83+ ws . onclose = ( ) => {
84+ // Only fallback if we didn't complete successfully
85+ if ( ! completedRef . current ) {
86+ fallbackToHttp ( )
87+ }
88+ }
89+
90+ } catch {
91+ fallbackToHttp ( )
92+ }
93+ }
94+
95+ const fallbackToHttp = async ( ) => {
96+ if ( completedRef . current ) return // Already completed
97+
98+ toast . loading ( 'Using fallback indexing...' , { id : 'reindex' } )
2199
22100 try {
23101 await onReindex ( )
24- toast . success ( 'Re-indexing started!' , {
25- id : 'reindex' ,
26- description : 'Using incremental mode - 100x faster!'
27- } )
102+ toast . success ( 'Re-indexing started!' , { id : 'reindex' } )
28103
29- // Simulate progress
104+ let pct = 10
30105 const interval = setInterval ( ( ) => {
31- setProgress ( prev => {
32- if ( prev >= 90 ) return prev
33- return prev + 10
34- } )
106+ pct = Math . min ( pct + 10 , 90 )
107+ setProgress ( prev => prev ? { ...prev , progress_pct : pct } : null )
35108 } , 1000 )
36109
37110 setTimeout ( ( ) => {
38111 clearInterval ( interval )
39- setProgress ( 100 )
112+ setProgress ( null )
40113 setIndexing ( false )
114+ completedRef . current = true
41115 } , 8000 )
42116
43- } catch ( error ) {
117+ } catch {
44118 setIndexing ( false )
119+ setProgress ( null )
45120 toast . error ( 'Failed to start re-indexing' , { id : 'reindex' } )
46121 }
47122 }
@@ -80,17 +155,18 @@ export function RepoOverview({ repo, onReindex, apiUrl, apiKey }: RepoOverviewPr
80155 </ div >
81156 </ div >
82157
83- { /* Indexing Progress */ }
84- { indexing && (
158+ { /* Indexing Progress - only show when indexing AND progress exists */ }
159+ { indexing && progress && (
85160 < div className = "card p-6 border-2 border-blue-500 bg-blue-50" >
86161 < div className = "flex items-center justify-between mb-3" >
87162 < h3 className = "text-base font-semibold text-gray-900" > 🔄 Indexing in Progress</ h3 >
88- < span className = "text-sm font-mono text-blue-600" > { progress } %</ span >
163+ < span className = "text-sm font-mono text-blue-600" > { progress . progress_pct } %</ span >
164+ </ div >
165+ < Progress value = { progress . progress_pct } className = "h-2" />
166+ < div className = "flex justify-between text-xs text-gray-600 mt-2" >
167+ < span > Files: { progress . files_processed } /{ progress . total_files || '?' } </ span >
168+ < span > Functions: { progress . functions_indexed } </ span >
89169 </ div >
90- < Progress value = { progress } className = "h-2" />
91- < p className = "text-xs text-gray-600 mt-2" >
92- Incremental mode - only processing changed files for 100x faster updates
93- </ p >
94170 </ div >
95171 ) }
96172
0 commit comments