Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
97dbd6e
Allow horizontal scroll fixes #14
ClaudioESSilva Mar 5, 2026
968f5ca
Fixes #15
ClaudioESSilva Mar 5, 2026
ac92495
implements #16
ClaudioESSilva Mar 5, 2026
1fe1855
Implements #17
ClaudioESSilva Mar 5, 2026
5597568
Add better icon for "fiter" and odering
ClaudioESSilva Mar 5, 2026
26989dc
Fix obsolete IClipboard.GetTextAsync() warnings
erikdarlingdata Mar 5, 2026
f1b484f
Merge pull request #39 from erikdarlingdata/fix/clipboard-obsolete-wa…
erikdarlingdata Mar 5, 2026
12a3e82
fix: LoadSelectedPlans_Click Should Use _filteredRows
ClaudioESSilva Mar 5, 2026
489c923
Fix: Query Text Column Width
ClaudioESSilva Mar 5, 2026
743e36b
Fix: Remove Dead Code
ClaudioESSilva Mar 5, 2026
9a13717
Show all plan warnings in root operator tooltip
erikdarlingdata Mar 5, 2026
55552de
Merge pull request #40 from erikdarlingdata/fix/root-tooltip-warnings
erikdarlingdata Mar 5, 2026
0b6b732
Fix icon for cross platform
ClaudioESSilva Mar 5, 2026
cf5d1d4
Rollback to 300 so we can see all columns headers and be able to resi…
ClaudioESSilva Mar 5, 2026
c961b1f
Add Server Context pane to Plan Insights and Advice for Humans
erikdarlingdata Mar 5, 2026
f89aedd
Merge pull request #41 from erikdarlingdata/feature/server-context-in…
erikdarlingdata Mar 5, 2026
b4e6c9e
Merge pull request #18 from ClaudioESSilva/fix/query-store-grid-usabi…
erikdarlingdata Mar 5, 2026
dbc1c67
Fix warnings gap in properties panel (#29)
erikdarlingdata Mar 5, 2026
259a101
Merge pull request #42 from erikdarlingdata/fix/issue-29-warnings-gap
erikdarlingdata Mar 5, 2026
fe399d5
Add MCP registration command copy button to About screen (#26)
erikdarlingdata Mar 5, 2026
f5f3fbb
Merge pull request #43 from erikdarlingdata/fix/issue-26-mcp-copy-button
erikdarlingdata Mar 5, 2026
cb234f3
Show loading placeholder tab for Run Repro Script (#24)
erikdarlingdata Mar 5, 2026
395da80
Merge pull request #44 from erikdarlingdata/fix/issue-24-loading-plac…
erikdarlingdata Mar 5, 2026
5032d63
Bump version to 0.9.0
erikdarlingdata Mar 5, 2026
72faa93
Merge pull request #45 from erikdarlingdata/release/v0.9.0
erikdarlingdata Mar 5, 2026
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
8 changes: 7 additions & 1 deletion src/PlanViewer.App/AboutWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="PlanViewer.App.AboutWindow"
Title="About Performance Studio"
Width="450" Height="420"
Width="450" Height="460"
CanResize="False"
WindowStartupLocation="CenterOwner"
Icon="avares://PlanViewer.App/EDD.ico"
Expand Down Expand Up @@ -63,6 +63,12 @@
<TextBlock Text="Restart the application after changing MCP settings."
FontSize="11" Foreground="{DynamicResource ForegroundMutedBrush}"
Margin="0,4,0,0"/>
<StackPanel Orientation="Horizontal" Spacing="8" Margin="0,8,0,0">
<Button x:Name="CopyMcpCommandButton" Content="Copy MCP Command"
Click="CopyMcpCommand_Click" Padding="10,4" FontSize="12"/>
<TextBlock x:Name="McpCopyStatus" FontSize="11" VerticalAlignment="Center"
Foreground="{DynamicResource ForegroundMutedBrush}"/>
</StackPanel>
</StackPanel>

<!-- Close -->
Expand Down
13 changes: 13 additions & 0 deletions src/PlanViewer.App/AboutWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Text.Json;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using PlanViewer.App.Mcp;

Expand Down Expand Up @@ -59,6 +60,18 @@ private void SaveMcpSettings()
private void GitHubLink_Click(object? sender, PointerPressedEventArgs e) => OpenUrl(GitHubUrl);
private void ReportIssueLink_Click(object? sender, PointerPressedEventArgs e) => OpenUrl(IssuesUrl);
private void DarlingDataLink_Click(object? sender, PointerPressedEventArgs e) => OpenUrl(DarlingDataUrl);
private async void CopyMcpCommand_Click(object? sender, RoutedEventArgs e)
{
var port = int.TryParse(McpPortInput.Text, out var p) && p >= 1024 && p <= 65535 ? p : 5152;
var command = $"claude mcp add --transport streamable-http --scope user performance-studio http://localhost:{port}/";
var clipboard = TopLevel.GetTopLevel(this)?.Clipboard;
if (clipboard != null)
{
await clipboard.SetTextAsync(command);
McpCopyStatus.Text = "Copied to clipboard!";
}
}

private void CloseButton_Click(object? sender, RoutedEventArgs e) => Close();

private static void OpenUrl(string url)
Expand Down
32 changes: 32 additions & 0 deletions src/PlanViewer.App/Controls/ColumnFilterPopup.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="PlanViewer.App.Controls.ColumnFilterPopup"
Width="220">
<Border Background="{DynamicResource BackgroundDarkBrush}"
BorderBrush="{DynamicResource BorderBrush}"
BorderThickness="1" CornerRadius="6">
<StackPanel Margin="12" Spacing="4">
<TextBlock x:Name="HeaderText" Text="Filter Column"
FontWeight="SemiBold" FontSize="13" Margin="0,0,0,8"
Foreground="{DynamicResource ForegroundBrush}"/>
<TextBlock Text="Operator:" FontSize="11" Margin="0,0,0,2"
Foreground="{DynamicResource ForegroundBrush}"/>
<ComboBox x:Name="OperatorComboBox" HorizontalAlignment="Stretch"
Height="28" FontSize="12" Margin="0,0,0,8"
SelectionChanged="OperatorComboBox_SelectionChanged"/>
<TextBlock x:Name="ValueLabel" Text="Value:" FontSize="11" Margin="0,0,0,2"
Foreground="{DynamicResource ForegroundBrush}"/>
<TextBox x:Name="ValueTextBox" HorizontalAlignment="Stretch"
Height="28" FontSize="12" Margin="0,0,0,12"
KeyDown="ValueTextBox_KeyDown"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="8">
<Button Content="Clear" Width="65" Height="28"
Click="ClearButton_Click"
Theme="{StaticResource AppButton}"/>
<Button Content="Apply" Width="65" Height="28"
Click="ApplyButton_Click"
Theme="{StaticResource AppButton}"/>
</StackPanel>
</StackPanel>
</Border>
</UserControl>
113 changes: 113 additions & 0 deletions src/PlanViewer.App/Controls/ColumnFilterPopup.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using System;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;

namespace PlanViewer.App.Controls;

public partial class ColumnFilterPopup : UserControl
{
public event EventHandler<FilterAppliedEventArgs>? FilterApplied;
public event EventHandler? FilterCleared;

private string _currentColumnName = "";

private static readonly (string Display, FilterOperator Op)[] Operators =
[
("Contains", FilterOperator.Contains),
("Equals (=)", FilterOperator.Equals),
("Not Equals (!=)", FilterOperator.NotEquals),
("Starts With", FilterOperator.StartsWith),
("Ends With", FilterOperator.EndsWith),
("Greater Than (>)", FilterOperator.GreaterThan),
("Greater or Equal (>=)", FilterOperator.GreaterThanOrEqual),
("Less Than (<)", FilterOperator.LessThan),
("Less or Equal (<=)", FilterOperator.LessThanOrEqual),
("Is Empty", FilterOperator.IsEmpty),
("Is Not Empty", FilterOperator.IsNotEmpty),
];

public ColumnFilterPopup()
{
InitializeComponent();
foreach (var (display, _) in Operators)
OperatorComboBox.Items.Add(display);
OperatorComboBox.SelectedIndex = 0;
}

public void Initialize(string columnName, ColumnFilterState? existingFilter)
{
_currentColumnName = columnName;
HeaderText.Text = $"Filter: {columnName}";

if (existingFilter?.IsActive == true)
{
var idx = Array.FindIndex(Operators, o => o.Op == existingFilter.Operator);
OperatorComboBox.SelectedIndex = idx >= 0 ? idx : 0;
ValueTextBox.Text = existingFilter.Value;
}
else
{
OperatorComboBox.SelectedIndex = 0;
ValueTextBox.Text = "";
}

UpdateValueVisibility();
ValueTextBox.Focus();
}

private void UpdateValueVisibility()
{
var idx = OperatorComboBox.SelectedIndex;
var op = (idx >= 0 && idx < Operators.Length) ? Operators[idx].Op : FilterOperator.Contains;
var showValue = op != FilterOperator.IsEmpty && op != FilterOperator.IsNotEmpty;
ValueLabel.IsVisible = showValue;
ValueTextBox.IsVisible = showValue;
}

private void OperatorComboBox_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
UpdateValueVisibility();
}

private void ApplyFilter()
{
var idx = OperatorComboBox.SelectedIndex;
if (idx < 0 || idx >= Operators.Length) return;

FilterApplied?.Invoke(this, new FilterAppliedEventArgs
{
FilterState = new ColumnFilterState
{
ColumnName = _currentColumnName,
Operator = Operators[idx].Op,
Value = ValueTextBox.Text ?? "",
}
});
}

private void ApplyButton_Click(object? sender, RoutedEventArgs e) => ApplyFilter();

private void ClearButton_Click(object? sender, RoutedEventArgs e)
{
FilterApplied?.Invoke(this, new FilterAppliedEventArgs
{
FilterState = new ColumnFilterState { ColumnName = _currentColumnName }
});
FilterCleared?.Invoke(this, EventArgs.Empty);
}

private void ValueTextBox_KeyDown(object? sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
ApplyFilter();
e.Handled = true;
}
else if (e.Key == Key.Escape)
{
FilterCleared?.Invoke(this, EventArgs.Empty);
e.Handled = true;
}
}
}
59 changes: 59 additions & 0 deletions src/PlanViewer.App/Controls/ColumnFilterState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;

namespace PlanViewer.App.Controls;

public enum FilterOperator
{
Contains,
Equals,
NotEquals,
StartsWith,
EndsWith,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
IsEmpty,
IsNotEmpty,
}

public class ColumnFilterState
{
public string ColumnName { get; set; } = string.Empty;
public FilterOperator Operator { get; set; } = FilterOperator.Contains;
public string Value { get; set; } = string.Empty;

public bool IsActive =>
!string.IsNullOrEmpty(Value) ||
Operator == FilterOperator.IsEmpty ||
Operator == FilterOperator.IsNotEmpty;

public string DisplayText
{
get
{
if (!IsActive) return string.Empty;

return Operator switch
{
FilterOperator.Contains => $"Contains '{Value}'",
FilterOperator.Equals => $"= '{Value}'",
FilterOperator.NotEquals => $"!= '{Value}'",
FilterOperator.GreaterThan => $"> {Value}",
FilterOperator.GreaterThanOrEqual => $">= {Value}",
FilterOperator.LessThan => $"< {Value}",
FilterOperator.LessThanOrEqual => $"<= {Value}",
FilterOperator.StartsWith => $"Starts with '{Value}'",
FilterOperator.EndsWith => $"Ends with '{Value}'",
FilterOperator.IsEmpty => "Is Empty",
FilterOperator.IsNotEmpty => "Is Not Empty",
_ => Value,
};
}
}
}

public class FilterAppliedEventArgs : EventArgs
{
public ColumnFilterState FilterState { get; set; } = new ColumnFilterState();
}
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
Loading
Loading