diff --git a/src/ClaudeDo.Localization/locales/de.json b/src/ClaudeDo.Localization/locales/de.json index de69634..229c443 100644 --- a/src/ClaudeDo.Localization/locales/de.json +++ b/src/ClaudeDo.Localization/locales/de.json @@ -233,6 +233,10 @@ "reviewContinueTip": "Dieses Feedback senden und die Aufgabe erneut ausführen", "reviewResetTip": "Alle Änderungen verwerfen und die Aufgabe auf Leerlauf zurücksetzen" }, + "missionControl": { + "openInApp": "In App öffnen", + "cancel": "Abbrechen" + }, "modals": { "logVisualizer": { "title": "WORKER-LOGS — LETZTE 30 MIN", diff --git a/src/ClaudeDo.Localization/locales/en.json b/src/ClaudeDo.Localization/locales/en.json index bdf966a..bc7ab70 100644 --- a/src/ClaudeDo.Localization/locales/en.json +++ b/src/ClaudeDo.Localization/locales/en.json @@ -233,6 +233,10 @@ "reviewContinueTip": "Send this feedback and re-run the task", "reviewResetTip": "Discard all changes and reset the task to Idle" }, + "missionControl": { + "openInApp": "Open in app", + "cancel": "Cancel" + }, "modals": { "logVisualizer": { "title": "WORKER LOGS — LAST 30 MIN", diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/TaskMonitorViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/TaskMonitorViewModel.cs index d06f69a..ce891f6 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/TaskMonitorViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/TaskMonitorViewModel.cs @@ -26,6 +26,13 @@ public sealed partial class TaskMonitorViewModel : ViewModelBase, IDisposable [ObservableProperty] private string _agentState = "idle"; + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(DisplayTitle))] + private string? _title; + + public string DisplayTitle => + string.IsNullOrWhiteSpace(Title) ? (SubscribedTaskId ?? "task") : Title!; + public string AgentStatusLabel => Loc.T($"vm.agentStatus.{AgentState}"); public bool IsIdle => AgentState == "idle"; public bool IsQueued => AgentState == "queued"; @@ -142,6 +149,13 @@ public sealed partial class TaskMonitorViewModel : ViewModelBase, IDisposable OpenInAppRequested?.Invoke(_subscribedTaskId); } + [RelayCommand] + private async System.Threading.Tasks.Task CancelTask() + { + if (!string.IsNullOrEmpty(_subscribedTaskId) && (IsRunning || IsQueued)) + await _worker.CancelTaskAsync(_subscribedTaskId); + } + public void SetTaskId(string id) => _subscribedTaskId = id; public void ApplyState(ClaudeDo.Data.Models.TaskStatus status) => diff --git a/src/ClaudeDo.Ui/ViewModels/MissionControlViewModel.cs b/src/ClaudeDo.Ui/ViewModels/MissionControlViewModel.cs index 570fd9e..298dca4 100644 --- a/src/ClaudeDo.Ui/ViewModels/MissionControlViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/MissionControlViewModel.cs @@ -77,6 +77,7 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable var entity = await ctx.Tasks.AsNoTracking().FirstOrDefaultAsync(t => t.Id == taskId); if (entity is null || monitor.SubscribedTaskId != taskId) return; monitor.ApplyState(entity.Status); + monitor.Title = entity.Title; var latestRun = await new TaskRunRepository(ctx).GetLatestByTaskIdAsync(taskId); monitor.ApplyOutcome(entity.Result, latestRun?.ErrorMarkdown); await monitor.ReplayLogFileAsync(entity.LogPath, CancellationToken.None); diff --git a/src/ClaudeDo.Ui/Views/MissionControl/MonitorPaneView.axaml b/src/ClaudeDo.Ui/Views/MissionControl/MonitorPaneView.axaml new file mode 100644 index 0000000..366b07e --- /dev/null +++ b/src/ClaudeDo.Ui/Views/MissionControl/MonitorPaneView.axaml @@ -0,0 +1,53 @@ + + + + + + + +