fix(ui): align virtual list semantics and complete planning roll-up coverage
This commit is contained in:
@@ -68,6 +68,15 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
|
||||
var list = _currentList;
|
||||
if (list is null) return;
|
||||
|
||||
// virtual:queued / virtual:running include Planning parents whose children match,
|
||||
// which can't be decided from a single entity. Always full-reload in those cases.
|
||||
if (list.Kind == ListKind.Virtual &&
|
||||
(list.Id == "virtual:queued" || list.Id == "virtual:running"))
|
||||
{
|
||||
LoadForList(list);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
@@ -97,14 +106,15 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
|
||||
catch { }
|
||||
}
|
||||
|
||||
// NOTE: virtual:queued/virtual:running cannot be decided by a single entity — a Planning
|
||||
// parent matches iff any child has the matching status. OnWorkerTaskUpdated handles those
|
||||
// lists via a full reload rather than the delta path.
|
||||
private static bool TaskMatchesList(TaskEntity t, ListNavItemViewModel list) => list.Kind switch
|
||||
{
|
||||
ListKind.Smart when list.Id == "smart:my-day" => t.IsMyDay,
|
||||
ListKind.Smart when list.Id == "smart:important" => t.IsStarred,
|
||||
ListKind.Smart when list.Id == "smart:planned" => t.ScheduledFor != null,
|
||||
ListKind.Virtual when list.Id == "virtual:queued" => t.Status == TaskStatus.Queued,
|
||||
ListKind.Virtual when list.Id == "virtual:running" => t.Status == TaskStatus.Running,
|
||||
ListKind.Virtual when list.Id == "virtual:review" => t.Status == TaskStatus.Done && t.Worktree?.State == WorktreeState.Active,
|
||||
ListKind.Virtual when list.Id == "virtual:review" => t.Status == TaskStatus.Done && t.Worktree?.State == WorktreeState.Active && t.ParentTaskId == null,
|
||||
ListKind.User => $"user:{t.ListId}" == list.Id,
|
||||
_ => false,
|
||||
};
|
||||
@@ -170,7 +180,7 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
|
||||
ListKind.Virtual when list.Id == "virtual:running" => all.Where(t =>
|
||||
(t.Status == TaskStatus.Running && t.ParentTaskId == null) ||
|
||||
(IsPlanningStatus(t.Status) && all.Any(c => c.ParentTaskId == t.Id && c.Status == TaskStatus.Running))),
|
||||
ListKind.Virtual when list.Id == "virtual:review" => all.Where(t => t.Status == TaskStatus.Done && t.Worktree?.State == WorktreeState.Active),
|
||||
ListKind.Virtual when list.Id == "virtual:review" => all.Where(t => t.Status == TaskStatus.Done && t.Worktree?.State == WorktreeState.Active && t.ParentTaskId == null),
|
||||
ListKind.User => all.Where(t => $"user:{t.ListId}" == list.Id),
|
||||
_ => Enumerable.Empty<TaskEntity>(),
|
||||
};
|
||||
@@ -213,6 +223,8 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
|
||||
foreach (var parent in topLevel)
|
||||
{
|
||||
flat.Add(parent);
|
||||
// Also expand for Done parents so their (Done) children reach the classification
|
||||
// loop and land in CompletedItems alongside the parent.
|
||||
if ((parent.IsPlanningParent || parent.Done) && parent.IsExpanded)
|
||||
{
|
||||
var children = Items.Where(r => r.ParentTaskId == parent.Id);
|
||||
|
||||
@@ -122,6 +122,22 @@ public class TasksIslandRegroupTests : IDisposable
|
||||
Assert.Contains(vm.Items, r => r.Id == "p1" && !r.IsChild);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task VirtualQueued_PlannedParentWithQueuedChild_ParentIsStandaloneRow_ChildIsNot()
|
||||
{
|
||||
await SeedPlanningWithChildAsync(
|
||||
parentStatus: TaskStatus.Planned,
|
||||
childStatus: TaskStatus.Queued,
|
||||
parentId: "p1",
|
||||
childId: "c1");
|
||||
|
||||
var vm = BuildViewModel();
|
||||
await LoadAndWaitAsync(vm, VirtualList("virtual:queued", "Queued"));
|
||||
|
||||
Assert.Contains(vm.Items, r => r.Id == "p1" && !r.IsChild);
|
||||
Assert.DoesNotContain(vm.Items, r => r.Id == "c1" && !r.IsChild);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task VirtualRunning_RunningChildOfPlanningParent_IsNotStandaloneRow()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user