1b10194634
- Client.UI-003: wire Serilog properly per CLAUDE.md — console sink + rolling daily file sink in Program.Main, Log.CloseAndFlush in finally, per-VM Log.ForContext<> loggers. - Client.UI-004: migrate the cert-store folder picker from the obsolete OpenFolderDialog to StorageProvider.OpenFolderPickerAsync (with TryGetFolderFromPathAsync seed + TryGetLocalPath extraction). - Client.UI-006: surface formerly silent catch blocks via an observable StatusMessage on the Subscriptions / Alarms VMs that bubbles up into the shell's status bar; soft fallbacks log at Information level so hard failures stay distinguishable. - Client.UI-009: docs/Client.UI.md now lists Standard Deviation in the Aggregate row of the Query Options table. - Client.UI-010: removed the unused MinDateTimeProperty / MaxDateTimeProperty styled properties from DateTimeRangePicker. - Client.UI-011: updated the cert-store TextBox watermark from the legacy AppData/LmxOpcUaClient/pki to the canonical AppData/OtOpcUaClient/pki. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
162 lines
8.8 KiB
XML
162 lines
8.8 KiB
XML
<Window xmlns="https://github.com/avaloniaui"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:vm="using:ZB.MOM.WW.OtOpcUa.Client.UI.ViewModels"
|
|
xmlns:views="using:ZB.MOM.WW.OtOpcUa.Client.UI.Views"
|
|
x:Class="ZB.MOM.WW.OtOpcUa.Client.UI.Views.MainWindow"
|
|
x:DataType="vm:MainWindowViewModel"
|
|
Title="OPC UA Client"
|
|
Width="1200"
|
|
Height="800">
|
|
<DockPanel>
|
|
<!-- Top Connection Bar -->
|
|
<Border DockPanel.Dock="Top" Background="#F0F0F0" Padding="12">
|
|
<StackPanel Spacing="4">
|
|
<!-- Always visible: URL + Connect/Disconnect -->
|
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
|
<StackPanel Spacing="2" VerticalAlignment="Bottom">
|
|
<TextBlock Text="Endpoint URL" FontSize="11" Foreground="Gray" />
|
|
<TextBox Text="{Binding EndpointUrl}"
|
|
Width="400"
|
|
Watermark="opc.tcp://host:port" />
|
|
</StackPanel>
|
|
<Button Content="Connect"
|
|
Command="{Binding ConnectCommand}"
|
|
VerticalAlignment="Bottom" Padding="16,6" />
|
|
<Button Content="Disconnect"
|
|
Command="{Binding DisconnectCommand}"
|
|
VerticalAlignment="Bottom" Padding="16,6" />
|
|
</StackPanel>
|
|
|
|
<!-- Expandable settings -->
|
|
<Expander Header="Connection Settings" Padding="0,4">
|
|
<StackPanel Spacing="10" Margin="4,8,4,4">
|
|
<!-- Row 1: Authentication -->
|
|
<StackPanel Orientation="Horizontal" Spacing="12">
|
|
<StackPanel Spacing="2">
|
|
<TextBlock Text="Username" FontSize="11" Foreground="Gray" />
|
|
<TextBox Text="{Binding Username}"
|
|
Width="160"
|
|
Watermark="(anonymous)" />
|
|
</StackPanel>
|
|
<StackPanel Spacing="2">
|
|
<TextBlock Text="Password" FontSize="11" Foreground="Gray" />
|
|
<TextBox Text="{Binding Password}"
|
|
Width="160"
|
|
Watermark="(none)"
|
|
PasswordChar="*" />
|
|
</StackPanel>
|
|
<StackPanel Spacing="2">
|
|
<TextBlock Text="Security Mode" FontSize="11" Foreground="Gray" />
|
|
<ComboBox ItemsSource="{Binding SecurityModes}"
|
|
SelectedItem="{Binding SelectedSecurityMode}"
|
|
Width="160" />
|
|
</StackPanel>
|
|
</StackPanel>
|
|
|
|
<!-- Row 2: Failover + Session -->
|
|
<StackPanel Orientation="Horizontal" Spacing="12">
|
|
<StackPanel Spacing="2">
|
|
<TextBlock Text="Failover URLs (comma-separated)" FontSize="11" Foreground="Gray" />
|
|
<TextBox Text="{Binding FailoverUrls}"
|
|
Width="400"
|
|
Watermark="opc.tcp://backup1:4840, opc.tcp://backup2:4840" />
|
|
</StackPanel>
|
|
<StackPanel Spacing="2">
|
|
<TextBlock Text="Session Timeout (s)" FontSize="11" Foreground="Gray" />
|
|
<NumericUpDown Value="{Binding SessionTimeoutSeconds}"
|
|
Minimum="1" Maximum="3600"
|
|
Width="120"
|
|
FormatString="0" />
|
|
</StackPanel>
|
|
</StackPanel>
|
|
|
|
<!-- Row 3: Certificates -->
|
|
<StackPanel Orientation="Horizontal" Spacing="12">
|
|
<StackPanel Spacing="2">
|
|
<TextBlock Text="Certificate Store Path" FontSize="11" Foreground="Gray" />
|
|
<StackPanel Orientation="Horizontal" Spacing="4">
|
|
<TextBox Text="{Binding CertificateStorePath}"
|
|
Width="370"
|
|
IsReadOnly="True"
|
|
Watermark="(default: AppData/OtOpcUaClient/pki)" />
|
|
<Button Name="BrowseCertPathButton"
|
|
Content="..."
|
|
Width="30"
|
|
ToolTip.Tip="Browse for folder" />
|
|
</StackPanel>
|
|
</StackPanel>
|
|
<CheckBox IsChecked="{Binding AutoAcceptCertificates}"
|
|
Content="Auto-accept untrusted server certificates"
|
|
VerticalAlignment="Bottom"
|
|
Margin="0,0,0,4" />
|
|
</StackPanel>
|
|
</StackPanel>
|
|
</Expander>
|
|
|
|
<!-- Redundancy Info -->
|
|
<StackPanel Orientation="Horizontal"
|
|
Spacing="16"
|
|
IsVisible="{Binding RedundancyInfo, Converter={x:Static ObjectConverters.IsNotNull}}"
|
|
Margin="0,2,0,0">
|
|
<TextBlock Text="{Binding RedundancyInfo.Mode, StringFormat='Redundancy: {0}'}"
|
|
FontSize="11" Foreground="Gray" />
|
|
<TextBlock Text="{Binding RedundancyInfo.ServiceLevel, StringFormat='Service Level: {0}'}"
|
|
FontSize="11" Foreground="Gray" />
|
|
<TextBlock Text="{Binding RedundancyInfo.ApplicationUri, StringFormat='URI: {0}'}"
|
|
FontSize="11" Foreground="Gray" />
|
|
</StackPanel>
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- Bottom Status Bar -->
|
|
<Border DockPanel.Dock="Bottom" Background="#F0F0F0" Padding="8,4">
|
|
<StackPanel Orientation="Horizontal" Spacing="20">
|
|
<TextBlock Text="{Binding StatusMessage}" />
|
|
<TextBlock Text="{Binding SessionLabel}" Foreground="Gray" />
|
|
<TextBlock Text="{Binding SubscriptionCount, StringFormat='Subscriptions: {0}'}" />
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- Main Content -->
|
|
<Grid ColumnDefinitions="300,8,*">
|
|
<!-- Left: Browse Tree -->
|
|
<Border Grid.Column="0" BorderBrush="#CCCCCC" BorderThickness="0,0,1,0">
|
|
<DockPanel>
|
|
<TextBlock DockPanel.Dock="Top" Text="Browse Tree" FontWeight="Bold" Margin="8,8,8,4" />
|
|
<views:BrowseTreeView DataContext="{Binding BrowseTree}"
|
|
Name="BrowseTreePanel">
|
|
<views:BrowseTreeView.ContextMenu>
|
|
<ContextMenu Name="TreeContextMenu">
|
|
<MenuItem Header="Subscribe" Name="SubscribeMenuItem" />
|
|
<MenuItem Header="View History" Name="ViewHistoryMenuItem" />
|
|
<Separator />
|
|
<MenuItem Header="Monitor Alarms" Name="MonitorAlarmsMenuItem" />
|
|
</ContextMenu>
|
|
</views:BrowseTreeView.ContextMenu>
|
|
</views:BrowseTreeView>
|
|
</DockPanel>
|
|
</Border>
|
|
|
|
<!-- Splitter -->
|
|
<GridSplitter Grid.Column="1" Width="8" Background="Transparent" />
|
|
|
|
<!-- Right: Tab panels -->
|
|
<TabControl Grid.Column="2"
|
|
IsEnabled="{Binding IsConnected}"
|
|
SelectedIndex="{Binding SelectedTabIndex}">
|
|
<TabItem Header="Read/Write">
|
|
<views:ReadWriteView DataContext="{Binding ReadWrite}" />
|
|
</TabItem>
|
|
<TabItem Header="{Binding SubscriptionsTabHeader}">
|
|
<views:SubscriptionsView DataContext="{Binding Subscriptions}" />
|
|
</TabItem>
|
|
<TabItem Header="{Binding AlarmsTabHeader}">
|
|
<views:AlarmsView DataContext="{Binding Alarms}" />
|
|
</TabItem>
|
|
<TabItem Header="History">
|
|
<views:HistoryView DataContext="{Binding History}" />
|
|
</TabItem>
|
|
</TabControl>
|
|
</Grid>
|
|
</DockPanel>
|
|
</Window> |