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
10 changes: 5 additions & 5 deletions src/PlanViewer.App/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@
<Setter Property="AllowAutoHide" Value="True"/>
</Style>

<!-- DataGrid does not scroll through a ScrollViewer, and the ScrollBar rule above
cannot reach its bars either: it assigns AllowAutoHide to them in code, and a
local value outranks any style. There is no DataGrid.AllowAutoHide to set, but
the value it pushes down is the ATTACHED ScrollViewer property read off itself,
so setting that here is what reaches the grids. -->
<!-- DataGrid does not scroll through a ScrollViewer, so the ScrollBar rule above
cannot reach its bars: PART_HorizontalScrollbar and PART_VerticalScrollbar are
bare ScrollBars inside its own template. There is no DataGrid.AllowAutoHide to
set, but the template binds each bar's AllowAutoHide to the ATTACHED ScrollViewer
property on the grid, so setting that here is what reaches them. -->
<Style Selector="DataGrid">
<Setter Property="ScrollViewer.AllowAutoHide" Value="True"/>
</Style>
Expand Down
2 changes: 1 addition & 1 deletion src/PlanViewer.App/Controls/PlanViewerControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@
Background="{DynamicResource BackgroundBrush}"
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="0,0,0,1">
<TextBox x:Name="PropertiesFilterBox"
Watermark="Filter properties..."
PlaceholderText="Filter properties..."
FontSize="11" Height="24" MinHeight="0" Padding="6,1"
VerticalContentAlignment="Center"
TextChanged="PropertiesFilter_TextChanged"
Expand Down
9 changes: 8 additions & 1 deletion src/PlanViewer.App/Controls/QuerySessionControl.Execution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ private async Task CaptureAndShowPlan(bool estimated, string? queryTextOverride
Height = 4,
Margin = new Avalonia.Thickness(0, 0, 0, 12)
};
// This overlay lives in tab content the user switches away from mid-capture.
Helpers.ProgressBarBehaviors.SetRestartOnReattach(progressBar, true);

/* #448: SelectableTextBlock and wrapping, because this label doubles as the place a query
failure is reported. A SQL error is the one string in this app a user most needs to copy
Expand Down Expand Up @@ -314,6 +316,8 @@ private async void GetActualPlan_Click(object? sender, RoutedEventArgs e)
Height = 4,
Margin = new Avalonia.Thickness(0, 0, 0, 12)
};
// This overlay lives in tab content the user switches away from mid-capture.
Helpers.ProgressBarBehaviors.SetRestartOnReattach(progressBar, true);

/* #448: see the note on the estimated-plan path — this label reports failures too. */
var statusLabel = new SelectableTextBlock
Expand Down Expand Up @@ -446,7 +450,10 @@ private Task<bool> ShowConfirmationDialog(string title, string message, string c

private Window GetParentWindow()
{
var parent = this.VisualRoot;
/* GetTopLevel rather than VisualRoot because Avalonia 12 hosts a Window inside a
TopLevelHost, so the visual root is no longer the Window and casting it to one always
misses — silently, since VisualRoot still compiles and still returns something. */
var parent = TopLevel.GetTopLevel(this);
return parent as Window ?? throw new InvalidOperationException("No parent window");
}
}
18 changes: 10 additions & 8 deletions src/PlanViewer.App/Controls/QueryStoreGridControl.axaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PlanViewer.App.Controls"
xmlns:helpers="using:PlanViewer.App.Helpers"
xmlns:models="using:PlanViewer.Core.Models"
x:Class="PlanViewer.App.Controls.QueryStoreGridControl"
Background="{DynamicResource BackgroundBrush}">
Expand Down Expand Up @@ -94,7 +95,7 @@
<StackPanel x:Name="SearchValuePanel" Spacing="4">
<TextBlock Text=" " FontSize="11"/>
<TextBox x:Name="SearchValueBox" Width="200" Height="36" FontSize="13"
Watermark="0x1AB2C3, dbo.MyProc"
PlaceholderText="0x1AB2C3, dbo.MyProc"
KeyDown="SearchValue_KeyDown"/>
</StackPanel>
<StackPanel x:Name="ExecutionTypePanel" Spacing="4" IsVisible="False">
Expand Down Expand Up @@ -170,12 +171,12 @@
<StackPanel Spacing="2">
<TextBlock Text="Query text contains" FontSize="11"
Foreground="{DynamicResource ForegroundBrush}"/>
<TextBox x:Name="TextSearchBox" Width="220" Height="32" Watermark="e.g. Votes"/>
<TextBox x:Name="TextSearchBox" Width="220" Height="32" PlaceholderText="e.g. Votes"/>
</StackPanel>
<StackPanel Spacing="2">
<TextBlock Text="Query text excludes" FontSize="11"
Foreground="{DynamicResource ForegroundBrush}"/>
<TextBox x:Name="TextExcludeBox" Width="220" Height="32" Watermark="e.g. #temp"/>
<TextBox x:Name="TextExcludeBox" Width="220" Height="32" PlaceholderText="e.g. #temp"/>
</StackPanel>
<CheckBox x:Name="EscapeBracketsBox" Content="Treat [ ] _ as literals"
VerticalAlignment="Bottom"
Expand All @@ -186,22 +187,22 @@
<StackPanel Spacing="2">
<TextBlock Text="Include query IDs" FontSize="11"
Foreground="{DynamicResource ForegroundBrush}"/>
<TextBox x:Name="IncludeQueryIdsBox" Width="180" Height="32" Watermark="1, 2, 3"/>
<TextBox x:Name="IncludeQueryIdsBox" Width="180" Height="32" PlaceholderText="1, 2, 3"/>
</StackPanel>
<StackPanel Spacing="2">
<TextBlock Text="Ignore query IDs" FontSize="11"
Foreground="{DynamicResource ForegroundBrush}"/>
<TextBox x:Name="IgnoreQueryIdsBox" Width="180" Height="32" Watermark="4, 5"/>
<TextBox x:Name="IgnoreQueryIdsBox" Width="180" Height="32" PlaceholderText="4, 5"/>
</StackPanel>
<StackPanel Spacing="2">
<TextBlock Text="Include plan IDs" FontSize="11"
Foreground="{DynamicResource ForegroundBrush}"/>
<TextBox x:Name="IncludePlanIdsBox" Width="180" Height="32" Watermark="10, 11"/>
<TextBox x:Name="IncludePlanIdsBox" Width="180" Height="32" PlaceholderText="10, 11"/>
</StackPanel>
<StackPanel Spacing="2">
<TextBlock Text="Ignore plan IDs" FontSize="11"
Foreground="{DynamicResource ForegroundBrush}"/>
<TextBox x:Name="IgnorePlanIdsBox" Width="180" Height="32" Watermark="12"/>
<TextBox x:Name="IgnorePlanIdsBox" Width="180" Height="32" PlaceholderText="12"/>
</StackPanel>
</StackPanel>
<!-- Actions -->
Expand Down Expand Up @@ -487,7 +488,8 @@
Background="#80000000" CornerRadius="0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8">
<ProgressBar IsIndeterminate="True" Width="200" Height="4"/>
<ProgressBar IsIndeterminate="True" Width="200" Height="4"
helpers:ProgressBarBehaviors.RestartOnReattach="True"/>
<TextBlock x:Name="GridLoadingText" Text="Fetching plans..."
FontSize="12" HorizontalAlignment="Center"
Foreground="{DynamicResource ForegroundBrush}"/>
Expand Down
4 changes: 3 additions & 1 deletion src/PlanViewer.App/Controls/QueryStoreHistoryControl.axaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:scottplot="clr-namespace:ScottPlot.Avalonia;assembly=ScottPlot.Avalonia"
xmlns:helpers="using:PlanViewer.App.Helpers"
x:Class="PlanViewer.App.Controls.QueryStoreHistoryControl"
Background="{DynamicResource BackgroundBrush}">

Expand Down Expand Up @@ -71,7 +72,8 @@
FontSize="12" Foreground="{DynamicResource ForegroundBrush}"/>
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="6" VerticalAlignment="Center"
x:Name="LoadingPanel" IsVisible="False" Margin="8,0,0,0">
<ProgressBar IsIndeterminate="True" Width="80" Height="6" VerticalAlignment="Center"/>
<ProgressBar IsIndeterminate="True" Width="80" Height="6" VerticalAlignment="Center"
helpers:ProgressBarBehaviors.RestartOnReattach="True"/>
<Button x:Name="CancelButton" Content="Cancel" Click="Cancel_Click"
Height="24" Padding="10,0" FontSize="11"
Theme="{StaticResource AppButton}"/>
Expand Down
2 changes: 2 additions & 0 deletions src/PlanViewer.App/Controls/QueryStoreOverviewControl.axaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:PlanViewer.App.Controls"
xmlns:helpers="using:PlanViewer.App.Helpers"
x:Class="PlanViewer.App.Controls.QueryStoreOverviewControl">
<UserControl.Resources>
<!--
Expand Down Expand Up @@ -179,6 +180,7 @@
<!-- Row 0: Progress bar + refresh-error badge -->
<Grid Grid.Row="0">
<ProgressBar x:Name="LoadingBar" IsIndeterminate="False"
helpers:ProgressBarBehaviors.RestartOnReattach="True"
Height="3" Margin="0"
VerticalAlignment="Top"
Foreground="{DynamicResource AccentBrush}"/>
Expand Down
4 changes: 3 additions & 1 deletion src/PlanViewer.App/Controls/WaitStatsProfileControl.axaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PlanViewer.App.Controls"
xmlns:helpers="using:PlanViewer.App.Helpers"
x:Class="PlanViewer.App.Controls.WaitStatsProfileControl">
<Grid RowDefinitions="Auto,*">
<!-- Header row: left controls + right-aligned legend button -->
Expand Down Expand Up @@ -35,7 +36,8 @@
Background="#80000000" CornerRadius="0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="6">
<ProgressBar IsIndeterminate="True" Width="140" Height="3"/>
<ProgressBar IsIndeterminate="True" Width="140" Height="3"
helpers:ProgressBarBehaviors.RestartOnReattach="True"/>
<TextBlock Text="Loading wait stats..."
FontSize="11" HorizontalAlignment="Center"
Foreground="{DynamicResource ForegroundBrush}"/>
Expand Down
8 changes: 4 additions & 4 deletions src/PlanViewer.App/Dialogs/ConnectionDialog.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
FontSize="12" Margin="0,0,0,4"/>
<Grid Grid.Row="1" x:Name="ServerNameGrid" ColumnDefinitions="*,Auto" Margin="0,0,0,12" ColumnSpacing="0">
<TextBox x:Name="ServerNameBox"
Watermark="e.g. sql2022 or server.database.windows.net"
PlaceholderText="e.g. sql2022 or server.database.windows.net"
TextChanged="RequiredField_TextChanged"
FontSize="13" Height="32"/>
<Button Grid.Column="1" Click="DropdownButton_Click"
Expand Down Expand Up @@ -57,7 +57,7 @@
<StackPanel Grid.Row="4" x:Name="LoginPanel" IsVisible="False" Margin="0,0,0,12">
<TextBlock Text="Login" Foreground="{DynamicResource ForegroundBrush}"
FontSize="12" Margin="0,0,0,4"/>
<TextBox x:Name="LoginBox" FontSize="13" Height="32" Watermark="sa"
<TextBox x:Name="LoginBox" FontSize="13" Height="32" PlaceholderText="sa"
TextChanged="RequiredField_TextChanged"/>
</StackPanel>

Expand All @@ -66,7 +66,7 @@
<TextBlock Text="Password" Foreground="{DynamicResource ForegroundBrush}"
FontSize="12" Margin="0,0,0,4"/>
<TextBox x:Name="PasswordBox" FontSize="13" Height="32"
PasswordChar="&#x25CF;" Watermark="Password"
PasswordChar="&#x25CF;" PlaceholderText="Password"
TextChanged="RequiredField_TextChanged"/>
</StackPanel>

Expand Down Expand Up @@ -94,7 +94,7 @@
<TextBlock Text="Initial database (optional)"
Foreground="{DynamicResource ForegroundBrush}" FontSize="12"/>
<TextBox x:Name="DatabaseInputBox" FontSize="13" Height="32"
Watermark="Leave empty to connect to master"
PlaceholderText="Leave empty to connect to master"
ToolTip.Tip="Connects directly to this database instead of master. Useful for Azure SQL Database or Just-In-Time access where the login can't open master. It is pre-selected below once the database list loads."/>
</StackPanel>
</StackPanel>
Expand Down
8 changes: 4 additions & 4 deletions src/PlanViewer.App/Dialogs/SettingsWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ private void EnsureIntegrationsLoaded()

/* The stored proxy password is deliberately not put into the TextBox. PasswordChar only
masks the glyph — the cleartext still sits in the visual and accessibility trees. The
watermark says it is saved, and an empty box at save time means "keep what is there". */
placeholder says it is saved, and an empty box at save time means "keep what is there". */
var proxy = ProxySettings.Load();
_hasStoredProxyPassword = !string.IsNullOrEmpty(proxy.Password);
_proxyMode = proxy.Mode;
Expand Down Expand Up @@ -506,10 +506,10 @@ void OnProxyModeChanged(object? sender, RoutedEventArgs _)
return panel;
}

private static TextBox CreateProxyInput(string text, string watermark) => new()
private static TextBox CreateProxyInput(string text, string placeholder) => new()
{
Text = text,
Watermark = watermark,
PlaceholderText = placeholder,
FontSize = 13,
Height = 32,
Padding = new Thickness(6, 2)
Expand Down Expand Up @@ -582,7 +582,7 @@ private void ResetIntegrations(bool clearStoredPassword)

/* This is the only way to delete a stored proxy password, because an empty password box
always means "keep what is there" — otherwise anyone who edited the proxy address would
have to retype the password. Clearing the flag too stops the watermark claiming a
have to retype the password. Clearing the flag too stops the placeholder claiming a
password is saved after the reset has taken it away. */
_clearStoredProxyPassword = _hasStoredProxyPassword;
_hasStoredProxyPassword = false;
Expand Down
2 changes: 1 addition & 1 deletion src/PlanViewer.App/Helpers/DataGridBehaviors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static void AttachCopyGuard(DataGrid grid, Func<object, string?> formatRo
{
// Mirror the built-in copy's exact gate: platform command modifier
// (Ctrl; Cmd on macOS), no Shift, no Alt.
var commandModifiers = TopLevel.GetTopLevel(grid)?.PlatformSettings?.HotkeyConfiguration.CommandModifiers
var commandModifiers = grid.GetPlatformSettings()?.HotkeyConfiguration.CommandModifiers
?? KeyModifiers.Control;
if (e.Key is not (Key.C or Key.Insert)
|| !e.KeyModifiers.HasFlag(commandModifiers)
Expand Down
65 changes: 65 additions & 0 deletions src/PlanViewer.App/Helpers/ProgressBarBehaviors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Threading;

namespace PlanViewer.App.Helpers;

/// <summary>
/// Restarts an indeterminate <see cref="ProgressBar"/>'s animation when it re-enters the
/// visual tree.
///
/// <para>Avalonia 12 completes a style-applied animation when its visual detaches — a handler
/// its changelog does not document, sitting outside the <c>PlaybackBehavior</c> pause guard —
/// and re-attaching re-applies the style without resurrecting the finished animation. Switch
/// tabs while a fetch is running and its loading bar comes back frozen mid-track, indistinguishable
/// from a hang. Avalonia 11 had no detach handling at all, so the bar just kept animating; this
/// restores that behavior at the seven bars whose hosts can detach mid-run.</para>
///
/// <para>The restart works by deactivating and reactivating the <c>:indeterminate</c> style:
/// flipping <see cref="ProgressBar.IsIndeterminate"/> off and, one dispatcher hop later, back on
/// makes the style system spawn a fresh animation instance. The hop is load-bearing — both flips
/// in the same pass coalesce into no style change at all.</para>
///
/// <para>Verified against the live symptom, not assumed: before this, five window captures
/// spanning a full animation cycle after a tab round-trip were pixel-identical in the bar's
/// region; with it, the sweep resumes. The headless suite cannot see any of this (animations
/// need frames), which is why the proof lives in a driven run rather than a test.</para>
/// </summary>
public static class ProgressBarBehaviors
{
/// <summary>
/// Set true on any indeterminate bar whose host can detach while it runs — tab content,
/// overlays inside documents, detachable panels.
/// </summary>
public static readonly AttachedProperty<bool> RestartOnReattachProperty =
AvaloniaProperty.RegisterAttached<ProgressBar, bool>(
"RestartOnReattach", typeof(ProgressBarBehaviors));

public static void SetRestartOnReattach(ProgressBar bar, bool value) =>
bar.SetValue(RestartOnReattachProperty, value);

public static bool GetRestartOnReattach(ProgressBar bar) =>
bar.GetValue(RestartOnReattachProperty);

static ProgressBarBehaviors()
{
RestartOnReattachProperty.Changed.AddClassHandler<ProgressBar>((bar, e) =>
{
if (e.NewValue is true)
bar.AttachedToVisualTree += Restart;
else
bar.AttachedToVisualTree -= Restart;
});
}

private static void Restart(object? sender, VisualTreeAttachmentEventArgs e)
{
/* An idle bar (Overview's LoadingBar between loads) has nothing to restart, and
flipping it would wrongly start one. */
if (sender is not ProgressBar bar || !bar.IsIndeterminate)
return;

bar.IsIndeterminate = false;
Dispatcher.UIThread.Post(() => bar.IsIndeterminate = true, DispatcherPriority.Loaded);
}
}
2 changes: 2 additions & 0 deletions src/PlanViewer.App/MainWindow.PlanViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@ emailed around. Name the target so "which server was that?" is answered
Height = 4,
Margin = new Avalonia.Thickness(0, 0, 0, 12)
};
// This loading tab detaches whenever the user switches top-level tabs mid-capture.
Helpers.ProgressBarBehaviors.SetRestartOnReattach(progressBar, true);

var statusText = new TextBlock
{
Expand Down
5 changes: 0 additions & 5 deletions src/PlanViewer.App/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -882,13 +882,8 @@ private void About_Click(object? sender, RoutedEventArgs e)
about.ShowDialog(this);
}

#pragma warning disable CS0618 // Data/DataFormats.Files deprecated but IDataTransfer API differs
private static readonly string[] _supportedExtensions = { ".sqlplan", ".xml", ".sql" };


#pragma warning restore CS0618


/// <summary>
/// Re-decides whether Compare Plans is offered, for every Compare button in the window (#447).
///
Expand Down
Loading
Loading