feat(ui): move review feedback to the Output tab + review/worktree polish
- Feedback box + a new "Resume session" button move from the Git tab to the Output tab; the Git review block keeps Approve & Merge / Park / Cancel / Reset. - Add a "Parked" chip for Idle tasks that still hold an Active worktree. - Stop showing the "Session was Cancelled" band on cancel (failed-only now). - Fix the Worktrees-overview state-chip contrast (dark text on the colour).
This commit is contained in:
@@ -442,7 +442,7 @@
|
|||||||
"connection": { "online": "Online", "connecting": "Verbinden…", "offline": "Offline" },
|
"connection": { "online": "Online", "connecting": "Verbinden…", "offline": "Offline" },
|
||||||
"shell": { "restartingWorker": "Worker wird neu gestartet…" },
|
"shell": { "restartingWorker": "Worker wird neu gestartet…" },
|
||||||
"agentStatus": { "idle": "Leerlauf", "queued": "In Warteschlange", "running": "Läuft", "review": "Prüfung", "children": "Wartet auf Verbesserungen", "done": "Fertig", "failed": "Fehlgeschlagen", "cancelled": "Abgebrochen" },
|
"agentStatus": { "idle": "Leerlauf", "queued": "In Warteschlange", "running": "Läuft", "review": "Prüfung", "children": "Wartet auf Verbesserungen", "done": "Fertig", "failed": "Fehlgeschlagen", "cancelled": "Abgebrochen" },
|
||||||
"taskStatus": { "idle": "Leerlauf", "queued": "In Warteschlange", "running": "Läuft", "waitingForReview": "Wartet auf Prüfung", "waitingForChildren": "Wartet auf Verbesserungen", "done": "Fertig", "failed": "Fehlgeschlagen", "cancelled": "Abgebrochen" },
|
"taskStatus": { "idle": "Leerlauf", "queued": "In Warteschlange", "running": "Läuft", "waitingForReview": "Wartet auf Prüfung", "waitingForChildren": "Wartet auf Verbesserungen", "done": "Fertig", "failed": "Fehlgeschlagen", "cancelled": "Abgebrochen", "parked": "Geparkt" },
|
||||||
"planningBadge": { "active": "PLANUNG", "finalized": "GEPLANT" },
|
"planningBadge": { "active": "PLANUNG", "finalized": "GEPLANT" },
|
||||||
"taskRow": { "createdPrefix": "Erstellt {0}", "stepsText": "{0}/{1} Schritte" },
|
"taskRow": { "createdPrefix": "Erstellt {0}", "stepsText": "{0}/{1} Schritte" },
|
||||||
"tasksIsland": { "completedHeader": "ABGESCHLOSSEN", "completedHeaderCount": "ABGESCHLOSSEN · {0}" },
|
"tasksIsland": { "completedHeader": "ABGESCHLOSSEN", "completedHeaderCount": "ABGESCHLOSSEN · {0}" },
|
||||||
|
|||||||
@@ -442,7 +442,7 @@
|
|||||||
"connection": { "online": "Online", "connecting": "Connecting…", "offline": "Offline" },
|
"connection": { "online": "Online", "connecting": "Connecting…", "offline": "Offline" },
|
||||||
"shell": { "restartingWorker": "Restarting worker…" },
|
"shell": { "restartingWorker": "Restarting worker…" },
|
||||||
"agentStatus": { "idle": "Idle", "queued": "Queued", "running": "Running", "review": "Review", "children": "Waiting for Improvements", "done": "Done", "failed": "Failed", "cancelled": "Cancelled" },
|
"agentStatus": { "idle": "Idle", "queued": "Queued", "running": "Running", "review": "Review", "children": "Waiting for Improvements", "done": "Done", "failed": "Failed", "cancelled": "Cancelled" },
|
||||||
"taskStatus": { "idle": "Idle", "queued": "Queued", "running": "Running", "waitingForReview": "Waiting for Review", "waitingForChildren": "Waiting for Improvements", "done": "Done", "failed": "Failed", "cancelled": "Cancelled" },
|
"taskStatus": { "idle": "Idle", "queued": "Queued", "running": "Running", "waitingForReview": "Waiting for Review", "waitingForChildren": "Waiting for Improvements", "done": "Done", "failed": "Failed", "cancelled": "Cancelled", "parked": "Parked" },
|
||||||
"planningBadge": { "active": "PLANNING", "finalized": "PLANNED" },
|
"planningBadge": { "active": "PLANNING", "finalized": "PLANNED" },
|
||||||
"taskRow": { "createdPrefix": "Created {0}", "stepsText": "{0}/{1} steps" },
|
"taskRow": { "createdPrefix": "Created {0}", "stepsText": "{0}/{1} steps" },
|
||||||
"tasksIsland": { "completedHeader": "COMPLETED", "completedHeaderCount": "COMPLETED · {0}" },
|
"tasksIsland": { "completedHeader": "COMPLETED", "completedHeaderCount": "COMPLETED · {0}" },
|
||||||
|
|||||||
@@ -229,6 +229,15 @@
|
|||||||
<Setter Property="Foreground" Value="{StaticResource TextMuteBrush}" />
|
<Setter Property="Foreground" Value="{StaticResource TextMuteBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<!-- parked → slate-blue: an Idle task still holding its Active worktree -->
|
||||||
|
<Style Selector="Border.chip.parked">
|
||||||
|
<Setter Property="Background" Value="#22303A" />
|
||||||
|
<Setter Property="BorderBrush" Value="#3A5060" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Border.chip.parked > TextBlock">
|
||||||
|
<Setter Property="Foreground" Value="#8FB9D6" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
<!-- BUTTONS -->
|
<!-- BUTTONS -->
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
|
|||||||
@@ -166,10 +166,9 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
public string DiffAddText => $"+{DiffAdditions}";
|
public string DiffAddText => $"+{DiffAdditions}";
|
||||||
public string DiffDelText => $"-{DiffDeletions}";
|
public string DiffDelText => $"-{DiffDeletions}";
|
||||||
|
|
||||||
public bool ShowRoadblock => IsFailed || IsCancelled;
|
public bool ShowRoadblock => IsFailed;
|
||||||
public string RoadblockMessage =>
|
public string RoadblockMessage =>
|
||||||
IsFailed ? "The session ended with an error." :
|
IsFailed ? "The session ended with an error." : "";
|
||||||
IsCancelled ? "The session was cancelled." : "";
|
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyPropertyChangedFor(nameof(ShowSessionOutcome))]
|
[NotifyPropertyChangedFor(nameof(ShowSessionOutcome))]
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public sealed partial class TaskRowViewModel : ViewModelBase
|
|||||||
[ObservableProperty] private PlanningPhase _planningPhase;
|
[ObservableProperty] private PlanningPhase _planningPhase;
|
||||||
[ObservableProperty] private string? _branch;
|
[ObservableProperty] private string? _branch;
|
||||||
[ObservableProperty] private string? _diffStat;
|
[ObservableProperty] private string? _diffStat;
|
||||||
|
[ObservableProperty] private ClaudeDo.Data.Models.WorktreeState? _worktreeState;
|
||||||
[ObservableProperty] private DateTime? _scheduledFor;
|
[ObservableProperty] private DateTime? _scheduledFor;
|
||||||
[ObservableProperty] private int _diffAdditions;
|
[ObservableProperty] private int _diffAdditions;
|
||||||
[ObservableProperty] private int _diffDeletions;
|
[ObservableProperty] private int _diffDeletions;
|
||||||
@@ -76,6 +77,8 @@ public sealed partial class TaskRowViewModel : ViewModelBase
|
|||||||
public bool IsOverdue => ScheduledFor is { } d && d.Date < DateTime.Today && !Done;
|
public bool IsOverdue => ScheduledFor is { } d && d.Date < DateTime.Today && !Done;
|
||||||
public bool IsRunning => Status == TaskStatus.Running;
|
public bool IsRunning => Status == TaskStatus.Running;
|
||||||
public bool IsWaitingForReview => Status == TaskStatus.WaitingForReview;
|
public bool IsWaitingForReview => Status == TaskStatus.WaitingForReview;
|
||||||
|
// Parked = set aside from review: Idle but still holding its Active worktree (vs a plain Idle task).
|
||||||
|
public bool IsParked => Status == TaskStatus.Idle && WorktreeState == ClaudeDo.Data.Models.WorktreeState.Active;
|
||||||
public bool IsQueued => Status == TaskStatus.Queued && string.IsNullOrEmpty(BlockedByTaskId);
|
public bool IsQueued => Status == TaskStatus.Queued && string.IsNullOrEmpty(BlockedByTaskId);
|
||||||
public bool IsWaiting => Status == TaskStatus.Queued && !string.IsNullOrEmpty(BlockedByTaskId);
|
public bool IsWaiting => Status == TaskStatus.Queued && !string.IsNullOrEmpty(BlockedByTaskId);
|
||||||
public bool CanRemoveFromQueue => IsQueued || HasQueuedSubtasks;
|
public bool CanRemoveFromQueue => IsQueued || HasQueuedSubtasks;
|
||||||
@@ -105,7 +108,7 @@ public sealed partial class TaskRowViewModel : ViewModelBase
|
|||||||
public string DiffDeletionsText => $"−{DiffDeletions}";
|
public string DiffDeletionsText => $"−{DiffDeletions}";
|
||||||
public string StepsText => Loc.T("vm.taskRow.stepsText", StepsCompleted, StepsCount);
|
public string StepsText => Loc.T("vm.taskRow.stepsText", StepsCompleted, StepsCount);
|
||||||
|
|
||||||
public string StatusLabel => Status switch
|
public string StatusLabel => IsParked ? Loc.T("vm.taskStatus.parked") : Status switch
|
||||||
{
|
{
|
||||||
TaskStatus.Idle => Loc.T("vm.taskStatus.idle"),
|
TaskStatus.Idle => Loc.T("vm.taskStatus.idle"),
|
||||||
TaskStatus.Queued => Loc.T("vm.taskStatus.queued"),
|
TaskStatus.Queued => Loc.T("vm.taskStatus.queued"),
|
||||||
@@ -136,6 +139,7 @@ public sealed partial class TaskRowViewModel : ViewModelBase
|
|||||||
OnPropertyChanged(nameof(StatusLabel));
|
OnPropertyChanged(nameof(StatusLabel));
|
||||||
OnPropertyChanged(nameof(IsRunning));
|
OnPropertyChanged(nameof(IsRunning));
|
||||||
OnPropertyChanged(nameof(IsWaitingForReview));
|
OnPropertyChanged(nameof(IsWaitingForReview));
|
||||||
|
OnPropertyChanged(nameof(IsParked));
|
||||||
OnPropertyChanged(nameof(IsQueued));
|
OnPropertyChanged(nameof(IsQueued));
|
||||||
OnPropertyChanged(nameof(IsWaiting));
|
OnPropertyChanged(nameof(IsWaiting));
|
||||||
OnPropertyChanged(nameof(IsDraft));
|
OnPropertyChanged(nameof(IsDraft));
|
||||||
@@ -210,6 +214,11 @@ public sealed partial class TaskRowViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
partial void OnBranchChanged(string? value) => OnPropertyChanged(nameof(HasBranch));
|
partial void OnBranchChanged(string? value) => OnPropertyChanged(nameof(HasBranch));
|
||||||
|
partial void OnWorktreeStateChanged(ClaudeDo.Data.Models.WorktreeState? value)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(IsParked));
|
||||||
|
OnPropertyChanged(nameof(StatusLabel));
|
||||||
|
}
|
||||||
partial void OnDoneChanged(bool value)
|
partial void OnDoneChanged(bool value)
|
||||||
{
|
{
|
||||||
OnPropertyChanged(nameof(IsOverdue));
|
OnPropertyChanged(nameof(IsOverdue));
|
||||||
@@ -252,6 +261,7 @@ public sealed partial class TaskRowViewModel : ViewModelBase
|
|||||||
PlanningPhase = t.PlanningPhase;
|
PlanningPhase = t.PlanningPhase;
|
||||||
Branch = t.Worktree?.BranchName;
|
Branch = t.Worktree?.BranchName;
|
||||||
DiffStat = t.Worktree?.DiffStat;
|
DiffStat = t.Worktree?.DiffStat;
|
||||||
|
WorktreeState = t.Worktree?.State;
|
||||||
ScheduledFor = t.ScheduledFor;
|
ScheduledFor = t.ScheduledFor;
|
||||||
DiffAdditions = add;
|
DiffAdditions = add;
|
||||||
DiffDeletions = del;
|
DiffDeletions = del;
|
||||||
|
|||||||
@@ -212,6 +212,28 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<!-- Review footer: feedback + Resume session, shown while awaiting review.
|
||||||
|
Lives here (with the live log) rather than the Git tab. -->
|
||||||
|
<Border DockPanel.Dock="Bottom"
|
||||||
|
IsVisible="{Binding IsWaitingForReview}"
|
||||||
|
Margin="12,6,12,2">
|
||||||
|
<StackPanel Spacing="8">
|
||||||
|
<TextBox Name="ReviewInput"
|
||||||
|
KeyDown="OnReviewInputKeyDown"
|
||||||
|
Text="{Binding ReviewFeedback, Mode=TwoWay}"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
MaxHeight="120"
|
||||||
|
PlaceholderText="Feedback for a re-run…"
|
||||||
|
FontFamily="{StaticResource MonoFont}"
|
||||||
|
FontSize="{StaticResource FontSizeMono}" />
|
||||||
|
<Button Classes="btn" Content="Resume session"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
ToolTip.Tip="{loc:Tr session.reviewContinueTip}"
|
||||||
|
Command="{Binding RejectReviewCommand}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<ScrollViewer Name="LogScroll"
|
<ScrollViewer Name="LogScroll"
|
||||||
VerticalScrollBarVisibility="Visible"
|
VerticalScrollBarVisibility="Visible"
|
||||||
AllowAutoHide="False"
|
AllowAutoHide="False"
|
||||||
@@ -291,28 +313,15 @@
|
|||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Review decision — feedback + the four review verbs. Always present while
|
<!-- Review decision — the merge verbs. Feedback + Resume session moved to the
|
||||||
awaiting review, even for sandbox runs with no worktree to merge. -->
|
Output tab. Present while awaiting review, even for sandbox runs. -->
|
||||||
<StackPanel Spacing="10" IsVisible="{Binding IsWaitingForReview}">
|
<StackPanel Spacing="10" IsVisible="{Binding IsWaitingForReview}">
|
||||||
<Border Height="1" Background="{DynamicResource LineBrush}"
|
<Border Height="1" Background="{DynamicResource LineBrush}"
|
||||||
IsVisible="{Binding Merge.ShowMergeSection}" />
|
IsVisible="{Binding Merge.ShowMergeSection}" />
|
||||||
|
|
||||||
<TextBox Name="ReviewInput"
|
|
||||||
KeyDown="OnReviewInputKeyDown"
|
|
||||||
Text="{Binding ReviewFeedback, Mode=TwoWay}"
|
|
||||||
AcceptsReturn="True"
|
|
||||||
TextWrapping="Wrap"
|
|
||||||
MaxHeight="120"
|
|
||||||
PlaceholderText="Feedback for a re-run…"
|
|
||||||
FontFamily="{StaticResource MonoFont}"
|
|
||||||
FontSize="{StaticResource FontSizeMono}" />
|
|
||||||
|
|
||||||
<WrapPanel Orientation="Horizontal">
|
<WrapPanel Orientation="Horizontal">
|
||||||
<Button Classes="btn accent" Content="Approve & Merge" Margin="0,0,8,8"
|
<Button Classes="btn accent" Content="Approve & Merge" Margin="0,0,8,8"
|
||||||
Command="{Binding ApproveReviewCommand}" />
|
Command="{Binding ApproveReviewCommand}" />
|
||||||
<Button Classes="btn" Content="Send back" Margin="0,0,8,8"
|
|
||||||
ToolTip.Tip="{loc:Tr session.reviewContinueTip}"
|
|
||||||
Command="{Binding RejectReviewCommand}" />
|
|
||||||
<Button Classes="btn" Content="Park" Margin="0,0,8,8"
|
<Button Classes="btn" Content="Park" Margin="0,0,8,8"
|
||||||
ToolTip.Tip="Set aside — back to Idle, keeps the worktree"
|
ToolTip.Tip="Set aside — back to Idle, keeps the worktree"
|
||||||
Command="{Binding ParkReviewCommand}" />
|
Command="{Binding ParkReviewCommand}" />
|
||||||
|
|||||||
@@ -152,6 +152,7 @@
|
|||||||
|
|
||||||
<!-- Status chip -->
|
<!-- Status chip -->
|
||||||
<Border Classes="chip"
|
<Border Classes="chip"
|
||||||
|
Classes.parked="{Binding IsParked}"
|
||||||
Classes.running="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=Running}"
|
Classes.running="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=Running}"
|
||||||
Classes.review="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=WaitingForReview}"
|
Classes.review="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=WaitingForReview}"
|
||||||
Classes.children="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=WaitingForChildren}"
|
Classes.children="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=WaitingForChildren}"
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
IsVisible="{Binding HasOutcome}"/>
|
IsVisible="{Binding HasOutcome}"/>
|
||||||
<Border Grid.Column="3" CornerRadius="3" Padding="6,2" VerticalAlignment="Center"
|
<Border Grid.Column="3" CornerRadius="3" Padding="6,2" VerticalAlignment="Center"
|
||||||
Background="{Binding State, Converter={StaticResource WorktreeStateColor}}">
|
Background="{Binding State, Converter={StaticResource WorktreeStateColor}}">
|
||||||
<TextBlock Classes="meta" Text="{Binding State}" Foreground="{DynamicResource TextBrush}"
|
<TextBlock Classes="meta" Text="{Binding State}" Foreground="{DynamicResource DeepBrush}"
|
||||||
HorizontalAlignment="Center"/>
|
HorizontalAlignment="Center"/>
|
||||||
</Border>
|
</Border>
|
||||||
<TextBlock Grid.Column="4" Classes="meta" Text="{Binding DiffStat}" VerticalAlignment="Center"/>
|
<TextBlock Grid.Column="4" Classes="meta" Text="{Binding DiffStat}" VerticalAlignment="Center"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user