Skip to content

Commit c67bf0c

Browse files
committed
fix(ui): handle indexing errors in frontend and ignore local npm cache
1 parent 684e35b commit c67bf0c

2 files changed

Lines changed: 44 additions & 5 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,6 @@ soak-results/
5959

6060
# LSP originality-check reference cache (scripts/check-lsp-originality.sh)
6161
.lsp-refs/
62+
63+
# Local npm cache
64+
graph-ui/.npm-cache-local/

graph-ui/src/components/StatsTab.tsx

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -274,19 +274,35 @@ function CreateIndexModal({ onClose, onCreated }: { onClose: () => void; onCreat
274274
/* ── Index Progress ─────────────────────────────────────── */
275275

276276
function 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

Comments
 (0)