Merge claudedo/3832008a0b5147bf8308407ed4bd1ded

This commit is contained in:
mika kuns
2026-07-29 13:26:15 +02:00
14 changed files with 284 additions and 25 deletions
@@ -311,6 +311,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
Prep = new PrepPanelViewModel(worker);
Notes = new NotesEditorViewModel(_notesApi);
Notes.ErrorReported += msg => { if (ShowErrorAsync is not null) _ = ShowErrorAsync(msg); };
Subtasks.CollectionChanged += (_, _) => NotifyStepsChanged();
Subtasks.CollectionChanged += (_, _) => Merge.SyncChildOutcomes(HasChildOutcomes, Subtasks.Count);
Attachments.CollectionChanged += (_, _) => OnPropertyChanged(nameof(FilesBadge));
@@ -24,6 +24,9 @@ public sealed partial class NotesEditorViewModel : ViewModelBase
public NotesEditorViewModel(INotesApi api) => _api = api;
// Raised when a worker call fails so the host VM can surface it (e.g. via ShowErrorAsync).
public event Action<string>? ErrorReported;
public ObservableCollection<NoteBulletViewModel> Bullets { get; } = new();
[ObservableProperty] private DateOnly _currentDay = DateOnly.FromDateTime(DateTime.Today);
@@ -55,9 +58,16 @@ public sealed partial class NotesEditorViewModel : ViewModelBase
{
var text = NewBulletText.Trim();
if (text.Length == 0) return;
var dto = await _api.AddAsync(CurrentDay, text);
if (dto is not null) Bullets.Add(MakeBullet(dto.Id, dto.Text));
NewBulletText = "";
try
{
var dto = await _api.AddAsync(CurrentDay, text);
if (dto is not null) Bullets.Add(MakeBullet(dto.Id, dto.Text));
NewBulletText = "";
}
catch (Exception ex)
{
ErrorReported?.Invoke(ex.Message);
}
}
[RelayCommand] private Task PrevDay() => LoadDayAsync(CurrentDay.AddDays(-1));
@@ -197,6 +197,11 @@ public sealed partial class DiffViewerViewModel : ViewModelBase
DisplayedDiff = "";
}
}
catch (Exception ex)
{
DisplayedDiff = "";
CombinedWarning = Loc.T("vm.planningDiff.buildFailed", ex.Message);
}
finally
{
IsLoadingCombined = false;
@@ -46,6 +46,7 @@ public sealed partial class WorktreesSettingsTabViewModel : ViewModelBase
var r = await _worker.CleanupFinishedWorktreesAsync();
StatusMessage = r is null ? Loc.T("vm.worktreesTab.workerOffline") : Loc.T("vm.worktreesTab.removed", r.Removed);
}
catch (Exception ex) { StatusMessage = Loc.T("vm.worktreesTab.cleanupFailed", ex.Message); }
finally { IsBusy = false; }
}
@@ -63,6 +64,7 @@ public sealed partial class WorktreesSettingsTabViewModel : ViewModelBase
else if (r.Blocked) StatusMessage = Loc.T("vm.worktreesTab.blocked", r.RunningTasks);
else StatusMessage = Loc.T("vm.worktreesTab.removedFrom", r.Removed, r.TasksAffected);
}
catch (Exception ex) { StatusMessage = Loc.T("vm.worktreesTab.resetFailed", ex.Message); }
finally { IsBusy = false; }
}
}
@@ -174,6 +174,7 @@ public sealed partial class WorktreesOverviewModalViewModel : ViewModelBase
StatusMessage = result is null ? Loc.T("vm.worktreesOverview.cleanupFailed") : Loc.T("vm.worktreesOverview.removed", result.Removed);
await LoadAsync();
}
catch (Exception ex) { StatusMessage = Loc.T("vm.worktreesOverview.cleanupFailedDetailed", ex.Message); }
finally { IsBusy = false; }
}
@@ -241,7 +242,16 @@ public sealed partial class WorktreesOverviewModalViewModel : ViewModelBase
if (row.IsRunning) { StatusMessage = Loc.T("vm.worktreesOverview.cannotForceRunning"); return; }
if (ConfirmAction is not null && !await ConfirmAction($"Force remove worktree for '{row.TaskTitle}'? This deletes the directory and branch.")) return;
var result = await _worker.ForceRemoveWorktreeAsync(row.TaskId);
ForceRemoveResultDto? result;
try
{
result = await _worker.ForceRemoveWorktreeAsync(row.TaskId);
}
catch (Exception ex)
{
StatusMessage = Loc.T("vm.worktreesOverview.forceRemoveFailedDetailed", ex.Message);
return;
}
if (result is null || !result.Removed)
{
StatusMessage = result?.Reason ?? Loc.T("vm.worktreesOverview.forceRemoveFailed");