- "+" öffnet ein Menü mit allen Listen (working dir) statt direkt den Ordner-Dialog; "Ordner wählen…" bleibt als Fallback erste Zeile, damit das Menü auch bei fehlgeschlagener Listen-Abfrage nutzbar bleibt - Rail-Rows: Kontextmenü "Sitzung öffnen" (gesperrt für Running — der Worktree gehört dort dem autonomen Lauf) - Aktivitäts-Strip statt reiner Queue: WaitingForReview/Failed/Roadblock kommen dazu, Attention zuerst, unterschieden nur über Farbe (Aktionen bleiben in der Task-Detailansicht)
164 lines
8.3 KiB
XML
164 lines
8.3 KiB
XML
<UserControl xmlns="https://github.com/avaloniaui"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:vm="using:ClaudeDo.Ui.ViewModels"
|
|
xmlns:vmm="using:ClaudeDo.Ui.ViewModels.MissionControl"
|
|
xmlns:mc="using:ClaudeDo.Ui.Views.MissionControl"
|
|
xmlns:controls="using:ClaudeDo.Ui.Views.Controls"
|
|
xmlns:conv="using:ClaudeDo.Ui.Converters"
|
|
xmlns:loc="using:ClaudeDo.Ui.Localization"
|
|
x:DataType="vm:MissionControlViewModel"
|
|
x:Class="ClaudeDo.Ui.Views.MissionControl.MissionControlView">
|
|
<UserControl.DataTemplates>
|
|
<!-- ConPtyPaneHost reuses the pane's one long-lived view across layout rebuilds and
|
|
tab switches — instantiating ConPtyPaneView here directly would detach (and, without
|
|
reparent suppression, kill) the running session every time a pane is added. -->
|
|
<DataTemplate DataType="vmm:ConPtyPaneViewModel">
|
|
<mc:ConPtyPaneHost Margin="6" />
|
|
</DataTemplate>
|
|
</UserControl.DataTemplates>
|
|
<DockPanel LastChildFill="True" Background="{DynamicResource VoidBrush}">
|
|
|
|
<!-- Header -->
|
|
<Border DockPanel.Dock="Top"
|
|
Background="{DynamicResource DeepBrush}"
|
|
BorderBrush="{DynamicResource LineBrush}"
|
|
BorderThickness="0,0,0,1" Padding="14,8">
|
|
<Grid ColumnDefinitions="*,Auto">
|
|
<TextBlock Grid.Column="0" Classes="eyebrow"
|
|
Text="{loc:Tr missionControl.windowTitle}"
|
|
Foreground="{DynamicResource TextBrush}"
|
|
LetterSpacing="1.4" VerticalAlignment="Center" />
|
|
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="8"
|
|
VerticalAlignment="Center">
|
|
<controls:UsagePill DataContext="{Binding UsagePill}"
|
|
Margin="0,0,4,0"
|
|
VerticalAlignment="Center"/>
|
|
<Button Classes="icon-btn"
|
|
ToolTip.Tip="{loc:Tr missionControl.newSession}">
|
|
<PathIcon Data="{StaticResource Icon.Plus}" Width="15" Height="15"/>
|
|
<Button.Flyout>
|
|
<MenuFlyout ItemsSource="{Binding SessionTargets}" Opening="OnSessionFlyoutOpening">
|
|
<MenuFlyout.ItemContainerTheme>
|
|
<ControlTheme TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}"
|
|
x:DataType="vm:SessionTargetViewModel">
|
|
<Setter Property="Header" Value="{Binding Label}"/>
|
|
<Setter Property="Command" Value="{Binding StartCommand}"/>
|
|
</ControlTheme>
|
|
</MenuFlyout.ItemContainerTheme>
|
|
</MenuFlyout>
|
|
</Button.Flyout>
|
|
</Button>
|
|
<Button Classes="icon-btn"
|
|
Command="{Binding ToggleLayoutCommand}"
|
|
ToolTip.Tip="{Binding LayoutToggleLabel}">
|
|
<PathIcon Data="{StaticResource Icon.Grid}" Width="15" Height="15"/>
|
|
</Button>
|
|
<Button Classes="icon-btn"
|
|
Command="{Binding OpenSettingsCommand}"
|
|
ToolTip.Tip="{loc:Tr missionControl.settings}">
|
|
<PathIcon Data="{StaticResource Icon.Settings}" Width="15" Height="15"/>
|
|
</Button>
|
|
</StackPanel>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- Body: main content | queue splitter | queue strip (widths managed in code-behind
|
|
so the queue column collapses to zero when nothing is queued). -->
|
|
<Grid x:Name="BodyGrid">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="0"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<!-- Grid / tabs / empty state -->
|
|
<Panel Grid.Column="0" Margin="6">
|
|
<!-- Overview mode: a real Grid built in code-behind so each pane is individually
|
|
resizable via GridSplitters, instead of a UniformGrid where every cell is forced
|
|
to the same size. -->
|
|
<Grid x:Name="OverviewGrid" IsVisible="{Binding !IsFocusMode}" />
|
|
|
|
<!-- Focus mode: one pane large, switched via tabs -->
|
|
<TabControl ItemsSource="{Binding Panes}"
|
|
SelectedItem="{Binding FocusedPane}"
|
|
IsVisible="{Binding IsFocusMode}">
|
|
<TabControl.ItemTemplate>
|
|
<DataTemplate x:DataType="vmm:ConPtyPaneViewModel">
|
|
<TextBlock Text="{Binding DisplayTitle}" TextTrimming="CharacterEllipsis" MaxWidth="160" />
|
|
</DataTemplate>
|
|
</TabControl.ItemTemplate>
|
|
</TabControl>
|
|
|
|
<TextBlock IsVisible="{Binding !HasPanes}"
|
|
Text="{loc:Tr missionControl.empty}"
|
|
Foreground="{DynamicResource TextMuteBrush}"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center" />
|
|
</Panel>
|
|
|
|
<GridSplitter x:Name="QueueSplitter" Grid.Column="1"
|
|
IsVisible="{Binding HasQueued}"
|
|
Width="6"
|
|
Background="Transparent"
|
|
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
|
ResizeDirection="Columns"
|
|
ResizeBehavior="PreviousAndNext"/>
|
|
|
|
<!-- Read-only queue strip — collapses when nothing is queued -->
|
|
<Border Grid.Column="2"
|
|
IsVisible="{Binding HasQueued}"
|
|
Background="{DynamicResource DeepBrush}"
|
|
BorderBrush="{DynamicResource LineBrush}"
|
|
BorderThickness="1,0,0,0">
|
|
<DockPanel LastChildFill="True" Margin="10,10">
|
|
<TextBlock DockPanel.Dock="Top" Classes="eyebrow"
|
|
Text="{loc:Tr missionControl.activity}"
|
|
Foreground="{DynamicResource TextMuteBrush}"
|
|
LetterSpacing="1.4" Margin="0,0,0,8" />
|
|
<ScrollViewer>
|
|
<ItemsControl ItemsSource="{Binding Queued}">
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate x:DataType="vm:QueuedTaskViewModel">
|
|
<Button Command="{Binding OpenInAppCommand}"
|
|
Padding="0" Margin="0,0,0,4"
|
|
Background="Transparent" BorderThickness="0"
|
|
HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
|
Cursor="Hand">
|
|
<Button.ContextMenu>
|
|
<ContextMenu>
|
|
<MenuItem Header="{loc:Tr missionControl.openSession}"
|
|
Command="{Binding OpenSessionCommand}"
|
|
IsEnabled="{Binding CanOpenSession}" />
|
|
</ContextMenu>
|
|
</Button.ContextMenu>
|
|
<Panel>
|
|
<Border Background="{DynamicResource SurfaceBrush}"
|
|
BorderBrush="{DynamicResource LineBrush}"
|
|
BorderThickness="1" CornerRadius="6" />
|
|
<!-- Single state tint; brush keys come from the VM (Tokens.axaml). -->
|
|
<Border Background="{Binding TintKey, Converter={x:Static conv:DotBrushConverter.Instance}}"
|
|
BorderBrush="{Binding TintBorderKey, Converter={x:Static conv:DotBrushConverter.Instance}}"
|
|
BorderThickness="1" CornerRadius="6"
|
|
IsVisible="{Binding TintKey, Converter={x:Static ObjectConverters.IsNotNull}}" />
|
|
<StackPanel Margin="8,6" Spacing="2">
|
|
<TextBlock Text="{Binding Title}"
|
|
TextTrimming="CharacterEllipsis"
|
|
ToolTip.Tip="{Binding Title}"
|
|
Foreground="{DynamicResource TextDimBrush}" />
|
|
<TextBlock Classes="meta"
|
|
Text="{Binding StatusLabel}"
|
|
IsVisible="{Binding StatusLabel, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
|
Foreground="{Binding StatusColorKey, Converter={x:Static conv:DotBrushConverter.Instance}}" />
|
|
</StackPanel>
|
|
</Panel>
|
|
</Button>
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
</ScrollViewer>
|
|
</DockPanel>
|
|
</Border>
|
|
</Grid>
|
|
|
|
</DockPanel>
|
|
</UserControl>
|