diff --git a/Dashboard/AddServerDialog.xaml b/Dashboard/AddServerDialog.xaml
index bcdb6cae..a4c788f1 100644
--- a/Dashboard/AddServerDialog.xaml
+++ b/Dashboard/AddServerDialog.xaml
@@ -2,13 +2,19 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Add SQL Server"
- SizeToContent="Height" Width="500" MaxHeight="1050"
+ Height="750" Width="500"
WindowStartupLocation="CenterOwner"
- ResizeMode="NoResize"
+ ResizeMode="CanResizeWithGrip"
Background="{DynamicResource BackgroundBrush}"
Foreground="{DynamicResource ForegroundBrush}">
-
-
+
+
+
+
+
+
+
+
@@ -16,7 +22,6 @@
-
@@ -217,14 +222,17 @@
Foreground="{DynamicResource ForegroundMutedBrush}"
TextWrapping="Wrap" Margin="0,8,0,0" Visibility="Collapsed"/>
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Dashboard/AddServerDialog.xaml.cs b/Dashboard/AddServerDialog.xaml.cs
index 1ab8bc60..7595d755 100644
--- a/Dashboard/AddServerDialog.xaml.cs
+++ b/Dashboard/AddServerDialog.xaml.cs
@@ -313,6 +313,24 @@ happens after the connection test in DetectDatabaseStatusAsync() */
return (connected, errorMessage, mfaCancelled, serverVersion);
}
+ private async void CheckForUpdates_Click(object sender, RoutedEventArgs e)
+ {
+ if (!ValidateInputs()) return;
+
+ CheckForUpdatesButton.IsEnabled = false;
+ CheckForUpdatesButton.Content = "Checking...";
+
+ try
+ {
+ await DetectDatabaseStatusAsync();
+ }
+ finally
+ {
+ CheckForUpdatesButton.IsEnabled = true;
+ CheckForUpdatesButton.Content = "Check for Updates";
+ }
+ }
+
private async void TestConnection_Click(object sender, RoutedEventArgs e)
{
if (!ValidateInputs()) return;
diff --git a/Dashboard/Controls/LandingPage.xaml b/Dashboard/Controls/LandingPage.xaml
index f55d8c5e..a98b29aa 100644
--- a/Dashboard/Controls/LandingPage.xaml
+++ b/Dashboard/Controls/LandingPage.xaml
@@ -74,7 +74,9 @@
+ CardClicked="ServerHealthCard_CardClicked"
+ EditServerRequested="ServerHealthCard_EditServerRequested"
+ CheckVersionRequested="ServerHealthCard_CheckVersionRequested"/>
diff --git a/Dashboard/Controls/LandingPage.xaml.cs b/Dashboard/Controls/LandingPage.xaml.cs
index b0816dee..d03902ef 100644
--- a/Dashboard/Controls/LandingPage.xaml.cs
+++ b/Dashboard/Controls/LandingPage.xaml.cs
@@ -10,6 +10,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -168,6 +169,10 @@ private async Task RefreshServerAsync(ServerHealthStatus status)
// and the UI updates automatically via data binding
await databaseService.RefreshNocHealthStatusAsync(status);
+ // Populate installed monitor version from connectivity check
+ var connStatus = _serverManager.GetConnectionStatus(server.Id);
+ status.MonitorVersion = connStatus.InstalledMonitorVersion;
+
// Update tab badges in MainWindow
UpdateTabBadges(status);
}
@@ -221,6 +226,80 @@ private void ServerHealthCard_CardClicked(object? sender, ServerHealthStatus sta
ServerCardClicked?.Invoke(this, status.Server);
}
+ private void ServerHealthCard_EditServerRequested(object? sender, ServerHealthStatus status)
+ {
+ var server = status.Server;
+ var dialog = new AddServerDialog(server);
+ dialog.Owner = Window.GetWindow(this);
+
+ if (dialog.ShowDialog() == true)
+ {
+ try
+ {
+ _serverManager.UpdateServer(dialog.ServerConnection, dialog.Username, dialog.Password);
+ _ = ReloadServersAsync();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"Failed to update server:\n\n{ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+ }
+
+ private async void ServerHealthCard_CheckVersionRequested(object? sender, ServerHealthStatus status)
+ {
+ var server = status.Server;
+
+ try
+ {
+ string? installedVersion = await _serverManager.GetInstalledVersionAsync(server);
+
+ if (installedVersion == null)
+ {
+ MessageBox.Show(
+ $"No PerformanceMonitor installation found on '{server.DisplayNameWithIntent}'.",
+ "Not Installed", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
+ string appVersion = Assembly.GetExecutingAssembly()
+ .GetCustomAttribute()?.InformationalVersion
+ ?? Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0";
+ int plusIndex = appVersion.IndexOf('+');
+ if (plusIndex >= 0) appVersion = appVersion[..plusIndex];
+
+ static string Normalize(string v) =>
+ Version.TryParse(v, out var p) ? new Version(p.Major, p.Minor, p.Build).ToString() : v;
+
+ string normalizedInstalled = Normalize(installedVersion);
+ string normalizedApp = Normalize(appVersion);
+
+ if (Version.TryParse(normalizedInstalled, out var installed) &&
+ Version.TryParse(normalizedApp, out var app) &&
+ installed < app)
+ {
+ var result = MessageBox.Show(
+ $"'{server.DisplayNameWithIntent}' has v{normalizedInstalled} installed.\n\nv{normalizedApp} is available. Open the server editor to upgrade?",
+ "Update Available", MessageBoxButton.YesNo, MessageBoxImage.Information);
+
+ if (result == MessageBoxResult.Yes)
+ {
+ ServerHealthCard_EditServerRequested(sender, status);
+ }
+ }
+ else
+ {
+ MessageBox.Show(
+ $"'{server.DisplayNameWithIntent}' is up to date (v{normalizedInstalled}).",
+ "No Updates", MessageBoxButton.OK, MessageBoxImage.Information);
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"Failed to check version:\n\n{ex.Message}", "Connection Error", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
///
/// Reloads the server list (call when servers are added/removed).
///
diff --git a/Dashboard/Controls/ServerHealthCard.xaml b/Dashboard/Controls/ServerHealthCard.xaml
index edca0408..50b7a619 100644
--- a/Dashboard/Controls/ServerHealthCard.xaml
+++ b/Dashboard/Controls/ServerHealthCard.xaml
@@ -8,6 +8,19 @@
Background="Transparent"
MouseLeftButtonDown="Card_MouseLeftButtonDown"
Cursor="Hand">
+
+
+
+
+
+
+
diff --git a/Dashboard/Controls/ServerHealthCard.xaml.cs b/Dashboard/Controls/ServerHealthCard.xaml.cs
index ef26523c..fe5f6acc 100644
--- a/Dashboard/Controls/ServerHealthCard.xaml.cs
+++ b/Dashboard/Controls/ServerHealthCard.xaml.cs
@@ -25,6 +25,8 @@ public partial class ServerHealthCard : UserControl
private static readonly SolidColorBrush UnknownBrush = new(Color.FromRgb(0x88, 0x88, 0x88)); // Gray
public event EventHandler? CardClicked;
+ public event EventHandler? EditServerRequested;
+ public event EventHandler? CheckVersionRequested;
public ServerHealthCard()
{
@@ -167,5 +169,23 @@ private void Card_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
CardClicked?.Invoke(this, status);
}
}
+
+ private void OpenInNewTab_Click(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ServerHealthStatus status)
+ CardClicked?.Invoke(this, status);
+ }
+
+ private void EditServer_Click(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ServerHealthStatus status)
+ EditServerRequested?.Invoke(this, status);
+ }
+
+ private void CheckVersion_Click(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ServerHealthStatus status)
+ CheckVersionRequested?.Invoke(this, status);
+ }
}
}
diff --git a/Dashboard/MainWindow.xaml b/Dashboard/MainWindow.xaml
index 7ac71af7..f279038a 100644
--- a/Dashboard/MainWindow.xaml
+++ b/Dashboard/MainWindow.xaml
@@ -118,6 +118,12 @@
Foreground="{Binding StatusColor}"
Margin="0,-1,0,0"
Visibility="{Binding HasBeenChecked, Converter={StaticResource BoolToVisibilityConverter}}"/>
+
+
@@ -137,6 +143,9 @@
+