Files
ClaudeDo/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml
T
mika kuns 22e70ffcb4 feat(ui): Mission Control als Session-Hub
- "+" ö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)
2026-08-28 14:17:38 +02:00

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>