Add Fetch Request pipeline UI with real-time SSEs #8
@@ -97,6 +97,33 @@ export default function FetchRequestDetail() {
|
|||||||
const resolveMutation = useResolveAmbiguity();
|
const resolveMutation = useResolveAmbiguity();
|
||||||
const { data: ambiguities, refetch: refetchAmbiguities } = useFetchRequestAmbiguities(id!);
|
const { data: ambiguities, refetch: refetchAmbiguities } = useFetchRequestAmbiguities(id!);
|
||||||
|
|
||||||
|
const stepMessages = React.useMemo(() => {
|
||||||
|
const msgs: Record<number, string> = {};
|
||||||
|
const source = (fetchRequest as any)?.source;
|
||||||
|
|
||||||
|
if (source?.raw_lines?.length)
|
||||||
|
msgs[0] = `${source.raw_lines.length} raw lines`;
|
||||||
|
|
||||||
|
const blocks = source?.txn_blocks ?? {};
|
||||||
|
const dicts = source?.txn_dicts ?? [];
|
||||||
|
const blockCount = typeof blocks === "object"
|
||||||
|
? Object.keys(blocks).length : Array.isArray(blocks) ? blocks.length : 0;
|
||||||
|
if (blockCount || dicts.length) {
|
||||||
|
const parts: string[] = [];
|
||||||
|
if (blockCount) parts.push(`${blockCount} blocks`);
|
||||||
|
if (dicts.length) parts.push(`${dicts.length} dicts`);
|
||||||
|
msgs[1] = parts.join(" · ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (["enriched_done", "completed"].includes((fetchRequest as any)?.status))
|
||||||
|
msgs[2] = "done";
|
||||||
|
if ((fetchRequest as any)?.status === "completed")
|
||||||
|
msgs[3] = (fetchRequest as any)?.completed_at
|
||||||
|
? new Date((fetchRequest as any).completed_at).toLocaleString() : "done";
|
||||||
|
|
||||||
|
return msgs;
|
||||||
|
}, [fetchRequest]);
|
||||||
|
|
||||||
const [sseEvents, setSseEvents] = React.useState<SSEEvent[]>([]);
|
const [sseEvents, setSseEvents] = React.useState<SSEEvent[]>([]);
|
||||||
const [sseConnected, setSseConnected] = React.useState(false);
|
const [sseConnected, setSseConnected] = React.useState(false);
|
||||||
const sseRef = React.useRef<EventSource | null>(null);
|
const sseRef = React.useRef<EventSource | null>(null);
|
||||||
@@ -284,12 +311,19 @@ export default function FetchRequestDetail() {
|
|||||||
icon = <Typography variant="caption" color="text.disabled">{index + 1}</Typography>;
|
icon = <Typography variant="caption" color="text.disabled">{index + 1}</Typography>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stepMsg = stepMessages[index];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Step key={label}>
|
<Step key={label}>
|
||||||
<StepLabel
|
<StepLabel
|
||||||
StepIconComponent={() => <Box sx={{ display: "flex", alignItems: "center" }}>{icon}</Box>}
|
StepIconComponent={() => <Box sx={{ display: "flex", alignItems: "center" }}>{icon}</Box>}
|
||||||
>
|
>
|
||||||
{label}
|
<Typography variant="body2" fontWeight={600}>{label}</Typography>
|
||||||
|
{stepMsg && (
|
||||||
|
<Typography variant="caption" color="text.secondary" sx={{ display: "block", lineHeight: 1.2 }}>
|
||||||
|
{stepMsg}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
</StepLabel>
|
</StepLabel>
|
||||||
</Step>
|
</Step>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ export type FetchRequestStatus =
|
|||||||
export interface FileSource {
|
export interface FileSource {
|
||||||
path: string;
|
path: string;
|
||||||
format: string;
|
format: string;
|
||||||
|
raw_lines?: string[];
|
||||||
|
txn_blocks?: Record<string, any>;
|
||||||
|
txn_dicts?: Record<string, any>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmailSource {
|
export interface EmailSource {
|
||||||
|
|||||||
Reference in New Issue
Block a user