feat(ui): add queueing and scheduling from task row context menu
- Right-click on a task row exposes Send to queue / Remove from queue and Schedule for... / Clear schedule actions. - New virtual:queued list in the sidebar with live count. - Sidebar counts are now computed (open per list, running, queued, review) and refreshed on task- and worker-side events. - Sending a task to the queue wakes the worker so it starts immediately.
This commit is contained in:
@@ -2,6 +2,8 @@ using System.Collections.ObjectModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using ClaudeDo.Data;
|
||||
using ClaudeDo.Data.Models;
|
||||
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||
using ClaudeDo.Data.Repositories;
|
||||
using ClaudeDo.Ui.Services;
|
||||
using ClaudeDo.Ui.ViewModels.Modals;
|
||||
@@ -68,7 +70,12 @@ public sealed partial class ListsIslandViewModel : ViewModelBase
|
||||
: Environment.UserName.ToUpperInvariant();
|
||||
|
||||
if (_worker is not null)
|
||||
_worker.ListUpdatedEvent += id => _ = RefreshRowAsync(id);
|
||||
{
|
||||
_worker.ListUpdatedEvent += id => _ = RefreshRowAsync(id);
|
||||
_worker.TaskStartedEvent += (_slot, _id, _at) => _ = RefreshCountsAsync();
|
||||
_worker.TaskFinishedEvent += (_slot, _id, _status, _at) => _ = RefreshCountsAsync();
|
||||
_worker.TaskUpdatedEvent += _id => _ = RefreshCountsAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task LoadAsync(CancellationToken ct = default)
|
||||
@@ -82,6 +89,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase
|
||||
new ListNavItemViewModel { Id = "smart:my-day", Name = "My Day", Kind = ListKind.Smart, IconKey = "Sun" },
|
||||
new ListNavItemViewModel { Id = "smart:important", Name = "Important", Kind = ListKind.Smart, IconKey = "Star" },
|
||||
new ListNavItemViewModel { Id = "smart:planned", Name = "Planned", Kind = ListKind.Smart, IconKey = "Calendar" },
|
||||
new ListNavItemViewModel { Id = "virtual:queued", Name = "Queue", Kind = ListKind.Virtual, IconKey = "Inbox" },
|
||||
new ListNavItemViewModel { Id = "virtual:running", Name = "Running", Kind = ListKind.Virtual, IconKey = "Activity" },
|
||||
new ListNavItemViewModel { Id = "virtual:review", Name = "Review", Kind = ListKind.Virtual, IconKey = "Eye" },
|
||||
};
|
||||
@@ -116,8 +124,46 @@ public sealed partial class ListsIslandViewModel : ViewModelBase
|
||||
|
||||
public async Task RefreshCountsAsync(CancellationToken ct = default)
|
||||
{
|
||||
foreach (var i in Items) i.Count = 0;
|
||||
await Task.CompletedTask;
|
||||
try
|
||||
{
|
||||
await using var ctx = await _dbFactory.CreateDbContextAsync(ct);
|
||||
|
||||
// Snapshot the open (non-Done) tasks once; small enough collection for client-side grouping.
|
||||
var open = await ctx.Tasks.AsNoTracking()
|
||||
.Where(t => t.Status != TaskStatus.Done)
|
||||
.Select(t => new { t.ListId, t.Status, t.IsMyDay, t.IsStarred, Scheduled = t.ScheduledFor })
|
||||
.ToListAsync(ct);
|
||||
|
||||
var running = open.Count(t => t.Status == TaskStatus.Running);
|
||||
var queued = open.Count(t => t.Status == TaskStatus.Queued);
|
||||
var review = await ctx.Tasks.AsNoTracking()
|
||||
.Where(t => t.Status == TaskStatus.Done && t.Worktree != null && t.Worktree.State == WorktreeState.Active)
|
||||
.CountAsync(ct);
|
||||
|
||||
foreach (var item in SmartLists)
|
||||
{
|
||||
item.Count = item.Id switch
|
||||
{
|
||||
"smart:my-day" => open.Count(t => t.IsMyDay),
|
||||
"smart:important" => open.Count(t => t.IsStarred),
|
||||
"smart:planned" => open.Count(t => t.Scheduled != null),
|
||||
"virtual:queued" => queued,
|
||||
"virtual:running" => running,
|
||||
"virtual:review" => review,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
||||
foreach (var item in UserLists)
|
||||
{
|
||||
var listId = item.Id.StartsWith("user:", StringComparison.Ordinal)
|
||||
? item.Id["user:".Length..]
|
||||
: item.Id;
|
||||
item.Count = open.Count(t => t.ListId == listId);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { throw; }
|
||||
catch { /* best-effort refresh */ }
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
||||
Reference in New Issue
Block a user