diff --git a/src/FetchRequestDetail.tsx b/src/FetchRequestDetail.tsx index 0181f54..dac90e7 100644 --- a/src/FetchRequestDetail.tsx +++ b/src/FetchRequestDetail.tsx @@ -63,39 +63,24 @@ function computeProgressPercent( liveCount: number, seenSteps: Set, stepStats: Record, + txnBlockCount: number, + txnDictCount: number, ): number { if (status === "pending") return 0; if (status === "completed") return 100; - const W_EXTRACT = 10; - const W_RAW = 20; - const W_ENRICH = 50; - const W_SAVE = 20; - let pct = 0; - if (seenSteps.has("raw_lines") || seenSteps.has("txn_blocks")) pct += W_EXTRACT; + if (seenSteps.has("raw_lines") || seenSteps.has("txn_blocks")) pct += 10; - const blocks = stepStats.txn_blocks ?? 0; - if (seenSteps.has("txn_dicts/completed") || status === "raw_expenses_done") { - pct += W_RAW; - } else if (blocks > 0 && liveCount > 0) { - pct += Math.min(1, liveCount / blocks) * W_RAW; + if (txnBlockCount > 0) { + const current = Math.max(liveCount, stepStats.txn_dicts ?? 0); + pct += Math.min(1, current / txnBlockCount) * 20; } - const totalDicts = stepStats.txn_dicts ?? 0; - const enrichCount = stepStats.enrich_count ?? 0; - if (seenSteps.has("enrich/completed") || (seenSteps.has("enrich") && totalDicts > 0 && enrichCount >= totalDicts)) { - pct += W_ENRICH; - } else if (totalDicts > 0 && enrichCount > 0) { - pct += Math.min(1, enrichCount / totalDicts) * W_ENRICH; - } - - const saveCount = stepStats.save_count ?? 0; - if (seenSteps.has("save_expenses/completed") || seenSteps.has("complete/completed")) { - pct += W_SAVE; - } else if (totalDicts > 0 && saveCount > 0) { - pct += Math.min(1, saveCount / totalDicts) * W_SAVE; + if (txnDictCount > 0) { + pct += Math.min(1, (stepStats.enrich_count ?? 0) / txnDictCount) * 50; + pct += Math.min(1, (stepStats.save_count ?? 0) / txnDictCount) * 20; } return Math.round(Math.min(100, pct)); @@ -172,29 +157,37 @@ export default function FetchRequestDetail() { const sseRef = React.useRef(null); const feedRef = React.useRef(null); + const txnBlockCount = React.useMemo(() => { + const blocks = (fetchRequest as any)?.source?.txn_blocks; + if (!blocks) return 0; + return Object.values(blocks).reduce( + (sum: number, list: any) => sum + (Array.isArray(list) ? list.length : 0), + 0, + ); + }, [fetchRequest]); + const stepMessages = React.useMemo(() => { const msgs: Record = {}; const source = (fetchRequest as any)?.source; const rawLineCount = stepStats.raw_lines ?? (source?.raw_lines?.length ?? 0); - const blockCount = stepStats.txn_blocks ?? 0; - if (rawLineCount || blockCount) msgs[0] = blockCount ? `${blockCount} blocks` : `${rawLineCount} raw lines`; + if (rawLineCount) msgs[0] = `${rawLineCount}`; const sourceDictCount = source?.txn_dict_count ?? source?.txn_dicts_count ?? 0; - const dictCount = stepStats.txn_dicts ?? liveParsedCount ?? sourceDictCount; - if (dictCount) msgs[1] = `${dictCount} dicts`; + const dictLive = liveParsedCount ?? stepStats.txn_dicts ?? 0; + const dictCurrent = Math.max(dictLive, sourceDictCount); + if (dictCurrent && txnBlockCount) msgs[1] = `${dictCurrent}/${txnBlockCount}`; + else if (dictCurrent) msgs[1] = `${dictCurrent}`; - if (stepStats.enrich_count) msgs[2] = `${stepStats.enrich_count} enriched`; - else if (["enriched_done", "completed"].includes((fetchRequest as any)?.status)) - msgs[2] = "done"; + const txnDictDenom = stepStats.txn_dicts ?? sourceDictCount; + if (stepStats.enrich_count && txnDictDenom) msgs[2] = `${stepStats.enrich_count}/${txnDictDenom}`; + else if (stepStats.enrich_count) msgs[2] = `${stepStats.enrich_count}`; - if (stepStats.save_count) msgs[3] = `${stepStats.save_count} saved`; - else if ((fetchRequest as any)?.status === "completed") - msgs[3] = (fetchRequest as any)?.completed_at - ? new Date((fetchRequest as any).completed_at).toLocaleString() : "done"; + if (stepStats.save_count && txnDictDenom) msgs[3] = `${stepStats.save_count}/${txnDictDenom}`; + else if (stepStats.save_count) msgs[3] = `${stepStats.save_count}`; return msgs; - }, [fetchRequest, stepStats, liveParsedCount]); + }, [fetchRequest, stepStats, liveParsedCount, txnBlockCount]); React.useEffect(() => { if (!id || !config?.baseUrl) return; @@ -284,16 +277,6 @@ export default function FetchRequestDetail() { return steps; }, [sseEvents]); - const progressPercent = React.useMemo( - () => computeProgressPercent( - (fetchRequest as any)?.status as FetchRequestStatus ?? "pending", - liveParsedCount ?? 0, - seenSteps, - stepStats, - ), - [fetchRequest, liveParsedCount, seenSteps, stepStats], - ); - const displayParsedCount = React.useMemo(() => { if (liveParsedCount && liveParsedCount > 0) return liveParsedCount; const source = (fetchRequest as any)?.source; @@ -304,6 +287,24 @@ export default function FetchRequestDetail() { return 0; }, [liveParsedCount, fetchRequest]); + const txnDictCount = React.useMemo(() => { + const source = (fetchRequest as any)?.source; + if (stepStats.txn_dicts && stepStats.txn_dicts > 0) return stepStats.txn_dicts; + return source?.txn_dict_count ?? source?.txn_dicts_count ?? 0; + }, [fetchRequest, stepStats]); + + const progressPercent = React.useMemo( + () => computeProgressPercent( + (fetchRequest as any)?.status as FetchRequestStatus ?? "pending", + displayParsedCount, + seenSteps, + stepStats, + txnBlockCount, + txnDictCount, + ), + [fetchRequest, displayParsedCount, seenSteps, stepStats, txnBlockCount, txnDictCount], + ); + const handleRetry = async () => { if (!id) return; try {