Skip to content

Commit 9e22f06

Browse files
Merge pull request #256 from microsoft/dev
fix: merging dev to main
2 parents 908a087 + b0b6b28 commit 9e22f06

File tree

5 files changed

+120
-28
lines changed

5 files changed

+120
-28
lines changed

.github/workflows/broken-links-checker.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
uses: lycheeverse/lychee-action@v2.6.1
3838
with:
3939
args: >
40-
--verbose --exclude-mail --no-progress --exclude ^https?://
40+
--verbose --no-progress --exclude ^https?://
4141
${{ steps.changed-markdown-files.outputs.all_changed_files }}
4242
failIfEmpty: false
4343
env:
@@ -50,7 +50,7 @@ jobs:
5050
uses: lycheeverse/lychee-action@v2.6.1
5151
with:
5252
args: >
53-
--verbose --exclude-mail --no-progress --exclude ^https?://
53+
--verbose --no-progress --exclude ^https?://
5454
'**/*.md'
5555
failIfEmpty: false
5656
env:

docs/DeploymentGuide.md

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ You can run this solution using GitHub Codespaces. The button will open a web-ba
7272
</details>
7373

7474
<details>
75-
<summary><b>Deploy in VS Code</b></summary>
75+
<summary><b>Deploy in VS Code Dev Containers</b></summary>
7676

7777
### VS Code Dev Containers
7878

@@ -122,22 +122,7 @@ Consider the following settings during your deployment to modify specific settin
122122
<details>
123123
<Summary><b>Configurable Deployment Settings</b></Summary>
124124

125-
When you start the deployment, most parameters will have **default values**, but you can update the following settings by following the steps [here](../docs/CustomizingAzdParameters.md):
126-
127-
| **Setting** | **Description** | **Default value** |
128-
|----------------------------------|------------------------------------------------------------------------------------------------------|----------------------------|
129-
| **Azure Region** | The region where resources will be created. | East US |
130-
| **Resource Prefix** | Prefix for all resources created by this template. This prefix will be used to create unique names for all resources. The prefix must be unique within the resource group. | azdtemp |
131-
| **Capacity** | Configure capacity for **gpt-4o**. | 200 |
132-
| **Model Deployment Type** | Change the Model Deployment Type (allowed values: Standard, GlobalStandard). | GlobalStandard |
133-
| **Model Name** | Set the Model Name (allowed values: gpt-4o). | gpt-4o |
134-
| **Model Version** | Set the Azure model version (allowed values: 2024-08-06). | 2024-08-06 |
135-
| **Image Tag** | Set the Image tag (allowed values: latest, dev, hotfix). | latest |
136-
| **Existing Log analytics workspace** | To reuse the existing Log analytics workspace Id. | `<Existing Workspace Id>` |
137-
| **Jumpbox Admin Username** | Specifies the administrator username for the Jumpbox Virtual Machine. | `JumpboxAdminUser` |
138-
| **Jumpbox Admin Password** | Specifies the administrator password for the Jumpbox Virtual Machine. | `JumpboxAdminP@ssw0rd1234!` |
139-
| **Cosmos DB Secondary Location** | Specifies the secondary region for Cosmos DB. Set this if redundancy (`enableRedundancy`) is enabled. | `<Secondary Region>` |
140-
125+
When you start the deployment, most parameters will have **default values**, but you can update the following settings by following the steps [here](../docs/CustomizingAzdParameters.md)
141126

142127
This accelerator can be configured to use authentication.
143128

src/frontend/src/components/uploadButton.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,16 +339,15 @@ const FileUploadZone: React.FC<FileUploadZoneProps> = ({
339339
};
340340

341341
if (uploadingFiles.length > 0) {
342-
// First navigate to loading page before starting processing
342+
// First navigate to modernization page to show progress
343343
navigate(`/batch-process/${batchId}`);
344344

345-
// Then dispatch the action and wait for it to complete
345+
// Then dispatch the action
346346
try {
347347
dispatch(startProcessing(payload));
348-
return batchId; // Return the batchId after processing completes
348+
return batchId;
349349
} catch (error) {
350350
console.error('Processing failed:', error);
351-
// Still return the batchId even if processing failed
352351
return batchId;
353352
}
354353
}

src/frontend/src/pages/modernizationPage.tsx

Lines changed: 108 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Header from "../components/Header/Header";
44
import HeaderTools from "../components/Header/HeaderTools";
55
import PanelLeft from "../components/Panels/PanelLeft";
66
import webSocketService from "../api/WebSocketService";
7+
import { useSelector } from 'react-redux';
78
import {
89
Button,
910
Text,
@@ -478,6 +479,9 @@ const ModernizationPage = () => {
478479
const { batchId } = useParams<{ batchId: string }>();
479480
const navigate = useNavigate()
480481

482+
// Redux state to listen for start processing completion
483+
const batchState = useSelector((state: any) => state.batch);
484+
481485
const [batchSummary, setBatchSummary] = useState<BatchSummary | null>(null);
482486
const styles = useStyles()
483487
const [text, setText] = useState("");
@@ -498,6 +502,8 @@ const ModernizationPage = () => {
498502
const [isZipButtonDisabled, setIsZipButtonDisabled] = useState(true);
499503
const [fileLoading, setFileLoading] = useState(false);
500504
const [selectedFileTranslatedContent, setSelectedFileTranslatedContent] = useState<string>("");
505+
const [lastActivityTime, setLastActivityTime] = useState<number>(Date.now());
506+
const [pageLoadTime] = useState<number>(Date.now());
501507

502508
// Fetch file content when a file is selected
503509
useEffect(() => {
@@ -593,6 +599,19 @@ const ModernizationPage = () => {
593599
fetchBatchData(batchId);
594600
}, [batchId]);
595601

602+
// Listen for startProcessing completion and navigate to batch view
603+
useEffect(() => {
604+
if (batchState && !batchState.loading && batchState.status === "Processing completed") {
605+
console.log("Start processing API completed successfully - processing is done!");
606+
607+
// Check if we have the response with batch_id that matches current batchId
608+
if (batchState.batchId === batchId) {
609+
console.log("Processing completed for current batch, navigating to batch view page");
610+
navigate(`/batch-view/${batchId}`);
611+
}
612+
}
613+
}, [batchState.loading, batchState.status, batchState.batchId, batchId, navigate]);
614+
596615
const handleDownloadZip = async () => {
597616
if (batchId) {
598617
try {
@@ -756,7 +775,7 @@ const ModernizationPage = () => {
756775
}
757776

758777
// Update text with file count
759-
setText(`${new Date().toLocaleDateString()} (${fileItems.length} files)`);
778+
setText(`${new Date().toLocaleDateString()} (${fileItems.length} ${fileItems.length === 1 ? 'file' : 'files'})`);
760779
}
761780
}, [reduxFileList, batchId]);
762781

@@ -789,11 +808,39 @@ const ModernizationPage = () => {
789808
try {
790809
const latestBatch = await fetchBatchSummary(batchId!);
791810
setBatchSummary(latestBatch);
811+
812+
// Check if all files are in terminal states OR if the batch itself is marked as completed
792813
const allFilesDone = latestBatch.files.every(file =>
793814
["completed", "failed", "error"].includes(file.status?.toLowerCase() || "")
794815
);
816+
817+
// Also check if batch status indicates completion (for cases where some files remain queued)
818+
const batchCompleted = latestBatch.status?.toLowerCase() === "completed" ||
819+
latestBatch.status?.toLowerCase() === "failed";
820+
821+
// Special handling for stuck processing files - if no completed files and long time passed
822+
const hasProcessingFiles = latestBatch.files.some(file =>
823+
file.status?.toLowerCase() === "in_process"
824+
);
825+
const hasCompletedFiles = latestBatch.files.some(file =>
826+
file.status?.toLowerCase() === "completed"
827+
);
828+
const timeSinceLastActivity = Date.now() - lastActivityTime;
829+
const likelyStuckProcessing = hasProcessingFiles &&
830+
!hasCompletedFiles &&
831+
timeSinceLastActivity > 60000; // 60 seconds of no activity
832+
833+
// Consider processing done if either all files are terminal OR batch is marked complete OR files appear stuck
834+
const processingComplete = allFilesDone || batchCompleted || likelyStuckProcessing;
795835

796-
if (allFilesDone) {
836+
if (processingComplete) {
837+
console.log("Processing complete detected:", {
838+
allFilesDone,
839+
batchCompleted,
840+
likelyStuckProcessing,
841+
batchStatus: latestBatch.status,
842+
timeSinceActivity: timeSinceLastActivity
843+
});
797844
setAllFilesCompleted(true);
798845
const hasUsableFile = latestBatch.files.some(file =>
799846
file.status?.toLowerCase() === "completed" &&
@@ -818,6 +865,10 @@ const ModernizationPage = () => {
818865

819866
return updated;
820867
});
868+
869+
// Navigate to batch view page when processing is complete
870+
console.log("Processing complete (either all files done or batch completed), navigating to batch view page");
871+
navigate(`/batch-view/${batchId}`);
821872
}
822873
} catch (err) {
823874
console.error("Failed to update summary status:", err);
@@ -834,6 +885,7 @@ const ModernizationPage = () => {
834885
}
835886

836887
setFileId(data.file_id);
888+
setLastActivityTime(Date.now()); // Update activity time on WebSocket message
837889

838890
const agent = formatAgent(data.agent_type);
839891
const message = formatDescription(data.agent_message);
@@ -896,11 +948,23 @@ useEffect(() => {
896948
file.id === "summary" || // skip summary
897949
["completed", "failed", "error"].includes(file.status?.toLowerCase() || "")
898950
);
951+
952+
// Also check if we have at least one completed file and no files currently processing
953+
const hasCompletedFiles = files.some(file =>
954+
file.id !== "summary" && file.status === "completed"
955+
);
956+
const hasProcessingFiles = files.some(file =>
957+
file.id !== "summary" && file.status === "in_process"
958+
);
959+
960+
// Consider done if all terminal OR (has completed files and no processing files)
961+
const effectivelyDone = areAllFilesTerminal || (hasCompletedFiles && !hasProcessingFiles);
899962

900-
if (files.length > 1 && areAllFilesTerminal && !allFilesCompleted) {
963+
if (files.length > 1 && effectivelyDone && !allFilesCompleted) {
964+
console.log("Files processing appears complete, checking batch status");
901965
updateSummaryStatus();
902966
}
903-
}, [files, allFilesCompleted]);
967+
}, [files, allFilesCompleted, updateSummaryStatus]);
904968

905969

906970
useEffect(() => {
@@ -958,6 +1022,45 @@ useEffect(() => {
9581022
return () => clearTimeout(loadingTimeout);
9591023
}, [progressPercentage, showLoading]);
9601024

1025+
// Add timeout mechanism to navigate if no activity for 30 seconds
1026+
useEffect(() => {
1027+
const checkInactivity = setInterval(() => {
1028+
const timeSinceLastActivity = Date.now() - lastActivityTime;
1029+
const hasCompletedFiles = files.some(file =>
1030+
file.id !== "summary" && file.status === "completed"
1031+
);
1032+
const hasProcessingFiles = files.some(file =>
1033+
file.id !== "summary" && file.status === "in_process"
1034+
);
1035+
const nonSummaryFiles = files.filter(f => f.id !== "summary");
1036+
1037+
// If we have completed files and no activity for 30 seconds, check if we should navigate
1038+
if (hasCompletedFiles && timeSinceLastActivity > 30000 && !allFilesCompleted) {
1039+
console.log("No activity for 30 seconds with completed files, checking final status");
1040+
updateSummaryStatus();
1041+
}
1042+
1043+
// Special case: If only harmful files that are stuck in processing for 60+ seconds
1044+
if (nonSummaryFiles.length > 0 &&
1045+
hasProcessingFiles &&
1046+
!hasCompletedFiles &&
1047+
timeSinceLastActivity > 60000 &&
1048+
!allFilesCompleted) {
1049+
console.log("Files stuck in processing for 60+ seconds, likely failed - checking batch status");
1050+
updateSummaryStatus();
1051+
}
1052+
1053+
// Ultimate fallback: If on page for 2+ minutes with no completion, force navigation
1054+
const timeSincePageLoad = Date.now() - pageLoadTime;
1055+
if (timeSincePageLoad > 120000 && !allFilesCompleted && nonSummaryFiles.length > 0) {
1056+
console.log("Page loaded for 2+ minutes without completion, forcing navigation to batch view");
1057+
navigate(`/batch-view/${batchId}`);
1058+
}
1059+
}, 5000); // Check every 5 seconds
1060+
1061+
return () => clearInterval(checkInactivity);
1062+
}, [lastActivityTime, files, allFilesCompleted, updateSummaryStatus, pageLoadTime, navigate, batchId]);
1063+
9611064

9621065
useEffect(() => {
9631066
console.log('Current files state:', files);
@@ -1218,6 +1321,7 @@ useEffect(() => {
12181321
</div>
12191322

12201323
</Card>
1324+
{expandedSections.includes("errors") && renderErrorContent(batchSummary)}
12211325

12221326
</div>
12231327
</>

src/frontend/src/slices/batchSlice.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ const initialState: {
174174
batchId: string | null;
175175
fileId: string | null;
176176
message: string;
177+
status: string | null;
177178
loading: boolean;
178179
error: string | null;
179180
uploadingFiles: boolean;
@@ -192,6 +193,7 @@ const initialState: {
192193
batchId: null,
193194
fileId: null,
194195
message: '',
196+
status: null,
195197
loading: false,
196198
error: null,
197199
uploadingFiles: false,
@@ -207,6 +209,7 @@ export const batchSlice = createSlice({
207209
state.batchId = null;
208210
state.fileId = null
209211
state.message = '';
212+
state.status = null;
210213
state.error = null;
211214
},
212215
},
@@ -288,7 +291,8 @@ export const batchSlice = createSlice({
288291
if (action.payload) {
289292
console.log("Action Payload", action.payload);
290293
state.batchId = action.payload.batch_id;
291-
state.message = "Processing started successfully";
294+
state.status = action.payload.status; // Store the actual status from backend
295+
state.message = action.payload.message; // Store the actual message from backend
292296
} else {
293297
state.error = "Unexpected response: Payload is undefined.";
294298
}

0 commit comments

Comments
 (0)