Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
40927cd
ux(write): carry verified compact typed legacy editor onto newest int…
masarray Oct 23, 2026
d2f2b5c
ux(write): carry verified compact typed legacy editor onto newest int…
masarray Oct 23, 2026
bcc95f8
ux(write): carry verified compact typed legacy editor onto newest int…
masarray Oct 23, 2026
4723ad2
ux(write): carry verified compact typed legacy editor onto newest int…
masarray Oct 23, 2026
dd5fc46
ux(write): carry verified compact typed legacy editor onto newest int…
masarray Oct 23, 2026
ac333db
ux(write): keep BOTH Browser Write entry points stable Material penci…
masarray Oct 23, 2026
e3df40a
ux(write): live-read-backed typed row presentation with per-row Boole…
masarray Oct 23, 2026
c44ff8c
ux(write): restore IEDScout-like unified native typed inline editor, …
masarray Oct 23, 2026
9127f10
ux(write): typed current values on open, Boolean/ctlModel selection, …
masarray Oct 23, 2026
9997f11
test(write): preserve earlier FAT controls and static write caption a…
masarray Oct 23, 2026
6fe2761
test(write): preserve earlier FAT controls and static write caption a…
masarray Oct 23, 2026
40a2200
test(write): regression guards for scalar, batch and unified native e…
masarray Oct 23, 2026
6ee863d
test(write): enforce read-backed Boolean and ctlModel editors, explic…
masarray Oct 23, 2026
b896e77
fix(cleanroom): keep UX code and comments independent of named extern…
masarray Oct 23, 2026
ae6421e
fix(cleanroom): keep UX code and comments independent of named extern…
masarray Oct 23, 2026
73af5bb
fix(cleanroom): keep UX code and comments independent of named extern…
masarray Oct 23, 2026
5789cf1
fix(write): exact vector of user-provided Material edit icon in unifi…
masarray Oct 23, 2026
ac13b6c
ux(write): unify two legacy and native config workflows behind one fi…
masarray Oct 23, 2026
0e99827
ux(write): hide duplicate config button; native editor remains reacha…
masarray Oct 23, 2026
102b1b1
test(write): protect one visible fixed Write button and all native ro…
masarray Oct 23, 2026
673cc8a
fix(build): remove orphaned duplicate single-DA class tail and initia…
masarray Oct 23, 2026
3dd52c3
sync(fat): preserve concurrent SG7 command, report scheduling and sor…
masarray Oct 23, 2026
71847f4
sync(fat): preserve concurrent SG7 command, report scheduling and sor…
masarray Oct 23, 2026
6d76437
sync(fat): preserve concurrent SG7 command, report scheduling and sor…
masarray Oct 23, 2026
85a8c4f
sync(fat): preserve concurrent SG7 command, report scheduling and sor…
masarray Oct 23, 2026
722445d
sync(fat): preserve concurrent SG7 command, report scheduling and sor…
masarray Oct 23, 2026
b614738
sync(fat): include concurrent SG7 safety regression tests from FAT so…
masarray Oct 23, 2026
f52cc93
sync(fat): include concurrent SG7 safety regression tests from FAT so…
masarray Oct 23, 2026
7671bac
sync(fat): keep latest SG7 MainWindow source and preserve single stab…
masarray Oct 23, 2026
8561212
test(write): follow compact grid row and pinned footer after removing…
masarray Oct 23, 2026
9e73fd1
merge(FAT): rebase guarded Browser multi-DA editor without overwritin…
masarray Oct 23, 2026
ff02f12
fix(write): forbid generic ctlModel and unverified enum encoding; exp…
masarray Oct 23, 2026
d95d44a
feat(write): surface verified enum-mapping absence in inline placeholder
masarray Oct 23, 2026
93241c7
fix(safety): enforce native ctlModel/CO ownership at final primitive …
masarray Oct 23, 2026
d6775c8
test(safety): prove dedicated ctlModel dispatch and fail-closed nonve…
masarray Oct 23, 2026
91a0583
test(write): reject missing enum metadata and generic ctlModel while …
masarray Oct 23, 2026
b66b09c
feat(write): fixed Material pencil+Write and Material Cancel in compa…
masarray Oct 23, 2026
e0c5ca3
feat(write): unify batch Inspect/Write/Close with registry Material a…
masarray Oct 23, 2026
45e895d
test(write): assert pinned Material pencil action and stable label on…
masarray Oct 23, 2026
d72b6f7
fix(write): restrict generic ctlModel/CO ban to Write entry; restore …
masarray Oct 23, 2026
b8dba5a
merge(FAT): harmonize typed Browser Write, native service safety and …
masarray Oct 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions BrowserBatchWriteWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,26 @@
VerticalAlignment="Center" Margin="0,0,8,0"/>
<Button x:Name="InspectButton" Grid.Column="1" Content="Inspect"
Style="{StaticResource SoftButton}" Width="89" Height="31"
ContentTemplate="{StaticResource MaterialReadAction}"
Margin="0,0,7,0" Click="Inspect_Click"/>
<Button x:Name="WriteButton" Grid.Column="2" Content="Write"
Width="94" Height="31" IsEnabled="False" Background="#255F99"
Foreground="White" BorderBrush="#255F99"
Margin="0,0,7,0" Click="Write_Click"/>
Margin="0,0,7,0" Click="Write_Click">
<Button.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Viewbox Width="15" Height="15" Margin="0,0,6,0" IsHitTestVisible="False">
<Path Data="{StaticResource MaterialEditIcon}" Fill="White"/>
</Viewbox>
<TextBlock Text="{Binding}" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Button.ContentTemplate>
</Button>
<Button Grid.Column="3" Content="Close" Width="72" Height="31"
Style="{StaticResource SoftButton}" Click="Close_Click"/>
Style="{StaticResource SoftButton}" ContentTemplate="{StaticResource MaterialCancelAction}"
Click="Close_Click"/>
</Grid>
</Grid>
</Grid>
Expand Down
18 changes: 15 additions & 3 deletions BrowserDataWriteWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,22 @@
Foreground="#61758A" TextTrimming="CharacterEllipsis"
VerticalAlignment="Center" FontSize="10.5" Margin="0,0,9,0"/>
<Button x:Name="WriteButton" Grid.Column="1" Content="Write"
Width="90" Height="31" IsEnabled="False"
Style="{StaticResource PrimaryButton}" Click="Write_Click" Margin="0,0,7,0"/>
Width="94" Height="31" IsEnabled="False"
Style="{StaticResource PrimaryButton}" Click="Write_Click" Margin="0,0,7,0">
<Button.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Viewbox Width="15" Height="15" Margin="0,0,6,0" IsHitTestVisible="False">
<Path Data="{StaticResource MaterialEditIcon}" Fill="White"/>
</Viewbox>
<TextBlock Text="{Binding}" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Button.ContentTemplate>
</Button>
<Button Grid.Column="2" Content="Cancel" Width="84" Height="31"
Style="{StaticResource SoftButton}" Click="Close_Click"/>
Style="{StaticResource SoftButton}"
ContentTemplate="{StaticResource MaterialCancelAction}" Click="Close_Click"/>
</Grid>
</Grid>
</Window>
184 changes: 111 additions & 73 deletions IedBrowserWriteWindow.xaml
Original file line number Diff line number Diff line change
@@ -1,111 +1,149 @@
<Window x:Class="ArIED61850Tester.IedBrowserWriteWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MMS Write · IED Browser" Width="1010" Height="670"
MinWidth="760" MinHeight="435" WindowStartupLocation="CenterOwner"
Background="#F5F8FC" Loaded="Window_Loaded" Closing="Window_Closing">
<Grid Margin="14,12" ClipToBounds="True">
Title="Write Data to IED" Width="940" Height="520"
MinWidth="750" MinHeight="390" MaxHeight="780"
WindowStartupLocation="CenterOwner" ResizeMode="CanResize"
Background="#F5F7FB" FontFamily="{StaticResource AppFontFamily}"
Icon="Assets/app-icon.ico" Loaded="Window_Loaded" Closing="Window_Closing">
<Grid Margin="14,11,14,11">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" MinHeight="150"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="3,0,3,12">
<TextBlock Text="MMS configuration Write" FontSize="16" FontWeight="SemiBold"
Foreground="#24354B"/>
<TextBlock x:Name="IdentityText" FontSize="11.5" Foreground="#596C82"
Margin="0,5,0,0" TextTrimming="CharacterEllipsis"/>
<TextBlock Text="Only live-discovered CF / DC / SP / SG / SE attributes. CO command services, process values and RCBs are excluded."
FontSize="11" Foreground="#8A5B17" TextWrapping="Wrap" Margin="0,4,0,0"/>
<StackPanel Grid.Row="0" Margin="1,0,1,10">
<TextBlock Text="Write Data to IED" FontSize="14" FontWeight="SemiBold"
Foreground="#273E58"/>
<TextBlock x:Name="IdentityText" FontSize="11" Foreground="#5A718A"
Margin="0,4,0,0" TextTrimming="CharacterEllipsis"
ToolTip="{Binding Text, RelativeSource={RelativeSource Self}}"/>
</StackPanel>
<TextBlock Grid.Row="1" Text="Select each DA, enter its typed value, then confirm. Bulk is sequential (not atomic); stops at first failure. Readback is required."
FontSize="11" Foreground="#3E5671" TextWrapping="Wrap" Margin="3,0,0,9"/>
<DataGrid Grid.Row="2" x:Name="WriteRowsGrid"
ItemsSource="{Binding Rows}"
<DataGrid Grid.Row="1" x:Name="WriteRowsGrid" ItemsSource="{Binding Rows}"
Style="{StaticResource ModernDataGrid}"
AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False"
IsReadOnly="False" RowHeight="35" ColumnHeaderHeight="33"
AlternatingRowBackground="#F1F5FA" Background="White" BorderBrush="#C6D3E3"
ScrollViewer.VerticalScrollBarVisibility="Visible"
IsReadOnly="False" RowHeight="34" ColumnHeaderHeight="30"
AlternatingRowBackground="#F5F8FC"
Background="White" BorderBrush="#CCD9E8"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Pixel"
EnableRowVirtualization="True" MinHeight="0" ClipToBounds="True">
VirtualizingPanel.VirtualizationMode="Recycling"
EnableRowVirtualization="True" MinHeight="0">
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="Write" Binding="{Binding Selected, Mode=TwoWay}"
Width="54"/>
<DataGridTextColumn Header="Exact IEC DA reference" Binding="{Binding Reference}"
Width="2.6*" MinWidth="220" IsReadOnly="True"/>
<DataGridCheckBoxColumn Header="" Binding="{Binding Selected, Mode=TwoWay}"
Width="42"/>
<DataGridTextColumn Header="Data Attribute" Binding="{Binding ShortName}"
Width="1.6*" MinWidth="132" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
<Setter Property="ToolTip" Value="{Binding Reference}"/>
<Setter Property="Foreground" Value="#314963"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="FC" Binding="{Binding FunctionalConstraint}"
Width="50" IsReadOnly="True"/>
<DataGridTextColumn Header="Type" Binding="{Binding DataType}"
Width="100" IsReadOnly="True"/>
<DataGridTextColumn Header="Live before" Binding="{Binding Current}"
Width="1*" MinWidth="95" IsReadOnly="True"/>
<DataGridTemplateColumn Header="New value" Width="1.3*" MinWidth="132">
Width="44" IsReadOnly="True"/>
<DataGridTextColumn Header="Current" Binding="{Binding Current}"
Width="1*" MinWidth="93" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
<Setter Property="ToolTip" Value="{Binding Current}"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTemplateColumn Header="Value" Width="1.45*" MinWidth="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid Margin="1">
<TextBox x:Name="ValueEditor" Text="{Binding RequestedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Padding="5,3" BorderBrush="#CED7E3" Background="White">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsControlModel}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<ComboBox x:Name="CtlPicker"
<Grid Margin="2,0" VerticalAlignment="Center">
<TextBox x:Name="ValueEditor"
Height="27" Padding="6,3" FontSize="11"
Text="{Binding RequestedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding TextEditorVisibility}"
BorderBrush="#B9CCE1"
ToolTip="Edit the live value that was read from this IED"/>
<ComboBox x:Name="BooleanPicker" Height="27" FontSize="11"
ItemsSource="{Binding BooleanOptions}"
SelectedItem="{Binding RequestedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding BooleanEditorVisibility}"
ToolTip="Choose true or false"/>
<ComboBox x:Name="CtlPicker" Height="27" FontSize="11"
SelectedValue="{Binding RequestedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="Tag" FontSize="11.5">
<ComboBox.Style>
<Style TargetType="ComboBox">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsControlModel}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
SelectedValuePath="Tag"
Visibility="{Binding CtlModelEditorVisibility}"
ToolTip="IEC 61850 ctlModel enumeration">
<ComboBoxItem Tag="0" Content="0 · status-only"/>
<ComboBoxItem Tag="1" Content="1 · direct-normal"/>
<ComboBoxItem Tag="2" Content="2 · sbo-normal"/>
<ComboBoxItem Tag="3" Content="3 · direct-enhanced"/>
<ComboBoxItem Tag="4" Content="4 · sbo-enhanced"/>
</ComboBox>
<TextBlock Text="{Binding PlaceholderText}" VerticalAlignment="Center"
Foreground="#8193A7" FontSize="10"
Visibility="{Binding PlaceholderVisibility}"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="MMS type" Binding="{Binding DataType}"
Width="1*" MinWidth="88" IsReadOnly="True"/>
<DataGridTextColumn Header="Result" Binding="{Binding Result}"
Width="1.1*" MinWidth="140" IsReadOnly="True"/>
Width="1.7*" MinWidth="145" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
<Setter Property="ToolTip" Value="{Binding Result}"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<TextBlock Grid.Row="3" x:Name="StatusText" Margin="3,10,3,8"
Text="No MMS operation has been sent." TextWrapping="Wrap"
Foreground="#455E78" FontSize="11.5"/>
<Grid Grid.Row="4" Margin="0,3,0,0">
<Grid Grid.Row="2" Margin="2,9,2,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Never use Write as a substitute for IEC control Operate."
Foreground="#8F5B18" FontSize="10.5" VerticalAlignment="Center" TextWrapping="Wrap"/>
<Button Grid.Column="1" x:Name="ReadButton" Content="Read selected"
Width="110" Height="31" Margin="0,0,8,0" Click="Read_Click"/>
<Button Grid.Column="2" x:Name="WriteButton" Content="Write selected…"
Width="135" Height="31" Margin="0,0,8,0" Click="Write_Click"
Background="#2762AF" Foreground="White"/>
<Button Grid.Column="3" Content="Close" Width="80" Height="31" Click="Close_Click"/>
<TextBlock x:Name="StatusText" Grid.Column="0"
Foreground="#58718B" FontSize="10.5"
TextWrapping="NoWrap" TextTrimming="CharacterEllipsis"
VerticalAlignment="Center" Margin="0,0,9,0"
ToolTip="{Binding Text, RelativeSource={RelativeSource Self}}"
Text="Reading current MMS values…"/>
<Button Grid.Column="1" x:Name="ReadButton" Width="82" Height="32"
Margin="0,0,7,0" Style="{StaticResource SoftButton}" Click="Read_Click">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Viewbox Width="15" Height="15" Margin="0,0,5,0">
<Path Data="{StaticResource MaterialRefreshIcon}" Fill="#45617C"/>
</Viewbox>
<TextBlock Text="Read" VerticalAlignment="Center"/>
</StackPanel>
</Button>
<Button Grid.Column="2" x:Name="WriteButton" Width="94" Height="32"
MinHeight="32" Margin="0,0,7,0" IsEnabled="False"
Style="{StaticResource PrimaryButton}" Click="Write_Click">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Viewbox Width="16" Height="16" Margin="0,0,6,0">
<Path Data="{StaticResource MaterialEditIcon}" Fill="White"/>
</Viewbox>
<TextBlock Text="Write" VerticalAlignment="Center"/>
</StackPanel>
</Button>
<Button Grid.Column="3" Width="82" Height="32"
Style="{StaticResource SoftButton}" Click="Close_Click">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Viewbox Width="12" Height="12" Margin="0,0,5,0">
<Path Data="{StaticResource MaterialCloseIcon}" Fill="#415771"/>
</Viewbox>
<TextBlock Text="Close" VerticalAlignment="Center"/>
</StackPanel>
</Button>
</Grid>
</Grid>
</Window>
Loading
Loading