Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions src/PlanViewer.App/Controls/PlanViewerControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,33 @@
</Expander.Header>
<Grid MaxHeight="220">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="0"/>
<ColumnDefinition Width="Auto" MinWidth="180"/>
<ColumnDefinition Width="*" MinWidth="200"/>
<ColumnDefinition Width="*" MinWidth="200"/>
<ColumnDefinition Width="*" MinWidth="200"/>
</Grid.ColumnDefinitions>

<!-- Runtime Summary (left) -->
<Border Grid.Column="0" Padding="10,4,10,8"
<!-- Server Context (first, only visible when connected) -->
<Border x:Name="ServerContextBorder" Grid.Column="0" Padding="10,4,10,8"
Background="#1A1A2D"
BorderBrush="#3A3A5A" BorderThickness="0,0,1,0"
IsVisible="False">
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<StackPanel>
<TextBlock Text="Server Context"
FontSize="13"
FontWeight="SemiBold"
Foreground="#9B9BFF"
Margin="0,0,0,6"/>
<StackPanel x:Name="ServerContextContent"/>
</StackPanel>
</ScrollViewer>
</Border>

<!-- Runtime Summary -->
<Border Grid.Column="1" Padding="10,4,10,8"
Background="{DynamicResource BackgroundDarkBrush}"
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="0,0,1,0">
<StackPanel>
Expand All @@ -81,7 +100,7 @@
</Border>

<!-- Missing Indexes (center) -->
<Border Grid.Column="1" Padding="10,4,10,8"
<Border Grid.Column="2" Padding="10,4,10,8"
Background="#3D2A0E"
BorderBrush="#7A5A1E" BorderThickness="0,0,1,0">
<ScrollViewer VerticalScrollBarVisibility="Auto"
Expand All @@ -102,7 +121,7 @@
</Border>

<!-- Parameters -->
<Border Grid.Column="2" Padding="10,4,10,8"
<Border Grid.Column="3" Padding="10,4,10,8"
Background="#1A2D1A"
BorderBrush="#3A5A3A" BorderThickness="0,0,1,0">
<ScrollViewer VerticalScrollBarVisibility="Auto"
Expand All @@ -123,7 +142,7 @@
</Border>

<!-- Wait Stats (right, fills remaining space) -->
<Border Grid.Column="3" Padding="10,4,10,8"
<Border Grid.Column="4" Padding="10,4,10,8"
Background="#1A2A3D">
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
Expand Down
86 changes: 86 additions & 0 deletions src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public partial class PlanViewerControl : UserControl
private ParsedPlan? _currentPlan;
private PlanStatement? _currentStatement;
private string? _queryText;
private ServerMetadata? _serverMetadata;
private double _zoomLevel = 1.0;
private const double ZoomStep = 0.15;
private const double MinZoom = 0.1;
Expand Down Expand Up @@ -146,6 +147,20 @@ public PlanViewerControl()
/// </summary>
public string? QueryText => _queryText;

/// <summary>
/// Server metadata for advice generation and Plan Insights display.
/// </summary>
public ServerMetadata? Metadata
{
get => _serverMetadata;
set
{
_serverMetadata = value;
if (_currentStatement != null)
ShowServerContext();
}
}

public void LoadPlan(string planXml, string label, string? queryText = null)
{
_label = label;
Expand Down Expand Up @@ -2327,6 +2342,77 @@ void AddRow(string label, string value)
AddRow("Early abort", statement.StatementOptmEarlyAbortReason);

RuntimeSummaryContent.Children.Add(grid);
ShowServerContext();
}

private void ShowServerContext()
{
ServerContextContent.Children.Clear();
if (_serverMetadata == null)
{
ServerContextBorder.IsVisible = false;
return;
}

var m = _serverMetadata;
var fgColor = "#E4E6EB";

var grid = new Grid { ColumnDefinitions = new ColumnDefinitions("Auto,*") };
int rowIndex = 0;

void AddRow(string label, string value)
{
grid.RowDefinitions.Add(new RowDefinition(GridLength.Auto));
var lb = new TextBlock
{
Text = label, FontSize = 11,
Foreground = new SolidColorBrush(Color.Parse(fgColor)),
HorizontalAlignment = HorizontalAlignment.Left,
Margin = new Thickness(0, 1, 8, 1)
};
Grid.SetRow(lb, rowIndex);
Grid.SetColumn(lb, 0);
grid.Children.Add(lb);

var vb = new TextBlock
{
Text = value, FontSize = 11,
Foreground = new SolidColorBrush(Color.Parse(fgColor)),
Margin = new Thickness(0, 1, 0, 1)
};
Grid.SetRow(vb, rowIndex);
Grid.SetColumn(vb, 1);
grid.Children.Add(vb);
rowIndex++;
}

// Server name + edition
var edition = m.Edition;
if (edition != null)
{
var idx = edition.IndexOf(" (64-bit)");
if (idx > 0) edition = edition[..idx];
}
var serverLine = m.ServerName ?? "Unknown";
if (edition != null) serverLine += $" ({edition})";
if (m.ProductVersion != null) serverLine += $", {m.ProductVersion}";
AddRow("Server", serverLine);

// Hardware
if (m.CpuCount > 0)
AddRow("Hardware", $"{m.CpuCount} CPUs, {m.PhysicalMemoryMB:N0} MB RAM");

// Instance settings
AddRow("MAXDOP", m.MaxDop.ToString());
AddRow("Cost threshold", m.CostThresholdForParallelism.ToString());
AddRow("Max memory", $"{m.MaxServerMemoryMB:N0} MB");

// Database
if (m.Database != null)
AddRow("Database", $"{m.Database.Name} (compat {m.Database.CompatibilityLevel})");

ServerContextContent.Children.Add(grid);
ServerContextBorder.IsVisible = true;
}

private void UpdateInsightsHeader()
Expand Down
1 change: 1 addition & 0 deletions src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ private void AddPlanTab(string planXml, string queryText, bool estimated, string
var label = labelOverride ?? (estimated ? $"Est Plan {_planCounter}" : $"Plan {_planCounter}");

var viewer = new PlanViewerControl();
viewer.Metadata = _serverMetadata;
viewer.LoadPlan(planXml, label, queryText);

// Build tab header with close button and right-click rename
Expand Down
16 changes: 14 additions & 2 deletions src/PlanViewer.App/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -442,14 +442,14 @@ private DockPanel CreatePlanTabContent(PlanViewerControl viewer)
humanBtn.Click += (_, _) =>
{
if (viewer.CurrentPlan == null) return;
var analysis = ResultMapper.Map(viewer.CurrentPlan, "file");
var analysis = ResultMapper.Map(viewer.CurrentPlan, "file", viewer.Metadata);
ShowAdviceWindow("Advice for Humans", TextFormatter.Format(analysis));
};

robotBtn.Click += (_, _) =>
{
if (viewer.CurrentPlan == null) return;
var analysis = ResultMapper.Map(viewer.CurrentPlan, "file");
var analysis = ResultMapper.Map(viewer.CurrentPlan, "file", viewer.Metadata);
var json = JsonSerializer.Serialize(analysis, new JsonSerializerOptions { WriteIndented = true });
ShowAdviceWindow("Advice for Robots", json);
};
Expand Down Expand Up @@ -1024,6 +1024,17 @@ private async Task GetActualPlanFromFile(PlanViewerControl viewer)

try
{
// Fetch server metadata for advice and Plan Insights
ServerMetadata? metadata = null;
try
{
metadata = await ServerMetadataService.FetchServerMetadataAsync(
connectionString, isAzure);
metadata.Database = await ServerMetadataService.FetchDatabaseMetadataAsync(
connectionString, metadata.SupportsScopedConfigs);
}
catch { /* Non-fatal — advice will just lack server context */ }

var cts = new System.Threading.CancellationTokenSource();
var sw = System.Diagnostics.Stopwatch.StartNew();

Expand All @@ -1042,6 +1053,7 @@ private async Task GetActualPlanFromFile(PlanViewerControl viewer)

// Add a new tab with the actual plan
var actualViewer = new PlanViewerControl();
actualViewer.Metadata = metadata;
actualViewer.LoadPlan(actualPlanXml, "Actual Plan", queryText);

var content = CreatePlanTabContent(actualViewer);
Expand Down
Loading