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:
mika kuns
2026-04-23 13:07:48 +02:00
parent 9952ff98f2
commit 6f725d12f5
7 changed files with 280 additions and 21 deletions

View File

@@ -1,16 +1,72 @@
using System.Linq;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Animation.Easings;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.VisualTree;
using ClaudeDo.Ui.ViewModels.Islands;
namespace ClaudeDo.Ui.Views.Islands;
public partial class TaskRowView : UserControl
{
private TaskRowViewModel? _pendingScheduleRow;
public TaskRowView() { InitializeComponent(); }
private TasksIslandViewModel? FindTasksVm() =>
this.GetVisualAncestors().OfType<ItemsControl>()
.Select(ic => ic.DataContext).OfType<TasksIslandViewModel>().FirstOrDefault();
private async void OnSendToQueueClick(object? sender, RoutedEventArgs e)
{
if (DataContext is TaskRowViewModel row && FindTasksVm() is { } vm)
await vm.SendToQueueCommand.ExecuteAsync(row);
}
private async void OnRemoveFromQueueClick(object? sender, RoutedEventArgs e)
{
if (DataContext is TaskRowViewModel row && FindTasksVm() is { } vm)
await vm.RemoveFromQueueCommand.ExecuteAsync(row);
}
private async void OnClearScheduleClick(object? sender, RoutedEventArgs e)
{
if (DataContext is TaskRowViewModel row && FindTasksVm() is { } vm)
await vm.ClearScheduleCommand.ExecuteAsync(row);
}
private void OnScheduleForClick(object? sender, RoutedEventArgs e)
{
if (DataContext is not TaskRowViewModel row) return;
_pendingScheduleRow = row;
var seed = row.ScheduledFor ?? DateTime.Now.AddHours(1);
ScheduleDate.SelectedDate = new DateTimeOffset(seed.Date, TimeSpan.Zero);
ScheduleTime.SelectedTime = seed.TimeOfDay;
ScheduleAnchor.Flyout?.ShowAt(ScheduleAnchor);
}
private async void OnScheduleSetClick(object? sender, RoutedEventArgs e)
{
ScheduleAnchor.Flyout?.Hide();
if (_pendingScheduleRow is null || ScheduleDate.SelectedDate is null) return;
var date = ScheduleDate.SelectedDate.Value.Date;
var time = ScheduleTime.SelectedTime ?? TimeSpan.FromHours(9);
var when = date + time;
if (FindTasksVm() is { } tvm)
await tvm.SetScheduledForAsync(_pendingScheduleRow, when);
_pendingScheduleRow = null;
}
private void OnScheduleCancelClick(object? sender, RoutedEventArgs e)
{
ScheduleAnchor.Flyout?.Hide();
_pendingScheduleRow = null;
}
protected override async void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);