import { useState, useEffect } from 'react'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { GitMerge, AlertTriangle, CheckCircle2 } from 'lucide-react'; import { Spinner } from '@/components/ui/spinner'; import { getElectronAPI } from '@/lib/electron'; import { toast } from 'sonner'; interface WorktreeInfo { path: string; branch: string; isMain: boolean; hasChanges?: boolean; changedFilesCount?: number; } interface MergeWorktreeDialogProps { open: boolean; onOpenChange: (open: boolean) => void; projectPath: string; worktree: WorktreeInfo | null; onMerged: (mergedWorktree: WorktreeInfo) => void; /** Number of features assigned to this worktree's branch */ affectedFeatureCount?: number; } type DialogStep = 'confirm' | 'verify'; export function MergeWorktreeDialog({ open, onOpenChange, projectPath, worktree, onMerged, affectedFeatureCount = 0, }: MergeWorktreeDialogProps) { const [isLoading, setIsLoading] = useState(false); const [step, setStep] = useState('confirm'); const [confirmText, setConfirmText] = useState(''); // Reset state when dialog opens useEffect(() => { if (open) { setIsLoading(false); setStep('confirm'); setConfirmText(''); } }, [open]); const handleProceedToVerify = () => { setStep('verify'); }; const handleMerge = async () => { if (!worktree) return; setIsLoading(true); try { const api = getElectronAPI(); if (!api?.worktree?.mergeFeature) { toast.error('Worktree API not available'); return; } // Pass branchName and worktreePath directly to the API const result = await api.worktree.mergeFeature(projectPath, worktree.branch, worktree.path); if (result.success) { toast.success('Branch merged to main', { description: `Branch "${worktree.branch}" has been merged and cleaned up`, }); onMerged(worktree); onOpenChange(false); } else { toast.error('Failed to merge branch', { description: result.error, }); } } catch (err) { toast.error('Failed to merge branch', { description: err instanceof Error ? err.message : 'Unknown error', }); } finally { setIsLoading(false); } }; if (!worktree) return null; const confirmationWord = 'merge'; const isConfirmValid = confirmText.toLowerCase() === confirmationWord; // First step: Show what will happen and ask for confirmation if (step === 'confirm') { return ( Merge to Main
Merge branch{' '} {worktree.branch} into main?
This will:
  • Merge the branch into the main branch
  • Remove the worktree directory
  • Delete the branch
{worktree.hasChanges && (
This worktree has {worktree.changedFilesCount} uncommitted change(s). Please commit or discard them before merging.
)} {affectedFeatureCount > 0 && (
{affectedFeatureCount} feature{affectedFeatureCount !== 1 ? 's' : ''}{' '} {affectedFeatureCount !== 1 ? 'are' : 'is'} assigned to this branch and will be unassigned after merge.
)}
); } // Second step: Type confirmation return ( Confirm Merge
This action cannot be undone. The branch{' '} {worktree.branch} will be permanently deleted after merging.
setConfirmText(e.target.value)} placeholder={confirmationWord} disabled={isLoading} className="font-mono" autoComplete="off" />
); }