feat(ui): roadblock badge on the task card; relocate review actions off the row

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-06-04 15:06:53 +02:00
parent d8b86e33a3
commit 2455eacb1f
4 changed files with 17 additions and 84 deletions

View File

@@ -129,6 +129,13 @@
<!-- 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}"/>
<!-- Status chip -->
<Border Classes="chip"
Classes.running="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=Running}"
@@ -139,23 +146,6 @@
<TextBlock Text="{Binding StatusLabel}"/>
</Border>
<!-- Review actions (visible when WaitingForReview) -->
<StackPanel Orientation="Horizontal" Spacing="4"
IsVisible="{Binding IsWaitingForReview}">
<Button Classes="btn" Content="{loc:Tr tasks.approve}" MinWidth="0" Padding="8,2"
ToolTip.Tip="{loc:Tr tasks.approveTip}"
Click="OnApproveReviewClick"/>
<Button Classes="btn" Content="{loc:Tr tasks.reject}" MinWidth="0" Padding="8,2"
ToolTip.Tip="{loc:Tr tasks.rejectTip}"
Click="OnRejectReviewClick"/>
<Button Classes="btn" Content="{loc:Tr tasks.park}" MinWidth="0" Padding="8,2"
ToolTip.Tip="{loc:Tr tasks.parkTip}"
Click="OnParkReviewClick"/>
<Button Classes="btn" Content="{loc:Tr tasks.cancel}" MinWidth="0" Padding="8,2"
ToolTip.Tip="{loc:Tr tasks.cancelTip}"
Click="OnCancelReviewClick"/>
</StackPanel>
<!-- Dequeue button (visible when row is Queued, or planning parent has queued subtasks) -->
<Button Classes="icon-btn dequeue-btn"
IsVisible="{Binding CanRemoveFromQueue}"
@@ -247,35 +237,5 @@
</Button.Flyout>
</Button>
<!-- Hidden reject-feedback anchor (its Flyout is shown from the Reject button) -->
<Button Grid.Row="1" x:Name="RejectAnchor"
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="320">
<StackPanel Spacing="12">
<TextBlock Classes="title" Text="{loc:Tr tasks.rejectRerunTitle}"/>
<StackPanel Spacing="6">
<TextBlock Classes="eyebrow" Text="{loc:Tr tasks.feedbackLabel}"
Foreground="{DynamicResource TextDimBrush}" Opacity="0.6"/>
<TextBox x:Name="RejectFeedback"
AcceptsReturn="True" TextWrapping="Wrap"
MinHeight="80" PlaceholderText="{loc:Tr tasks.feedbackPlaceholder}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="8"
HorizontalAlignment="Right" Margin="0,4,0,0">
<Button Classes="btn" Content="{loc:Tr tasks.cancel}" Click="OnRejectCancelClick" MinWidth="76"/>
<Button Content="{loc:Tr tasks.rerun}" Classes="accent" Click="OnRejectConfirmClick" MinWidth="76"/>
</StackPanel>
</StackPanel>
</Border>
</Flyout>
</Button.Flyout>
</Button>
</Grid>
</UserControl>

View File

@@ -88,43 +88,6 @@ public partial class TaskRowView : UserControl
await vm.SetStatusOnRowAsync(row, status);
}
private async void OnApproveReviewClick(object? sender, RoutedEventArgs e)
{
if (DataContext is TaskRowViewModel row && FindTasksVm() is { } vm)
await vm.ApproveReviewCommand.ExecuteAsync(row);
}
private async void OnParkReviewClick(object? sender, RoutedEventArgs e)
{
if (DataContext is TaskRowViewModel row && FindTasksVm() is { } vm)
await vm.RejectReviewToIdleCommand.ExecuteAsync(row);
}
private async void OnCancelReviewClick(object? sender, RoutedEventArgs e)
{
if (DataContext is TaskRowViewModel row && FindTasksVm() is { } vm)
await vm.CancelReviewCommand.ExecuteAsync(row);
}
private void OnRejectReviewClick(object? sender, RoutedEventArgs e)
{
if (DataContext is not TaskRowViewModel) return;
RejectFeedback.Text = "";
RejectAnchor.Flyout?.ShowAt(RejectAnchor);
}
private async void OnRejectConfirmClick(object? sender, RoutedEventArgs e)
{
RejectAnchor.Flyout?.Hide();
if (DataContext is not TaskRowViewModel row || FindTasksVm() is not { } vm) return;
var feedback = RejectFeedback.Text ?? "";
if (string.IsNullOrWhiteSpace(feedback)) return;
await vm.RejectReviewToQueueAsync(row, feedback);
}
private void OnRejectCancelClick(object? sender, RoutedEventArgs e)
=> RejectAnchor.Flyout?.Hide();
private void OnScheduleForClick(object? sender, RoutedEventArgs e)
{
if (DataContext is not TaskRowViewModel row) return;