using System.Collections.ObjectModel; using ClaudeDo.Ui.Services; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace ClaudeDo.Ui.ViewModels.Modals; public sealed partial class MergeModalViewModel : ViewModelBase { private readonly WorkerClient _worker; public string TaskId { get; set; } = ""; public string TaskTitle { get; set; } = ""; public ObservableCollection Branches { get; } = new(); [ObservableProperty] private string? _selectedBranch; [ObservableProperty] private bool _removeWorktree = true; [ObservableProperty] private string _commitMessage = ""; [ObservableProperty] private bool _isBusy; [ObservableProperty] private string? _errorMessage; [ObservableProperty] private string? _warningMessage; [ObservableProperty] private string? _successMessage; [ObservableProperty] private bool _hasConflict; [ObservableProperty] private IReadOnlyList _conflictFiles = Array.Empty(); public Action? CloseAction { get; set; } public MergeModalViewModel(WorkerClient worker) { _worker = worker; } public async Task InitializeAsync(string taskId, string taskTitle) { TaskId = taskId; TaskTitle = taskTitle; CommitMessage = $"Merge task: {taskTitle}"; IsBusy = true; try { var targets = await _worker.GetMergeTargetsAsync(taskId); Branches.Clear(); if (targets is null) { ErrorMessage = "Worker offline — cannot list branches."; return; } foreach (var b in targets.LocalBranches) Branches.Add(b); SelectedBranch = Branches.Contains(targets.DefaultBranch) ? targets.DefaultBranch : Branches.FirstOrDefault(); } catch (Exception ex) { ErrorMessage = $"Failed to load branches: {ex.Message}"; } finally { IsBusy = false; } } private bool CanSubmit() => !IsBusy && !HasConflict && !string.IsNullOrWhiteSpace(SelectedBranch); [RelayCommand(CanExecute = nameof(CanSubmit))] private async Task SubmitAsync() { if (string.IsNullOrWhiteSpace(SelectedBranch)) return; IsBusy = true; ErrorMessage = null; WarningMessage = null; SuccessMessage = null; try { var result = await _worker.MergeTaskAsync( TaskId, SelectedBranch!, RemoveWorktree, CommitMessage); switch (result.Status) { case "merged": SuccessMessage = result.ErrorMessage is not null ? $"Merged with warning: {result.ErrorMessage}" : "Merged."; // Auto-close after a short delay. _ = Task.Run(async () => { await Task.Delay(1200); Avalonia.Threading.Dispatcher.UIThread.Post(() => CloseAction?.Invoke()); }); break; case "conflict": HasConflict = true; ConflictFiles = result.ConflictFiles; ErrorMessage = "Merge conflict — target branch restored. Resolve manually or via Continue, then retry."; break; case "blocked": ErrorMessage = $"Blocked: {result.ErrorMessage}"; break; default: ErrorMessage = $"Unknown status: {result.Status}"; break; } } catch (Exception ex) { ErrorMessage = $"Merge failed: {ex.Message}"; } finally { IsBusy = false; } } [RelayCommand] private void Cancel() => CloseAction?.Invoke(); }