junction/src/Junction.App/Views/MachineConfigView.axaml
dtrentin f4abdc0039 feat: themed + iconed UI polish (v0.3.1)
Fluent light/dark theme dictionaries (accent/surface/card/border/danger),
OS-following variant, App-level text/button/card styles. Per-protocol vector
icons via ProtocolIdToIconConverter (mirrors StatusKindToBrushConverter,
view-layer, safe fallback, no external assets). Curated layout across
dashboard/detail/config: consistent spacing scale, card grouping, theme brushes,
accent/danger buttons. App-only; no VM contract change, no new NuGet, no fw bump.

Projects: Junction.App (+ Junction.Tests: +10 converter tests, 148 pass).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 07:23:47 +02:00

127 lines
5.6 KiB
XML

<UserControl xmlns="https://github.com/avaloniaui"
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:Junction.App.ViewModels"
mc:Ignorable="d"
x:Class="Junction.App.Views.MachineConfigView"
x:DataType="vm:MachineConfigViewModel"
x:CompileBindings="True">
<DockPanel Margin="20">
<!-- Header -->
<TextBlock DockPanel.Dock="Top" Classes="h1"
Text="{Binding Title}"
Margin="0,0,0,16" />
<!-- Action bar -->
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Spacing="12" Margin="0,16,0,0">
<Button Classes="accent" Content="Save" Command="{Binding SaveCommand}" IsDefault="True" />
<Button Content="Cancel" Command="{Binding CancelCommand}" />
</StackPanel>
<!-- Inline validation hint -->
<TextBlock DockPanel.Dock="Bottom"
Text="{Binding ValidationError}"
IsVisible="{Binding HasValidationError}"
Foreground="{DynamicResource DangerBrush}"
TextWrapping="Wrap"
Margin="0,12,0,0" />
<!-- Form -->
<Border DockPanel.Dock="Top" Classes="card" MaxWidth="480" HorizontalAlignment="Left">
<StackPanel Spacing="12">
<StackPanel Spacing="4">
<TextBlock Classes="fieldLabel" Text="Name" />
<TextBox Text="{Binding Name}" Watermark="Machine name" />
</StackPanel>
<StackPanel Spacing="4">
<TextBlock Classes="fieldLabel" Text="Protocol" />
<ComboBox ItemsSource="{Binding AvailableProtocols}"
SelectedItem="{Binding SelectedProtocol}"
HorizontalAlignment="Stretch"
PlaceholderText="Select a protocol" />
</StackPanel>
<StackPanel Spacing="4">
<TextBlock Classes="fieldLabel" Text="Agent URL" />
<TextBox Text="{Binding AgentUrl}" Watermark="http://host:5000" />
</StackPanel>
<StackPanel Spacing="4">
<TextBlock Classes="fieldLabel" Text="Poll Interval (seconds)" />
<TextBox Text="{Binding PollIntervalSeconds}" Width="120" HorizontalAlignment="Left" />
</StackPanel>
</StackPanel>
</Border>
<!-- Data items to monitor (fills remaining space) -->
<Border Classes="card" Margin="0,16,0,0" MaxWidth="640" HorizontalAlignment="Left">
<DockPanel>
<TextBlock DockPanel.Dock="Top" Classes="h2" Text="Data items to monitor"
Margin="0,0,0,8" />
<!-- Controls row -->
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Spacing="8" Margin="0,0,0,8">
<Button Content="Load available items"
Command="{Binding LoadItemsCommand}" />
<Button Content="Select all"
Command="{Binding SelectAllCommand}" />
<Button Content="Select none"
Command="{Binding SelectNoneCommand}" />
<ProgressBar IsIndeterminate="True"
IsVisible="{Binding IsProbing}"
Width="120" VerticalAlignment="Center" />
</StackPanel>
<!-- Status message -->
<TextBlock DockPanel.Dock="Top" Classes="subtle"
Text="{Binding ItemsStatus}"
IsVisible="{Binding HasItemsStatus}"
TextWrapping="Wrap" Margin="0,0,0,8" />
<!-- Column header -->
<Border DockPanel.Dock="Top"
BorderThickness="0,0,0,1"
BorderBrush="{DynamicResource CardBorderBrush}"
Padding="0,0,0,4" Margin="0,0,0,4">
<Grid ColumnDefinitions="Auto,2*,1.2*,1.2*,1*" Margin="0,0,8,0">
<TextBlock Grid.Column="0" Text="" Width="28" />
<TextBlock Grid.Column="1" Classes="fieldLabel" Text="Name" />
<TextBlock Grid.Column="2" Classes="fieldLabel" Text="Type" />
<TextBlock Grid.Column="3" Classes="fieldLabel" Text="Category" />
<TextBlock Grid.Column="4" Classes="fieldLabel" Text="Units" />
</Grid>
</Border>
<!-- Scrollable checklist -->
<ScrollViewer MaxHeight="320">
<ItemsControl ItemsSource="{Binding AvailableItems}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:SelectableDataItemViewModel">
<Grid ColumnDefinitions="Auto,2*,1.2*,1.2*,1*" Margin="0,3">
<CheckBox Grid.Column="0" Width="28"
IsChecked="{Binding IsSelected}"
VerticalAlignment="Center" />
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" TextWrapping="Wrap" />
<TextBlock Text="{Binding Id}" Classes="subtle" FontSize="11" TextWrapping="Wrap" />
</StackPanel>
<TextBlock Grid.Column="2" Text="{Binding Type}" VerticalAlignment="Center" TextWrapping="Wrap" />
<TextBlock Grid.Column="3" Text="{Binding Category}" VerticalAlignment="Center" TextWrapping="Wrap" />
<TextBlock Grid.Column="4" Text="{Binding Units}" VerticalAlignment="Center" TextWrapping="Wrap" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
</Border>
</DockPanel>
</UserControl>