feat(ui): add reconcile tick to self-heal lost worker broadcasts

TasksIslandViewModel now runs a periodic tick that diffs the flat Items
collection against SQLite and patches properties in place (capped at 500
rows, sharing the Phase 1 delta sequence guard so it never overtakes a
fresher broadcast). Never rebuilds rows or triggers Regroup/LoadForList, so
it stays decoupled from the parallel Phase 2b virtualization work. The same
cadence now refreshes the long-lived Worktrees Overview, Log Visualizer, and
Merge Helper selection overlays; short-lived modals are untouched.
This commit is contained in:
mika kuns
2026-08-10 15:56:05 +02:00
parent 514d6111fe
commit 1cad264967
7 changed files with 381 additions and 4 deletions
@@ -100,8 +100,20 @@ public sealed partial class WorktreesOverviewModalViewModel : ViewModelBase
_worker = worker;
_diffVmFactory = diffVmFactory;
_merge = merge;
// Phase 3 reconcile tick: this overlay is long-lived (stays open while the user reviews
// worktrees), so refresh it on the same cadence as TasksIslandViewModel's tick instead of
// leaving it frozen at the moment it was opened. Skipped while a load or batch merge is
// already in flight — reloading mid-merge would replace the row instances the merge loop
// is still updating.
_reconcileTimer.Elapsed += (_, _) =>
Avalonia.Threading.Dispatcher.UIThread.Post(() => _ = ReconcileTickAsync());
_reconcileTimer.Start();
}
private readonly System.Timers.Timer _reconcileTimer = new(4_000);
internal Task ReconcileTickAsync() => IsBusy || IsMerging ? Task.CompletedTask : LoadAsync();
public void SelectRow(WorktreeOverviewRowViewModel row)
{
if (SelectedRow is not null) SelectedRow.IsSelected = false;
@@ -179,7 +191,12 @@ public sealed partial class WorktreesOverviewModalViewModel : ViewModelBase
}
[RelayCommand]
private void Close() => CloseAction?.Invoke();
private void Close()
{
_reconcileTimer.Stop();
_reconcileTimer.Dispose();
CloseAction?.Invoke();
}
[RelayCommand]
private void ShowDiff(WorktreeOverviewRowViewModel? row)