Bundles several feature streams that have been iterating on the working tree: - Developer Tools page (Debug-only via DEVELOPER_TOOLS symbol): hosts the identification card, manual KWP write + transaction log, ROM/EEPROM dump card with progress banner and completion message, persisted custom-commands library, persisted EEPROM passwords library. New service primitives: IKwpService.SendRawCustomAsync / ReadEepromAsync / ReadRomEepromAsync. Persistence mirrors the Clients XML pattern in two new files (custom_commands.xml, eeprom_passwords.xml). - Auto-test orchestrator (IAutoTestOrchestrator + AutoTestState): linear K-Line read -> unlock -> bench-on -> test sequence with snackbar UI and progress dialog VM, gated on dashboard alarms. - BIP-STATUS display: BipDisplayViewModel + BipDisplayView, RAM read at 0x0106 via IKwpService.ReadBipStatusAsync; status definitions in BipStatusDefinition. - Tests page redesign: TestSectionCard + PhaseTileView replacing the old TestPlanView/TestRunningView/TestDoneView/TestPreconditionsView/ TestSectionView controls and their VMs. - Pump command sliders: Fluent thick-track style with overhang thumb, click-anywhere-and-drag, mouse-wheel adjustment. - Window startup: app.manifest declares PerMonitorV2 DPI awareness, MainWindow installs a WM_GETMINMAXINFO hook in OnSourceInitialized and maximizes there (after the hook is in place) so the app fits the work area exactly on any display configuration. - Misc: PercentToPixelsConverter, seed_aliases.py one-shot pump-alias importer, tools/Import-BipStatus.ps1, kline_eeprom_spec.md and dump-functions reference docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
368 lines
22 KiB
XML
368 lines
22 KiB
XML
<UserControl x:Class="HC_APTBS.Views.Pages.TestsPage"
|
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
|
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
|
|
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
|
|
xmlns:vmp="clr-namespace:HC_APTBS.ViewModels.Pages"
|
|
mc:Ignorable="d"
|
|
d:DesignHeight="860" d:DesignWidth="1740"
|
|
d:DataContext="{d:DesignInstance Type=vmp:TestsPageViewModel, IsDesignTimeCreatable=False}">
|
|
<!--
|
|
Single-page Tests view.
|
|
Row 0: status bar — headline + blocker text + phase progress when running.
|
|
Row 1: section cards (always visible) with full live-bar indicators so
|
|
phase state is readable at rest and during a run.
|
|
Row 2: action bar — toolbar (Check all) + primary action (Start / Abort /
|
|
Report + Clear).
|
|
Overlay: PASSED / FAILED snackbar pinned to the bottom-right.
|
|
-->
|
|
<UserControl.Resources>
|
|
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
|
|
|
<DataTemplate DataType="{x:Type vm:TestSectionViewModel}">
|
|
<uc:TestSectionCard Width="430" Compact="False"/>
|
|
</DataTemplate>
|
|
</UserControl.Resources>
|
|
|
|
<Grid>
|
|
<Grid Margin="12">
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="*"/>
|
|
<RowDefinition Height="Auto"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- ── Status bar ─────────────────────────────────────────────── -->
|
|
<Border Style="{StaticResource PumpCard}" Margin="4,0,4,6" Padding="14,10" Height="66">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
</Grid.RowDefinitions>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<!-- State glyph -->
|
|
<Border Grid.Column="0" Width="14" Height="14" CornerRadius="7"
|
|
VerticalAlignment="Center" Margin="0,0,10,0">
|
|
<Border.Style>
|
|
<Style TargetType="Border">
|
|
<Setter Property="Background" Value="#BBB"/>
|
|
<Style.Triggers>
|
|
<DataTrigger Binding="{Binding AllPreconditionsPassed}" Value="True">
|
|
<Setter Property="Background" Value="#26C200"/>
|
|
</DataTrigger>
|
|
<DataTrigger Binding="{Binding IsTestRunning}" Value="True">
|
|
<Setter Property="Background" Value="#F9A825"/>
|
|
</DataTrigger>
|
|
<MultiDataTrigger>
|
|
<MultiDataTrigger.Conditions>
|
|
<Condition Binding="{Binding HasCompletedResults}" Value="True"/>
|
|
<Condition Binding="{Binding IsTestRunning}" Value="False"/>
|
|
<Condition Binding="{Binding LastRunPassed}" Value="True"/>
|
|
</MultiDataTrigger.Conditions>
|
|
<Setter Property="Background" Value="#2E7D32"/>
|
|
</MultiDataTrigger>
|
|
<MultiDataTrigger>
|
|
<MultiDataTrigger.Conditions>
|
|
<Condition Binding="{Binding HasCompletedResults}" Value="True"/>
|
|
<Condition Binding="{Binding IsTestRunning}" Value="False"/>
|
|
<Condition Binding="{Binding LastRunPassed}" Value="False"/>
|
|
</MultiDataTrigger.Conditions>
|
|
<Setter Property="Background" Value="#B71C1C"/>
|
|
</MultiDataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</Border.Style>
|
|
</Border>
|
|
|
|
<!-- Headline + blocker -->
|
|
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
|
<StackPanel Orientation="Horizontal">
|
|
<TextBlock Text="{Binding StatusHeadline}"
|
|
FontSize="15" FontWeight="SemiBold"
|
|
Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
|
<TextBlock Text="{Binding TestPanel.CurrentPhaseName}"
|
|
FontSize="13"
|
|
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
|
|
Margin="10,0,0,0"
|
|
Visibility="{Binding IsTestRunning, Converter={StaticResource BoolToVis}}"/>
|
|
<TextBlock Text="{Binding TestPanel.SectionLabel}"
|
|
FontSize="11" FontStyle="Italic"
|
|
Foreground="{DynamicResource TextFillColorTertiaryBrush}"
|
|
Margin="8,0,0,0" VerticalAlignment="Center"
|
|
Visibility="{Binding IsTestRunning, Converter={StaticResource BoolToVis}}"/>
|
|
</StackPanel>
|
|
<TextBlock Text="{Binding BlockingReason}"
|
|
FontSize="11"
|
|
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
|
Margin="0,2,0,0">
|
|
<TextBlock.Style>
|
|
<Style TargetType="TextBlock">
|
|
<Setter Property="Visibility" Value="Visible"/>
|
|
<Style.Triggers>
|
|
<DataTrigger Binding="{Binding AllPreconditionsPassed}" Value="True">
|
|
<Setter Property="Visibility" Value="Collapsed"/>
|
|
</DataTrigger>
|
|
<DataTrigger Binding="{Binding IsTestRunning}" Value="True">
|
|
<Setter Property="Visibility" Value="Collapsed"/>
|
|
</DataTrigger>
|
|
<DataTrigger Binding="{Binding HasCompletedResults}" Value="True">
|
|
<Setter Property="Visibility" Value="Collapsed"/>
|
|
</DataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</TextBlock.Style>
|
|
</TextBlock>
|
|
</StackPanel>
|
|
|
|
<!-- Right pills: estimated time / countdown -->
|
|
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
|
<!-- Running: phase remaining / total -->
|
|
<StackPanel Orientation="Horizontal"
|
|
Visibility="{Binding IsTestRunning, Converter={StaticResource BoolToVis}}">
|
|
<TextBlock FontFamily="Consolas" FontSize="20" FontWeight="SemiBold"
|
|
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
|
|
VerticalAlignment="Center">
|
|
<Run Text="{Binding TestPanel.PhaseRemainingSeconds, Mode=OneWay}"/>
|
|
</TextBlock>
|
|
<TextBlock Text="s" FontSize="12"
|
|
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
|
|
VerticalAlignment="Bottom" Margin="2,0,8,3"/>
|
|
<TextBlock FontSize="11"
|
|
Foreground="{DynamicResource TextFillColorTertiaryBrush}"
|
|
VerticalAlignment="Bottom" Margin="0,0,0,3">
|
|
<Run Text="/ "/>
|
|
<Run Text="{Binding TestPanel.PhaseTotalSeconds, Mode=OneWay}"/>
|
|
<Run Text="s"/>
|
|
</TextBlock>
|
|
</StackPanel>
|
|
|
|
<!-- Idle: estimated total time -->
|
|
<Border Padding="10,4" CornerRadius="12">
|
|
<Border.Style>
|
|
<Style TargetType="Border" BasedOn="{StaticResource TestMetaPill}">
|
|
<Style.Triggers>
|
|
<DataTrigger Binding="{Binding IsTestRunning}" Value="True">
|
|
<Setter Property="Visibility" Value="Collapsed"/>
|
|
</DataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</Border.Style>
|
|
<StackPanel Orientation="Horizontal">
|
|
<ui:SymbolIcon Symbol="Timer24" FontSize="14"
|
|
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
|
VerticalAlignment="Center"/>
|
|
<TextBlock Style="{StaticResource TestMetaPillText}" Margin="6,0,0,0"
|
|
FontSize="12" FontFamily="Consolas">
|
|
<Run Text="~"/>
|
|
<Run Text="{Binding TestPanel.RemainingSeconds, Mode=OneWay}"/>
|
|
<Run Text=" s"/>
|
|
</TextBlock>
|
|
<TextBlock Style="{StaticResource TestMetaPillText}" Margin="6,0,0,0"
|
|
Text="{DynamicResource Test.Plan.Remaining}"/>
|
|
</StackPanel>
|
|
</Border>
|
|
</StackPanel>
|
|
|
|
<!-- Phase progress bar (only while running) -->
|
|
<ProgressBar Grid.Row="1" Grid.ColumnSpan="3"
|
|
Minimum="0" Maximum="1"
|
|
Value="{Binding TestPanel.PhaseProgress, Mode=OneWay}"
|
|
Height="4" Margin="0,8,0,0"
|
|
BorderThickness="0"
|
|
Visibility="{Binding IsTestRunning, Converter={StaticResource BoolToVis}}"/>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- ── Section cards (always visible) ─────────────────────────── -->
|
|
<ScrollViewer Grid.Row="1"
|
|
Margin="0,0,0,8"
|
|
HorizontalScrollBarVisibility="Disabled"
|
|
VerticalScrollBarVisibility="Disabled">
|
|
<ItemsControl ItemsSource="{Binding TestPanel.Tests}"
|
|
Margin="4,0,4,0">
|
|
<ItemsControl.ItemsPanel>
|
|
<ItemsPanelTemplate>
|
|
<WrapPanel Orientation="Horizontal"/>
|
|
</ItemsPanelTemplate>
|
|
</ItemsControl.ItemsPanel>
|
|
</ItemsControl>
|
|
</ScrollViewer>
|
|
|
|
<!-- ── Action bar ─────────────────────────────────────────────── -->
|
|
<Border Grid.Row="2" Style="{StaticResource PumpCard}" Margin="4,6,4,0" Padding="12,8">
|
|
<Grid>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<!-- Left toolbar: Check-all toggle -->
|
|
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
|
<ui:Button Command="{Binding TestPanel.ToggleCheckAllCommand}"
|
|
Content="{DynamicResource Test.CheckAll}"
|
|
Appearance="Secondary"
|
|
Padding="12,5" FontSize="12"
|
|
ToolTip="{DynamicResource Test.Plan.EnableAll}">
|
|
<ui:Button.Icon><ui:SymbolIcon Symbol="SelectAllOn24"/></ui:Button.Icon>
|
|
<ui:Button.Style>
|
|
<Style TargetType="ui:Button" BasedOn="{StaticResource {x:Type ui:Button}}">
|
|
<Setter Property="IsEnabled" Value="True"/>
|
|
<Style.Triggers>
|
|
<DataTrigger Binding="{Binding IsTestRunning}" Value="True">
|
|
<Setter Property="IsEnabled" Value="False"/>
|
|
</DataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</ui:Button.Style>
|
|
</ui:Button>
|
|
</StackPanel>
|
|
|
|
<!-- Right action cluster — switches by state -->
|
|
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
|
|
|
<!-- Idle: Start -->
|
|
<ui:Button Command="{Binding StartTestCommand}"
|
|
Content="{DynamicResource Test.StartTest}"
|
|
Appearance="Primary"
|
|
Padding="18,6" FontSize="14" FontWeight="SemiBold">
|
|
<ui:Button.Icon><ui:SymbolIcon Symbol="Play24"/></ui:Button.Icon>
|
|
<ui:Button.Style>
|
|
<Style TargetType="ui:Button" BasedOn="{StaticResource {x:Type ui:Button}}">
|
|
<Setter Property="Visibility" Value="Visible"/>
|
|
<Style.Triggers>
|
|
<DataTrigger Binding="{Binding IsTestRunning}" Value="True">
|
|
<Setter Property="Visibility" Value="Collapsed"/>
|
|
</DataTrigger>
|
|
<DataTrigger Binding="{Binding HasCompletedResults}" Value="True">
|
|
<Setter Property="Visibility" Value="Collapsed"/>
|
|
</DataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</ui:Button.Style>
|
|
</ui:Button>
|
|
|
|
<!-- Running: Abort -->
|
|
<ui:Button Command="{Binding AbortCommand}"
|
|
Content="{DynamicResource Test.Running.Abort}"
|
|
Appearance="Danger"
|
|
Padding="18,6" FontSize="14" FontWeight="SemiBold"
|
|
Visibility="{Binding IsTestRunning, Converter={StaticResource BoolToVis}}">
|
|
<ui:Button.Icon><ui:SymbolIcon Symbol="Stop24"/></ui:Button.Icon>
|
|
</ui:Button>
|
|
|
|
<!-- Done: Report + Clear -->
|
|
<StackPanel Orientation="Horizontal">
|
|
<StackPanel.Style>
|
|
<Style TargetType="StackPanel">
|
|
<Setter Property="Visibility" Value="Collapsed"/>
|
|
<Style.Triggers>
|
|
<MultiDataTrigger>
|
|
<MultiDataTrigger.Conditions>
|
|
<Condition Binding="{Binding HasCompletedResults}" Value="True"/>
|
|
<Condition Binding="{Binding IsTestRunning}" Value="False"/>
|
|
</MultiDataTrigger.Conditions>
|
|
<Setter Property="Visibility" Value="Visible"/>
|
|
</MultiDataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</StackPanel.Style>
|
|
|
|
<ui:Button Command="{Binding ClearTestDataCommand}"
|
|
Content="{DynamicResource Test.Done.ClearData}"
|
|
Appearance="Secondary"
|
|
Padding="14,6" FontSize="12" Margin="0,0,8,0">
|
|
<ui:Button.Icon><ui:SymbolIcon Symbol="Delete24"/></ui:Button.Icon>
|
|
</ui:Button>
|
|
<ui:Button Command="{Binding Root.GenerateReportCommand}"
|
|
Content="{DynamicResource Test.Report}"
|
|
Appearance="Primary"
|
|
Padding="18,6" FontSize="14" FontWeight="SemiBold">
|
|
<ui:Button.Icon><ui:SymbolIcon Symbol="DocumentPdf24"/></ui:Button.Icon>
|
|
</ui:Button>
|
|
</StackPanel>
|
|
</StackPanel>
|
|
</Grid>
|
|
</Border>
|
|
</Grid>
|
|
|
|
<!-- ── Done snackbar overlay (auto-dismiss) ─────────────────────── -->
|
|
<Border HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
|
Margin="0,0,24,24"
|
|
CornerRadius="6"
|
|
Padding="14,10"
|
|
BorderThickness="1"
|
|
Visibility="{Binding ShowDoneSnackbar, Converter={StaticResource BoolToVis}}">
|
|
<Border.Style>
|
|
<Style TargetType="Border">
|
|
<Setter Property="Background" Value="#FFCDD2"/>
|
|
<Setter Property="BorderBrush" Value="#B71C1C"/>
|
|
<Style.Triggers>
|
|
<DataTrigger Binding="{Binding LastRunPassed}" Value="True">
|
|
<Setter Property="Background" Value="#C8E6C9"/>
|
|
<Setter Property="BorderBrush" Value="#2E7D32"/>
|
|
</DataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</Border.Style>
|
|
<Grid>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<ui:SymbolIcon Grid.Column="0" FontSize="20"
|
|
VerticalAlignment="Center" Margin="0,0,10,0">
|
|
<ui:SymbolIcon.Style>
|
|
<Style TargetType="ui:SymbolIcon">
|
|
<Setter Property="Symbol" Value="ErrorCircle24"/>
|
|
<Setter Property="Foreground" Value="#B71C1C"/>
|
|
<Style.Triggers>
|
|
<DataTrigger Binding="{Binding LastRunPassed}" Value="True">
|
|
<Setter Property="Symbol" Value="CheckmarkCircle24"/>
|
|
<Setter Property="Foreground" Value="#2E7D32"/>
|
|
</DataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</ui:SymbolIcon.Style>
|
|
</ui:SymbolIcon>
|
|
|
|
<TextBlock Grid.Column="1"
|
|
FontSize="14" FontWeight="SemiBold"
|
|
VerticalAlignment="Center">
|
|
<TextBlock.Style>
|
|
<Style TargetType="TextBlock">
|
|
<Setter Property="Text" Value="{DynamicResource Test.Done.Failed}"/>
|
|
<Setter Property="Foreground" Value="#B71C1C"/>
|
|
<Style.Triggers>
|
|
<DataTrigger Binding="{Binding LastRunPassed}" Value="True">
|
|
<Setter Property="Text" Value="{DynamicResource Test.Done.Passed}"/>
|
|
<Setter Property="Foreground" Value="#2E7D32"/>
|
|
</DataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</TextBlock.Style>
|
|
</TextBlock>
|
|
|
|
<ui:Button Grid.Column="2"
|
|
Command="{Binding DismissSnackbarCommand}"
|
|
Appearance="Transparent"
|
|
Padding="6,2" Margin="12,0,0,0"
|
|
VerticalAlignment="Center"
|
|
ToolTip="{DynamicResource Test.Abort.Cancel}">
|
|
<ui:Button.Icon><ui:SymbolIcon Symbol="Dismiss24"/></ui:Button.Icon>
|
|
</ui:Button>
|
|
</Grid>
|
|
</Border>
|
|
</Grid>
|
|
</UserControl>
|