Merge claudedo/181d4abf368046b99bd57d5e2a7ab97a
This commit is contained in:
@@ -363,6 +363,10 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
|
||||
{
|
||||
if (Task?.IsPlanningParent == true) _ = RefreshPlanningChildAsync(taskId);
|
||||
_ = RefreshChildOutcomeAsync(taskId);
|
||||
// The bound row's own status can change from outside (worker run, MCP tool, another
|
||||
// session) — refresh it directly instead of relying on TasksIslandViewModel mutating
|
||||
// the same instance, so the detail pane stays correct even if that row was replaced.
|
||||
if (Task?.Id == taskId) _ = RefreshBoundTaskAsync(taskId);
|
||||
};
|
||||
_worker.TaskUpdatedEvent += _workerTaskUpdatedHandler;
|
||||
|
||||
@@ -767,6 +771,27 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
|
||||
catch { /* best-effort */ }
|
||||
}
|
||||
|
||||
// Refreshes the bound row itself (status, planning phase, worktree/branch mirrors, etc.) from
|
||||
// the DB. Kept independent of TasksIslandViewModel's own handler: the row instance backing
|
||||
// Task may have been replaced by a full list reload, so this must not assume it stayed live.
|
||||
private async System.Threading.Tasks.Task RefreshBoundTaskAsync(string taskId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var ctx = await _dbFactory.CreateDbContextAsync();
|
||||
var entity = await ctx.Tasks
|
||||
.AsNoTracking()
|
||||
.Include(t => t.Worktree)
|
||||
.Include(t => t.List)
|
||||
.FirstOrDefaultAsync(t => t.Id == taskId);
|
||||
if (entity is null || Task?.Id != taskId) return;
|
||||
Task.UpdateFromEntity(entity);
|
||||
OnPropertyChanged(nameof(CanPickUpInTerminal));
|
||||
OnPropertyChanged(nameof(CanAcceptDrop));
|
||||
}
|
||||
catch { /* best-effort */ }
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task RefreshWorktreeAsync(string taskId)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -237,6 +237,12 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable
|
||||
// the selection so a live update never yanks the detail pane away.
|
||||
var listChanged = !string.Equals(_currentList?.Id, list?.Id, StringComparison.Ordinal);
|
||||
|
||||
// A same-list reload (triggered by OnWorkerTaskUpdated's full-reload branches) rebuilds
|
||||
// every row from scratch. Reusing the previous instances by id — instead of handing back
|
||||
// brand new ones — keeps SelectedTask (and the bound DetailsIslandViewModel.Task) pointed
|
||||
// at a live row instead of an orphan that never receives another update.
|
||||
var reusable = listChanged ? null : Items.ToDictionary(r => r.Id);
|
||||
|
||||
if (_currentList is not null)
|
||||
_currentList.PropertyChanged -= OnCurrentListPropertyChanged;
|
||||
_currentList = list;
|
||||
@@ -261,10 +267,11 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable
|
||||
IsMyDayList = list.Id == "smart:my-day";
|
||||
IsLetClaudeVisible = list.Kind == ListKind.User && !string.IsNullOrWhiteSpace(list.WorkingDir);
|
||||
|
||||
LoadTask = LoadForListAsync(list, ct);
|
||||
LoadTask = LoadForListAsync(list, ct, reusable);
|
||||
}
|
||||
|
||||
private async Task LoadForListAsync(ListNavItemViewModel list, CancellationToken ct)
|
||||
private async Task LoadForListAsync(
|
||||
ListNavItemViewModel list, CancellationToken ct, Dictionary<string, TaskRowViewModel>? reusable)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -292,7 +299,16 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable
|
||||
var showListChip = list.Kind == ListKind.Virtual;
|
||||
foreach (var t in filteredList)
|
||||
{
|
||||
var row = TaskRowViewModel.FromEntity(t);
|
||||
TaskRowViewModel row;
|
||||
if (reusable is not null && reusable.TryGetValue(t.Id, out var existing))
|
||||
{
|
||||
row = existing;
|
||||
row.UpdateFromEntity(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
row = TaskRowViewModel.FromEntity(t);
|
||||
}
|
||||
row.ShowListChip = showListChip;
|
||||
row.HasInteractiveSession = _interactiveSessionIds.Contains(row.Id);
|
||||
Items.Add(row);
|
||||
|
||||
Reference in New Issue
Block a user