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:
@@ -198,16 +198,15 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" /> <!-- Top bar -->
|
||||
<RowDefinition Height="Auto" /> <!-- Health banner -->
|
||||
<RowDefinition Height="*" /> <!-- Body (sidebar + content) -->
|
||||
<RowDefinition Height="Auto" /> <!-- Footer -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Background image : limité à la zone content (Row 1, Col 1) pour ne pas
|
||||
passer derrière la sidebar ni le footer. ImageBrush avec AlignmentX=Right
|
||||
+ AlignmentY=Bottom : si le ratio fenêtre force un crop, on rogne en
|
||||
haut/à gauche — le logo ASTERION VR en bas-droite reste TOUJOURS visible. -->
|
||||
<Rectangle Grid.Row="1" Grid.Column="1" IsHitTestVisible="False">
|
||||
<!-- Background image : limité à la zone content (Row 2, Col 1) pour ne pas
|
||||
passer derrière la sidebar, le banner ou le footer. -->
|
||||
<Rectangle Grid.Row="2" Grid.Column="1" IsHitTestVisible="False">
|
||||
<Rectangle.Fill>
|
||||
<ImageBrush ImageSource="pack://application:,,,/Resources/Background.png"
|
||||
Stretch="UniformToFill"
|
||||
@@ -216,10 +215,7 @@
|
||||
Opacity="0.25" />
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<!-- Voile bleuté (~8% opacité) posé sur l'image pour donner la teinte
|
||||
navy/cyan d'ASTERION VR. IsHitTestVisible=False pour ne pas bloquer
|
||||
les clics qui visent le content area. -->
|
||||
<Rectangle Grid.Row="1" Grid.Column="1"
|
||||
<Rectangle Grid.Row="2" Grid.Column="1"
|
||||
Fill="{StaticResource Brush.Bg.BlueTint}"
|
||||
IsHitTestVisible="False" />
|
||||
|
||||
@@ -345,10 +341,54 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ============== Content area (Row 1, Col 1, swap par CurrentPage) ==============
|
||||
<!-- ============== Health banner (Row 1, ColSpan 2) ==============
|
||||
Pills colorées indiquant l'état des dépendances système (SteamVR,
|
||||
Vive Streaming, ping casque…). Cachée si la config n'a aucun check.
|
||||
Tooltip détaillé au survol de chaque pill. -->
|
||||
<Border Grid.Row="1" Grid.ColumnSpan="2"
|
||||
Background="{StaticResource Brush.Bg.Sidebar}"
|
||||
BorderBrush="{StaticResource Brush.Border}"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="16,8"
|
||||
Visibility="{Binding HasHealthIndicators, Converter={StaticResource BoolToVisibility}}">
|
||||
<ItemsControl ItemsSource="{Binding HealthIndicators}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{Binding StatusBrush}"
|
||||
BorderBrush="{Binding BorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12"
|
||||
Padding="10,4"
|
||||
Margin="0,0,8,0"
|
||||
ToolTip="{Binding Tooltip}"
|
||||
ToolTipService.InitialShowDelay="200"
|
||||
ToolTipService.ShowDuration="20000">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Icon}"
|
||||
FontSize="14"
|
||||
Foreground="{Binding IconForeground}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding Name}"
|
||||
Margin="6,0,0,0"
|
||||
FontSize="12"
|
||||
Foreground="{StaticResource Brush.Text.Primary}"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
<!-- ============== Content area (Row 2, Col 1, swap par CurrentPage) ==============
|
||||
Superpose plusieurs blocs (Library / Report / Documentation) gérés par
|
||||
leur Visibility liée à CurrentPage. -->
|
||||
<Grid Grid.Row="1" Grid.Column="1">
|
||||
<Grid Grid.Row="2" Grid.Column="1">
|
||||
|
||||
<!-- ====================== LIBRARY PAGE ====================== -->
|
||||
<Grid Visibility="{Binding IsLibrary, Converter={StaticResource BoolToVisibility}}">
|
||||
@@ -611,10 +651,10 @@
|
||||
<!-- ============== END Content area ============== -->
|
||||
|
||||
<!-- ============== Left sidebar : nav buttons ==============
|
||||
Row 1 + Row 2 (RowSpan=2) → la sidebar s'étend depuis le bas du
|
||||
top bar jusqu'en bas de la fenêtre, peu importe la visibilité du
|
||||
footer ou de la taille de la zone content. -->
|
||||
<Border Grid.Row="1" Grid.RowSpan="2" Grid.Column="0"
|
||||
Row 2 + RowSpan=2 → la sidebar s'étend depuis le bas du health
|
||||
banner jusqu'en bas de la fenêtre, couvrant content + footer.
|
||||
(Row 0 = top bar, Row 1 = health banner full-width.) -->
|
||||
<Border Grid.Row="2" Grid.RowSpan="2" Grid.Column="0"
|
||||
Background="#0A0A0E"
|
||||
BorderBrush="{StaticResource Brush.Border}"
|
||||
BorderThickness="0,0,1,0">
|
||||
@@ -647,9 +687,10 @@
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Footer : Row 2, Col 1 → cantonné à la colonne content, sous la zone
|
||||
Library/Report/Doc. La sidebar (RowSpan=2) le contourne par sa colonne. -->
|
||||
<Border Grid.Row="2" Grid.Column="1"
|
||||
<!-- Footer : Row 3, Col 1 → cantonné à la colonne content, sous la zone
|
||||
Library/Report/Doc. La sidebar (RowSpan=2 sur rows 2-3) le contourne
|
||||
par sa colonne. -->
|
||||
<Border Grid.Row="3" Grid.Column="1"
|
||||
Background="{StaticResource Brush.Bg.Footer}"
|
||||
BorderBrush="{StaticResource Brush.Border}" BorderThickness="0,1,0,0"
|
||||
Padding="20,10"
|
||||
|
||||
Reference in New Issue
Block a user