import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Button } from './Button'; import { classNames } from '~/utils/classNames'; import { GitBranch, Check, Shield, Star, RefreshCw, X } from 'lucide-react'; interface BranchInfo { name: string; sha: string; protected: boolean; isDefault: boolean; canPush?: boolean; // GitLab specific } interface BranchSelectorProps { provider: 'github' | 'gitlab'; repoOwner: string; repoName: string; projectId?: string | number; // GitLab specific token: string; gitlabUrl?: string; defaultBranch?: string; onBranchSelect: (branch: string) => void; onClose: () => void; isOpen: boolean; className?: string; } export function BranchSelector({ provider, repoOwner, repoName, projectId, token, gitlabUrl, defaultBranch, onBranchSelect, onClose, isOpen, className, }: BranchSelectorProps) { const [branches, setBranches] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [selectedBranch, setSelectedBranch] = useState(''); const filteredBranches = branches.filter((branch) => branch.name.toLowerCase().includes(searchQuery.toLowerCase())); const fetchBranches = async () => { setIsLoading(true); setError(null); try { let response: Response; if (provider === 'github') { response = await fetch('/api/github-branches', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ owner: repoOwner, repo: repoName, token, }), }); } else { // GitLab if (!projectId) { throw new Error('Project ID is required for GitLab repositories'); } response = await fetch('/api/gitlab-branches', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token, gitlabUrl: gitlabUrl || 'https://gitlab.com', projectId, }), }); } if (!response.ok) { const errorData: any = await response.json().catch(() => ({ error: 'Failed to fetch branches' })); throw new Error(errorData.error || `HTTP ${response.status}`); } const data: any = await response.json(); setBranches(data.branches || []); // Set default selected branch const defaultBranchToSelect = data.defaultBranch || defaultBranch || 'main'; setSelectedBranch(defaultBranchToSelect); } catch (err) { console.error('Failed to fetch branches:', err); setError(err instanceof Error ? err.message : 'Failed to fetch branches'); setBranches([]); } finally { setIsLoading(false); } }; const handleBranchSelect = (branchName: string) => { setSelectedBranch(branchName); }; const handleConfirmSelection = () => { onBranchSelect(selectedBranch); onClose(); }; useEffect(() => { if (isOpen && !branches.length) { fetchBranches(); } }, [isOpen, repoOwner, repoName, projectId]); // Reset search when closing useEffect(() => { if (!isOpen) { setSearchQuery(''); } }, [isOpen]); if (!isOpen) { return null; } return (
{/* Header */}

Select Branch

{repoOwner}/{repoName}

{/* Content */}
{isLoading ? (

Loading branches...

) : error ? (

{error}

) : ( <> {/* Search */} {branches.length > 10 && (
setSearchQuery(e.target.value)} className="w-full px-3 py-2 rounded-lg bg-bolt-elements-background-depth-1 border border-bolt-elements-borderColor text-bolt-elements-textPrimary placeholder-bolt-elements-textTertiary focus:outline-none focus:ring-1 focus:ring-bolt-elements-borderColorActive" />
)} {/* Branch List */}
{filteredBranches.length > 0 ? (
{filteredBranches.map((branch) => ( ))}
) : (

{searchQuery ? 'No branches found matching your search.' : 'No branches available.'}

)}
)}
{/* Footer */} {!isLoading && !error && branches.length > 0 && (
{selectedBranch && ( <> Selected: {selectedBranch} )}
)}
); }