feat(ui): add Continue and Reset commands to DetailsIslandViewModel

This commit is contained in:
Mika Kuns
2026-04-21 17:40:32 +02:00
parent 2278b516ea
commit b03e858a8f

View File

@@ -39,11 +39,21 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
public bool IsDone => AgentStatusLabel == "Done"; public bool IsDone => AgentStatusLabel == "Done";
public bool IsFailed => AgentStatusLabel == "Failed"; public bool IsFailed => AgentStatusLabel == "Failed";
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ContinueCommand))]
[NotifyCanExecuteChangedFor(nameof(ResetCommand))]
private bool _showFailedActions;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ContinueCommand))]
private string? _latestRunSessionId;
partial void OnAgentStatusLabelChanged(string value) partial void OnAgentStatusLabelChanged(string value)
{ {
OnPropertyChanged(nameof(IsRunning)); OnPropertyChanged(nameof(IsRunning));
OnPropertyChanged(nameof(IsDone)); OnPropertyChanged(nameof(IsDone));
OnPropertyChanged(nameof(IsFailed)); OnPropertyChanged(nameof(IsFailed));
ShowFailedActions = value == "Failed";
} }
[ObservableProperty] private string? _model; [ObservableProperty] private string? _model;
[ObservableProperty] private string? _worktreePath; [ObservableProperty] private string? _worktreePath;
@@ -108,11 +118,15 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
// Subscribe once; filter by current task id inside the handler // Subscribe once; filter by current task id inside the handler
_worker.TaskMessageEvent += OnTaskMessage; _worker.TaskMessageEvent += OnTaskMessage;
// Re-evaluate RunNow CanExecute when worker connection flips. // Re-evaluate CanExecute when worker connection flips.
_worker.PropertyChanged += (_, e) => _worker.PropertyChanged += (_, e) =>
{ {
if (e.PropertyName == nameof(WorkerClient.IsConnected)) if (e.PropertyName == nameof(WorkerClient.IsConnected))
{
RunNowCommand.NotifyCanExecuteChanged(); RunNowCommand.NotifyCanExecuteChanged();
ContinueCommand.NotifyCanExecuteChanged();
ResetCommand.NotifyCanExecuteChanged();
}
}; };
// If the task row's live status changes (e.g. TaskStarted/Finished), mirror it. // If the task row's live status changes (e.g. TaskStarted/Finished), mirror it.
@@ -215,6 +229,8 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
WorktreePath = null; WorktreePath = null;
BranchLine = null; BranchLine = null;
AgentStatusLabel = "Idle"; AgentStatusLabel = "Idle";
LatestRunSessionId = null;
ShowFailedActions = false;
return; return;
} }
@@ -243,6 +259,11 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
BranchLine = entity.Worktree is { } w ? $"{w.BranchName} \u2190 main" : null; BranchLine = entity.Worktree is { } w ? $"{w.BranchName} \u2190 main" : null;
AgentStatusLabel = entity.Status.ToString(); AgentStatusLabel = entity.Status.ToString();
var runRepo = new TaskRunRepository(ctx);
var latestRun = await runRepo.GetLatestByTaskIdAsync(row.Id, ct);
ct.ThrowIfCancellationRequested();
LatestRunSessionId = latestRun?.SessionId;
// Subscribe only after DB load confirms the task exists // Subscribe only after DB load confirms the task exists
_subscribedTaskId = row.Id; _subscribedTaskId = row.Id;
@@ -391,6 +412,32 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
private bool CanRunNow() => private bool CanRunNow() =>
Task != null && _worker.IsConnected && !IsRunning; Task != null && _worker.IsConnected && !IsRunning;
[RelayCommand(CanExecute = nameof(CanContinue))]
private async System.Threading.Tasks.Task ContinueAsync()
{
if (Task == null) return;
await _worker.ContinueTaskAsync(Task.Id, "Continue working on this task.");
}
private bool CanContinue() =>
Task != null && _worker.IsConnected && ShowFailedActions && !string.IsNullOrEmpty(LatestRunSessionId);
[RelayCommand(CanExecute = nameof(CanReset))]
private async System.Threading.Tasks.Task ResetAsync()
{
if (Task == null) return;
if (ConfirmAsync != null)
{
var branchName = $"claudedo/{Task.Id.Replace("-", "")}";
var ok = await ConfirmAsync($"Discard worktree and reset task?\nThis deletes branch {branchName} and all uncommitted changes.");
if (!ok) return;
}
await _worker.ResetTaskAsync(Task.Id);
}
private bool CanReset() =>
Task != null && _worker.IsConnected && ShowFailedActions;
} }
public sealed partial class SubtaskRowViewModel : ViewModelBase public sealed partial class SubtaskRowViewModel : ViewModelBase