Skip to content

Commit a59df85

Browse files
Merge pull request #416 from microsoft/psl-navigation-fix
fix: Infinite loading when uploaded one harmful content file
2 parents 049b9e5 + 73ed7eb commit a59df85

1 file changed

Lines changed: 60 additions & 6 deletions

File tree

src/frontend/src/pages/modernizationPage.tsx

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { Light as SyntaxHighlighter } from "react-syntax-highlighter"
3131
import { vs } from "react-syntax-highlighter/dist/esm/styles/hljs"
3232
import sql from "react-syntax-highlighter/dist/cjs/languages/hljs/sql"
3333
import { useNavigate, useParams } from "react-router-dom"
34-
import { useState, useEffect, useCallback } from "react"
34+
import { useState, useEffect, useCallback, useRef } from "react"
3535
import { getApiUrl, headerBuilder } from '../api/config';
3636
import BatchHistoryPanel from "../components/batchHistoryPanel"
3737
import PanelRight from "../components/Panels/PanelRight";
@@ -501,6 +501,7 @@ const ModernizationPage = () => {
501501
const [isZipButtonDisabled, setIsZipButtonDisabled] = useState(true);
502502
const [fileLoading, setFileLoading] = useState(false);
503503
const [lastActivityTime, setLastActivityTime] = useState<number>(Date.now());
504+
const hasNavigatedRef = useRef(false);
504505
//const [pageLoadTime] = useState<number>(Date.now());
505506

506507
// Fetch file content when a file is selected
@@ -536,12 +537,22 @@ const ModernizationPage = () => {
536537
setBatchSummary(data);
537538
if (data) {
538539

539-
const batchCompleted = data.status?.toLowerCase() === "completed" || data.status === "failed";
540-
if (batchCompleted) {
540+
const batchCompleted = data.status?.toLowerCase() === "completed" || data.status?.toLowerCase() === "failed";
541+
const allFilesTerminal = data.files.every((file: any) =>
542+
["completed", "failed", "error"].includes(file.status?.toLowerCase() || "")
543+
);
544+
545+
if (batchCompleted || allFilesTerminal) {
541546
setAllFilesCompleted(true);
542547
if (data.hasFiles > 0) {
543548
setIsZipButtonDisabled(false);
544549
}
550+
// Batch already finished (e.g., all files were harmful content) — navigate directly
551+
if (!hasNavigatedRef.current) {
552+
hasNavigatedRef.current = true;
553+
navigate(`/batch-view/${batchId}`);
554+
return;
555+
}
545556
}
546557
// Transform the server response to an array of your FileItem objects
547558
const fileItems: FileItem[] = data.files.map((file: any, index: number) => ({
@@ -725,7 +736,10 @@ const ModernizationPage = () => {
725736
// Update files state when Redux fileList changes
726737
useEffect(() => {
727738
if (reduxFileList && reduxFileList.length > 0) {
728-
setAllFilesCompleted(false);
739+
// Only reset completion state if not already finalized
740+
if (!allFilesCompleted) {
741+
setAllFilesCompleted(false);
742+
}
729743
// Map the Redux fileList to our FileItem format
730744
const fileItems: FileItem[] = reduxFileList.filter(file => file.type !== 'summary').map((file: any, index: number) => ({
731745

@@ -832,8 +846,11 @@ const ModernizationPage = () => {
832846
});
833847

834848
// Navigate only after all files have reached terminal states.
835-
console.log("Processing complete (all files done), navigating to batch view page");
836-
navigate(`/batch-view/${batchId}`);
849+
if (!hasNavigatedRef.current) {
850+
hasNavigatedRef.current = true;
851+
console.log("Processing complete (all files done), navigating to batch view page");
852+
navigate(`/batch-view/${batchId}`);
853+
}
837854
}
838855
} catch (err) {
839856
console.error("Failed to update summary status:", err);
@@ -996,6 +1013,43 @@ useEffect(() => {
9961013
return () => clearInterval(checkInactivity);
9971014
}, [lastActivityTime, files, allFilesCompleted, updateSummaryStatus, navigate, batchId]);
9981015

1016+
// Fallback polling: periodically re-fetch batch summary to catch cases where
1017+
// WebSocket events were missed (e.g., all files were harmful and processed
1018+
// before WebSocket connected). Polls every 5 seconds until all files are done.
1019+
useEffect(() => {
1020+
if (allFilesCompleted || !batchId || hasNavigatedRef.current) return;
1021+
1022+
const pollInterval = setInterval(async () => {
1023+
if (hasNavigatedRef.current || allFilesCompleted) {
1024+
clearInterval(pollInterval);
1025+
return;
1026+
}
1027+
try {
1028+
const data = await fetchBatchSummary(batchId);
1029+
if (!data) return;
1030+
1031+
const batchTerminal = ["completed", "failed"].includes(data.status?.toLowerCase() || "");
1032+
const allTerminal = data.files.every((file: any) =>
1033+
["completed", "failed", "error"].includes(file.status?.toLowerCase() || "")
1034+
);
1035+
1036+
if (batchTerminal || allTerminal) {
1037+
console.log("Fallback poll detected batch completion, navigating to batch view");
1038+
clearInterval(pollInterval);
1039+
setAllFilesCompleted(true);
1040+
if (!hasNavigatedRef.current) {
1041+
hasNavigatedRef.current = true;
1042+
navigate(`/batch-view/${batchId}`);
1043+
}
1044+
}
1045+
} catch (err) {
1046+
console.error("Fallback poll error:", err);
1047+
}
1048+
}, 5000);
1049+
1050+
return () => clearInterval(pollInterval);
1051+
}, [batchId, allFilesCompleted, navigate]);
1052+
9991053

10001054
useEffect(() => {
10011055
console.log('Current files state:', files);

0 commit comments

Comments
 (0)