feat(ui): merge action and robust jump-to-task in worktrees overview
Add Merge entry to the worktrees overview context menu wiring the existing MergeModalViewModel, replace fire-and-forget list selection with a collection-change-aware JumpToTaskHelper, and propagate list renames to visible task rows via a new ListUpdated event. Harden worktree state changes: WorkerHub.SetWorktreeState now rejects invalid transitions, WorktreeMaintenanceService only drops the DB row when the on-disk worktree was actually removed, and Cleanup/Reset broadcast WorktreeUpdated for affected tasks. SetWorktreeStateAsync returns the hub error message so the modal can surface it. Also: de-duplicate the worktrees overview modal opener, hook OnParentTaskIdChanged to refresh IsDraft, fix MergeModal CanExecute notifications, and add WorktreeStateHubTests for the transition rules. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -239,12 +239,16 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
||||
public async Task<WorktreeCleanupDto> CleanupFinishedWorktrees(string? listId = null)
|
||||
{
|
||||
var result = await _wtMaintenance.CleanupFinishedAsync(listId, Context.ConnectionAborted);
|
||||
foreach (var id in result.RemovedTaskIds)
|
||||
await _broadcaster.WorktreeUpdated(id);
|
||||
return new WorktreeCleanupDto(result.Removed);
|
||||
}
|
||||
|
||||
public async Task<WorktreeResetDto> ResetAllWorktrees()
|
||||
{
|
||||
var result = await _wtMaintenance.ResetAllAsync();
|
||||
foreach (var id in result.RemovedTaskIds)
|
||||
await _broadcaster.WorktreeUpdated(id);
|
||||
return new WorktreeResetDto(result.Removed, result.TasksAffected, result.Blocked, result.RunningTasks);
|
||||
}
|
||||
|
||||
@@ -262,6 +266,12 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
||||
var repo = new WorktreeRepository(ctx);
|
||||
var existing = await repo.GetByTaskIdAsync(taskId, Context.ConnectionAborted);
|
||||
if (existing is null) throw new HubException("worktree not found");
|
||||
|
||||
// Allowed transitions: Active -> Merged | Discarded | Kept. Terminal states are final.
|
||||
if (existing.State == newState) return true;
|
||||
if (existing.State != WorktreeState.Active || newState == WorktreeState.Active)
|
||||
throw new HubException($"invalid worktree state transition {existing.State} -> {newState}");
|
||||
|
||||
await repo.SetStateAsync(taskId, newState, Context.ConnectionAborted);
|
||||
await _broadcaster.WorktreeUpdated(taskId);
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user