/* ============================================ INGESTION DASHBOARD — Upload + live polling ============================================ */ function IngestionScreen({ onNavigate }) { const [drag, setDrag] = useState(false); const [tasks, setTasks] = useState([]); // [{task_id, filename, status, processed_pages, total_pages, ...}] const [activeTaskId, setActiveTaskId] = useState(localStorage.getItem(window.API.TASK_KEY)); const [uploading, setUploading] = useState(false); const [error, setError] = useState(null); const fileInputRef = useRef(null); // Resume polling on mount if there's a task_id in localStorage. useEffect(() => { if (!activeTaskId) return; let stop = false; const tick = async () => { try { const data = await window.API.status(activeTaskId); if (stop) return; setTasks((prev) => { const i = prev.findIndex((t) => t.task_id === activeTaskId); if (i === -1) return [data, ...prev]; const next = [...prev]; next[i] = data; return next; }); if (data.status === "COMPLETED" || data.status === "FAILED") { localStorage.removeItem(window.API.TASK_KEY); setActiveTaskId(null); } else { setTimeout(tick, 3000); } } catch (err) { // 404 or 401 — give up on this task if (err.status === 404 || err.status === 401) { localStorage.removeItem(window.API.TASK_KEY); setActiveTaskId(null); } else if (!stop) { setTimeout(tick, 5000); } } }; tick(); return () => { stop = true; }; }, [activeTaskId]); const onPick = async (file) => { if (!file) return; if (!file.name.toLowerCase().endsWith(".pdf")) { setError("Only PDF files are accepted."); return; } setError(null); setUploading(true); try { const res = await window.API.upload(file); localStorage.setItem(window.API.TASK_KEY, res.task_id); setTasks((prev) => [ { task_id: res.task_id, filename: res.filename, status: "QUEUED", processed_pages: 0, total_pages: null }, ...prev, ]); setActiveTaskId(res.task_id); } catch (err) { setError(err.message || "Upload failed."); } finally { setUploading(false); } }; const onDropFile = (e) => { e.preventDefault(); setDrag(false); onPick(e.dataTransfer.files?.[0]); }; const stats = { queued: tasks.filter((t) => t.status === "QUEUED").length, processing: tasks.filter((t) => t.status === "PROCESSING").length, failed: tasks.filter((t) => t.status === "FAILED").length, completed: tasks.filter((t) => t.status === "COMPLETED").length, }; return ( <>
Upload a PDF — progress polled every 3 seconds.
PDF only · max 500 MB · machine-readable (no OCR in v1)
| Document | Status | Progress | Pages |
|---|---|---|---|
|
{r.filename}
{r.task_id.slice(0, 8)}
|
|
{r.status === "FAILED" ? (r.error_message || "Failed") :
r.status === "COMPLETED" ? "Indexed" :
r.status === "PROCESSING" ? "Embedding chunks…" :
"Waiting for worker"}
|
{r.processed_pages || 0}{r.total_pages ? ` / ${r.total_pages}` : ""} |