From 20719088ffbe72bc0a63301c0c6c11f73f573a61 Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Mon, 23 Mar 2026 19:02:22 +0530 Subject: [PATCH 1/6] fix bug and Managed identity changes --- src/backend/.env.sample | 4 ++-- src/backend/common/config/config.py | 18 +++++++++------- src/backend/sql_agents/convert_script.py | 7 +++++-- src/frontend/.dockerignore | 3 +++ src/frontend/src/pages/modernizationPage.tsx | 22 +++++++------------- 5 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 src/frontend/.dockerignore diff --git a/src/backend/.env.sample b/src/backend/.env.sample index 3cced35e..2de06e7a 100644 --- a/src/backend/.env.sample +++ b/src/backend/.env.sample @@ -28,9 +28,9 @@ AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = "" APP_ENV = "dev" # Basic application logging (default: INFO level) -AZURE_BASIC_LOGGING_LEVEL=INFO +AZURE_BASIC_LOGGING_LEVEL=DEBUG # Azure package logging (default: WARNING level to suppress INFO) -AZURE_PACKAGE_LOGGING_LEVEL=WARNING +AZURE_PACKAGE_LOGGING_LEVEL=DEBUG # Comma-separated list of specific logger names to configure (default: empty - no custom loggers) # Example: AZURE_LOGGING_PACKAGES=azure.identity.aio._internal,azure.monitor.opentelemetry.exporter.export._base AZURE_LOGGING_PACKAGES= \ No newline at end of file diff --git a/src/backend/common/config/config.py b/src/backend/common/config/config.py index faccdde1..18fcb15b 100644 --- a/src/backend/common/config/config.py +++ b/src/backend/common/config/config.py @@ -15,6 +15,8 @@ import os from azure.identity.aio import ClientSecretCredential +from azure.identity.aio import DefaultAzureCredential as AioDefaultAzureCredential +from azure.identity.aio import ManagedIdentityCredential as AioManagedIdentityCredential from helper.azure_credential_utils import get_azure_credential @@ -54,13 +56,15 @@ def __init__(self): def get_azure_credentials(self): """Retrieve Azure credentials, either from environment variables or managed identity.""" - if all([self.azure_tenant_id, self.azure_client_id, self.azure_client_secret]): - return ClientSecretCredential( - tenant_id=self.azure_tenant_id, - client_id=self.azure_client_id, - client_secret=self.azure_client_secret, - ) - return self.__azure_credentials + if os.getenv("APP_ENV", "prod").lower() == "dev": + if all([self.azure_tenant_id, self.azure_client_id, self.azure_client_secret]): + return ClientSecretCredential( + tenant_id=self.azure_tenant_id, + client_id=self.azure_client_id, + client_secret=self.azure_client_secret, + ) + return AioDefaultAzureCredential() + return AioManagedIdentityCredential(client_id=self.azure_client_id) app_config = Config() diff --git a/src/backend/sql_agents/convert_script.py b/src/backend/sql_agents/convert_script.py index eb4a2767..789bf36f 100644 --- a/src/backend/sql_agents/convert_script.py +++ b/src/backend/sql_agents/convert_script.py @@ -66,7 +66,8 @@ async def convert_script( # orchestrate the chat current_migration = "No migration" - while True: + is_complete: bool = False + while not is_complete: await comms_manager.group_chat.add_chat_message( ChatMessageContent(role=AuthorRole.USER, content=source_script) ) @@ -273,7 +274,9 @@ async def convert_script( break if comms_manager.group_chat.is_complete: - break + is_complete = True + + break migrated_query = current_migration diff --git a/src/frontend/.dockerignore b/src/frontend/.dockerignore new file mode 100644 index 00000000..a21f178d --- /dev/null +++ b/src/frontend/.dockerignore @@ -0,0 +1,3 @@ +node_modules +dist +.git diff --git a/src/frontend/src/pages/modernizationPage.tsx b/src/frontend/src/pages/modernizationPage.tsx index 53f128b5..7f232148 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"; @@ -497,6 +497,7 @@ const ModernizationPage = () => { const [fileId, setFileId] = React.useState(""); const [expandedSections, setExpandedSections] = React.useState([]); const [allFilesCompleted, setAllFilesCompleted] = useState(false); + const [progressPercentage, setProgressPercentage] = useState(0); const [isZipButtonDisabled, setIsZipButtonDisabled] = useState(true); const [fileLoading, setFileLoading] = useState(false); const [lastActivityTime, setLastActivityTime] = useState(Date.now()); @@ -514,18 +515,9 @@ const ModernizationPage = () => { if (!selectedFile || !selectedFile.translatedCode) { setFileLoading(true); const newFileUpdate = await fetchFileFromAPI(selectedFile?.fileId || ""); - setFiles((prevFiles) => - prevFiles.map((file) => - file.fileId === selectedFile?.fileId - ? { - ...file, - code: newFileUpdate.content, - translatedCode: newFileUpdate.translated_content, - } - : file - ) - ); setFileLoading(false); + } else { + } } catch (err) { @@ -1013,16 +1005,16 @@ useEffect(() => { }; }, [handleWebSocketMessage]); - // Set a timeout for initial loading - if still loading after 30 seconds, show a warning message + // Set a timeout for initial loading - if no progress after 30 seconds, show error useEffect(() => { const loadingTimeout = setTimeout(() => { - if (showLoading) { + if (progressPercentage < 5 && showLoading) { setLoadingError('Processing is taking longer than expected. You can continue waiting or try again later.'); } }, 30000); return () => clearTimeout(loadingTimeout); - }, [showLoading]); + }, [progressPercentage, showLoading]); // Add timeout mechanism to navigate if no activity for 30 seconds useEffect(() => { From e8bab676aa72eddd3f34f76c22673163ff2a3569 Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Thu, 9 Apr 2026 16:23:28 +0530 Subject: [PATCH 2/6] modified process page --- src/frontend/src/pages/modernizationPage.tsx | 89 ++++---------------- 1 file changed, 15 insertions(+), 74 deletions(-) diff --git a/src/frontend/src/pages/modernizationPage.tsx b/src/frontend/src/pages/modernizationPage.tsx index 7f232148..e8b1b8ad 100644 --- a/src/frontend/src/pages/modernizationPage.tsx +++ b/src/frontend/src/pages/modernizationPage.tsx @@ -501,7 +501,7 @@ const ModernizationPage = () => { const [isZipButtonDisabled, setIsZipButtonDisabled] = useState(true); const [fileLoading, setFileLoading] = useState(false); const [lastActivityTime, setLastActivityTime] = useState(Date.now()); - const [pageLoadTime] = useState(Date.now()); + //const [pageLoadTime] = useState(Date.now()); // Fetch file content when a file is selected useEffect(() => { @@ -595,18 +595,9 @@ const ModernizationPage = () => { fetchBatchData(batchId); }, [batchId]); - // Listen for startProcessing completion and navigate to batch view - useEffect(() => { - if (batchState && !batchState.loading && batchState.status === "Processing completed") { - console.log("Start processing API completed successfully - processing is done!"); - - // Check if we have the response with batch_id that matches current batchId - if (batchState.batchId === batchId) { - console.log("Processing completed for current batch, navigating to batch view page"); - navigate(`/batch-view/${batchId}`); - } - } - }, [batchState.loading, batchState.status, batchState.batchId, batchId, navigate]); + // Do NOT navigate based on Redux startProcessing state. + // The start-processing API may return 504 even if backend work is ongoing. + // Navigation is ONLY triggered by actual file completion via WebSocket/polling. const handleDownloadZip = async () => { if (batchId) { @@ -803,37 +794,17 @@ const ModernizationPage = () => { const latestBatch = await fetchBatchSummary(batchId!); setBatchSummary(latestBatch); - // Check if all files are in terminal states OR if the batch itself is marked as completed + // Only complete when all files reach terminal states. const allFilesDone = latestBatch.files.every(file => ["completed", "failed", "error"].includes(file.status?.toLowerCase() || "") ); - - // Also check if batch status indicates completion (for cases where some files remain queued) - const batchCompleted = latestBatch.status?.toLowerCase() === "completed" || - latestBatch.status?.toLowerCase() === "failed"; - - // Special handling for stuck processing files - if no completed files and long time passed - const hasProcessingFiles = latestBatch.files.some(file => - file.status?.toLowerCase() === "in_process" - ); - const hasCompletedFiles = latestBatch.files.some(file => - file.status?.toLowerCase() === "completed" - ); - const timeSinceLastActivity = Date.now() - lastActivityTime; - const likelyStuckProcessing = hasProcessingFiles && - !hasCompletedFiles && - timeSinceLastActivity > 60000; // 60 seconds of no activity - - // Consider processing done if either all files are terminal OR batch is marked complete OR files appear stuck - const processingComplete = allFilesDone || batchCompleted || likelyStuckProcessing; + + const processingComplete = allFilesDone; if (processingComplete) { console.log("Processing complete detected:", { allFilesDone, - batchCompleted, - likelyStuckProcessing, - batchStatus: latestBatch.status, - timeSinceActivity: timeSinceLastActivity + batchStatus: latestBatch.status }); setAllFilesCompleted(true); const hasUsableFile = latestBatch.files.some(file => @@ -860,8 +831,8 @@ const ModernizationPage = () => { return updated; }); - // Navigate to batch view page when processing is complete - console.log("Processing complete (either all files done or batch completed), navigating to batch view page"); + // 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}`); } } catch (err) { @@ -942,17 +913,8 @@ useEffect(() => { file.id === "summary" || // skip summary ["completed", "failed", "error"].includes(file.status?.toLowerCase() || "") ); - - // Also check if we have at least one completed file and no files currently processing - const hasCompletedFiles = files.some(file => - file.id !== "summary" && file.status === "completed" - ); - const hasProcessingFiles = files.some(file => - file.id !== "summary" && file.status === "in_process" - ); - - // Consider done if all terminal OR (has completed files and no processing files) - const effectivelyDone = areAllFilesTerminal || (hasCompletedFiles && !hasProcessingFiles); + + const effectivelyDone = areAllFilesTerminal; if (files.length > 1 && effectivelyDone && !allFilesCompleted) { console.log("Files processing appears complete, checking batch status"); @@ -1016,44 +978,23 @@ useEffect(() => { return () => clearTimeout(loadingTimeout); }, [progressPercentage, showLoading]); - // Add timeout mechanism to navigate if no activity for 30 seconds + // Poll summary status during inactivity, but do not force completion/navigation by timeout. useEffect(() => { const checkInactivity = setInterval(() => { const timeSinceLastActivity = Date.now() - lastActivityTime; const hasCompletedFiles = files.some(file => file.id !== "summary" && file.status === "completed" ); - const hasProcessingFiles = files.some(file => - file.id !== "summary" && file.status === "in_process" - ); - const nonSummaryFiles = files.filter(f => f.id !== "summary"); - // If we have completed files and no activity for 30 seconds, check if we should navigate + // If we have completed files and no activity for 30 seconds, refresh status. if (hasCompletedFiles && timeSinceLastActivity > 30000 && !allFilesCompleted) { console.log("No activity for 30 seconds with completed files, checking final status"); updateSummaryStatus(); } - - // Special case: If only harmful files that are stuck in processing for 60+ seconds - if (nonSummaryFiles.length > 0 && - hasProcessingFiles && - !hasCompletedFiles && - timeSinceLastActivity > 60000 && - !allFilesCompleted) { - console.log("Files stuck in processing for 60+ seconds, likely failed - checking batch status"); - updateSummaryStatus(); - } - - // Ultimate fallback: If on page for 2+ minutes with no completion, force navigation - const timeSincePageLoad = Date.now() - pageLoadTime; - if (timeSincePageLoad > 120000 && !allFilesCompleted && nonSummaryFiles.length > 0) { - console.log("Page loaded for 2+ minutes without completion, forcing navigation to batch view"); - navigate(`/batch-view/${batchId}`); - } }, 5000); // Check every 5 seconds return () => clearInterval(checkInactivity); - }, [lastActivityTime, files, allFilesCompleted, updateSummaryStatus, pageLoadTime, navigate, batchId]); + }, [lastActivityTime, files, allFilesCompleted, updateSummaryStatus, navigate, batchId]); useEffect(() => { From d89741a67b18350123817238f4a489d231063aeb Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Thu, 9 Apr 2026 17:26:12 +0530 Subject: [PATCH 3/6] Update src/frontend/src/pages/modernizationPage.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/frontend/src/pages/modernizationPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/pages/modernizationPage.tsx b/src/frontend/src/pages/modernizationPage.tsx index e8b1b8ad..eb22ed07 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, useRef } from "react" +import { useState, useEffect, useCallback } from "react" import { getApiUrl, headerBuilder } from '../api/config'; import BatchHistoryPanel from "../components/batchHistoryPanel" import PanelRight from "../components/Panels/PanelRight"; From 8aab26e4defd4595c9b6e14a897f06927785c4da Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Thu, 9 Apr 2026 17:43:25 +0530 Subject: [PATCH 4/6] Delete src/frontend/.dockerignore --- src/frontend/.dockerignore | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 src/frontend/.dockerignore diff --git a/src/frontend/.dockerignore b/src/frontend/.dockerignore deleted file mode 100644 index a21f178d..00000000 --- a/src/frontend/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -dist -.git From e08f74245d4ea14be84bc8adda1ca80737ae87a3 Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Thu, 9 Apr 2026 18:28:26 +0530 Subject: [PATCH 5/6] copilot comment resolving --- src/backend/.env.sample | 4 ++-- src/backend/common/config/config.py | 20 ++++++++------------ src/backend/sql_agents/convert_script.py | 4 ++-- src/frontend/.dockerignore | 3 --- 4 files changed, 12 insertions(+), 19 deletions(-) delete mode 100644 src/frontend/.dockerignore diff --git a/src/backend/.env.sample b/src/backend/.env.sample index 2de06e7a..3cced35e 100644 --- a/src/backend/.env.sample +++ b/src/backend/.env.sample @@ -28,9 +28,9 @@ AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = "" APP_ENV = "dev" # Basic application logging (default: INFO level) -AZURE_BASIC_LOGGING_LEVEL=DEBUG +AZURE_BASIC_LOGGING_LEVEL=INFO # Azure package logging (default: WARNING level to suppress INFO) -AZURE_PACKAGE_LOGGING_LEVEL=DEBUG +AZURE_PACKAGE_LOGGING_LEVEL=WARNING # Comma-separated list of specific logger names to configure (default: empty - no custom loggers) # Example: AZURE_LOGGING_PACKAGES=azure.identity.aio._internal,azure.monitor.opentelemetry.exporter.export._base AZURE_LOGGING_PACKAGES= \ No newline at end of file diff --git a/src/backend/common/config/config.py b/src/backend/common/config/config.py index 18fcb15b..bc5f2817 100644 --- a/src/backend/common/config/config.py +++ b/src/backend/common/config/config.py @@ -15,8 +15,6 @@ import os from azure.identity.aio import ClientSecretCredential -from azure.identity.aio import DefaultAzureCredential as AioDefaultAzureCredential -from azure.identity.aio import ManagedIdentityCredential as AioManagedIdentityCredential from helper.azure_credential_utils import get_azure_credential @@ -56,16 +54,14 @@ def __init__(self): def get_azure_credentials(self): """Retrieve Azure credentials, either from environment variables or managed identity.""" - if os.getenv("APP_ENV", "prod").lower() == "dev": - if all([self.azure_tenant_id, self.azure_client_id, self.azure_client_secret]): - return ClientSecretCredential( - tenant_id=self.azure_tenant_id, - client_id=self.azure_client_id, - client_secret=self.azure_client_secret, - ) - return AioDefaultAzureCredential() - return AioManagedIdentityCredential(client_id=self.azure_client_id) + if all([self.azure_tenant_id, self.azure_client_id, self.azure_client_secret]): + return ClientSecretCredential( + tenant_id=self.azure_tenant_id, + client_id=self.azure_client_id, + client_secret=self.azure_client_secret, + ) + return self.__azure_credentials app_config = Config() -print(f"[DEBUG] AI_PROJECT_ENDPOINT: '{os.getenv('AI_PROJECT_ENDPOINT')}'") +print(f"[DEBUG] AI_PROJECT_ENDPOINT: '{os.getenv('AI_PROJECT_ENDPOINT')}'") \ No newline at end of file diff --git a/src/backend/sql_agents/convert_script.py b/src/backend/sql_agents/convert_script.py index 789bf36f..f5b44128 100644 --- a/src/backend/sql_agents/convert_script.py +++ b/src/backend/sql_agents/convert_script.py @@ -101,6 +101,7 @@ async def convert_script( AuthorRole(response.role), ) current_migration = None + is_complete = True break case AgentType.SYNTAX_CHECKER.value: result = SyntaxCheckerResponse.model_validate_json( @@ -271,13 +272,12 @@ async def convert_script( FileResult.ERROR, ), ) + is_complete = True break if comms_manager.group_chat.is_complete: is_complete = True - break - migrated_query = current_migration # Handle the case where migration failed and current_migration is None diff --git a/src/frontend/.dockerignore b/src/frontend/.dockerignore deleted file mode 100644 index a21f178d..00000000 --- a/src/frontend/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -dist -.git From f518de42064e463947bfab2be7cae07f8cf3d891 Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Thu, 9 Apr 2026 18:33:52 +0530 Subject: [PATCH 6/6] resolve pylint --- src/backend/common/config/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/common/config/config.py b/src/backend/common/config/config.py index bc5f2817..faccdde1 100644 --- a/src/backend/common/config/config.py +++ b/src/backend/common/config/config.py @@ -64,4 +64,4 @@ def get_azure_credentials(self): app_config = Config() -print(f"[DEBUG] AI_PROJECT_ENDPOINT: '{os.getenv('AI_PROJECT_ENDPOINT')}'") \ No newline at end of file +print(f"[DEBUG] AI_PROJECT_ENDPOINT: '{os.getenv('AI_PROJECT_ENDPOINT')}'")