diff --git a/src/PlanViewer.App/MainWindow.axaml.cs b/src/PlanViewer.App/MainWindow.axaml.cs index 2c39362..15cad87 100644 --- a/src/PlanViewer.App/MainWindow.axaml.cs +++ b/src/PlanViewer.App/MainWindow.axaml.cs @@ -1022,6 +1022,43 @@ private async Task GetActualPlanFromFile(PlanViewerControl viewer) dialog.ResultConnection.ServerName.Contains(".database.azure.com", StringComparison.OrdinalIgnoreCase); + // Create a loading placeholder tab immediately + var loadingPanel = new StackPanel + { + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Center, + Width = 300 + }; + + var progressBar = new ProgressBar + { + IsIndeterminate = true, + Height = 4, + Margin = new Avalonia.Thickness(0, 0, 0, 12) + }; + + var statusText = new TextBlock + { + Text = "Executing query...", + FontSize = 14, + Foreground = new SolidColorBrush(Color.Parse("#B0B6C0")), + HorizontalAlignment = HorizontalAlignment.Center + }; + + loadingPanel.Children.Add(progressBar); + loadingPanel.Children.Add(statusText); + + var loadingContainer = new Grid + { + Background = new SolidColorBrush(Color.Parse("#1A1D23")), + Children = { loadingPanel } + }; + + var tab = CreateTab("Actual Plan", loadingContainer); + MainTabControl.Items.Add(tab); + MainTabControl.SelectedItem = tab; + UpdateEmptyOverlay(); + try { // Fetch server metadata for advice and Plan Insights @@ -1035,6 +1072,8 @@ private async Task GetActualPlanFromFile(PlanViewerControl viewer) } catch { /* Non-fatal — advice will just lack server context */ } + statusText.Text = "Capturing actual plan..."; + var cts = new System.Threading.CancellationTokenSource(); var sw = System.Diagnostics.Stopwatch.StartNew(); @@ -1047,24 +1086,22 @@ private async Task GetActualPlanFromFile(PlanViewerControl viewer) if (string.IsNullOrEmpty(actualPlanXml)) { - ShowError($"No actual plan returned ({sw.Elapsed.TotalSeconds:F1}s)."); + statusText.Text = $"No actual plan returned ({sw.Elapsed.TotalSeconds:F1}s)."; + progressBar.IsVisible = false; return; } - // Add a new tab with the actual plan + // Replace loading content with the actual plan var actualViewer = new PlanViewerControl(); actualViewer.Metadata = metadata; actualViewer.LoadPlan(actualPlanXml, "Actual Plan", queryText); - var content = CreatePlanTabContent(actualViewer); - var tab = CreateTab("Actual Plan", content); - MainTabControl.Items.Add(tab); - MainTabControl.SelectedItem = tab; - UpdateEmptyOverlay(); + tab.Content = CreatePlanTabContent(actualViewer); } catch (Exception ex) { - ShowError($"Error capturing actual plan:\n\n{ex.Message}"); + statusText.Text = $"Error: {ex.Message}"; + progressBar.IsVisible = false; } }