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
36 changes: 22 additions & 14 deletions Dashboard/AddServerDialog.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@
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}">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid Margin="20">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<!-- Header -->
Expand Down Expand Up @@ -217,14 +222,17 @@
Foreground="{DynamicResource ForegroundMutedBrush}"
TextWrapping="Wrap" Margin="0,8,0,0" Visibility="Collapsed"/>

<!-- Buttons -->
<StackPanel Grid.Row="6" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,15,0,0">
<Button x:Name="ViewReportButton" Content="View Report" Margin="0,0,8,0"
Click="ViewReport_Click" Visibility="Collapsed"/>
<Button x:Name="TestConnectionButton" Content="Test Connection" Margin="0,0,8,0" Click="TestConnection_Click"/>
<Button x:Name="SaveButton" Content="Save" MinWidth="80" Height="30" Padding="12,0" Margin="0,0,10,0" Click="Save_Click" IsDefault="True" Style="{StaticResource AccentButton}"/>
<Button Content="Cancel" Width="80" Height="30" Click="Cancel_Click" IsCancel="True"/>
</StackPanel>
</Grid>
</ScrollViewer>
</ScrollViewer>

<!-- Buttons pinned to bottom -->
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,15,0,0">
<Button x:Name="ViewReportButton" Content="View Report" Margin="0,0,8,0"
Click="ViewReport_Click" Visibility="Collapsed"/>
<Button x:Name="CheckForUpdatesButton" Content="Check for Updates" Margin="0,0,8,0" Click="CheckForUpdates_Click"/>
<Button x:Name="TestConnectionButton" Content="Test Connection" Margin="0,0,8,0" Click="TestConnection_Click"/>
<Button x:Name="SaveButton" Content="Save" MinWidth="80" Height="30" Padding="12,0" Margin="0,0,10,0" Click="Save_Click" IsDefault="True" Style="{StaticResource AccentButton}"/>
<Button Content="Cancel" Width="80" Height="30" Click="Cancel_Click" IsCancel="True"/>
</StackPanel>
</Grid>
</Window>
18 changes: 18 additions & 0 deletions Dashboard/AddServerDialog.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion Dashboard/Controls/LandingPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@
<DataTemplate>
<local:ServerHealthCard Width="300"
Height="220"
CardClicked="ServerHealthCard_CardClicked"/>
CardClicked="ServerHealthCard_CardClicked"
EditServerRequested="ServerHealthCard_EditServerRequested"
CheckVersionRequested="ServerHealthCard_CheckVersionRequested"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Expand Down
79 changes: 79 additions & 0 deletions Dashboard/Controls/LandingPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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<AssemblyInformationalVersionAttribute>()?.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);
}
}

/// <summary>
/// Reloads the server list (call when servers are added/removed).
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions Dashboard/Controls/ServerHealthCard.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@
Background="Transparent"
MouseLeftButtonDown="Card_MouseLeftButtonDown"
Cursor="Hand">
<UserControl.ContextMenu>
<ContextMenu>
<MenuItem Header="Open in New Tab" Click="OpenInNewTab_Click">
<MenuItem.Icon><TextBlock Text="&#x1F5C2;"/></MenuItem.Icon>
</MenuItem>
<MenuItem Header="Edit Server..." Click="EditServer_Click">
<MenuItem.Icon><TextBlock Text="&#x270F;"/></MenuItem.Icon>
</MenuItem>
<MenuItem Header="Check Server Version" Click="CheckVersion_Click">
<MenuItem.Icon><TextBlock Text="&#x1F504;"/></MenuItem.Icon>
</MenuItem>
</ContextMenu>
</UserControl.ContextMenu>
<UserControl.Resources>
<ResourceDictionary>
<!-- Severity to color converter -->
Expand Down
20 changes: 20 additions & 0 deletions Dashboard/Controls/ServerHealthCard.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public partial class ServerHealthCard : UserControl
private static readonly SolidColorBrush UnknownBrush = new(Color.FromRgb(0x88, 0x88, 0x88)); // Gray

public event EventHandler<ServerHealthStatus>? CardClicked;
public event EventHandler<ServerHealthStatus>? EditServerRequested;
public event EventHandler<ServerHealthStatus>? CheckVersionRequested;

public ServerHealthCard()
{
Expand Down Expand Up @@ -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);
}
}
}
9 changes: 9 additions & 0 deletions Dashboard/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@
Foreground="{Binding StatusColor}"
Margin="0,-1,0,0"
Visibility="{Binding HasBeenChecked, Converter={StaticResource BoolToVisibilityConverter}}"/>
<!-- Monitor Version -->
<TextBlock Text="{Binding MonitorVersionDisplay, Mode=OneWay}"
FontSize="11"
Foreground="{DynamicResource ForegroundMutedBrush}"
Margin="0,-1,0,0"
Visibility="{Binding HasBeenChecked, Converter={StaticResource BoolToVisibilityConverter}}"/>
<!-- Last Checked Timestamp -->
<TextBlock FontSize="12" Foreground="{DynamicResource ForegroundDimBrush}" Margin="0,-1,0,0">
<Run Text="{Binding LastCheckedDisplay, Mode=OneWay}"/>
Expand All @@ -137,6 +143,9 @@
<MenuItem Header="Edit Server..." Click="EditServer_Click">
<MenuItem.Icon><TextBlock Text="&#x270F;"/></MenuItem.Icon>
</MenuItem>
<MenuItem Header="Check Server Version" Click="CheckServerVersion_Click">
<MenuItem.Icon><TextBlock Text="&#x1F504;"/></MenuItem.Icon>
</MenuItem>
<Separator/>
<MenuItem x:Name="ToggleFavoriteMenuItem" Header="Set as Favorite" Click="ToggleFavorite_Click">
<MenuItem.Icon><TextBlock Text="&#x2B50;"/></MenuItem.Icon>
Expand Down
71 changes: 71 additions & 0 deletions Dashboard/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using System.Threading.Tasks;
using PerformanceMonitorDashboard.Mcp;
using PerformanceMonitorDashboard.Models;
using System.Reflection;
using PerformanceMonitorDashboard.Controls;
using PerformanceMonitorDashboard.Helpers;
using PerformanceMonitorDashboard.Services;
Expand Down Expand Up @@ -978,6 +979,76 @@ private async void EditServer_Click(object sender, RoutedEventArgs e)
}
}

private async void CheckServerVersion_Click(object sender, RoutedEventArgs e)
{
if (ServerListView.SelectedItem is not ServerListItem item) return;
var server = item.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<AssemblyInformationalVersionAttribute>()?.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)
{
var dialog = new AddServerDialog(server);
if (dialog.ShowDialog() == true)
{
_serverManager.UpdateServer(dialog.ServerConnection, dialog.Username, dialog.Password);
await LoadServerListAsync();
}
}
}
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);
}
}

private async void RemoveServer_Click(object sender, RoutedEventArgs e)
{
if (ServerListView.SelectedItem is ServerListItem item)
Expand Down
1 change: 1 addition & 0 deletions Dashboard/ManageServersWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<Button Content="Add Server..." Width="100" Height="30" Margin="0,0,8,0" Click="AddServer_Click"/>
<Button Content="Edit..." Width="80" Height="30" Margin="0,0,8,0" Click="EditServer_Click"/>
<Button x:Name="ToggleFavoriteButton" Content="Toggle Favorite" Width="110" Height="30" Margin="0,0,8,0" Click="ToggleFavorite_Click"/>
<Button x:Name="CheckUpdatesButton" Content="Check Server Version" Width="140" Height="30" Margin="0,0,8,0" Click="CheckForUpdates_Click"/>
<Button Content="Remove" Width="80" Height="30" Margin="0,0,8,0" Click="RemoveServer_Click"
Foreground="{DynamicResource ErrorBrush}"/>
</StackPanel>
Expand Down
Loading
Loading