v0.21.0 — System health banner with colored indicators + tooltips

New row between top bar and content showing pill-shaped status indicators
for the system dependencies that PROSERVE needs (SteamVR, Vive Business
Streaming process, VR headset reachable on the network, etc.). Each pill
is colored : 🟢 OK, 🟠 limitation détectée (e.g. ping élevé), 🔴 KO,
gris = non configuré. Hover → tooltip with full check kind, target,
last RTT/process count and timestamp.

Architecture
- LocalConfig.HealthChecksConfig : list of HealthCheckEntry (Kind=Ping
  or Process, Target=IP/host or process name, ping thresholds in ms,
  refresh interval in s).
- ISystemHealthService + SystemHealthService : ping via
  System.Net.NetworkInformation.Ping (no admin required), process
  lookup via System.Diagnostics.Process.GetProcessesByName. Returns
  HealthResult { Severity, Detail }.
- HealthIndicatorViewModel : observable wrapper per entry with
  Severity-driven Brushes (background pill, border, icon colour) and
  composed Tooltip text.
- MainViewModel.InitHealthIndicators + StartHealthLoop : populates
  ObservableCollection<HealthIndicatorViewModel> from config and runs
  parallel checks every RefreshIntervalSeconds (default 10s).
- MainWindow.xaml : new Row 1 (between top bar and body) hosting an
  ItemsControl bound to HealthIndicators. Row collapses cleanly if the
  list is empty (HasHealthIndicators=false).

Defaults shipped (all editable in %LocalAppData%\PSLauncher\config.json)
- 🎮 SteamVR (Process : vrserver)
- 📡 Vive Business Streaming (Process : HtcConnectionUtility)
- 🥽 Casque VR (Ping : empty, user fills in the headset IP)

The Settings UI editor for managing the list is intentionally deferred
to a future iteration — config.json edit is enough to start using it.

Versions bumped to 0.21.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-03 18:44:15 +02:00
parent 30eceaea2c
commit 60358a6cf5
10 changed files with 450 additions and 26 deletions

View File

@@ -64,6 +64,14 @@ public sealed class LocalConfig
/// </summary>
public DocToolConfig DocTool { get; set; } = new();
/// <summary>
/// Surveillance d'état système affichée en bandeau sous la top bar
/// (pings d'IP, processus requis comme SteamVR / Vive Business Streaming…).
/// Chaque check a un statut Vert (OK) / Orange (warn, ex. ping élevé) / Rouge
/// (KO). Tooltip détaillé au survol.
/// </summary>
public HealthChecksConfig HealthChecks { get; set; } = new();
/// <summary>
/// Connexion à la base MySQL locale (XAMPP) utilisée par PROSERVE pour ses
/// statistiques. Le launcher s'en sert pour appliquer les migrations bundled
@@ -142,6 +150,74 @@ public sealed class DocToolConfig
public int MaxBackups { get; set; } = 3;
}
public sealed class HealthChecksConfig
{
/// <summary>Période de re-vérification, en secondes. 0 = désactivé.</summary>
public int RefreshIntervalSeconds { get; set; } = 10;
/// <summary>
/// Liste des checks à effectuer. Defaults = exemples typiques setup VR
/// (SteamVR + Vive Business Streaming + ping casque). L'utilisateur édite
/// la liste via <c>%LocalAppData%\PSLauncher\config.json</c> pour ajuster
/// les noms de processus, IPs et seuils ; un éditeur Settings est prévu
/// en v2 si le besoin est récurrent.
/// </summary>
public List<HealthCheckEntry> Checks { get; set; } = new()
{
new HealthCheckEntry
{
Name = "SteamVR",
Icon = "🎮",
Kind = "Process",
Target = "vrserver",
},
new HealthCheckEntry
{
Name = "Vive Business Streaming",
Icon = "📡",
Kind = "Process",
Target = "HtcConnectionUtility",
},
new HealthCheckEntry
{
Name = "Casque VR",
Icon = "🥽",
Kind = "Ping",
Target = "", // À remplir avec l'IP réseau du casque ; vide = check désactivé
PingWarnMs = 50,
PingErrorMs = 200,
PingTimeoutMs = 1000,
},
};
}
public sealed class HealthCheckEntry
{
/// <summary>Libellé affiché dans le bandeau, ex. "SteamVR".</summary>
public string Name { get; set; } = "";
/// <summary>Pictogramme emoji affiché à côté du nom, ex. "🎮", "📡", "🥽".</summary>
public string Icon { get; set; } = "🔌";
/// <summary>"Process" ou "Ping" (case-insensitive).</summary>
public string Kind { get; set; } = "Process";
/// <summary>
/// Selon Kind : nom du processus (sans .exe) pour Process,
/// IP/hostname pour Ping. Vide = check ignoré (statut Unknown).
/// </summary>
public string Target { get; set; } = "";
/// <summary>Pour Ping : RTT au-dessus duquel le statut passe en Warning (Orange). Default 50 ms.</summary>
public int? PingWarnMs { get; set; } = 50;
/// <summary>Pour Ping : RTT au-dessus duquel le statut passe en Error (Rouge). Default 200 ms.</summary>
public int? PingErrorMs { get; set; } = 200;
/// <summary>Pour Ping : timeout de la requête ICMP. Default 1 s.</summary>
public int? PingTimeoutMs { get; set; } = 1000;
}
public sealed class LicenseConfig
{
public string? EncryptedKey { get; set; }