'use client'; import { memo, useCallback } from 'react'; import { IconGitCommit, IconGitPullRequest, IconGitMerge, IconGitCherryPick, IconLoader2, IconChevronDown, IconCloudDownload, IconCloudUpload, IconAlertTriangle, } from '@tabler/icons-react'; import { Button } from '@kandev/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, } from '@kandev/ui/dropdown-menu'; import { Tooltip, TooltipContent, TooltipTrigger } from '@kandev/ui/tooltip'; import { useSessionGitStatus } from '@/hooks/domains/session/use-session-git-status'; import { useGitOperations } from '@/hooks/use-git-operations'; import { useGitWithFeedback } from '@/hooks/use-git-with-feedback'; import { useVcsDialogs } from '@/components/vcs/vcs-dialogs'; type VcsSplitButtonProps = { sessionId: string | null; baseBranch?: string; }; const VcsSplitButton = memo(function VcsSplitButton({ sessionId, baseBranch, }: VcsSplitButtonProps) { const gitWithFeedback = useGitWithFeedback(); const gitStatus = useSessionGitStatus(sessionId); const { pull, push, rebase, merge, isLoading: isGitLoading } = useGitOperations(sessionId); const { openCommitDialog, openPRDialog } = useVcsDialogs(); // Check if remote branch tracks current branch const currentBranch = gitStatus?.branch; const remoteBranch = gitStatus?.remote_branch; const hasMatchingUpstream = remoteBranch && currentBranch && remoteBranch === `origin/${currentBranch}`; // Uncommitted file stats const uncommittedFileCount = gitStatus?.files ? Object.keys(gitStatus.files).length : 0; const aheadCount = gitStatus?.ahead ?? 0; const behindCount = gitStatus?.behind ?? 0; // --- handlers --- const handlePull = useCallback(() => { gitWithFeedback(() => pull(), 'Pull'); }, [gitWithFeedback, pull]); const handlePush = useCallback( (force = false) => { gitWithFeedback( () => push({ force }), force ? 'Force Push' : 'Push' ); }, [gitWithFeedback, push] ); const handleRebase = useCallback(() => { const targetBranch = baseBranch?.replace(/^origin\//, '') || 'main'; gitWithFeedback(() => rebase(targetBranch), 'Rebase'); }, [gitWithFeedback, rebase, baseBranch]); const handleMerge = useCallback(() => { const targetBranch = baseBranch?.replace(/^origin\//, '') || 'main'; gitWithFeedback(() => merge(targetBranch), 'Merge'); }, [gitWithFeedback, merge, baseBranch]); // --- dynamic primary action --- const primaryAction = uncommittedFileCount > 0 ? ('commit' as const) : aheadCount > 0 ? ('pr' as const) : behindCount > 0 ? ('rebase' as const) : ('commit' as const); const primaryButtonConfig = { commit: { icon: , label: 'Commit', badge: uncommittedFileCount > 0 ? uncommittedFileCount : null, tooltip: uncommittedFileCount > 0 ? `Commit ${uncommittedFileCount} changed file${uncommittedFileCount !== 1 ? 's' : ''}` : 'No changes to commit', onClick: openCommitDialog, }, pr: { icon: , label: 'Create PR', badge: aheadCount > 0 ? aheadCount : null, tooltip: `Create PR (${aheadCount} commit${aheadCount !== 1 ? 's' : ''} ahead)`, onClick: openPRDialog, }, rebase: { icon: , label: 'Rebase', badge: behindCount > 0 ? behindCount : null, tooltip: `Rebase onto ${baseBranch || 'origin/main'} (${behindCount} behind)`, onClick: handleRebase, }, }[primaryAction]; return (
{primaryButtonConfig.tooltip} Create PR Pull {hasMatchingUpstream && (gitStatus?.behind ?? 0) > 0 && ( ↓{gitStatus?.behind} )} Push {hasMatchingUpstream && (gitStatus?.ahead ?? 0) > 0 && ( ↑{gitStatus?.ahead} )} handlePush(false)} disabled={isGitLoading || !sessionId} > Push handlePush(true)} disabled={isGitLoading || !sessionId} > Force Push Rebase onto {baseBranch || 'origin/main'} Merge from {baseBranch || 'origin/main'}
); }); export { VcsSplitButton };