feat(ui): Mission Control als Session-Hub
- "+" öffnet ein Menü mit allen Listen (working dir) statt direkt den Ordner-Dialog; "Ordner wählen…" bleibt als Fallback erste Zeile, damit das Menü auch bei fehlgeschlagener Listen-Abfrage nutzbar bleibt - Rail-Rows: Kontextmenü "Sitzung öffnen" (gesperrt für Running — der Worktree gehört dort dem autonomen Lauf) - Aktivitäts-Strip statt reiner Queue: WaitingForReview/Failed/Roadblock kommen dazu, Attention zuerst, unterschieden nur über Farbe (Aktionen bleiben in der Task-Detailansicht)
This commit is contained in:
@@ -202,6 +202,66 @@ public class MissionControlViewModelTests : IDisposable
|
||||
Assert.Equal(new[] { "first", "second" }, vm.Queued.Select(q => q.Title).ToArray());
|
||||
}
|
||||
|
||||
// ── activity strip: attention rows come first and carry a tint ─────────────
|
||||
|
||||
[Fact]
|
||||
public async Task RefreshQueueAsync_IncludesAttentionRows_AttentionFirst_WithTint()
|
||||
{
|
||||
await using (var db = NewContext())
|
||||
{
|
||||
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
|
||||
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "q1", ListId = "L1", Title = "queued", Status = TaskStatus.Queued, CreatedAt = DateTime.UtcNow, SortOrder = 0 });
|
||||
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "run1", ListId = "L1", Title = "running", Status = TaskStatus.Running, CreatedAt = DateTime.UtcNow, SortOrder = 1 });
|
||||
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "rev1", ListId = "L1", Title = "review", Status = TaskStatus.WaitingForReview, CreatedAt = DateTime.UtcNow, SortOrder = 2 });
|
||||
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "rb1", ListId = "L1", Title = "roadblocked", Status = TaskStatus.WaitingForReview, RoadblockCount = 2, CreatedAt = DateTime.UtcNow, SortOrder = 3 });
|
||||
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "f1", ListId = "L1", Title = "failed", Status = TaskStatus.Failed, CreatedAt = DateTime.UtcNow, SortOrder = 4 });
|
||||
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "done1", ListId = "L1", Title = "done", Status = TaskStatus.Done, CreatedAt = DateTime.UtcNow, SortOrder = 5 });
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
using var vm = BuildVm(new FakeWorker());
|
||||
await vm.RefreshQueueAsync();
|
||||
|
||||
// Done is not activity; the other five are, ordered failed → review → running → queued.
|
||||
Assert.Equal(new[] { "f1", "rev1", "rb1", "run1", "q1" }, vm.Queued.Select(q => q.Id).ToArray());
|
||||
|
||||
Assert.Equal("ErrorTint", vm.Queued[0].TintKey);
|
||||
Assert.Equal("DoneTint", vm.Queued[1].TintKey);
|
||||
Assert.Equal("RoadblockTint", vm.Queued[2].TintKey); // roadblocks outrank plain review
|
||||
Assert.Equal("RunningTint", vm.Queued[3].TintKey);
|
||||
Assert.Null(vm.Queued[4].TintKey);
|
||||
Assert.Equal("RunningTintBorder", vm.Queued[3].TintBorderKey);
|
||||
|
||||
// A running task's worktree belongs to the autonomous run — no interactive session on it.
|
||||
Assert.False(vm.Queued[3].CanOpenSession);
|
||||
Assert.True(vm.Queued[4].CanOpenSession);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RefreshSessionTargetsAsync_ListsWithWorkingDir_PlusBrowse()
|
||||
{
|
||||
await using (var db = NewContext())
|
||||
{
|
||||
db.Lists.Add(new ListEntity { Id = "L1", Name = "Alpha", WorkingDir = @"C:\repos\alpha", CreatedAt = DateTime.UtcNow, SortOrder = 1 });
|
||||
db.Lists.Add(new ListEntity { Id = "L2", Name = "Beta", WorkingDir = @"C:\repos\beta", CreatedAt = DateTime.UtcNow, SortOrder = 0 });
|
||||
db.Lists.Add(new ListEntity { Id = "L3", Name = "NoDir", CreatedAt = DateTime.UtcNow, SortOrder = 2 });
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
using var vm = BuildVm(new FakeWorker());
|
||||
var browsed = false;
|
||||
vm.BrowseForSessionRequested = () => browsed = true;
|
||||
|
||||
await vm.RefreshSessionTargetsAsync();
|
||||
|
||||
// Browse first (survives a failing list query), then the lists in sort order.
|
||||
Assert.Equal(3, vm.SessionTargets.Count);
|
||||
Assert.Equal(new[] { "Beta", "Alpha" }, vm.SessionTargets.Skip(1).Select(t => t.Label).ToArray());
|
||||
|
||||
vm.SessionTargets[0].StartCommand.Execute(null);
|
||||
Assert.True(browsed);
|
||||
}
|
||||
|
||||
private async Task SeedQueueAsync()
|
||||
{
|
||||
await using var db = NewContext();
|
||||
|
||||
Reference in New Issue
Block a user