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: 1 addition & 9 deletions src/PlanViewer.App/Controls/QuerySessionControl.Format.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,7 @@ private async void Format_Click(object? sender, RoutedEventArgs e)

try
{
var settings = SqlFormatSettingsService.Load(out var loadError);
if (loadError != null)
SetStatus("Warning: using default format settings (load failed)");
var settings = AppSettingsService.Load().FormatOptions ?? new SqlFormatSettings();

var (formatted, errors) = await Task.Run(() => SqlFormattingService.Format(sql, settings));

Expand Down Expand Up @@ -150,10 +148,4 @@ private async void Format_Click(object? sender, RoutedEventArgs e)
FormatButton.IsEnabled = true;
}
}

private void FormatOptions_Click(object? sender, RoutedEventArgs e)
{
var dialog = new Dialogs.FormatOptionsWindow();
dialog.ShowDialog(GetParentWindow());
}
}
4 changes: 0 additions & 4 deletions src/PlanViewer.App/Controls/QuerySessionControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,6 @@
Height="28" Padding="10,0" FontSize="12"
Theme="{StaticResource AppButton}"
ToolTip.Tip="Format the SQL query"/>
<Button x:Name="FormatOptionsButton" Content="&#x2699; Format Options" Click="FormatOptions_Click"
Height="28" Padding="10,0" FontSize="12"
Theme="{StaticResource AppButton}"
ToolTip.Tip="Configure SQL formatting options"/>
</WrapPanel>
</DockPanel>
</Border>
Expand Down
32 changes: 31 additions & 1 deletion src/PlanViewer.App/Controls/QueryStoreGridControl.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,23 @@ public QueryStoreGridControl(ServerConnection serverConnection, ICredentialServi
_database = initialDatabase;
_connectionString = serverConnection.GetConnectionString(credentialService, initialDatabase);
_waitStatsSupported = supportsWaitStats;
_slicerDaysBack = AppSettingsService.Load().QueryStoreSlicerDays;

var userSettings = AppSettingsService.Load();
_slicerDaysBack = userSettings.QueryStoreSlicerDays;

InitializeComponent();

// Apply user defaults to UI controls
TopNBox.Value = userSettings.QueryStoreTopLimit;
SelectComboByTag(OrderByBox, userSettings.QueryStoreDefaultMetric);
SelectComboByTag(GroupByBox, userSettings.QueryStoreDefaultGroupBy switch
{
"QueryHash" => "query-hash",
"Module" => "module",
"None" => "none",
_ => "query-hash"
});

ResultsGrid.ItemsSource = _filteredRows;
Helpers.DataGridBehaviors.Attach(ResultsGrid);
EnsureFilterPopup();
Expand Down Expand Up @@ -227,6 +242,21 @@ private static readonly (string ColumnId, Func<QueryStoreRow, double> Accessor)[
["AvgMemSort"] = "AvgMemory",
};

private static void SelectComboByTag(ComboBox box, string tag)
{
for (int i = 0; i < box.Items.Count; i++)
{
if (box.Items[i] is ComboBoxItem item && item.Tag?.ToString() == tag)
{
box.SelectedIndex = i;
return;
}
}
// Unknown tag — fall back to the first item so the combo is never empty
if (box.Items.Count > 0)
box.SelectedIndex = 0;
}


}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,14 @@ private async System.Threading.Tasks.Task LoadHistoryAsync()
private void BuildColorMap()
{
_planHashColorMap.Clear();
var hashes = _historyData.Select(r => r.QueryPlanHash).Distinct().OrderBy(h => h).ToList();
var maxPlans = Services.AppSettingsService.Load().QueryHistoryMaxPlans;
var hashes = _historyData
.GroupBy(r => r.QueryPlanHash)
.OrderByDescending(g => g.Sum(r => r.CountExecutions))
.Take(maxPlans)
.Select(g => g.Key)
.OrderBy(h => h)
.ToList();
for (int i = 0; i < hashes.Count; i++)
_planHashColorMap[hashes[i]] = PlanColors[i % PlanColors.Length];
}
Expand Down
31 changes: 15 additions & 16 deletions src/PlanViewer.App/Controls/QueryStoreOverviewControl.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
using PlanViewer.App.Services;
using PlanViewer.Core.Interfaces;
using PlanViewer.Core.Models;
using PlanViewer.Core.Services;
Expand All @@ -38,18 +39,8 @@ public partial class QueryStoreOverviewControl : UserControl
private DateTime _slicerEndUtc;
private int _daysBack = 30;

// Color palette for databases (minimizes color dispersion)
private static readonly Color[] Palette = new[]
{
Color.Parse("#2EAEF1"), // blue
Color.Parse("#F2994A"), // orange
Color.Parse("#27AE60"), // green
Color.Parse("#9B51E0"), // purple
Color.Parse("#EB5757"), // red
Color.Parse("#F2C94C"), // yellow
Color.Parse("#56CCF2"), // light blue
Color.Parse("#BB6BD9"), // violet
};
// Color palette for databases — loaded from user settings
private readonly Color[] _palette;

private static readonly Color OthersColor = Color.Parse("#555555");

Expand All @@ -69,13 +60,21 @@ public class DrillDownEventArgs(string database, DateTime startUtc, DateTime end
public event EventHandler<DrillDownEventArgs>? DrillDownRequested;

public QueryStoreOverviewControl(ServerConnection serverConnection,
ICredentialService credentialService, int maxDop = 8, int topN = 4, bool supportsWaitStats = true)
ICredentialService credentialService, int maxDop = 8, int? topN = null, bool supportsWaitStats = true)
{
_serverConnection = serverConnection;
_credentialService = credentialService;
_masterConnectionString = serverConnection.GetConnectionString(credentialService, "master");
_maxDop = maxDop;
_topN = topN;

var userSettings = AppSettingsService.Load();
_topN = topN ?? userSettings.MultiQsTopDbCount;
_palette = userSettings.MultiQsTopDbColors
.Select(hex => { try { return Color.Parse(hex); } catch { return Color.Parse("#555555"); } })
.ToArray();
if (_palette.Length == 0)
_palette = AppSettingsService.DefaultTopDbColors.Select(hex => Color.Parse(hex)).ToArray();

_supportsWaitStats = supportsWaitStats;
_slicerEndUtc = DateTime.UtcNow;
_slicerStartUtc = _slicerEndUtc.AddHours(-24);
Expand Down Expand Up @@ -668,8 +667,8 @@ private void DrawBarCards()
.Select(m => m.DatabaseName)
.ToList();
var topDbs = ranked.Take(_topN).ToList();
for (int i = 0; i < topDbs.Count && i < Palette.Length; i++)
_dbColorMap[topDbs[i]] = Palette[i];
for (int i = 0; i < topDbs.Count && i < _palette.Length; i++)
_dbColorMap[topDbs[i]] = _palette[i];

DrawMetricRow(TotalMetricsGrid, isTotal: true, topDbs);
DrawMetricRow(AvgMetricsGrid, isTotal: false, topDbs);
Expand Down
10 changes: 6 additions & 4 deletions src/PlanViewer.App/Controls/TimeRangeSlicerControl.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
using PlanViewer.App.Services;
using PlanViewer.Core.Models;
using PlanViewer.Core.Services;

Expand Down Expand Up @@ -52,13 +53,14 @@ private enum DragMode { None, MoveRange, DragStart, DragEnd, SelectRect }
private double _selectRectOriginX; // canvas-x where drag-select started
private double _selectRectCurrentX; // canvas-x of current pointer during drag-select

private string _activeFilterTag = "24"; // tag of the currently active quick-filter button
private string _activeFilterTag; // tag from user settings
private DispatcherTimer? _rangeChangedDebounce;

public event EventHandler<TimeRangeChangedEventArgs>? RangeChanged;

public TimeRangeSlicerControl()
{
_activeFilterTag = AppSettingsService.Load().QueryStoreDefaultTimeRange;
InitializeComponent();
SlicerBorder.SizeChanged += (_, _) => Redraw();
SlicerCanvas.Focusable = true;
Expand All @@ -80,13 +82,13 @@ public void LoadData(List<QueryStoreTimeSlice> data, string metric,
}
else
{
// Default selection: last 24 hours
// Default selection from user settings
_rangeEnd = 1.0;
_activeFilterTag = "24";
var defaultHours = int.TryParse(_activeFilterTag, out var h) ? h : 24;
if (_data.Count >= 2)
{
var last = _data[^1].IntervalStartUtc.AddHours(1);
var start24h = last.AddHours(-24);
var start24h = last.AddHours(-defaultHours);
_rangeStart = GetNormFromDateTime(start24h);
}
else
Expand Down
56 changes: 56 additions & 0 deletions src/PlanViewer.App/Dialogs/FormatOptionRow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.ComponentModel;
using System.Reflection;

namespace PlanViewer.App.Dialogs;

internal class FormatOptionRow : INotifyPropertyChanged
{
private string _currentValue = "";
private bool _boolValue;

public string Name { get; set; } = "";

public bool IsBool { get; set; }

public bool BoolValue
{
get => _boolValue;
set
{
if (_boolValue == value) return;
_boolValue = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(BoolValue)));
// Keep CurrentValue in sync for serialization
if (IsBool)
{
_currentValue = value.ToString();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentValue)));
}
}
}

public bool DefaultBoolValue { get; set; }

public string[]? ChoiceOptions { get; set; }

public bool IsChoice => ChoiceOptions != null;

public bool IsText => !IsBool && !IsChoice;

public string CurrentValue
{
get => _currentValue;
set
{
if (_currentValue == value) return;
_currentValue = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentValue)));
}
}

public string DefaultValue { get; set; } = "";

internal PropertyInfo PropertyInfo { get; set; } = null!;

public event PropertyChangedEventHandler? PropertyChanged;
}
121 changes: 0 additions & 121 deletions src/PlanViewer.App/Dialogs/FormatOptionsWindow.axaml

This file was deleted.

Loading
Loading