fix(ui): duplizierter Confirm-Dialog mit "Delete"-Knopf – zusammenfuehren und lokalisieren

F4: DetailsIslandView/TasksIslandView hatten je eine view-lokale Confirm/Error-Dialog-Kopie,
teils mit hartkodiertem "Delete"-Knopf fuer jede Aktion (inkl. der Stash+Merge-Bestaetigung,
die nichts loescht). Beide Kopien entfernt; DetailsIslandViewModel/TasksIslandViewModel routen
Confirm/Error jetzt durch den geteilten Dialogs-Seam (IDialogService, propagiert vom Shell wie
schon bei Lists/Tasks) statt ueber eine vom Code-behind gesetzte Func-Property.

IDialogService.ConfirmAsync bekommt einen optionalen confirmLabel-Parameter (Default: lokalisiertes
"Confirm"); nur die echten Delete-Aktionen (Task loeschen, abgeschlossene Tasks leeren) uebergeben
das lokalisierte "Delete"-Label.

F5: "Cancel"/"Confirm"/"Delete"/"OK" und die Titel "Confirm"/"Error" durch Loc.T mit neuen Keys
unter "dialog.*" ersetzt (en.json + de.json). Mission Controls eigene Dialog-Kopie bleibt bestehen
(eigenes Fenster, WindowDialogService ist an den Haupt-Owner gebunden) — nur ihre Labels wurden
lokalisiert.

Out of scope (siehe Task-Beschreibung): die Nachrichtentexte der Dialoge bleiben unlokalisiert.
This commit is contained in:
Mika Kuns
2026-09-16 15:43:38 +02:00
committed by mika kuns
parent 684b0115e5
commit 86cc309ba9
17 changed files with 126 additions and 199 deletions
@@ -90,12 +90,12 @@ public class DetailsIslandDeleteTaskTests : IDisposable
vm.DeleteFromList = _ => { deleteFromListCalled = true; return Task.CompletedTask; };
var closed = false;
vm.CloseDetail = () => closed = true;
string? reportedError = null;
vm.ShowErrorAsync = msg => { reportedError = msg; return Task.CompletedTask; };
var dialogs = new RecordingDialogService();
vm.Dialogs = dialogs;
await vm.DeleteTaskCommand.ExecuteAsync(null);
Assert.Equal(fkMessage, reportedError);
Assert.Equal(fkMessage, dialogs.LastErrorMessage);
Assert.False(deleteFromListCalled);
Assert.False(closed);
}
@@ -136,12 +136,12 @@ public class DetailsIslandDeleteTaskTests : IDisposable
vm.DeleteFromList = _ => { deleteFromListCalled = true; return Task.CompletedTask; };
var closed = false;
vm.CloseDetail = () => closed = true;
string? reportedError = null;
vm.ShowErrorAsync = msg => { reportedError = msg; return Task.CompletedTask; };
var dialogs = new RecordingDialogService();
vm.Dialogs = dialogs;
await vm.DeleteTaskCommand.ExecuteAsync(null);
Assert.Equal("Connection is not active.", reportedError);
Assert.Equal("Connection is not active.", dialogs.LastErrorMessage);
Assert.False(deleteFromListCalled);
Assert.False(closed);
}
@@ -164,7 +164,7 @@ public class DetailsIslandErrorFeedbackTests : IDisposable
var vm = BuildVm(worker);
vm.Bind(new TaskRowViewModel { Id = "task-reset-throw", Status = TaskStatus.Failed });
vm.Monitor.ApplyState(TaskStatus.Failed);
vm.ConfirmAsync = _ => Task.FromResult(true);
vm.Dialogs = new RecordingDialogService { ConfirmResult = true };
string? reportedError = null;
vm.ErrorReported += msg => reportedError = msg;
@@ -153,12 +153,12 @@ public class DetailsIslandReviewActionsTests : IDisposable
vm.Bind(new TaskRowViewModel { Id = "task-err-1", Status = TaskStatus.WaitingForReview });
vm.Monitor.ApplyState(TaskStatus.WaitingForReview);
string? reportedError = null;
vm.ShowErrorAsync = msg => { reportedError = msg; return Task.CompletedTask; };
var dialogs = new RecordingDialogService();
vm.Dialogs = dialogs;
await vm.ApproveReviewCommand.ExecuteAsync(null);
Assert.Equal(worker.ExceptionMessage, reportedError);
Assert.Equal(worker.ExceptionMessage, dialogs.LastErrorMessage);
Assert.False(vm.ApproveOp.IsRunning);
Assert.True(vm.ApproveReviewCommand.CanExecute(null));
}
@@ -62,7 +62,7 @@ public class ListsIslandCreateListCancelTests : IDisposable
public Task ShowWorkerConnectionAsync(WorkerConnectionModalViewModel vm) => throw new NotImplementedException();
public Task ShowConflictResolverAsync(ConflictResolverViewModel vm) => throw new NotImplementedException();
public Task ShowLogVisualizerAsync(LogVisualizerViewModel vm) => throw new NotImplementedException();
public Task<bool> ConfirmAsync(string message) => Task.FromResult(true);
public Task<bool> ConfirmAsync(string message, string? confirmLabel = null) => Task.FromResult(true);
public Task ShowErrorAsync(string message) => Task.CompletedTask;
public void ShowMissionControl(MissionControlViewModel vm) => throw new NotImplementedException();
public void ShowCheatSheets(CheatSheetsViewModel vm) => throw new NotImplementedException();
@@ -43,7 +43,7 @@ public class TasksIslandMoveToListTests : IDisposable
public int ConfirmCalls;
public string? LastMessage;
public Task<bool> ConfirmAsync(string message)
public Task<bool> ConfirmAsync(string message, string? confirmLabel = null)
{
ConfirmCalls++;
LastMessage = message;