feat(ui): add skip-and-continue batch merge orchestration
This commit is contained in:
@@ -69,9 +69,18 @@ public sealed partial class WorktreesOverviewModalViewModel : ViewModelBase
|
||||
[ObservableProperty] private bool _isBusy;
|
||||
[ObservableProperty] private string? _statusMessage;
|
||||
[ObservableProperty] private WorktreeOverviewRowViewModel? _selectedRow;
|
||||
[ObservableProperty] private string? _selectedTarget;
|
||||
[ObservableProperty] private int _selectedCount;
|
||||
[ObservableProperty] private bool _isMerging;
|
||||
[ObservableProperty] private string? _batchProgress;
|
||||
|
||||
public ObservableCollection<WorktreeOverviewRowViewModel> Rows { get; } = new();
|
||||
public ObservableCollection<WorktreesGroupViewModel> Groups { get; } = new();
|
||||
public ObservableCollection<string> MergeTargets { get; } = new();
|
||||
public ObservableCollection<WorktreeOverviewRowViewModel> ConflictRows { get; } = new();
|
||||
|
||||
/// Inert seam wired by the integrator to Layer C's resolver at merge time. (taskId, targetBranch)
|
||||
public Func<string, string, Task>? RequestConflictResolution { get; set; }
|
||||
|
||||
public Action? CloseAction { get; set; }
|
||||
public Action<WorktreeModalViewModel>? ShowDiffAction { get; set; }
|
||||
@@ -265,4 +274,68 @@ public sealed partial class WorktreesOverviewModalViewModel : ViewModelBase
|
||||
Path = d.Path, BranchName = d.BranchName, BaseCommit = d.BaseCommit, State = d.State,
|
||||
DiffStat = d.DiffStat, CreatedAt = d.CreatedAt, PathExistsOnDisk = d.PathExistsOnDisk,
|
||||
};
|
||||
|
||||
public IEnumerable<WorktreeOverviewRowViewModel> AllRows =>
|
||||
IsGlobal ? Groups.SelectMany(g => g.Rows) : Rows;
|
||||
|
||||
public async Task MergeSelectedAsync(
|
||||
Func<string, string, bool, string, Task<MergeResultDto>> mergeFn,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var target = SelectedTarget;
|
||||
if (string.IsNullOrWhiteSpace(target)) return;
|
||||
|
||||
var selected = AllRows.Where(r => r.IsChecked && r.IsActive).ToList();
|
||||
if (selected.Count == 0) return;
|
||||
|
||||
IsMerging = true;
|
||||
ConflictRows.Clear();
|
||||
var done = 0;
|
||||
try
|
||||
{
|
||||
foreach (var row in selected)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
row.MergeOutcome = BatchMergeOutcome.Merging;
|
||||
BatchProgress = Loc.T("vm.worktreesOverview.batchProgress", ++done, selected.Count);
|
||||
|
||||
MergeResultDto result;
|
||||
try
|
||||
{
|
||||
result = await mergeFn(row.TaskId, target!, false,
|
||||
Loc.T("vm.merge.commitMessage", row.TaskTitle));
|
||||
}
|
||||
catch
|
||||
{
|
||||
row.MergeOutcome = BatchMergeOutcome.Failed;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (result.Status)
|
||||
{
|
||||
case "merged":
|
||||
row.MergeOutcome = BatchMergeOutcome.Merged;
|
||||
row.State = WorktreeState.Merged;
|
||||
row.IsChecked = false;
|
||||
break;
|
||||
case "conflict":
|
||||
row.MergeOutcome = BatchMergeOutcome.Conflict;
|
||||
ConflictRows.Add(row);
|
||||
break;
|
||||
case "blocked":
|
||||
row.MergeOutcome = BatchMergeOutcome.Blocked;
|
||||
break;
|
||||
default:
|
||||
row.MergeOutcome = BatchMergeOutcome.Failed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BatchProgress = Loc.T("vm.worktreesOverview.batchDone",
|
||||
selected.Count(r => r.MergeOutcome == BatchMergeOutcome.Merged), ConflictRows.Count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsMerging = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user