feat(ui): add conflict resolution dialog for planning merge-all
Opens a modal when PlanningMergeConflict fires, listing conflicted files with options to open in VS Code, continue, or abort the merge. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,9 +4,12 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using ClaudeDo.Data;
|
||||
using ClaudeDo.Data.Models;
|
||||
using ClaudeDo.Ui.Services;
|
||||
using ClaudeDo.Ui.ViewModels.Islands;
|
||||
using ClaudeDo.Ui.ViewModels.Planning;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ClaudeDo.Ui.ViewModels;
|
||||
|
||||
@@ -27,6 +30,10 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
||||
|
||||
private readonly UpdateCheckService _updateCheck;
|
||||
private readonly InstallerLocator _installerLocator;
|
||||
private readonly IDbContextFactory<ClaudeDoDbContext>? _dbFactory;
|
||||
|
||||
// Set by MainWindow to open the conflict resolution dialog.
|
||||
public Func<ConflictResolutionViewModel, Task>? ShowConflictDialog { get; set; }
|
||||
|
||||
[ObservableProperty] private bool _isUpdateBannerVisible;
|
||||
[ObservableProperty] private string? _updateBannerLatestVersion;
|
||||
@@ -84,6 +91,47 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
||||
WorkerLogText = null;
|
||||
}
|
||||
|
||||
private void OnPlanningMergeConflict(string planningTaskId, string subtaskId, IReadOnlyList<string> conflictedFiles)
|
||||
{
|
||||
// Already on UI thread (WorkerClient dispatches via Dispatcher.UIThread.Post).
|
||||
_ = OpenConflictDialogAsync(planningTaskId, subtaskId, conflictedFiles);
|
||||
}
|
||||
|
||||
private async Task OpenConflictDialogAsync(string planningTaskId, string subtaskId, IReadOnlyList<string> conflictedFiles)
|
||||
{
|
||||
if (ShowConflictDialog == null || _dbFactory == null) return;
|
||||
|
||||
string subtaskTitle = subtaskId;
|
||||
string worktreePath = System.Environment.CurrentDirectory;
|
||||
string targetBranch = Worker?.LastMergeAllTarget ?? "main";
|
||||
|
||||
try
|
||||
{
|
||||
await using var ctx = await _dbFactory.CreateDbContextAsync();
|
||||
var entity = await ctx.Tasks
|
||||
.Include(t => t.Worktree)
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(t => t.Id == subtaskId);
|
||||
if (entity != null)
|
||||
{
|
||||
subtaskTitle = entity.Title;
|
||||
if (entity.Worktree?.Path is { } p)
|
||||
worktreePath = p;
|
||||
}
|
||||
}
|
||||
catch { /* Non-fatal: fall back to subtaskId and cwd */ }
|
||||
|
||||
var vm = new ConflictResolutionViewModel(
|
||||
Worker!,
|
||||
planningTaskId,
|
||||
subtaskTitle,
|
||||
targetBranch,
|
||||
conflictedFiles,
|
||||
worktreePath);
|
||||
|
||||
await ShowConflictDialog(vm);
|
||||
}
|
||||
|
||||
// For tests only — does NOT wire up events.
|
||||
internal IslandsShellViewModel() { }
|
||||
|
||||
@@ -93,11 +141,13 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
||||
DetailsIslandViewModel details,
|
||||
WorkerClient worker,
|
||||
UpdateCheckService updateCheck,
|
||||
InstallerLocator installerLocator)
|
||||
InstallerLocator installerLocator,
|
||||
IDbContextFactory<ClaudeDoDbContext> dbFactory)
|
||||
{
|
||||
Lists = lists; Tasks = tasks; Details = details; Worker = worker;
|
||||
_updateCheck = updateCheck;
|
||||
_installerLocator = installerLocator;
|
||||
_dbFactory = dbFactory;
|
||||
Lists.SelectionChanged += (_, _) => Tasks.LoadForList(Lists.SelectedList);
|
||||
Tasks.SelectionChanged += (_, _) => Details.Bind(Tasks.SelectedTask);
|
||||
Tasks.TasksChanged += (_, _) => _ = Lists.RefreshCountsAsync();
|
||||
@@ -122,6 +172,7 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
||||
}
|
||||
};
|
||||
Worker.WorkerLogReceivedEvent += OnWorkerLogReceived;
|
||||
Worker.PlanningMergeConflictEvent += OnPlanningMergeConflict;
|
||||
_clearTimer.Elapsed += (_, _) =>
|
||||
{
|
||||
if (Dispatcher.UIThread.CheckAccess())
|
||||
|
||||
Reference in New Issue
Block a user