feat: page-based navigation shell + Tests page wizard
Replace the monolithic MainWindow with a SelectedPage-driven shell (Dashboard / Pump / Bench / Tests / Results / Settings). The Tests page gets the Plan -> Preconditions -> Running -> Done wizard from ui-structure.md \u00a74, backed by a 7-item precondition gate and shared sub-views (PhaseCardView / TestSectionView / GraphicIndicatorView) extracted from the now-deleted monolithic TestPanelView. New VMs / views: - Tests wizard: TestPreconditions, PhaseCard, GraphicIndicator, TestSection, TestPlan, TestRunning, TestDone - Dashboard panels: DashboardConnection, DashboardReadings, DashboardAlarms, InterlockBanner, ResultHistory - Pump / bench panels: PumpIdentificationPanel, PumpLiveData, UnlockPanel, BenchDriveControl, BenchReadings, RelayBank, TemperatureControl, DtcList, AuthGate - Dialogs: generic ConfirmDialog, UserManageDialog, UserPromptDialog Supporting changes: - IsOilPumpOn exposed on MainViewModel for precondition evaluation - RequiresAuth added to TestDefinition (XML round-trip) - BipStatusDefinition + CompletedTestRun models - ~35 new Test.* localization keys (en + es) - Settings moved from modal dialog to full page - Pause / Retry / Skip stubs in TestRunningView; full spec in docs/gap-test-running-controls.md for follow-up implementation - docs/ui-structure.md captures the wizard design Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
51
Views/Dialogs/ConfirmDialog.xaml
Normal file
51
Views/Dialogs/ConfirmDialog.xaml
Normal file
@@ -0,0 +1,51 @@
|
||||
<Window x:Class="HC_APTBS.Views.Dialogs.ConfirmDialog"
|
||||
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:vm="clr-namespace:HC_APTBS.ViewModels.Dialogs"
|
||||
mc:Ignorable="d"
|
||||
Title="{Binding Title}"
|
||||
Height="200" Width="440"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
d:DataContext="{d:DesignInstance Type=vm:ConfirmDialogViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Generic Yes/No modal. DataContext: ConfirmDialogViewModel.
|
||||
-->
|
||||
<Grid Margin="16,12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="48"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.RowSpan="2" Text="?"
|
||||
FontSize="36" Foreground="#1565C0"
|
||||
FontWeight="Bold"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Center"
|
||||
Margin="0,0,8,0"/>
|
||||
|
||||
<TextBlock Grid.Column="1" Text="{Binding Title}"
|
||||
FontSize="16" FontWeight="Bold" Foreground="#222"
|
||||
Margin="0,0,0,8"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="1"
|
||||
Text="{Binding Message}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalAlignment="Top"/>
|
||||
|
||||
<StackPanel Grid.Row="2" Grid.Column="1"
|
||||
Orientation="Horizontal" HorizontalAlignment="Right"
|
||||
Margin="0,12,0,0">
|
||||
<Button Content="{Binding ConfirmText}" MinWidth="80" Height="26" Margin="0,0,8,0"
|
||||
Command="{Binding ConfirmCommand}" IsDefault="True"/>
|
||||
<Button Content="{Binding CancelText}" MinWidth="80" Height="26"
|
||||
Command="{Binding CancelCommand}" IsCancel="True"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
21
Views/Dialogs/ConfirmDialog.xaml.cs
Normal file
21
Views/Dialogs/ConfirmDialog.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Windows;
|
||||
using HC_APTBS.ViewModels.Dialogs;
|
||||
|
||||
namespace HC_APTBS.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic Yes/No (or Confirm/Cancel) modal dialog. See <see cref="ConfirmDialogViewModel"/>
|
||||
/// for call-site usage — caller configures Title/Message/button text and inspects
|
||||
/// <see cref="ConfirmDialogViewModel.Accepted"/> after closing.
|
||||
/// </summary>
|
||||
public partial class ConfirmDialog : Window
|
||||
{
|
||||
/// <summary>Creates the dialog and wires the ViewModel.</summary>
|
||||
public ConfirmDialog(ConfirmDialogViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = vm;
|
||||
vm.RequestClose += Close;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@
|
||||
<GroupBox Grid.Column="1" Grid.Row="3" Header="{DynamicResource Dialog.Report.Observations}"
|
||||
Margin="8,0,8,4" FontSize="13">
|
||||
<TextBox Text="{Binding Observations, UpdateSourceTrigger=PropertyChanged}"
|
||||
TextWrapping="Wrap"
|
||||
TextWrapping="Wrap" AcceptsReturn="True"
|
||||
BorderBrush="{x:Null}" FontSize="12"/>
|
||||
</GroupBox>
|
||||
|
||||
|
||||
@@ -1,333 +0,0 @@
|
||||
<Window x:Class="HC_APTBS.Views.Dialogs.SettingsDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{DynamicResource Dialog.Settings.Title}"
|
||||
Height="560" Width="680"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FontFamily="Ebrima"
|
||||
Background="#FFEDEDED">
|
||||
|
||||
<DockPanel Margin="8">
|
||||
|
||||
<!-- ── Bottom button bar ─────────────────────────────────────────── -->
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal"
|
||||
HorizontalAlignment="Right" Margin="0,8,0,0">
|
||||
<Button Content="{DynamicResource Common.Accept}" Width="80" Height="26"
|
||||
Margin="0,0,8,0" Command="{Binding AcceptCommand}" IsDefault="True"/>
|
||||
<Button Content="{DynamicResource Common.Cancel}" Width="80" Height="26"
|
||||
Command="{Binding CancelCommand}" IsCancel="True"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ── Tab control ───────────────────────────────────────────────── -->
|
||||
<TabControl>
|
||||
|
||||
<!-- ══ General ══════════════════════════════════════════════════ -->
|
||||
<TabItem Header="{DynamicResource Dialog.Settings.Tab.General}">
|
||||
<StackPanel Margin="16">
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.Language}"
|
||||
FontWeight="SemiBold" Margin="0,0,0,4"/>
|
||||
<ComboBox ItemsSource="{Binding AvailableLanguages}"
|
||||
SelectedItem="{Binding SelectedLanguage}"
|
||||
Width="120" HorizontalAlignment="Left"/>
|
||||
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.DaysKeepLogs}"
|
||||
FontWeight="SemiBold" Margin="0,16,0,4"/>
|
||||
<TextBox Text="{Binding DaysKeepLogs, UpdateSourceTrigger=LostFocus}"
|
||||
Width="80" HorizontalAlignment="Left"/>
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
|
||||
<!-- ══ Safety ═══════════════════════════════════════════════════ -->
|
||||
<TabItem Header="{DynamicResource Dialog.Settings.Tab.Safety}">
|
||||
<Grid Margin="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<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>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="{DynamicResource Dialog.Settings.TempMax}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TempMax, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="{DynamicResource Dialog.Settings.TempMin}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TempMin, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="{DynamicResource Dialog.Settings.SecurityRpmLimit}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding SecurityRpmLimit, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="{DynamicResource Dialog.Settings.MaxPressureBar}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding MaxPressureBar, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Text="{DynamicResource Dialog.Settings.ToleranceUp}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding ToleranceUpExtension, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Text="{DynamicResource Dialog.Settings.TolerancePfp}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding TolerancePfpExtension, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<CheckBox Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2"
|
||||
Content="{DynamicResource Dialog.Settings.IgnoreTin}"
|
||||
IsChecked="{Binding DefaultIgnoreTin}" Margin="0,4,0,0"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<!-- ══ PID ══════════════════════════════════════════════════════ -->
|
||||
<TabItem Header="{DynamicResource Dialog.Settings.Tab.Pid}">
|
||||
<Grid Margin="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="{DynamicResource Dialog.Settings.PidP}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding PidP, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="{DynamicResource Dialog.Settings.PidI}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding PidI, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="{DynamicResource Dialog.Settings.PidD}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding PidD, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="{DynamicResource Dialog.Settings.PidLoopMs}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding PidLoopMs, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<!-- ══ Motor ════════════════════════════════════════════════════ -->
|
||||
<TabItem Header="{DynamicResource Dialog.Settings.Tab.Motor}">
|
||||
<DockPanel Margin="16">
|
||||
<!-- Top: motor parameters -->
|
||||
<Grid DockPanel.Dock="Top">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="{DynamicResource Dialog.Settings.EncoderRes}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding EncoderResolution, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="{DynamicResource Dialog.Settings.VoltMaxRpm}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding VoltageForMaxRpm, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="{DynamicResource Dialog.Settings.MaxRpm}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding MaxRpm, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"
|
||||
Content="{DynamicResource Dialog.Settings.RightRelay}"
|
||||
IsChecked="{Binding RightRelayValue}" Margin="0,4,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<!-- RPM-Voltage relation table -->
|
||||
<GroupBox Margin="0,12,0,0">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.Relations}" FontWeight="SemiBold"/>
|
||||
</GroupBox.Header>
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Margin="0,4,0,0">
|
||||
<Button Content="{DynamicResource Dialog.Settings.AddRow}"
|
||||
Command="{Binding AddRelationCommand}"
|
||||
Width="75" Margin="0,0,8,0"/>
|
||||
<Button Content="{DynamicResource Dialog.Settings.RemoveRow}"
|
||||
Command="{Binding RemoveRelationCommand}"
|
||||
CommandParameter="{Binding SelectedItem, ElementName=RelationsGrid}"
|
||||
Width="75"/>
|
||||
</StackPanel>
|
||||
<DataGrid x:Name="RelationsGrid"
|
||||
ItemsSource="{Binding Relations}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
CanUserDeleteRows="False"
|
||||
SelectionMode="Single"
|
||||
HeadersVisibility="Column"
|
||||
GridLinesVisibility="Horizontal"
|
||||
MinHeight="120">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.RelRpm}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Rpm}" VerticalAlignment="Center" Margin="4,0"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellEditingTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox Text="{Binding Rpm, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellEditingTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.RelVoltage}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Voltage}" VerticalAlignment="Center" Margin="4,0"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellEditingTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox Text="{Binding Voltage, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellEditingTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</DockPanel>
|
||||
</GroupBox>
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
<!-- ══ Company ══════════════════════════════════════════════════ -->
|
||||
<TabItem Header="{DynamicResource Dialog.Settings.Tab.Company}">
|
||||
<StackPanel Margin="16">
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.CompanyName}"
|
||||
FontWeight="SemiBold" Margin="0,0,0,4"/>
|
||||
<TextBox Text="{Binding CompanyName, UpdateSourceTrigger=LostFocus}"/>
|
||||
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.CompanyInfo}"
|
||||
FontWeight="SemiBold" Margin="0,12,0,4"/>
|
||||
<TextBox Text="{Binding CompanyInfo, UpdateSourceTrigger=LostFocus}"
|
||||
TextWrapping="Wrap" AcceptsReturn="True" Height="80"
|
||||
VerticalScrollBarVisibility="Auto"/>
|
||||
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.ReportLogo}"
|
||||
FontWeight="SemiBold" Margin="0,12,0,4"/>
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Content="..." Width="30"
|
||||
Margin="4,0,0,0" Command="{Binding BrowseLogoCommand}"/>
|
||||
<TextBox Text="{Binding ReportLogoPath, UpdateSourceTrigger=LostFocus}"
|
||||
IsReadOnly="True" Background="#F0F0F0"/>
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
|
||||
<!-- ══ K-Line ═══════════════════════════════════════════════════ -->
|
||||
<TabItem Header="{DynamicResource Dialog.Settings.Tab.KLine}">
|
||||
<StackPanel Margin="16">
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.KLinePort}"
|
||||
FontWeight="SemiBold" Margin="0,0,0,4"/>
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right"
|
||||
Content="{DynamicResource Dialog.Settings.RefreshPorts}"
|
||||
Margin="8,0,0,0" Width="80"
|
||||
Command="{Binding RefreshPortsCommand}"/>
|
||||
<ComboBox ItemsSource="{Binding AvailablePorts}"
|
||||
SelectedItem="{Binding SelectedKLinePort}"
|
||||
IsEditable="True"
|
||||
Text="{Binding SelectedKLinePort, UpdateSourceTrigger=LostFocus}"/>
|
||||
</DockPanel>
|
||||
<TextBlock Text="{DynamicResource Dialog.Settings.KLineHint}"
|
||||
FontStyle="Italic" Foreground="Gray" Margin="0,8,0,0"
|
||||
TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
|
||||
<!-- ══ Advanced ═════════════════════════════════════════════════ -->
|
||||
<TabItem Header="{DynamicResource Dialog.Settings.Tab.Advanced}">
|
||||
<Grid Margin="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<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>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="{DynamicResource Dialog.Settings.RefreshBench}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding RefreshBenchInterfaceMs, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="{DynamicResource Dialog.Settings.RefreshReading}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding RefreshWhileReadingMs, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="{DynamicResource Dialog.Settings.RefreshCanBus}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding RefreshCanBusReadMs, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="{DynamicResource Dialog.Settings.RefreshPumpReq}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding RefreshPumpRequestMs, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Text="{DynamicResource Dialog.Settings.RefreshPumpParams}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding RefreshPumpParamsMs, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Text="{DynamicResource Dialog.Settings.BlinkInterval}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding BlinkIntervalMs, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Text="{DynamicResource Dialog.Settings.FlasherInterval}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,6"/>
|
||||
<TextBox Grid.Row="6" Grid.Column="1" Text="{Binding FlasherIntervalMs, UpdateSourceTrigger=LostFocus}"
|
||||
Margin="0,0,0,6"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
@@ -1,18 +0,0 @@
|
||||
using System.Windows;
|
||||
using HC_APTBS.ViewModels.Dialogs;
|
||||
|
||||
namespace HC_APTBS.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialog for editing all application settings.
|
||||
/// </summary>
|
||||
public partial class SettingsDialog : Window
|
||||
{
|
||||
public SettingsDialog(SettingsViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = vm;
|
||||
vm.RequestClose += Close;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Views/Dialogs/UserManageDialog.xaml
Normal file
60
Views/Dialogs/UserManageDialog.xaml
Normal file
@@ -0,0 +1,60 @@
|
||||
<Window x:Class="HC_APTBS.Views.Dialogs.UserManageDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{DynamicResource Dialog.UserManage.Title}"
|
||||
Height="360" Width="460"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FontFamily="Ebrima"
|
||||
Background="#FFEDEDED">
|
||||
|
||||
<DockPanel Margin="12">
|
||||
|
||||
<!-- ── Bottom bar: Close ─────────────────────────────────────────── -->
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal"
|
||||
HorizontalAlignment="Right" Margin="0,12,0,0">
|
||||
<Button Content="{DynamicResource Dialog.UserManage.Close}" Width="90" Height="26"
|
||||
Command="{Binding CloseCommand}" IsCancel="True" IsDefault="True"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ── Action buttons under the grid ─────────────────────────────── -->
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Button Content="{DynamicResource Dialog.UserManage.Add}" Width="95" Height="26"
|
||||
Margin="0,0,8,0" Command="{Binding AddCommand}"/>
|
||||
<Button Content="{DynamicResource Dialog.UserManage.Remove}" Width="95" Height="26"
|
||||
Margin="0,0,8,0" Command="{Binding RemoveCommand}"/>
|
||||
<Button Content="{DynamicResource Dialog.UserManage.ChangePassword}" Width="140" Height="26"
|
||||
Command="{Binding ChangePasswordCommand}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ── User list ─────────────────────────────────────────────────── -->
|
||||
<DataGrid x:Name="UsersGrid"
|
||||
ItemsSource="{Binding Users}"
|
||||
SelectedItem="{Binding SelectedUser, Mode=TwoWay}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
CanUserDeleteRows="False"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeRows="False"
|
||||
IsReadOnly="True"
|
||||
SelectionMode="Single"
|
||||
HeadersVisibility="Column"
|
||||
GridLinesVisibility="Horizontal">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{DynamicResource Dialog.UserManage.ColumnUsername}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" VerticalAlignment="Center" Margin="6,0"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
</DockPanel>
|
||||
</Window>
|
||||
21
Views/Dialogs/UserManageDialog.xaml.cs
Normal file
21
Views/Dialogs/UserManageDialog.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Windows;
|
||||
using HC_APTBS.ViewModels.Dialogs;
|
||||
|
||||
namespace HC_APTBS.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// Admin dialog for managing the stored user list: add, remove, and change password.
|
||||
/// Each action persists immediately via <see cref="Services.IConfigurationService"/>;
|
||||
/// the Close button simply dismisses the window.
|
||||
/// </summary>
|
||||
public partial class UserManageDialog : Window
|
||||
{
|
||||
/// <summary>Creates the dialog and wires the ViewModel.</summary>
|
||||
public UserManageDialog(UserManageViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = vm;
|
||||
vm.RequestClose += Close;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Views/Dialogs/UserPromptDialog.xaml
Normal file
48
Views/Dialogs/UserPromptDialog.xaml
Normal file
@@ -0,0 +1,48 @@
|
||||
<Window x:Class="HC_APTBS.Views.Dialogs.UserPromptDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
Title="{DynamicResource Dialog.UserManage.Prompt.AddTitle}"
|
||||
Height="170" Width="420"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FontFamily="Ebrima"
|
||||
Background="#FFEDEDED">
|
||||
|
||||
<Grid Margin="16,12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="110"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Username (hidden when UsernameVisible == false) -->
|
||||
<Label x:Name="LblUsername"
|
||||
Content="{DynamicResource Dialog.UserCheck.Username}"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<TextBox x:Name="TbUsername" Grid.Column="1"
|
||||
Margin="8,4" Height="26" VerticalContentAlignment="Center"/>
|
||||
|
||||
<!-- Password -->
|
||||
<Label Grid.Row="1"
|
||||
Content="{DynamicResource Dialog.UserCheck.Password}"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<PasswordBox x:Name="PbPassword" Grid.Row="1" Grid.Column="1"
|
||||
Margin="8,4" Height="26" VerticalContentAlignment="Center"/>
|
||||
|
||||
<!-- Buttons -->
|
||||
<StackPanel Grid.Row="2" Grid.Column="1"
|
||||
Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,12,0,0">
|
||||
<Button Content="{DynamicResource Common.Accept}" Width="80" Height="26" Margin="0,0,8,0"
|
||||
Click="OnAccept" IsDefault="True"/>
|
||||
<Button Content="{DynamicResource Common.Cancel}" Width="80" Height="26"
|
||||
IsCancel="True"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
59
Views/Dialogs/UserPromptDialog.xaml.cs
Normal file
59
Views/Dialogs/UserPromptDialog.xaml.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace HC_APTBS.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// Small input dialog that prompts for a username and password, or a password only.
|
||||
/// Used by <see cref="Views.Dialogs.UserManageDialog"/> when adding a new user or
|
||||
/// changing an existing user's password. Kept as a code-behind dialog (not MVVM)
|
||||
/// because it is a transient prompt with no shared state.
|
||||
/// </summary>
|
||||
public partial class UserPromptDialog : Window
|
||||
{
|
||||
/// <summary>Username entered by the operator. Empty when <see cref="UsernameVisible"/> is false.</summary>
|
||||
public string EnteredUsername { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>Password entered by the operator.</summary>
|
||||
public string EnteredPassword { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the dialog.
|
||||
/// </summary>
|
||||
/// <param name="title">Window title (already-localised string).</param>
|
||||
/// <param name="usernameVisible">
|
||||
/// True to show the username field (Add user flow); false to hide it (Change password flow).
|
||||
/// </param>
|
||||
/// <param name="prefillUsername">
|
||||
/// Pre-filled, read-only username shown as a label when <paramref name="usernameVisible"/> is false.
|
||||
/// Ignored otherwise.
|
||||
/// </param>
|
||||
public UserPromptDialog(string title, bool usernameVisible, string prefillUsername = "")
|
||||
{
|
||||
InitializeComponent();
|
||||
Title = title;
|
||||
|
||||
if (usernameVisible)
|
||||
{
|
||||
EnteredUsername = string.Empty;
|
||||
TbUsername.Focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide username row; reserve width so layout doesn't shift.
|
||||
LblUsername.Visibility = Visibility.Collapsed;
|
||||
TbUsername.Visibility = Visibility.Collapsed;
|
||||
EnteredUsername = prefillUsername;
|
||||
PbPassword.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAccept(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (TbUsername.Visibility == Visibility.Visible)
|
||||
EnteredUsername = TbUsername.Text;
|
||||
EnteredPassword = PbPassword.Password;
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user