feat(ui): host review actions in the details panel; show review state and diff meter
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -110,12 +110,13 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
[NotifyCanExecuteChangedFor(nameof(ContinueCommand))]
|
||||
private string _agentState = "idle";
|
||||
public string AgentStatusLabel => Loc.T($"vm.agentStatus.{AgentState}");
|
||||
public bool IsIdle => AgentState == "idle";
|
||||
public bool IsQueued => AgentState == "queued";
|
||||
public bool IsRunning => AgentState == "running";
|
||||
public bool IsDone => AgentState == "done";
|
||||
public bool IsFailed => AgentState == "failed";
|
||||
public bool IsCancelled => AgentState == "cancelled";
|
||||
public bool IsIdle => AgentState == "idle";
|
||||
public bool IsQueued => AgentState == "queued";
|
||||
public bool IsRunning => AgentState == "running";
|
||||
public bool IsWaitingForReview => AgentState == "review";
|
||||
public bool IsDone => AgentState == "done";
|
||||
public bool IsFailed => AgentState == "failed";
|
||||
public bool IsCancelled => AgentState == "cancelled";
|
||||
|
||||
// Recovery actions: Continue (resume session) for Failed/Cancelled.
|
||||
public bool ShowContinue => IsFailed || IsCancelled;
|
||||
@@ -132,6 +133,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
OnPropertyChanged(nameof(IsIdle));
|
||||
OnPropertyChanged(nameof(IsQueued));
|
||||
OnPropertyChanged(nameof(IsRunning));
|
||||
OnPropertyChanged(nameof(IsWaitingForReview));
|
||||
OnPropertyChanged(nameof(IsDone));
|
||||
OnPropertyChanged(nameof(IsFailed));
|
||||
OnPropertyChanged(nameof(IsCancelled));
|
||||
@@ -279,7 +281,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
{
|
||||
ClaudeDo.Data.Models.TaskStatus.Queued => "queued",
|
||||
ClaudeDo.Data.Models.TaskStatus.Running => "running",
|
||||
ClaudeDo.Data.Models.TaskStatus.WaitingForReview => "running",
|
||||
ClaudeDo.Data.Models.TaskStatus.WaitingForReview => "review",
|
||||
ClaudeDo.Data.Models.TaskStatus.Done => "done",
|
||||
ClaudeDo.Data.Models.TaskStatus.Failed => "failed",
|
||||
ClaudeDo.Data.Models.TaskStatus.Cancelled => "cancelled",
|
||||
@@ -291,7 +293,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
"done" => "done",
|
||||
"failed" => "failed",
|
||||
"cancelled" => "cancelled",
|
||||
"waiting_for_review" => "running",
|
||||
"waiting_for_review" => "review",
|
||||
_ => status.ToLowerInvariant(),
|
||||
};
|
||||
|
||||
@@ -880,6 +882,9 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
AgentState = StatusToStateKey(entity.Status);
|
||||
if (Task is { } row && entity.Worktree?.DiffStat is { } stat)
|
||||
row.DiffStat = stat;
|
||||
var (add, del) = ParseDiffStat(entity.Worktree?.DiffStat);
|
||||
DiffAdditions = add;
|
||||
DiffDeletions = del;
|
||||
}
|
||||
catch { /* best-effort refresh */ }
|
||||
}
|
||||
@@ -1131,6 +1136,52 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
[RelayCommand] private void ResetTaskModel() => TaskModelSelection = null;
|
||||
[RelayCommand] private void ResetTaskTurns() => TaskMaxTurns = null;
|
||||
[RelayCommand] private void ResetTaskAgent() => TaskSelectedAgent = TaskAgentOptions.Count > 0 ? TaskAgentOptions[0] : null;
|
||||
|
||||
// ── Review actions ──────────────────────────────────────────────────────────
|
||||
[ObservableProperty] private string _reviewFeedback = "";
|
||||
|
||||
[RelayCommand]
|
||||
private async System.Threading.Tasks.Task ApproveReviewAsync()
|
||||
{
|
||||
if (Task is null || !_worker.IsConnected) return;
|
||||
await _worker.ApproveReviewAsync(Task.Id);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async System.Threading.Tasks.Task RejectReviewAsync()
|
||||
{
|
||||
if (Task is null || !_worker.IsConnected) return;
|
||||
var feedback = ReviewFeedback;
|
||||
if (string.IsNullOrWhiteSpace(feedback)) return;
|
||||
await _worker.RejectReviewToQueueAsync(Task.Id, feedback);
|
||||
ReviewFeedback = "";
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async System.Threading.Tasks.Task ParkReviewAsync()
|
||||
{
|
||||
if (Task is null || !_worker.IsConnected) return;
|
||||
await _worker.RejectReviewToIdleAsync(Task.Id);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async System.Threading.Tasks.Task CancelReviewAsync()
|
||||
{
|
||||
if (Task is null || !_worker.IsConnected) return;
|
||||
await _worker.CancelReviewAsync(Task.Id);
|
||||
}
|
||||
|
||||
// ── Diff meter parser ───────────────────────────────────────────────────────
|
||||
internal static (int Additions, int Deletions) ParseDiffStat(string? stat)
|
||||
{
|
||||
if (string.IsNullOrEmpty(stat)) return (0, 0);
|
||||
int add = 0, del = 0;
|
||||
var m1 = System.Text.RegularExpressions.Regex.Match(stat, @"(\d+)\s+insertion");
|
||||
var m2 = System.Text.RegularExpressions.Regex.Match(stat, @"(\d+)\s+deletion");
|
||||
if (m1.Success) int.TryParse(m1.Groups[1].Value, out add);
|
||||
if (m2.Success) int.TryParse(m2.Groups[1].Value, out del);
|
||||
return (add, del);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class SubtaskRowViewModel : ViewModelBase
|
||||
|
||||
Reference in New Issue
Block a user