fix(ui): Aktions- und Bestätigungs-Konsistenz (UX-Audit #3)

Sechs Konsistenz-Fixes: Delete-Task ins Zeilen-Kontextmenü (routet über den
Worker wie DetailsIslandViewModel.DeleteTaskAsync, damit ein gelöschtes Child
den WaitingForChildren-Parent korrekt weiterschaltet); EnqueueCommand als
"Send to queue"-Button im Detail-Pane verdrahtet; Settings-Eintrag im
Listen-Kontextmenü ergänzt; Worktree-Discard und Reset-All laufen jetzt über
das jeweils vorhandene Confirm-Hook (ConfirmAction / neuer ConfirmAsync-Hook
auf WorktreesSettingsTabViewModel) statt ohne Rückfrage bzw. über ein
Inline-Reveal-Banner; killSessionTip/closeSession und die deutschen
Queue-Strings im usageMonitor vereinheitlicht.

Kein zweiter Dialog-Mechanismus eingeführt — überall die vorhandenen Hooks
wiederverwendet.
This commit is contained in:
mika kuns
2026-08-21 09:51:51 +02:00
parent cc60cb4f0a
commit 2935eef75a
12 changed files with 144 additions and 32 deletions
@@ -76,4 +76,25 @@ public class WorktreesOverviewModalErrorTests
Assert.False(vm.RefreshStatus.IsRunning);
}
[Fact]
public async Task Discard_WhenConfirmDeclined_LeavesStateUnchanged()
{
var worker = new ThrowingWorker();
var vm = NewVm(worker);
vm.ConfirmAction = _ => Task.FromResult(false);
var row = new WorktreeOverviewRowViewModel
{
TaskId = "task-1",
TaskTitle = "Task 1",
TaskStatus = ClaudeDo.Data.Models.TaskStatus.Idle,
State = ClaudeDo.Data.Models.WorktreeState.Active,
};
vm.AddRowForTest(row);
await vm.DiscardCommand.ExecuteAsync(row);
Assert.Equal(ClaudeDo.Data.Models.WorktreeState.Active, row.State);
Assert.Null(vm.StatusMessage);
}
}
@@ -26,6 +26,16 @@ public class WorktreesSettingsTabViewModelTests
throw new Exception(ExceptionMessage);
}
private sealed class CountingWorker : StubWorkerClient
{
public int ResetCallCount;
public override Task<WorktreeResetDto?> ResetAllWorktreesAsync()
{
ResetCallCount++;
return Task.FromResult<WorktreeResetDto?>(new WorktreeResetDto(0, 0, false, 0));
}
}
[Fact]
public async Task CleanupWorktrees_WhenWorkerThrows_ShowsExceptionMessage()
{
@@ -42,12 +52,33 @@ public class WorktreesSettingsTabViewModelTests
public async Task ConfirmResetAll_WhenWorkerThrows_ShowsExceptionMessage()
{
var worker = new ThrowingWorker();
var vm = new WorktreesSettingsTabViewModel(worker);
var vm = new WorktreesSettingsTabViewModel(worker) { ConfirmAsync = _ => Task.FromResult(true) };
await vm.ConfirmResetAllCommand.ExecuteAsync(null);
Assert.Contains(worker.ExceptionMessage, vm.StatusMessage);
Assert.False(vm.ResetStatus.IsRunning);
Assert.False(vm.ShowResetConfirm);
}
[Fact]
public async Task ConfirmResetAll_WhenConfirmDeclined_DoesNotCallWorker()
{
var worker = new CountingWorker();
var vm = new WorktreesSettingsTabViewModel(worker) { ConfirmAsync = _ => Task.FromResult(false) };
await vm.ConfirmResetAllCommand.ExecuteAsync(null);
Assert.Equal(0, worker.ResetCallCount);
}
[Fact]
public async Task ConfirmResetAll_WhenConfirmHookMissing_DoesNotCallWorker()
{
var worker = new CountingWorker();
var vm = new WorktreesSettingsTabViewModel(worker);
await vm.ConfirmResetAllCommand.ExecuteAsync(null);
Assert.Equal(0, worker.ResetCallCount);
}
}