feat(ui): mission control detach/redock toggle, clear review panes, reorder helper

This commit is contained in:
Mika Kuns
2026-06-25 16:24:21 +02:00
parent 5f6e7480f2
commit fbcffce79c
7 changed files with 130 additions and 2 deletions

View File

@@ -1,3 +1,4 @@
using System.Linq;
using ClaudeDo.Data;
using ClaudeDo.Ui.Services;
using ClaudeDo.Ui.ViewModels;
@@ -152,4 +153,65 @@ public class MissionControlViewModelTests : IDisposable
Assert.Single(vm.Monitors);
Assert.Same(monitor, vm.Monitors[0]);
}
[Fact]
public void ClearFinished_AlsoRemoves_WaitingForReview()
{
var worker = new FakeWorker();
using var vm = BuildVm(worker);
worker.RaiseTaskStarted("slot-1", "t1", DateTime.UtcNow);
worker.RaiseTaskFinished("slot-1", "t1", "waiting_for_review", DateTime.UtcNow);
Assert.True(vm.Monitors[0].IsWaitingForReview);
vm.ClearFinishedCommand.Execute(null);
Assert.Empty(vm.Monitors);
}
[Fact]
public void Detach_SetsIsDetached_AndReDockClearsIt()
{
var worker = new FakeWorker();
using var vm = BuildVm(worker);
Action? reDock = null;
vm.ShowDetached = (m, rd) => reDock = rd;
worker.RaiseTaskStarted("slot-1", "t1", DateTime.UtcNow);
var monitor = vm.Monitors[0];
monitor.DetachCommand.Execute(null);
Assert.True(monitor.IsDetached);
Assert.Empty(vm.Monitors);
reDock!.Invoke();
Assert.False(monitor.IsDetached);
Assert.Single(vm.Monitors);
}
[Fact]
public void DetachCommand_WhenDetached_RequestsWindowClose()
{
var worker = new FakeWorker();
using var vm = BuildVm(worker);
vm.ShowDetached = (m, rd) => { };
worker.RaiseTaskStarted("slot-1", "t1", DateTime.UtcNow);
var monitor = vm.Monitors[0];
var closeRequested = false;
monitor.DetachCommand.Execute(null); // detach (IsDetached = true)
monitor.CloseWindowRequested = () => closeRequested = true;
monitor.DetachCommand.Execute(null); // now acts as re-dock
Assert.True(closeRequested);
}
[Fact]
public void MoveMonitor_ReordersCollection()
{
var worker = new FakeWorker();
using var vm = BuildVm(worker);
worker.RaiseTaskStarted("s1", "t1", DateTime.UtcNow);
worker.RaiseTaskStarted("s2", "t2", DateTime.UtcNow);
worker.RaiseTaskStarted("s3", "t3", DateTime.UtcNow);
vm.MoveMonitor(vm.Monitors[0], vm.Monitors[2]); // move t1 to t3's slot
Assert.Equal(new[] { "t2", "t3", "t1" }, vm.Monitors.Select(m => m.SubscribedTaskId).ToArray());
}
}

View File

@@ -99,4 +99,25 @@ public class TaskMonitorViewModelTests : IDisposable
Assert.Equal("Summary text", vm.SessionOutcome);
Assert.Equal("- something broke", vm.Roadblocks);
}
[Fact]
public void HasRoadblock_TrueAfterRoadblockOutcome()
{
var worker = new FakeWorker();
using var vm = Build(worker);
vm.ApplyOutcome("Summary\n\nRoadblocks reported during the run:\n- broke", errorFallback: null);
Assert.True(vm.HasRoadblock);
}
[Fact]
public void Detach_WhenNotDetached_InvokesDetachRequested()
{
var worker = new FakeWorker();
using var vm = Build(worker);
vm.SetTaskId("t1");
TaskMonitorViewModel? requested = null;
vm.DetachRequested = m => requested = m;
vm.DetachCommand.Execute(null);
Assert.Same(vm, requested);
}
}