feat(frontend): add status page for loading dataset
This commit is contained in:
111
frontend/src/pages/DatasetStatus.tsx
Normal file
111
frontend/src/pages/DatasetStatus.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import StatsStyling from "../styles/stats_styling";
|
||||
|
||||
type DatasetStatusResponse = {
|
||||
status?: "processing" | "complete" | "error";
|
||||
status_message?: string | null;
|
||||
completed_at?: string | null;
|
||||
};
|
||||
|
||||
const styles = StatsStyling;
|
||||
const API_BASE_URL = "http://localhost:5000";
|
||||
|
||||
const DatasetStatusPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const { datasetId } = useParams<{ datasetId: string }>();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [status, setStatus] = useState<DatasetStatusResponse["status"]>("processing");
|
||||
const [statusMessage, setStatusMessage] = useState("");
|
||||
const parsedDatasetId = useMemo(() => Number(datasetId), [datasetId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!Number.isInteger(parsedDatasetId) || parsedDatasetId <= 0) {
|
||||
setLoading(false);
|
||||
setStatus("error");
|
||||
setStatusMessage("Invalid dataset id.");
|
||||
return;
|
||||
}
|
||||
|
||||
let pollTimer: number | undefined;
|
||||
|
||||
const pollStatus = async () => {
|
||||
try {
|
||||
const response = await axios.get<DatasetStatusResponse>(
|
||||
`${API_BASE_URL}/dataset/${parsedDatasetId}/status`
|
||||
);
|
||||
|
||||
const nextStatus = response.data.status ?? "processing";
|
||||
setStatus(nextStatus);
|
||||
setStatusMessage(String(response.data.status_message ?? ""));
|
||||
setLoading(false);
|
||||
|
||||
if (nextStatus === "complete") {
|
||||
window.setTimeout(() => {
|
||||
navigate("/stats", { replace: true });
|
||||
}, 800);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
setLoading(false);
|
||||
setStatus("error");
|
||||
if (axios.isAxiosError(error)) {
|
||||
const message = String(error.response?.data?.error || error.message || "Request failed");
|
||||
setStatusMessage(message);
|
||||
} else {
|
||||
setStatusMessage("Unable to fetch dataset status.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void pollStatus();
|
||||
pollTimer = window.setInterval(() => {
|
||||
if (status !== "complete" && status !== "error") {
|
||||
void pollStatus();
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
return () => {
|
||||
if (pollTimer) {
|
||||
window.clearInterval(pollTimer);
|
||||
}
|
||||
};
|
||||
}, [navigate, parsedDatasetId, status]);
|
||||
|
||||
const isProcessing = loading || status === "processing";
|
||||
const isError = status === "error";
|
||||
|
||||
return (
|
||||
<div style={styles.page}>
|
||||
<div style={{ ...styles.container, maxWidth: 720 }}>
|
||||
<div style={{ ...styles.card, marginTop: 28 }}>
|
||||
<h1 style={{ margin: 0, fontSize: 28, color: "#111827" }}>
|
||||
{isProcessing ? "Processing dataset..." : isError ? "Dataset processing failed" : "Dataset ready"}
|
||||
</h1>
|
||||
|
||||
<p style={{ ...styles.sectionSubtitle, marginTop: 10 }}>
|
||||
{isProcessing &&
|
||||
"Your dataset is being analyzed. This page will redirect to stats automatically once complete."}
|
||||
{isError && "There was an issue while processing your dataset. Please review the error details."}
|
||||
{status === "complete" && "Processing complete. Redirecting to your stats now..."}
|
||||
</p>
|
||||
|
||||
<div
|
||||
style={{
|
||||
...styles.card,
|
||||
marginTop: 12,
|
||||
borderColor: isError ? "rgba(185, 28, 28, 0.28)" : "rgba(0,0,0,0.06)",
|
||||
background: isError ? "#fff5f5" : "#ffffff",
|
||||
color: isError ? "#991b1b" : "#374151",
|
||||
boxShadow: "none",
|
||||
}}
|
||||
>
|
||||
{statusMessage || (isProcessing ? "Waiting for updates from the worker queue..." : "No details provided.")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DatasetStatusPage;
|
||||
Reference in New Issue
Block a user