Two context-menu entries opened a Claude session for the same task via different mechanisms (embedded ConPTY vs. an external wt terminal). Drop the external-terminal path entirely, including its worker hub method, launcher plumbing, and localization keys, since the embedded ConPTY session already covers every case it did.
294 lines
15 KiB
XML
294 lines
15 KiB
XML
<UserControl xmlns="https://github.com/avaloniaui"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:vm="using:ClaudeDo.Ui.ViewModels.Islands"
|
|
xmlns:ctl="using:ClaudeDo.Ui.Views.Controls"
|
|
xmlns:loc="using:ClaudeDo.Ui.Localization"
|
|
x:Class="ClaudeDo.Ui.Views.Islands.TaskRowView"
|
|
x:DataType="vm:TaskRowViewModel">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="6"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- Above-row indicator: lives in the 6px gap between cards -->
|
|
<Border Grid.Row="0" Height="2" VerticalAlignment="Center" Margin="4,0"
|
|
Background="{DynamicResource MossBrush}" CornerRadius="1"
|
|
IsVisible="{Binding DropHintAbove}"/>
|
|
|
|
<!-- Indent wrapper: col 0 = 24px child indent track, col 1 = content -->
|
|
<Grid Grid.Row="1" ColumnDefinitions="Auto,*">
|
|
|
|
<!-- Indent track (only while the parent shares this view; orphaned children render flat) -->
|
|
<Border Grid.Column="0" Width="24" IsVisible="{Binding ShowAsChild}" VerticalAlignment="Stretch">
|
|
<Rectangle Width="1" Fill="{DynamicResource LineBrush}"
|
|
HorizontalAlignment="Right" Margin="0,4"/>
|
|
</Border>
|
|
|
|
<!-- Main task card -->
|
|
<Border Grid.Column="1" Classes="task-row"
|
|
Margin="0"
|
|
Classes.selected="{Binding IsSelected}"
|
|
Classes.dragging="{Binding IsDragging}"
|
|
Classes.done="{Binding Done}">
|
|
<Border.ContextMenu>
|
|
<ContextMenu>
|
|
<MenuItem Header="{loc:Tr tasks.ctxSendToQueue}"
|
|
IsVisible="{Binding CanSendToQueue}"
|
|
Click="OnSendToQueueClick"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxRemoveFromQueue}"
|
|
IsVisible="{Binding CanRemoveFromQueue}"
|
|
Click="OnRemoveFromQueueClick"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxCancelExecution}"
|
|
IsVisible="{Binding IsRunning}"
|
|
Click="OnCancelExecutionClick"/>
|
|
<Separator/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxMarkAs}">
|
|
<MenuItem Header="{loc:Tr tasks.ctxMarkDone}" Tag="Done" Click="OnSetStatusClick"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxMarkCancelled}" Tag="Cancelled" Click="OnSetStatusClick"/>
|
|
<Separator/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxMarkManual}"
|
|
IsVisible="{Binding !IsManual}"
|
|
Click="OnToggleManualClick"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxMarkClaudeTask}"
|
|
IsVisible="{Binding IsManual}"
|
|
Click="OnToggleManualClick"/>
|
|
</MenuItem>
|
|
<Separator/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxOpenConPtySession}"
|
|
Click="OnOpenConPtySessionClick"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxOpenPlanningSession}"
|
|
Click="OnOpenPlanningSessionClick"
|
|
IsVisible="{Binding CanOpenPlanningSession}"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxResumePlanningSession}"
|
|
Click="OnResumePlanningSessionClick"
|
|
IsVisible="{Binding CanResumeOrDiscardPlanning}"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxFinalizePlanningSession}"
|
|
Click="OnFinalizePlanningSessionClick"
|
|
IsVisible="{Binding CanFinalizePlanning}"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxDiscardPlanningSession}"
|
|
Click="OnDiscardPlanningSessionClick"
|
|
IsVisible="{Binding CanResumeOrDiscardPlanning}"/>
|
|
<Separator/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxScheduleFor}" Click="OnScheduleForClick"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxClearSchedule}"
|
|
IsVisible="{Binding HasSchedule}"
|
|
Click="OnClearScheduleClick"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxAddToMyDay}"
|
|
IsVisible="{Binding CanAddToMyDay}"
|
|
Click="OnAddToMyDayClick"/>
|
|
<MenuItem Header="{loc:Tr tasks.ctxRemoveFromMyDay}"
|
|
IsVisible="{Binding IsMyDay}"
|
|
Click="OnRemoveFromMyDayClick"/>
|
|
</ContextMenu>
|
|
</Border.ContextMenu>
|
|
<Grid ColumnDefinitions="0,18,32,*,Auto,Auto,32" Margin="6,8,10,8">
|
|
|
|
<!-- Chevron toggle (only for planning parent tasks) -->
|
|
<Button Grid.Column="1"
|
|
IsVisible="{Binding IsPlanningParent}"
|
|
Command="{Binding $parent[ItemsControl].((vm:TasksIslandViewModel)DataContext).ToggleExpandCommand}"
|
|
CommandParameter="{Binding}"
|
|
Classes="icon-btn"
|
|
Width="18" Height="18"
|
|
VerticalAlignment="Center"
|
|
ToolTip.Tip="{loc:Tr tasks.toggleSubtasksTip}">
|
|
<Panel>
|
|
<PathIcon Width="12" Height="12" Data="{StaticResource Icon.ChevronDown}"
|
|
Foreground="{DynamicResource TextDimBrush}" IsVisible="{Binding IsExpanded}"/>
|
|
<PathIcon Width="12" Height="12" Data="{StaticResource Icon.ChevronRight}"
|
|
Foreground="{DynamicResource TextDimBrush}" IsVisible="{Binding !IsExpanded}"/>
|
|
</Panel>
|
|
</Button>
|
|
|
|
<!-- Done toggle -->
|
|
<Button Grid.Column="2" Classes="flat" VerticalAlignment="Top"
|
|
Margin="0,2,0,0"
|
|
Command="{Binding $parent[ItemsControl].((vm:TasksIslandViewModel)DataContext).ToggleDoneCommand}"
|
|
CommandParameter="{Binding}">
|
|
<Ellipse Width="18" Height="18" Classes="task-check"
|
|
Classes.done="{Binding Done}"/>
|
|
</Button>
|
|
|
|
<!-- Title + chip row + live tail -->
|
|
<StackPanel Grid.Column="3" Spacing="6" VerticalAlignment="Center">
|
|
<Grid ColumnDefinitions="*,Auto" VerticalAlignment="Center">
|
|
<TextBlock Grid.Column="0"
|
|
Classes="task-title"
|
|
Text="{Binding Title}" FontSize="{StaticResource FontSizeTaskTitle}"
|
|
Foreground="{DynamicResource TextBrush}"
|
|
TextWrapping="Wrap"
|
|
FontStyle="{Binding IsDraft, Converter={StaticResource BoolToItalic}}"
|
|
Opacity="{Binding IsDraft, Converter={StaticResource BoolToDraftOpacity}}"
|
|
TextDecorations="{Binding Done, Converter={StaticResource StrikeIfTrue}}"/>
|
|
|
|
<!-- Badges: DRAFT and planning session -->
|
|
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="4"
|
|
VerticalAlignment="Center" Margin="4,0,0,0">
|
|
<Border Classes="badge draft" IsVisible="{Binding IsDraft}">
|
|
<TextBlock Text="{loc:Tr tasks.badgeDraft}"/>
|
|
</Border>
|
|
<Border Classes="badge planned" IsVisible="{Binding IsPlanned}">
|
|
<TextBlock Text="{loc:Tr tasks.badgePlanned}"/>
|
|
</Border>
|
|
<Border Classes="badge"
|
|
Classes.planning="{Binding IsPlanActive}"
|
|
Classes.planned="{Binding IsPlanFinalized}"
|
|
IsVisible="{Binding IsPlanningParent}">
|
|
<TextBlock Text="{Binding PlanningBadge}"/>
|
|
</Border>
|
|
<Border Classes="badge manual" IsVisible="{Binding IsManual}"
|
|
ToolTip.Tip="{loc:Tr tasks.manualTip}">
|
|
<TextBlock Text="{Binding ManualBadge}"/>
|
|
</Border>
|
|
</StackPanel>
|
|
</Grid>
|
|
|
|
<!-- Chip row -->
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
|
|
<!-- Roadblock badge -->
|
|
<PathIcon Width="13" Height="13" VerticalAlignment="Center"
|
|
Data="{StaticResource Icon.Warning}"
|
|
Foreground="#E0A800"
|
|
IsVisible="{Binding HasRoadblock}"
|
|
ToolTip.Tip="{Binding RoadblockTooltip}"/>
|
|
|
|
<!-- Agent-suggested badge -->
|
|
<PathIcon Width="10" Height="10" VerticalAlignment="Center"
|
|
Data="{StaticResource Icon.AgentSuggested}"
|
|
Foreground="#5C8FA8"
|
|
IsVisible="{Binding IsAgentSuggested}"
|
|
ToolTip.Tip="{loc:Tr tasks.agentSuggestedTip}"/>
|
|
|
|
<!-- Status chip. When a ConPTY session is open it reads "Interactive" and is tappable —
|
|
it jumps to that pane in Mission Control. -->
|
|
<Border Classes="chip"
|
|
IsVisible="{Binding ShowStatusChip}"
|
|
Tapped="OnStatusChipTapped"
|
|
ToolTip.Tip="{Binding InteractiveChipTooltip}"
|
|
Classes.interactive="{Binding HasInteractiveSession}"
|
|
Classes.parked="{Binding IsParked}"
|
|
Classes.running="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=Running}"
|
|
Classes.review="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=WaitingForReview}"
|
|
Classes.children="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=WaitingForChildren}"
|
|
Classes.done="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=Done}"
|
|
Classes.error="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=Failed}"
|
|
Classes.queued="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=Queued}">
|
|
<TextBlock Text="{Binding StatusLabel}"/>
|
|
</Border>
|
|
|
|
<!-- Dequeue button (visible when row is Queued, or planning parent has queued subtasks) -->
|
|
<Button Classes="icon-btn dequeue-btn"
|
|
IsVisible="{Binding CanRemoveFromQueue}"
|
|
ToolTip.Tip="{loc:Tr tasks.removeFromQueueTip}"
|
|
Command="{Binding $parent[ItemsControl].((vm:TasksIslandViewModel)DataContext).RemoveFromQueueCommand}"
|
|
CommandParameter="{Binding}">
|
|
<PathIcon Width="10" Height="10" Data="{StaticResource Icon.X}"/>
|
|
</Button>
|
|
|
|
<!-- List chip with dot -->
|
|
<Border Classes="chip chip-list" IsVisible="{Binding ShowListChip}">
|
|
<StackPanel Orientation="Horizontal" Spacing="5" VerticalAlignment="Center">
|
|
<Ellipse Width="6" Height="6"
|
|
Fill="{DynamicResource MossBrush}"
|
|
VerticalAlignment="Center"/>
|
|
<TextBlock Text="{Binding ListName}"/>
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- Branch chip -->
|
|
<Border Classes="chip chip-branch" IsVisible="{Binding HasBranch}">
|
|
<StackPanel Orientation="Horizontal" Spacing="4" VerticalAlignment="Center">
|
|
<PathIcon Width="10" Height="10"
|
|
Data="{StaticResource Icon.GitBranch}"
|
|
Foreground="{DynamicResource TextDimBrush}"/>
|
|
<TextBlock Text="{Binding Branch}"/>
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- Diff chip -->
|
|
<Border Classes="chip chip-diff" IsVisible="{Binding HasDiff}">
|
|
<StackPanel Orientation="Horizontal" Spacing="4" VerticalAlignment="Center">
|
|
<TextBlock Classes="diff-add" Text="{Binding DiffAdditionsText}"/>
|
|
<TextBlock Classes="diff-del" Text="{Binding DiffDeletionsText}"/>
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
</StackPanel>
|
|
</StackPanel>
|
|
|
|
<!-- Refine button, replaced by a spinner while the refine run is in flight -->
|
|
<Panel Grid.Column="5">
|
|
<Button Classes="icon-btn refine-btn"
|
|
IsVisible="{Binding CanRefine}"
|
|
VerticalAlignment="Top" Margin="0,2,0,0"
|
|
Command="{Binding $parent[ItemsControl].((vm:TasksIslandViewModel)DataContext).RefineTaskCommand}"
|
|
CommandParameter="{Binding}"
|
|
ToolTip.Tip="{loc:Tr tasks.refineTip}">
|
|
<Viewbox Width="16" Height="16">
|
|
<Path Classes="plan-icon" Data="{StaticResource Icon.Refine}"/>
|
|
</Viewbox>
|
|
</Button>
|
|
<Ellipse Classes="spinner"
|
|
IsVisible="{Binding IsRefining}"
|
|
VerticalAlignment="Top" Margin="0,4,2,0"
|
|
ToolTip.Tip="{loc:Tr tasks.refiningTip}"/>
|
|
</Panel>
|
|
|
|
<!-- Star toggle -->
|
|
<Button Grid.Column="6" Classes="icon-btn star-btn"
|
|
Classes.on="{Binding IsStarred}"
|
|
VerticalAlignment="Top" Margin="0,2,0,0"
|
|
Command="{Binding $parent[ItemsControl].((vm:TasksIslandViewModel)DataContext).ToggleStarCommand}"
|
|
CommandParameter="{Binding}"
|
|
ToolTip.Tip="{loc:Tr details.starTip}">
|
|
<PathIcon Width="14" Height="14" Data="{StaticResource Icon.Star}"/>
|
|
</Button>
|
|
</Grid>
|
|
</Border>
|
|
|
|
</Grid>
|
|
|
|
<!-- Below-row indicator: only expands when visible (used for the last row of a section) -->
|
|
<Grid Grid.Row="2" Height="6" IsVisible="{Binding DropHintBelow}">
|
|
<Border Height="2" VerticalAlignment="Center" Margin="4,0"
|
|
Background="{DynamicResource MossBrush}" CornerRadius="1"/>
|
|
</Grid>
|
|
|
|
<!-- Hidden schedule anchor (its Flyout is shown from the context menu) -->
|
|
<Button Grid.Row="1" x:Name="ScheduleAnchor"
|
|
Width="1" Height="1" Opacity="0"
|
|
HorizontalAlignment="Left" VerticalAlignment="Top"
|
|
IsHitTestVisible="False" Focusable="False">
|
|
<Button.Flyout>
|
|
<Flyout Placement="Bottom" ShowMode="Standard">
|
|
<Border Background="{DynamicResource Surface2Brush}"
|
|
BorderBrush="{DynamicResource LineBrush}"
|
|
BorderThickness="1" CornerRadius="10"
|
|
Padding="16" Width="300">
|
|
<StackPanel Spacing="12">
|
|
<TextBlock Classes="title" Text="{loc:Tr tasks.scheduleTitle}"/>
|
|
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Classes="eyebrow" Text="{loc:Tr tasks.scheduleWhen}"
|
|
Foreground="{DynamicResource TextDimBrush}" Opacity="0.6"/>
|
|
<ctl:ThemedDatePicker x:Name="ScheduleDate" ShowTime="True"
|
|
HorizontalAlignment="Stretch"/>
|
|
</StackPanel>
|
|
|
|
<StackPanel Orientation="Horizontal" Spacing="8"
|
|
HorizontalAlignment="Right" Margin="0,4,0,0">
|
|
<Button Classes="btn" Content="{loc:Tr tasks.cancel}" Click="OnScheduleCancelClick" MinWidth="76"/>
|
|
<Button Content="{loc:Tr tasks.scheduleConfirm}" Classes="accent" Click="OnScheduleSetClick" MinWidth="76"/>
|
|
</StackPanel>
|
|
</StackPanel>
|
|
</Border>
|
|
</Flyout>
|
|
</Button.Flyout>
|
|
</Button>
|
|
|
|
</Grid>
|
|
</UserControl>
|