Files
8damon-Blackbird-Platform/Client/host/MainWindow.xaml
T
2026-04-03 14:23:15 +10:00

356 lines
21 KiB
XML

<Window x:Class="BlackbirdOperator.MainWindow"
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"
mc:Ignorable="d"
Title="Blackbird Operator"
Width="1680"
Height="960"
MinWidth="1320"
MinHeight="760"
ResizeMode="CanResize"
Background="{StaticResource WinBgBrush}"
SnapsToDevicePixels="True"
UseLayoutRounding="True">
<Border Background="{StaticResource WinBgBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="1"
SnapsToDevicePixels="True">
<DockPanel Background="{StaticResource WinBgBrush}" LastChildFill="True">
<!-- Top command bar -->
<Border DockPanel.Dock="Top"
Background="{StaticResource CommandBarBackgroundBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="0,0,0,1"
Padding="12,10"
SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="AdapterSummaryText"
Foreground="{StaticResource WinMutedTextBrush}"
VerticalAlignment="Center" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
<Button x:Name="ConfigureNetworkButton"
Content="Configure Network"
Click="ConfigureNetworkButton_Click" />
<Button x:Name="ResetConfigButton"
Content="Reset Config"
Click="ResetConfigButton_Click" />
<TextBox x:Name="ManualAddressBox"
Width="200"
Height="26"
Margin="0,0,8,0"
VerticalContentAlignment="Center"
ToolTip="Manual VM address or hostname" />
<Button x:Name="ConnectAddressButton"
Content="Connect Address"
Click="ConnectAddressButton_Click" />
<Button x:Name="RefreshNodesButton"
Content="Refresh Nodes"
Click="RefreshNodesButton_Click" />
<Button x:Name="ConnectNodeButton"
Content="Connect"
Click="ConnectNodeButton_Click" />
</StackPanel>
</Grid>
</Border>
<!-- Three-column body: node list | control center | node detail -->
<Grid Margin="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<!-- LEFT: Node list -->
<Border Grid.Column="0"
Background="{StaticResource WinPanelBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="1"
Margin="0,0,10,0"
SnapsToDevicePixels="True">
<DockPanel>
<Border DockPanel.Dock="Top"
Background="{StaticResource WinHeaderBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="0,0,0,1"
Padding="10,8"
SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="Nodes" FontWeight="SemiBold" />
<TextBlock Grid.Column="1"
x:Name="NodeCountText"
Foreground="{StaticResource WinMutedTextBrush}" />
</Grid>
</Border>
<DataGrid x:Name="NodesGrid"
ItemsSource="{Binding Nodes}"
AutoGenerateColumns="False"
HeadersVisibility="Column"
SelectionMode="Single"
SelectionUnit="FullRow"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserResizeRows="False"
IsReadOnly="True"
SelectionChanged="NodesGrid_SelectionChanged"
MouseDoubleClick="NodesGrid_MouseDoubleClick">
<DataGrid.Columns>
<DataGridTextColumn Header="Node" Binding="{Binding DisplayName}" Width="*" />
<DataGridTextColumn Header="Addr" Binding="{Binding Address}" Width="*" />
<DataGridTextColumn Header="State" Binding="{Binding StatusSummary}" Width="*" />
<DataGridTextColumn Header="Driver" Binding="{Binding DriverStatus}" Width="*" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Border>
<!-- MIDDLE: Control center -->
<Border Grid.Column="1"
Background="{StaticResource WinPanelBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="1"
Margin="0,0,10,0"
SnapsToDevicePixels="True">
<DockPanel>
<Border DockPanel.Dock="Top"
Background="{StaticResource WinHeaderBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="0,0,0,1"
Padding="10,8"
SnapsToDevicePixels="True">
<TextBlock Text="Control Center" FontWeight="SemiBold" />
</Border>
<!-- Command input bar -->
<Border DockPanel.Dock="Top"
Background="{StaticResource WinHeaderBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="0,0,0,1"
Padding="10,8">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Content="Ping"
Margin="0,0,6,0"
Tag="PING"
Click="QuickCommandButton_Click" />
<Button Grid.Column="1"
Content="Status"
Margin="0,0,6,0"
Tag="STATUS"
Click="QuickCommandButton_Click" />
<Button Grid.Column="2"
x:Name="SendFileButton"
Content="Send File"
Margin="0,0,12,0"
Click="SendFileButton_Click" />
<TextBox Grid.Column="4"
x:Name="CommandInputBox"
Height="26"
Margin="0,0,6,0"
VerticalContentAlignment="Center"
ToolTip="Command (e.g. PING, STATUS) — Enter to send"
KeyDown="CommandInputBox_KeyDown" />
<Button Grid.Column="5"
x:Name="SendCommandButton"
Content="Send"
Click="SendCommandButton_Click" />
</Grid>
</Border>
<!-- Output area + status -->
<Border DockPanel.Dock="Bottom"
Background="{StaticResource WinHeaderBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="0,1,0,0"
Padding="10,8">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="OperatorStatusText"
Foreground="{StaticResource WinMutedTextBrush}"
TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis"
VerticalAlignment="Center"
Text="Waiting for discovery traffic." />
<Button Grid.Column="1"
Content="Clear"
Margin="8,0,0,0"
Click="ClearCommandOutputButton_Click" />
</Grid>
</Border>
<!-- File drop zone -->
<Border x:Name="FileDropZone"
DockPanel.Dock="Bottom"
Height="52"
AllowDrop="True"
Background="{StaticResource WinHeaderBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="0,1,0,0"
SnapsToDevicePixels="True"
DragEnter="FileDropZone_DragEnter"
DragLeave="FileDropZone_DragLeave"
DragOver="FileDropZone_DragOver"
Drop="FileDropZone_Drop">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="&#x2193;"
FontSize="16"
VerticalAlignment="Center"
Margin="12,0,8,0"
Foreground="{StaticResource WinMutedTextBrush}" />
<StackPanel Grid.Column="1"
VerticalAlignment="Center">
<TextBlock x:Name="FileDropPrimaryText"
Text="Drop file to send to node"
FontSize="12"
Foreground="{StaticResource WinMutedTextBrush}" />
<TextBlock x:Name="FileDropSecondaryText"
Text="File is uploaded and analyzed on the remote node"
FontSize="10"
Margin="0,2,0,0"
Foreground="{StaticResource WinMutedTextBrush}" />
</StackPanel>
</Grid>
</Border>
<TextBox x:Name="CommandOutputBox"
IsReadOnly="True"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto"
AcceptsReturn="True"
FontFamily="Consolas"
FontSize="12"
Background="#FF0A0A0A"
Foreground="#FFCCCCCC"
BorderThickness="0"
Padding="12" />
</DockPanel>
</Border>
<!-- RIGHT: Node detail -->
<Border Grid.Column="2"
Background="{StaticResource WinPanelBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="1"
SnapsToDevicePixels="True">
<DockPanel>
<Border DockPanel.Dock="Top"
Background="{StaticResource WinHeaderBrush}"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="0,0,0,1"
Padding="10,8"
SnapsToDevicePixels="True">
<TextBlock Text="Node Detail" FontWeight="SemiBold" />
</Border>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Margin="10">
<Border Background="#FF111111"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="1"
Padding="10"
Margin="0,0,0,10">
<StackPanel>
<TextBlock x:Name="DetailTitleText"
FontSize="14"
FontWeight="SemiBold"
Text="No node selected" />
<TextBlock x:Name="DetailSubtitleText"
Margin="0,5,0,0"
Foreground="{StaticResource WinMutedTextBrush}"
TextWrapping="Wrap"
Text="Select a node to query live status." />
</StackPanel>
</Border>
<UniformGrid Columns="2" Margin="0,0,0,10">
<Border Background="#FF101010" BorderBrush="{StaticResource WinBorderBrush}" BorderThickness="1" Margin="0,0,6,6" Padding="8">
<StackPanel>
<TextBlock Text="Address" Foreground="{StaticResource WinMutedTextBrush}" FontSize="10" />
<TextBlock x:Name="DetailAddressText" Margin="0,4,0,0" TextWrapping="Wrap" />
</StackPanel>
</Border>
<Border Background="#FF101010" BorderBrush="{StaticResource WinBorderBrush}" BorderThickness="1" Margin="0,0,0,6" Padding="8">
<StackPanel>
<TextBlock Text="Status Port" Foreground="{StaticResource WinMutedTextBrush}" FontSize="10" />
<TextBlock x:Name="DetailPortText" Margin="0,4,0,0" />
</StackPanel>
</Border>
<Border Background="#FF101010" BorderBrush="{StaticResource WinBorderBrush}" BorderThickness="1" Margin="0,0,6,6" Padding="8">
<StackPanel>
<TextBlock Text="OS" Foreground="{StaticResource WinMutedTextBrush}" FontSize="10" />
<TextBlock x:Name="DetailOsText" Margin="0,4,0,0" TextWrapping="Wrap" FontSize="11" />
</StackPanel>
</Border>
<Border Background="#FF101010" BorderBrush="{StaticResource WinBorderBrush}" BorderThickness="1" Margin="0,0,0,6" Padding="8">
<StackPanel>
<TextBlock Text="Kernel" Foreground="{StaticResource WinMutedTextBrush}" FontSize="10" />
<TextBlock x:Name="DetailKernelText" Margin="0,4,0,0" FontSize="11" />
</StackPanel>
</Border>
<Border Background="#FF101010" BorderBrush="{StaticResource WinBorderBrush}" BorderThickness="1" Margin="0,0,6,6" Padding="8">
<StackPanel>
<TextBlock Text="Controller" Foreground="{StaticResource WinMutedTextBrush}" FontSize="10" />
<TextBlock x:Name="DetailControllerText" Margin="0,4,0,0" FontSize="11" />
</StackPanel>
</Border>
<Border Background="#FF101010" BorderBrush="{StaticResource WinBorderBrush}" BorderThickness="1" Margin="0,0,0,6" Padding="8">
<StackPanel>
<TextBlock Text="Observed" Foreground="{StaticResource WinMutedTextBrush}" FontSize="10" />
<TextBlock x:Name="DetailLastSeenText" Margin="0,4,0,0" FontSize="11" />
</StackPanel>
</Border>
</UniformGrid>
<Border Background="#FF101010"
BorderBrush="{StaticResource WinBorderBrush}"
BorderThickness="1"
Padding="8"
Margin="0,0,0,10">
<StackPanel>
<TextBlock Text="Live Flags" Foreground="{StaticResource WinMutedTextBrush}" FontSize="10" />
<TextBlock x:Name="DetailFlagsText"
Margin="0,6,0,0"
TextWrapping="Wrap"
FontSize="11" />
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</DockPanel>
</Border>
</Grid>
</DockPanel>
</Border>
</Window>