@@ -274,19 +274,35 @@ function CreateIndexModal({ onClose, onCreated }: { onClose: () => void; onCreat
274274/* ── Index Progress ─────────────────────────────────────── */
275275
276276function IndexProgress ( { onDone } : { onDone : ( ) => void } ) {
277- const [ jobs , setJobs ] = useState < { slot : number ; status : string ; path : string } [ ] > ( [ ] ) ;
277+ const [ jobs , setJobs ] = useState < { slot : number ; status : string ; path : string ; error ?: string } [ ] > ( [ ] ) ;
278+ const [ hasActive , setHasActive ] = useState ( true ) ;
279+
278280 useEffect ( ( ) => {
281+ if ( ! hasActive ) return ;
279282 const poll = setInterval ( async ( ) => {
280283 try {
281284 const data = await ( await fetch ( "/api/index-status" ) ) . json ( ) ;
282285 setJobs ( data ) ;
283- if ( data . length > 0 && data . every ( ( j : { status : string } ) => j . status !== "indexing" ) ) onDone ( ) ;
284- } catch { /* */ }
286+ const stillIndexing = data . some ( ( j : { status : string } ) => j . status === "indexing" ) ;
287+ if ( ! stillIndexing ) {
288+ setHasActive ( false ) ;
289+ const hasErrors = data . some ( ( j : { status : string } ) => j . status === "error" ) ;
290+ if ( ! hasErrors ) {
291+ onDone ( ) ;
292+ }
293+ }
294+ } catch ( error ) {
295+ console . error ( "[IndexProgress] Poll failed:" , error ) ;
296+ }
285297 } , 2000 ) ;
286298 return ( ) => clearInterval ( poll ) ;
287- } , [ onDone ] ) ;
299+ } , [ onDone , hasActive ] ) ;
300+
288301 const active = jobs . filter ( ( j ) => j . status === "indexing" ) ;
289- if ( active . length === 0 ) return null ;
302+ const errors = jobs . filter ( ( j ) => j . status === "error" ) ;
303+
304+ if ( active . length === 0 && errors . length === 0 ) return null ;
305+
290306 return (
291307 < div className = "rounded-xl border border-primary/20 bg-primary/5 p-4 mb-6" >
292308 { active . map ( ( j ) => (
@@ -298,6 +314,26 @@ function IndexProgress({ onDone }: { onDone: () => void }) {
298314 </ div >
299315 </ div >
300316 ) ) }
317+ { errors . map ( ( j ) => (
318+ < div key = { j . slot } className = "flex items-start gap-3 mt-3 first:mt-0 p-3 rounded-lg border border-destructive/20 bg-destructive/5 text-destructive" >
319+ < span className = "text-[14px]" > ⚠️</ span >
320+ < div className = "flex-1 min-w-0" >
321+ < p className = "text-[12px] font-semibold" > Indexing Failed</ p >
322+ < p className = "text-[11px] font-mono truncate" > { j . path } </ p >
323+ { j . error && < p className = "text-[10px] opacity-75 mt-1 font-mono" > { j . error } </ p > }
324+ </ div >
325+ </ div >
326+ ) ) }
327+ { errors . length > 0 && (
328+ < div className = "flex justify-end mt-3" >
329+ < button
330+ onClick = { onDone }
331+ className = "px-3 py-1 rounded bg-destructive/10 hover:bg-destructive/20 text-destructive text-[11px] font-medium transition-all"
332+ >
333+ Dismiss
334+ </ button >
335+ </ div >
336+ ) }
301337 </ div >
302338 ) ;
303339}
0 commit comments