From 3f1b99cac4228c9ed1dee81ef0b0051f9112bdfa Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Tue, 14 Apr 2026 16:40:19 +0530 Subject: [PATCH 1/2] fix: handle navigation when all files are harmful content When all uploaded files contain harmful content, the backend processes them very fast (before WebSocket connects), causing the UI to get stuck loading indefinitely. This fix: - Detects already-completed batches on initial fetch and navigates directly - Checks both batch status and individual file terminal states - Adds navigation guard (useRef) to prevent duplicate navigations - Prevents resetting allFilesCompleted state after it's been finalized Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/frontend/src/pages/modernizationPage.tsx | 29 ++++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/frontend/src/pages/modernizationPage.tsx b/src/frontend/src/pages/modernizationPage.tsx index eb22ed07..d3cd69d9 100644 --- a/src/frontend/src/pages/modernizationPage.tsx +++ b/src/frontend/src/pages/modernizationPage.tsx @@ -31,7 +31,7 @@ import { Light as SyntaxHighlighter } from "react-syntax-highlighter" import { vs } from "react-syntax-highlighter/dist/esm/styles/hljs" import sql from "react-syntax-highlighter/dist/cjs/languages/hljs/sql" import { useNavigate, useParams } from "react-router-dom" -import { useState, useEffect, useCallback } from "react" +import { useState, useEffect, useCallback, useRef } from "react" import { getApiUrl, headerBuilder } from '../api/config'; import BatchHistoryPanel from "../components/batchHistoryPanel" import PanelRight from "../components/Panels/PanelRight"; @@ -501,6 +501,7 @@ const ModernizationPage = () => { const [isZipButtonDisabled, setIsZipButtonDisabled] = useState(true); const [fileLoading, setFileLoading] = useState(false); const [lastActivityTime, setLastActivityTime] = useState(Date.now()); + const hasNavigatedRef = useRef(false); //const [pageLoadTime] = useState(Date.now()); // Fetch file content when a file is selected @@ -536,12 +537,22 @@ const ModernizationPage = () => { setBatchSummary(data); if (data) { - const batchCompleted = data.status?.toLowerCase() === "completed" || data.status === "failed"; - if (batchCompleted) { + const batchCompleted = data.status?.toLowerCase() === "completed" || data.status?.toLowerCase() === "failed"; + const allFilesTerminal = data.files.every((file: any) => + ["completed", "failed", "error"].includes(file.status?.toLowerCase() || "") + ); + + if (batchCompleted || allFilesTerminal) { setAllFilesCompleted(true); if (data.hasFiles > 0) { setIsZipButtonDisabled(false); } + // Batch already finished (e.g., all files were harmful content) — navigate directly + if (!hasNavigatedRef.current) { + hasNavigatedRef.current = true; + navigate(`/batch-view/${batchId}`); + return; + } } // Transform the server response to an array of your FileItem objects const fileItems: FileItem[] = data.files.map((file: any, index: number) => ({ @@ -725,7 +736,10 @@ const ModernizationPage = () => { // Update files state when Redux fileList changes useEffect(() => { if (reduxFileList && reduxFileList.length > 0) { - setAllFilesCompleted(false); + // Only reset completion state if not already finalized + if (!allFilesCompleted) { + setAllFilesCompleted(false); + } // Map the Redux fileList to our FileItem format const fileItems: FileItem[] = reduxFileList.filter(file => file.type !== 'summary').map((file: any, index: number) => ({ @@ -832,8 +846,11 @@ const ModernizationPage = () => { }); // Navigate only after all files have reached terminal states. - console.log("Processing complete (all files done), navigating to batch view page"); - navigate(`/batch-view/${batchId}`); + if (!hasNavigatedRef.current) { + hasNavigatedRef.current = true; + console.log("Processing complete (all files done), navigating to batch view page"); + navigate(`/batch-view/${batchId}`); + } } } catch (err) { console.error("Failed to update summary status:", err); From 73ed7ebb3ad1ca63fdfca203fd4619f3c536a468 Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Tue, 14 Apr 2026 22:16:46 +0530 Subject: [PATCH 2/2] fix: add fallback polling for missed WebSocket events The initial fix only handled the case where processing was already complete on initial page load. This adds a 5-second polling fallback that re-fetches batch summary to detect completion when WebSocket events are missed (e.g., all harmful content files processed before WebSocket connected). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/frontend/src/pages/modernizationPage.tsx | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/frontend/src/pages/modernizationPage.tsx b/src/frontend/src/pages/modernizationPage.tsx index d3cd69d9..7752908f 100644 --- a/src/frontend/src/pages/modernizationPage.tsx +++ b/src/frontend/src/pages/modernizationPage.tsx @@ -1013,6 +1013,43 @@ useEffect(() => { return () => clearInterval(checkInactivity); }, [lastActivityTime, files, allFilesCompleted, updateSummaryStatus, navigate, batchId]); + // Fallback polling: periodically re-fetch batch summary to catch cases where + // WebSocket events were missed (e.g., all files were harmful and processed + // before WebSocket connected). Polls every 5 seconds until all files are done. + useEffect(() => { + if (allFilesCompleted || !batchId || hasNavigatedRef.current) return; + + const pollInterval = setInterval(async () => { + if (hasNavigatedRef.current || allFilesCompleted) { + clearInterval(pollInterval); + return; + } + try { + const data = await fetchBatchSummary(batchId); + if (!data) return; + + const batchTerminal = ["completed", "failed"].includes(data.status?.toLowerCase() || ""); + const allTerminal = data.files.every((file: any) => + ["completed", "failed", "error"].includes(file.status?.toLowerCase() || "") + ); + + if (batchTerminal || allTerminal) { + console.log("Fallback poll detected batch completion, navigating to batch view"); + clearInterval(pollInterval); + setAllFilesCompleted(true); + if (!hasNavigatedRef.current) { + hasNavigatedRef.current = true; + navigate(`/batch-view/${batchId}`); + } + } + } catch (err) { + console.error("Fallback poll error:", err); + } + }, 5000); + + return () => clearInterval(pollInterval); + }, [batchId, allFilesCompleted, navigate]); + useEffect(() => { console.log('Current files state:', files);