fix(ui): live-update child outcomes + enable Review combined diff for improvement parents
This commit is contained in:
@@ -358,6 +358,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
_worker.TaskStartedEvent += (slot, taskId, startedAt) =>
|
||||
{
|
||||
if (Task?.Id == taskId) AgentState = "running";
|
||||
_ = RefreshChildOutcomeAsync(taskId);
|
||||
};
|
||||
_worker.TaskFinishedEvent += (slot, taskId, status, finishedAt) =>
|
||||
{
|
||||
@@ -371,18 +372,21 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
AgentState = FinishedStatusToStateKey(status);
|
||||
// Re-query to pick up worktree created during the run.
|
||||
_ = RefreshWorktreeAsync(taskId);
|
||||
_ = RefreshChildOutcomeAsync(taskId);
|
||||
};
|
||||
|
||||
_worker.WorktreeUpdatedEvent += taskId =>
|
||||
{
|
||||
if (Task?.Id == taskId) _ = RefreshWorktreeAsync(taskId);
|
||||
if (Task?.IsPlanningParent == true) _ = RefreshPlanningChildAsync(taskId);
|
||||
_ = RefreshChildOutcomeAsync(taskId);
|
||||
};
|
||||
|
||||
_worker.TaskUpdatedEvent += taskId =>
|
||||
{
|
||||
if (Task?.Id == taskId) _ = RefreshStatusAsync(taskId);
|
||||
if (Task?.IsPlanningParent == true) _ = RefreshPlanningChildAsync(taskId);
|
||||
_ = RefreshChildOutcomeAsync(taskId);
|
||||
};
|
||||
|
||||
Subtasks.CollectionChanged += (_, _) =>
|
||||
@@ -391,6 +395,12 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
ReviewCombinedDiffCommand.NotifyCanExecuteChanged();
|
||||
};
|
||||
|
||||
ChildOutcomes.CollectionChanged += (_, _) =>
|
||||
{
|
||||
RecomputeCanMergeAll();
|
||||
ReviewCombinedDiffCommand.NotifyCanExecuteChanged();
|
||||
};
|
||||
|
||||
PrepLog.CollectionChanged += (_, _) => OnPropertyChanged(nameof(ShowPrepEmptyState));
|
||||
}
|
||||
|
||||
@@ -887,6 +897,30 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
catch { /* best-effort */ }
|
||||
}
|
||||
|
||||
// Live-update a single improvement child's outcome row from a task event. No-op if the
|
||||
// updated task isn't one of this parent's children.
|
||||
private async System.Threading.Tasks.Task RefreshChildOutcomeAsync(string childTaskId)
|
||||
{
|
||||
var row = ChildOutcomes.FirstOrDefault(c => c.Id == childTaskId);
|
||||
if (row is null) return;
|
||||
try
|
||||
{
|
||||
await using var ctx = await _dbFactory.CreateDbContextAsync();
|
||||
var child = await ctx.Tasks
|
||||
.AsNoTracking()
|
||||
.Include(t => t.Worktree)
|
||||
.FirstOrDefaultAsync(t => t.Id == childTaskId);
|
||||
if (child is null) return;
|
||||
row.Status = child.Status;
|
||||
row.RoadblockCount = child.RoadblockCount;
|
||||
row.WorktreeState = child.Worktree?.State ?? ClaudeDo.Data.Models.WorktreeState.Active;
|
||||
RecomputeCanMergeAll();
|
||||
MergeAllCommand.NotifyCanExecuteChanged();
|
||||
ReviewCombinedDiffCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
catch { /* best-effort */ }
|
||||
}
|
||||
|
||||
internal void RecomputeCanMergeAll()
|
||||
{
|
||||
// Improvement parent: merge is allowed once every child is terminal. The
|
||||
@@ -937,7 +971,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
await ShowPlanningDiffModal(vm);
|
||||
}
|
||||
|
||||
private bool CanReviewDiff() => Task?.IsPlanningParent == true && Subtasks.Any();
|
||||
private bool CanReviewDiff() => (Task?.IsPlanningParent == true && Subtasks.Any()) || HasChildOutcomes;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanMergeAll))]
|
||||
private async System.Threading.Tasks.Task MergeAllAsync()
|
||||
@@ -1283,14 +1317,24 @@ public sealed partial class SubtaskRowViewModel : ViewModelBase
|
||||
[ObservableProperty] private ClaudeDo.Data.Models.WorktreeState _worktreeState = ClaudeDo.Data.Models.WorktreeState.Active;
|
||||
}
|
||||
|
||||
// Read-only row on an improvement parent's review card: a suggested child's outcome.
|
||||
public sealed class ChildOutcomeRowViewModel
|
||||
// A suggested child's outcome on an improvement parent's review card. Observable so the
|
||||
// row reflects the child's live status (Idle → Running → Done/Failed) as it executes.
|
||||
public sealed partial class ChildOutcomeRowViewModel : ViewModelBase
|
||||
{
|
||||
public required string Id { get; init; }
|
||||
public required string Title { get; init; }
|
||||
public required ClaudeDo.Data.Models.TaskStatus Status { get; init; }
|
||||
public int RoadblockCount { get; init; }
|
||||
public ClaudeDo.Data.Models.WorktreeState WorktreeState { get; init; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(StatusLabel))]
|
||||
private ClaudeDo.Data.Models.TaskStatus _status;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(HasRoadblock))]
|
||||
[NotifyPropertyChangedFor(nameof(RoadblockText))]
|
||||
private int _roadblockCount;
|
||||
|
||||
[ObservableProperty]
|
||||
private ClaudeDo.Data.Models.WorktreeState _worktreeState = ClaudeDo.Data.Models.WorktreeState.Active;
|
||||
|
||||
public string StatusLabel => Status switch
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user