feat(ui): editable task status and tags from details panel

Adds a status ComboBox in the Details header (no transition guards)
and a Tags section with chips + AutoCompleteBox. TaskRowViewModel.Tags
becomes an ObservableCollection so chip lists stay live. TasksIsland
caches AllTags for the row context menu and exposes Set/Toggle helpers.
Test fakes updated for the new IWorkerClient methods.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-04-29 10:40:03 +02:00
parent 47b07373af
commit c1856657b5
10 changed files with 252 additions and 4 deletions

View File

@@ -1,5 +1,6 @@
using System.ComponentModel;
using ClaudeDo.Data.Models;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
namespace ClaudeDo.Ui.Services;
@@ -27,6 +28,9 @@ public interface IWorkerClient : INotifyPropertyChanged
Task<List<AgentInfo>> GetAgentsAsync();
Task<ListConfigDto?> GetListConfigAsync(string listId);
Task UpdateTaskAgentSettingsAsync(UpdateTaskAgentSettingsDto dto);
Task SetTaskStatusAsync(string taskId, TaskStatus status);
Task SetTaskTagsAsync(string taskId, IEnumerable<string> tagNames);
Task<List<string>> GetAllTagsAsync();
Task StartPlanningSessionAsync(string taskId, CancellationToken ct = default);
Task OpenInteractiveTerminalAsync(string taskId, CancellationToken ct = default);
Task ResumePlanningSessionAsync(string taskId, CancellationToken ct = default);

View File

@@ -381,6 +381,28 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
await _hub.InvokeAsync("UpdateTaskAgentSettings", dto);
}
public async Task SetTaskStatusAsync(string taskId, ClaudeDo.Data.Models.TaskStatus status)
{
await _hub.InvokeAsync("SetTaskStatus", taskId, status.ToString());
}
public async Task SetTaskTagsAsync(string taskId, IEnumerable<string> tagNames)
{
await _hub.InvokeAsync("SetTaskTags", taskId, tagNames.ToArray());
}
public async Task<List<string>> GetAllTagsAsync()
{
try
{
return await _hub.InvokeAsync<List<string>>("GetAllTags") ?? new List<string>();
}
catch
{
return new List<string>();
}
}
public async Task<WorktreeCleanupDto?> CleanupFinishedWorktreesAsync()
{
try