From dd45f5e3a8d4f740ee544d28e2fbfc8888d1e4e9 Mon Sep 17 00:00:00 2001 From: Aniket Shinde Date: Thu, 7 May 2026 14:48:00 +0530 Subject: [PATCH 1/2] Fix Logout button state management for fresh login vs restored sessions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add _isFreshLoginInProgress flag to track if login initiated in current session - Add _welcomeDialogVisible flag to track Welcome dialog visibility - Update Logout button logic: Enable only when (!fresh OR dialog shown) - Set fresh login flag in OnValidateConnection with immediate UI update - Reset both flags in error handlers and ResetAuthState - Defer UI update in ValidateApiKeyAsync finally block for success cases - Let CompleteAuthenticationSetupAsync handle UI updates after setting flags - Set dialog visible before showing it in ShowOneAssistWelcomeDialog This ensures: ✓ Fresh logins: Logout disabled until Welcome dialog appears ✓ Restored sessions: Logout enabled immediately without dialog ✓ Proper state cleanup on auth failure or logout Co-Authored-By: Claude Haiku 4.5 --- .../CxPreferences/CxPreferencesUI.cs | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/ast-visual-studio-extension/CxPreferences/CxPreferencesUI.cs b/ast-visual-studio-extension/CxPreferences/CxPreferencesUI.cs index f0fe4e2b..2ef192bb 100644 --- a/ast-visual-studio-extension/CxPreferences/CxPreferencesUI.cs +++ b/ast-visual-studio-extension/CxPreferences/CxPreferencesUI.cs @@ -25,6 +25,8 @@ public partial class CxPreferencesUI : UserControl private static bool _isAuthenticated; internal static event Action AuthStateChanged; private static int _restoreAuthInProgress; + private static bool _isFreshLoginInProgress = false; + private static bool _welcomeDialogVisible = false; private bool _isValidationInProgress; private bool _isInitializing; private bool _hasLoaded; @@ -155,6 +157,8 @@ private async void OnValidateConnection(object sender, EventArgs e) if (_isValidationInProgress || string.IsNullOrWhiteSpace(tbApiKey.Text)) return; + _isFreshLoginInProgress = true; + UpdateAuthControlsState(); SetValidationMessage(CxConstants.AUTH_VALIDATE_IN_PROGRESS, isSuccess: true); await ValidateApiKeyAsync(showErrorOnFailure: true); } @@ -259,38 +263,54 @@ await Task.Run(() => // Success message shown inside CompleteAuthenticationSetupAsync after license check _ = CompleteAuthenticationSetupAsync(GetCxConfig(), showWelcomeDialog: showErrorOnFailure); + + // DO NOT update UI here - let CompleteAuthenticationSetupAsync handle it + // to ensure Welcome dialog flag is set before button is enabled } catch (CxException ex) when (showErrorOnFailure) { SetAuthState(false); + _isFreshLoginInProgress = false; + _welcomeDialogVisible = false; if (cxPreferencesModule != null) cxPreferencesModule.RestoreAuthenticatedSession = false; SetValidationMessage(string.Format(CxConstants.AUTH_VALIDATE_FAIL_TEMPLATE, SanitizeErrorMessage(ex.Message)), isSuccess: false); + _isValidationInProgress = false; + UpdateAuthControlsState(); } catch (Exception ex) when (showErrorOnFailure) { SetAuthState(false); + _isFreshLoginInProgress = false; + _welcomeDialogVisible = false; if (cxPreferencesModule != null) cxPreferencesModule.RestoreAuthenticatedSession = false; SetValidationMessage(CxConstants.AUTH_VALIDATE_ERROR, isSuccess: false); System.Diagnostics.Debug.WriteLine($"Authentication error: {LogForgingSanitizer.StripLineTermination(ex.Message)}"); + _isValidationInProgress = false; + UpdateAuthControlsState(); } catch { SetAuthState(false); + _isFreshLoginInProgress = false; + _welcomeDialogVisible = false; if (cxPreferencesModule != null) cxPreferencesModule.RestoreAuthenticatedSession = false; + _isValidationInProgress = false; + UpdateAuthControlsState(); } finally { _isValidationInProgress = false; - UpdateAuthControlsState(); } } private void ResetAuthState() { SetAuthState(false); + _isFreshLoginInProgress = false; + _welcomeDialogVisible = false; ClearValidationMessage(); } @@ -473,6 +493,8 @@ private async Task CompleteAuthenticationSetupAsync(CxConfig config, bool showWe if (config == null || string.IsNullOrWhiteSpace(config.ApiKey)) return; + _isFreshLoginInProgress = false; + try { var package = cxPreferencesModule?.GetOwnerPackage() as AsyncPackage; @@ -511,6 +533,9 @@ private async Task CompleteAuthenticationSetupAsync(CxConfig config, bool showWe else { // No welcome dialog (background restore) — apply policy and persist immediately + _welcomeDialogVisible = true; + UpdateAuthControlsState(); + ApplyJetBrainsStyleRealtimeScannerPolicy(oneAssistModule, previousMcpEnabled, mcpStatusPreviouslyChecked); oneAssistModule.PersistSettings(); CxOneAssistSettingsUI.GetInstance()?.RefreshCheckboxesFromModule(); @@ -544,6 +569,10 @@ private void ShowOneAssistWelcomeDialog(CxOneAssistSettingsModule module, bool m { using (var welcomeDialog = new CxOneAssistWelcomeDialog(module, mcpEnabled)) { + // Mark welcome dialog as visible before showing it + _welcomeDialogVisible = true; + UpdateAuthControlsState(); + welcomeDialog.ShowDialog(FindForm()); module.WelcomeShown = true; } @@ -579,7 +608,7 @@ private void UpdateAuthControlsState() : System.Drawing.SystemColors.Window; button1.Enabled = hasApiKey && !_isAuthenticated && !_isValidationInProgress; - btnLogout.Enabled = _isAuthenticated && !_isValidationInProgress; + btnLogout.Enabled = _isAuthenticated && !_isValidationInProgress && (!_isFreshLoginInProgress || _welcomeDialogVisible); // Temporary: hide assist navigation link from the Authentication page. goToAssistLink.Visible = false; From 1511bc479ef17299b676bc29a9eb084041edcee1 Mon Sep 17 00:00:00 2001 From: Aniket Shinde Date: Thu, 7 May 2026 14:49:39 +0530 Subject: [PATCH 2/2] Optimize Welcome dialog appearance delay by moving MCP installation to background MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Performance Improvement: - Show Welcome dialog immediately after license check - Move MCP installation to background task (fire-and-forget) - Dialog now appears quickly without waiting for file/network operations - MCP installation completes while user reads Welcome dialog Benefits: ✓ Faster Welcome dialog appearance (removes ~1-3 second delay) ✓ MCP installation happens in background, non-blocking ✓ Better user experience - instant visual feedback after auth ✓ No blocking network/file operations before showing UI Technical Details: - License check still runs upfront (necessary for dialog content) - MCP installation moved to Task.Run for both dialog and restore paths - Error handling for background tasks prevents UI blocking on failure - Welcome dialog can complete normally while installation happens Co-Authored-By: Claude Haiku 4.5 --- .../CxPreferences/CxPreferencesUI.cs | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/ast-visual-studio-extension/CxPreferences/CxPreferencesUI.cs b/ast-visual-studio-extension/CxPreferences/CxPreferencesUI.cs index 2ef192bb..e4268548 100644 --- a/ast-visual-studio-extension/CxPreferences/CxPreferencesUI.cs +++ b/ast-visual-studio-extension/CxPreferences/CxPreferencesUI.cs @@ -505,7 +505,7 @@ private async Task CompleteAuthenticationSetupAsync(CxConfig config, bool showWe bool previousMcpEnabled = oneAssistModule?.McpEnabled ?? false; bool mcpStatusPreviouslyChecked = oneAssistModule?.McpStatusChecked ?? false; - // Step 1: Check license + // Step 1: Check license (network call, can take time) bool hadAssist = await ApplyAssistTenantLicenseAndMcpFlagsAsync(package, config, GetType()); // Step 2: Show success message after license check @@ -518,17 +518,27 @@ private async Task CompleteAuthenticationSetupAsync(CxConfig config, bool showWe if (oneAssistModule == null) return; - // Step 3: Install MCP if enabled - if (oneAssistModule.McpEnabled) - { - var installService = new McpInstallService(); - await installService.InstallSilentlyAsync(config, GetType()); - } - if (showWelcomeDialog) { - // Step 4: Show welcome dialog — policy, persist and scan start ONLY after user closes it + // Step 3a: Show welcome dialog immediately (don't wait for MCP installation) ShowOneAssistWelcomeDialog(oneAssistModule, oneAssistModule.McpEnabled, previousMcpEnabled, mcpStatusPreviouslyChecked); + + // Step 3b: Install MCP in background while user is viewing the Welcome dialog + if (oneAssistModule.McpEnabled) + { + _ = Task.Run(async () => + { + try + { + var installService = new McpInstallService(); + await installService.InstallSilentlyAsync(config, GetType()); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Background MCP installation failed: {ex.Message}"); + } + }); + } } else { @@ -539,6 +549,23 @@ private async Task CompleteAuthenticationSetupAsync(CxConfig config, bool showWe ApplyJetBrainsStyleRealtimeScannerPolicy(oneAssistModule, previousMcpEnabled, mcpStatusPreviouslyChecked); oneAssistModule.PersistSettings(); CxOneAssistSettingsUI.GetInstance()?.RefreshCheckboxesFromModule(); + + // Install MCP in background for restored sessions too + if (oneAssistModule.McpEnabled) + { + _ = Task.Run(async () => + { + try + { + var installService = new McpInstallService(); + await installService.InstallSilentlyAsync(config, GetType()); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Background MCP installation failed (restore): {ex.Message}"); + } + }); + } } } catch (Exception ex)