Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
6c628be
Fix XE ring buffer query timeouts on large buffers (#37)
erikdarlingdata Feb 15, 2026
7506cb6
Merge pull request #38 from erikdarlingdata/feature/23-xe-ring-buffer…
erikdarlingdata Feb 15, 2026
e21f642
Add Collection Health tab to Lite UI (#39)
erikdarlingdata Feb 15, 2026
98e4aac
Merge pull request #42 from erikdarlingdata/feature/39-collector-heal…
erikdarlingdata Feb 15, 2026
b9a6d71
Add collector performance diagnostics to Lite UI (#40)
erikdarlingdata Feb 15, 2026
ac0ae5b
Merge pull request #43 from erikdarlingdata/feature/40-collector-diag…
erikdarlingdata Feb 15, 2026
27ade9d
Fix query_cost overflow in memory grant collector, add Last Error At …
erikdarlingdata Feb 15, 2026
c957c0d
Merge pull request #47 from erikdarlingdata/feature/fix-query-cost-ov…
erikdarlingdata Feb 15, 2026
5bfc15d
Use locale-aware date/time formatting throughout UI (#41)
erikdarlingdata Feb 15, 2026
f132193
Switch time range picker to 24-hour format in both apps
erikdarlingdata Feb 15, 2026
f5caef2
Merge pull request #48 from erikdarlingdata/feature/41-locale-aware-d…
erikdarlingdata Feb 15, 2026
259b4d4
Fix chart X-axis double-converting custom range to server time (#49)
erikdarlingdata Feb 15, 2026
638b1ed
Merge pull request #50 from erikdarlingdata/feature/49-chart-timezone…
erikdarlingdata Feb 15, 2026
e235703
Persist dismissed alerts across restarts, fix time-range ack bug (#44)
erikdarlingdata Feb 15, 2026
e4b94f4
Merge pull request #51 from erikdarlingdata/feature/44-alert-persistence
erikdarlingdata Feb 15, 2026
5e49b10
Add average ms per wait chart toggle to both apps (#22)
erikdarlingdata Feb 16, 2026
ee3fcb2
Merge pull request #54 from erikdarlingdata/feature/22-avg-ms-per-wait
erikdarlingdata Feb 16, 2026
3f23f55
Fix minimize-to-tray setting ignored in Dashboard, add setting to Lit…
erikdarlingdata Feb 16, 2026
57ea5ac
Merge pull request #55 from erikdarlingdata/feature/53-minimize-to-tray
erikdarlingdata Feb 16, 2026
177f57d
Add alert types, alerts history view, column filtering, and dismiss/h…
erikdarlingdata Feb 16, 2026
81d3316
Validate XML processor output before marking rows as processed
erikdarlingdata Feb 16, 2026
0e97b16
It sure was doing that. You know when you remove a WHERE clause to ma…
erikdarlingdata Feb 16, 2026
ed5e6cc
Merge pull request #65 from erikdarlingdata/feature/61-fix-lite-dupli…
erikdarlingdata Feb 16, 2026
5a72be7
Add commercial support tiers to README
erikdarlingdata Feb 16, 2026
b0dcf67
Merge pull request #66 from erikdarlingdata/feature/readme-commercial…
erikdarlingdata Feb 16, 2026
51f4a80
Fix Dashboard sub-tab badges and DuckDB migration for dismissed column
erikdarlingdata Feb 16, 2026
4b3d7ef
Merge pull request #68 from erikdarlingdata/feature/dashboard-badge-f…
erikdarlingdata Feb 16, 2026
f60d654
Add hover tooltips to all Dashboard charts (fixes #70)
erikdarlingdata Feb 16, 2026
031da8d
Merge pull request #74 from erikdarlingdata/feature/dashboard-hover-t…
erikdarlingdata Feb 16, 2026
c0ed5fb
Add CI pipelines for build validation, SQL install testing, and DuckD…
erikdarlingdata Feb 16, 2026
65cbb28
Fix SQL validation CI: use log-based health check and handle pre-conf…
erikdarlingdata Feb 16, 2026
3452f4d
Fix procedure_stats_collector truncation on DDL triggers (fixes #69)
erikdarlingdata Feb 16, 2026
bf937f2
Merge pull request #76 from erikdarlingdata/feature/fix-trigger-name-…
erikdarlingdata Feb 16, 2026
09b2d84
Merge pull request #75 from erikdarlingdata/feature/ci-pipelines
erikdarlingdata Feb 16, 2026
95755f0
Increase DataGrid row height from 25 to 28 to fix text clipping
erikdarlingdata Feb 16, 2026
47010a9
Add FocusServerTabOnClick user setting for server tab navigation
erikdarlingdata Feb 16, 2026
b5d8477
Fix deadlock charts not populating data (fixes #73)
erikdarlingdata Feb 16, 2026
3932bb5
Merge pull request #80 from erikdarlingdata/feature/fix-deadlock-charts
erikdarlingdata Feb 16, 2026
6375ffa
Merge pull request #78 from erikdarlingdata/feature/fix-row-height-cl…
erikdarlingdata Feb 16, 2026
5427618
Merge pull request #79 from erikdarlingdata/feature/auto-focus-server…
erikdarlingdata Feb 16, 2026
4efc6f6
Add missing chart hover tooltips for CPU, Memory, and TempDB charts i…
erikdarlingdata Feb 16, 2026
716cfd0
Merge pull request #82 from erikdarlingdata/feature/fix-lite-chart-to…
erikdarlingdata Feb 16, 2026
ea13df4
Pass @skip_locks and @skip_waits to sp_HealthParser in collector wrapper
erikdarlingdata Feb 17, 2026
cc15b19
Chain-trigger blocking/deadlock parsers, optimize XML collection, tun…
erikdarlingdata Feb 17, 2026
ee58115
Merge pull request #87 from erikdarlingdata/feature/skip-waits-wrapper
erikdarlingdata Feb 17, 2026
0b8a840
Replace all AddWithValue with explicit SqlParameter types, fix alert …
erikdarlingdata Feb 17, 2026
f8d1b63
Fix chart zero lines, collection log server name, and overview online…
erikdarlingdata Feb 17, 2026
d5df71c
Merge pull request #95 from erikdarlingdata/feature/fixes-85-91-93
erikdarlingdata Feb 17, 2026
cdc2e6d
Merge pull request #88 from erikdarlingdata/feature/86-collector-chai…
erikdarlingdata Feb 17, 2026
a5884e6
Update schema version assertion to v10 in tests
erikdarlingdata Feb 17, 2026
24a5e38
Merge pull request #96 from erikdarlingdata/fix/schema-version-test
erikdarlingdata Feb 17, 2026
0a2148f
Use DuckDbInitializer.CurrentSchemaVersion in tests instead of hardco…
erikdarlingdata Feb 17, 2026
991c2b2
Merge pull request #97 from erikdarlingdata/fix/schema-version-test-d…
erikdarlingdata Feb 17, 2026
0fb96eb
Add --reset-schedule flag to reset collection schedule on re-install
erikdarlingdata Feb 17, 2026
22bd9b6
Merge pull request #98 from erikdarlingdata/feature/92-reset-schedule
erikdarlingdata Feb 17, 2026
6218041
Skip offline servers during collection and reduce connection timeout
erikdarlingdata Feb 17, 2026
f43e507
Merge pull request #99 from erikdarlingdata/feature/90-skip-offline-s…
erikdarlingdata Feb 17, 2026
ecad30b
Issue #101 update NuGet packages to latest stable version
OZTPR Feb 18, 2026
cd790c3
Add dev branch to CI build trigger
erikdarlingdata Feb 18, 2026
b12d20e
Merge pull request #103 from erikdarlingdata/feature/ci-dev-trigger
erikdarlingdata Feb 18, 2026
5ae4469
Merge branch 'dev' into update-nuget
erikdarlingdata Feb 18, 2026
58f1f15
Merge pull request #102 from MisterZeus/update-nuget
erikdarlingdata Feb 18, 2026
cfe5cf4
Bump version to 1.2.0
erikdarlingdata Feb 18, 2026
cc7cde8
Merge pull request #114 from erikdarlingdata/feature/v1.2.0-release
erikdarlingdata Feb 18, 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
207 changes: 207 additions & 0 deletions .github/sql/ci_validate_installation.sql

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
branches: [main]
pull_request:
branches: [main]
branches: [main, dev]
release:
types: [created]

Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI

on:
push:
branches: [dev]
pull_request:
branches: [dev]

jobs:
build:
runs-on: windows-latest

steps:
- uses: actions/checkout@v4

- name: Setup .NET 8.0
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x

- name: Restore dependencies
run: |
dotnet restore Dashboard/Dashboard.csproj
dotnet restore Lite/PerformanceMonitorLite.csproj
dotnet restore Installer/PerformanceMonitorInstaller.csproj
dotnet restore InstallerGui/InstallerGui.csproj
dotnet restore Lite.Tests/Lite.Tests.csproj

- name: Build all projects
run: |
dotnet build Dashboard/Dashboard.csproj -c Release --no-restore
dotnet build Lite/PerformanceMonitorLite.csproj -c Release --no-restore
dotnet build Installer/PerformanceMonitorInstaller.csproj -c Release --no-restore
dotnet build InstallerGui/InstallerGui.csproj -c Release --no-restore
dotnet build Lite.Tests/Lite.Tests.csproj -c Release --no-restore

- name: Run tests
run: dotnet test Lite.Tests/Lite.Tests.csproj -c Release --no-build --verbosity normal
79 changes: 79 additions & 0 deletions .github/workflows/sql-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: SQL Validation

on:
push:
branches: [dev]
paths: ['install/**']
pull_request:
branches: [dev]
paths: ['install/**']

jobs:
validate-sql:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- version: '2017'
image: mcr.microsoft.com/mssql/server:2017-latest
- version: '2019'
image: mcr.microsoft.com/mssql/server:2019-latest
- version: '2022'
image: mcr.microsoft.com/mssql/server:2022-latest
- version: '2025'
image: mcr.microsoft.com/mssql/server:2025-latest

name: SQL Server ${{ matrix.version }}

services:
sqlserver:
image: ${{ matrix.image }}
env:
ACCEPT_EULA: Y
MSSQL_SA_PASSWORD: CI_Test#2026!
ports:
- 1433:1433
options: >-
--health-cmd "grep -q 'SQL Server is now ready for client connections' /var/opt/mssql/log/errorlog || exit 1"
--health-interval 10s
--health-timeout 5s
--health-retries 15

steps:
- uses: actions/checkout@v4

- name: Install sqlcmd
run: |
# Ubuntu 24.04 runners have Microsoft repo pre-configured; avoid Signed-By conflicts
if ! grep -rql 'packages.microsoft.com' /etc/apt/sources.list.d/ 2>/dev/null; then
curl -sSL https://packages.microsoft.com/keys/microsoft.asc | sudo gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg
source /etc/os-release
echo "deb [arch=amd64,signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/ubuntu/${VERSION_ID}/prod ${VERSION_CODENAME} main" | sudo tee /etc/apt/sources.list.d/mssql-release.list
fi
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools18

- name: Run install scripts
env:
SA_PASSWORD: CI_Test#2026!
run: |
for script in $(ls install/[0-9]*.sql | sort); do
filename=$(basename "$script")

# Skip scripts that require SQL Agent or are test/troubleshooting
case "$filename" in
45_*) echo "Skipping $filename (requires SQL Agent)"; continue;;
97_*|98_*|99_*) echo "Skipping $filename (test/troubleshooting)"; continue;;
esac

echo "Running $filename..."
/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$SA_PASSWORD" -C -No -b -i "$script"
echo " OK"
done

- name: Validate installation
env:
SA_PASSWORD: CI_Test#2026!
run: |
/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$SA_PASSWORD" -C -No -b -i .github/sql/ci_validate_installation.sql
2 changes: 1 addition & 1 deletion Dashboard/AboutWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<!-- Title -->
<TextBlock Grid.Row="0" Text="Performance Monitor Dashboard" FontWeight="Bold" FontSize="18" Margin="0,0,0,5"/>
<TextBlock Grid.Row="1" x:Name="VersionText" Text="Version 1.1.0" FontSize="12" Foreground="{DynamicResource ForegroundMutedBrush}" Margin="0,0,0,20"/>
<TextBlock Grid.Row="1" x:Name="VersionText" Text="Version 1.2.0" FontSize="12" Foreground="{DynamicResource ForegroundMutedBrush}" Margin="0,0,0,20"/>

<!-- Copyright -->
<StackPanel Grid.Row="2" Margin="0,0,0,20">
Expand Down
4 changes: 2 additions & 2 deletions Dashboard/CollectorScheduleWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
<DataGridTextColumn Header="Collector" Binding="{Binding DisplayName}" Width="180" IsReadOnly="True"/>
<DataGridTextColumn Header="Frequency (min)" Binding="{Binding FrequencyMinutes, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Width="110"/>
<DataGridTextColumn Header="Retention (days)" Binding="{Binding RetentionDays, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Width="110"/>
<DataGridTextColumn Header="Last Run" Binding="{Binding LastRunTime, StringFormat='{}{0:MM/dd HH:mm}'}" Width="100" IsReadOnly="True"/>
<DataGridTextColumn Header="Next Run" Binding="{Binding NextRunTime, StringFormat='{}{0:MM/dd HH:mm}'}" Width="100" IsReadOnly="True"/>
<DataGridTextColumn Header="Last Run" Binding="{Binding LastRunTime, StringFormat='{}{0:g}'}" Width="100" IsReadOnly="True"/>
<DataGridTextColumn Header="Next Run" Binding="{Binding NextRunTime, StringFormat='{}{0:g}'}" Width="100" IsReadOnly="True"/>
<DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="*" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
Expand Down
157 changes: 157 additions & 0 deletions Dashboard/Controls/AlertsHistoryContent.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<UserControl x:Class="PerformanceMonitorDashboard.Controls.AlertsHistoryContent"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/DarkTheme.xaml"/>
</ResourceDictionary.MergedDictionaries>

<!-- Context Menu for DataGrid Copy/Export -->
<ContextMenu x:Key="DataGridContextMenu">
<MenuItem Header="Copy Cell" Click="CopyCell_Click"/>
<MenuItem Header="Copy Row" Click="CopyRow_Click"/>
<MenuItem Header="Copy All Rows" Click="CopyAllRows_Click"/>
<Separator/>
<MenuItem Header="Export to CSV..." Click="ExportToCsv_Click"/>
</ContextMenu>

<Style x:Key="DefaultRowStyle" TargetType="DataGridRow">
<Setter Property="ContextMenu" Value="{StaticResource DataGridContextMenu}"/>
</Style>

<Style x:Key="AlertRowStyle" TargetType="DataGridRow" BasedOn="{StaticResource DefaultRowStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsCritical}" Value="True">
<Setter Property="Background" Value="#33DC2626"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsWarning}" Value="True">
<Setter Property="Background" Value="#33D97706"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsResolved}" Value="True">
<Setter Property="Background" Value="#3322C55E"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<!-- Header Controls -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="10,5" Background="{DynamicResource BackgroundLightBrush}" Height="40">
<TextBlock Text="Alert History" VerticalAlignment="Center" Margin="5,0,10,0" FontWeight="Bold" FontSize="14"
Foreground="{DynamicResource ForegroundBrush}"/>
<TextBlock Text="Time Range:" VerticalAlignment="Center" Margin="5,0,4,0"
Foreground="{DynamicResource ForegroundMutedBrush}"/>
<ComboBox x:Name="TimeRangeComboBox" Width="100" VerticalAlignment="Center"
SelectionChanged="TimeRangeComboBox_SelectionChanged">
<ComboBoxItem Content="Last 1 Hour" Tag="1"/>
<ComboBoxItem Content="Last 4 Hours" Tag="4"/>
<ComboBoxItem Content="Last 24 Hours" Tag="24" IsSelected="True"/>
<ComboBoxItem Content="Last 7 Days" Tag="168"/>
<ComboBoxItem Content="All" Tag="0"/>
</ComboBox>
<TextBlock Text="Server:" VerticalAlignment="Center" Margin="12,0,4,0"
Foreground="{DynamicResource ForegroundMutedBrush}"/>
<ComboBox x:Name="ServerFilterComboBox" Width="160" VerticalAlignment="Center"
SelectionChanged="ServerFilterComboBox_SelectionChanged">
<ComboBoxItem Content="All Servers" IsSelected="True"/>
</ComboBox>
<Button Content="Refresh" Click="RefreshButton_Click" Margin="12,0,0,0" Padding="10,4" MinWidth="70"
Style="{StaticResource SuccessButton}"/>
<Button x:Name="DismissSelectedButton" Content="Dismiss Selected" Click="DismissSelected_Click"
Margin="8,0,0,0" Padding="10,4" MinWidth="90" IsEnabled="False"/>
<Button Content="Dismiss All" Click="DismissAll_Click"
Margin="4,0,0,0" Padding="10,4" MinWidth="70"/>
<TextBlock x:Name="AlertCountIndicator" Text="" Margin="12,0,0,0" VerticalAlignment="Center"
FontStyle="Italic" Foreground="{DynamicResource AccentBrush}" FontWeight="SemiBold"/>
</StackPanel>

<!-- DataGrid -->
<Grid Grid.Row="1">
<DataGrid x:Name="AlertsDataGrid"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserSortColumns="True"
GridLinesVisibility="Horizontal"
CanUserResizeColumns="True"
SelectionMode="Extended"
SelectionChanged="AlertsDataGrid_SelectionChanged"
RowStyle="{StaticResource AlertRowStyle}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding TimeLocal}" Width="150">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="TimeLocal" Click="AlertFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Time" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding ServerName}" Width="140">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="ServerName" Click="AlertFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Server" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MetricName}" Width="160">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MetricName" Click="AlertFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Alert Type" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding CurrentValue}" Width="200">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="CurrentValue" Click="AlertFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Value" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding ThresholdValue}" Width="140">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="ThresholdValue" Click="AlertFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Threshold" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding NotificationType}" Width="80">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="NotificationType" Click="AlertFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Channel" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding StatusDisplay}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="StatusDisplay" Click="AlertFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Status" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>

<!-- Empty State -->
<TextBlock x:Name="NoAlertsMessage"
Text="No alerts recorded in the selected time range"
FontSize="14" Foreground="{DynamicResource ForegroundMutedBrush}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Visibility="Collapsed"/>
</Grid>
</Grid>
</UserControl>
Loading
Loading