diff --git a/src/PlanViewer.App/Controls/PlanViewerControl.axaml b/src/PlanViewer.App/Controls/PlanViewerControl.axaml
index db9d492..ef2ed43 100644
--- a/src/PlanViewer.App/Controls/PlanViewerControl.axaml
+++ b/src/PlanViewer.App/Controls/PlanViewerControl.axaml
@@ -228,6 +228,7 @@
+
diff --git a/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs b/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs
index debb21c..0adcfd2 100644
--- a/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs
+++ b/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs
@@ -171,6 +171,7 @@ public ServerMetadata? Metadata
public event EventHandler? HumanAdviceRequested;
public event EventHandler? RobotAdviceRequested;
public event EventHandler? CopyReproRequested;
+ public event EventHandler? OpenInEditorRequested;
///
/// Navigates to a specific plan node by ID: selects it, zooms to show it,
@@ -3269,6 +3270,15 @@ private async void CopyStatementText_Click(object? sender, RoutedEventArgs e)
await topLevel.Clipboard.SetTextAsync(text);
}
+ private void OpenInEditor_Click(object? sender, RoutedEventArgs e)
+ {
+ if (StatementsGrid.SelectedItem is not StatementRow row) return;
+ var text = row.Statement.StatementText;
+ if (string.IsNullOrEmpty(text)) return;
+
+ OpenInEditorRequested?.Invoke(this, text);
+ }
+
private static void CollectNodeWarnings(PlanNode node, List warnings)
{
warnings.AddRange(node.Warnings);
diff --git a/src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs b/src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs
index 49c0c57..ef556d4 100644
--- a/src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs
+++ b/src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs
@@ -590,6 +590,13 @@ private static string BracketName(string name)
return $"[{name}]";
}
+ private void OnOpenInEditorRequested(object? sender, string queryText)
+ {
+ QueryEditor.Text = queryText;
+ SubTabControl.SelectedIndex = 0; // Switch to the editor tab
+ QueryEditor.Focus();
+ }
+
private void OnKeyDown(object? sender, KeyEventArgs e)
{
// F5 or Ctrl+E → Execute (actual plan)
@@ -1067,6 +1074,7 @@ private async Task CaptureAndShowPlan(bool estimated, string? queryTextOverride
SetStatus($"{planType} plan captured ({sw.Elapsed.TotalSeconds:F1}s)");
var viewer = new PlanViewerControl();
viewer.Metadata = _serverMetadata;
+ viewer.OpenInEditorRequested += OnOpenInEditorRequested;
viewer.LoadPlan(planXml, tabLabel, queryText);
loadingTab.Content = viewer;
HumanAdviceButton.IsEnabled = true;
@@ -1148,6 +1156,7 @@ private void AddPlanTab(string planXml, string queryText, bool estimated, string
var viewer = new PlanViewerControl();
viewer.Metadata = _serverMetadata;
+ viewer.OpenInEditorRequested += OnOpenInEditorRequested;
viewer.LoadPlan(planXml, label, queryText);
// Build tab header with close button and right-click rename
@@ -1836,6 +1845,7 @@ private async void GetActualPlan_Click(object? sender, RoutedEventArgs e)
SetStatus($"Actual plan captured ({sw.Elapsed.TotalSeconds:F1}s)");
var actualViewer = new PlanViewerControl();
actualViewer.Metadata = _serverMetadata;
+ actualViewer.OpenInEditorRequested += OnOpenInEditorRequested;
actualViewer.LoadPlan(actualPlanXml, tabLabel, queryText);
loadingTab.Content = actualViewer;
}
diff --git a/src/PlanViewer.App/MainWindow.axaml.cs b/src/PlanViewer.App/MainWindow.axaml.cs
index 0a055f9..92de531 100644
--- a/src/PlanViewer.App/MainWindow.axaml.cs
+++ b/src/PlanViewer.App/MainWindow.axaml.cs
@@ -530,6 +530,16 @@ private DockPanel CreatePlanTabContent(PlanViewerControl viewer)
viewer.HumanAdviceRequested += (_, _) => showHumanAdvice();
viewer.RobotAdviceRequested += (_, _) => showRobotAdvice();
viewer.CopyReproRequested += async (_, _) => await copyRepro();
+ viewer.OpenInEditorRequested += (_, queryText) =>
+ {
+ _queryCounter++;
+ var session = new QuerySessionControl(_credentialService, _connectionStore);
+ session.QueryEditor.Text = queryText;
+ var tab = CreateTab($"Query {_queryCounter}", session);
+ MainTabControl.Items.Add(tab);
+ MainTabControl.SelectedItem = tab;
+ UpdateEmptyOverlay();
+ };
var getActualPlanBtn = new Button
{