import React from 'react'; import { RiGitBranchLine, RiEditLine, RiCheckLine, RiCloseLine, RiLoader4Line } from '@remixicon/react'; import { Button } from '@/components/ui/button'; interface WorktreeBranchDisplayProps { currentBranch: string | null | undefined; onRename?: (oldName: string, newName: string) => Promise; } const sanitizeBranchNameInput = (value: string): string => { return value .trim() .replace(/\s+/g, '-') .replace(/[^A-Za-z0-9._/-]/g, '-') .replace(/-+/g, '-') .replace(/\/{2,}/g, '/') .replace(/\/-+/g, '/') .replace(/-+\//g, '/') .replace(/^[-/]+/, '') .replace(/[-/]+$/, ''); }; export const WorktreeBranchDisplay: React.FC = ({ currentBranch, onRename, }) => { const [isEditing, setIsEditing] = React.useState(false); const [editBranchName, setEditBranchName] = React.useState(currentBranch || ''); const [isRenaming, setIsRenaming] = React.useState(false); const inputRef = React.useRef(null); const handleStartEdit = () => { if (!currentBranch || !onRename) return; setEditBranchName(currentBranch); setIsEditing(true); // Focus input after state update setTimeout(() => inputRef.current?.focus(), 0); }; const handleSaveEdit = async () => { if (!currentBranch || !onRename || !editBranchName.trim()) return; const sanitizedName = sanitizeBranchNameInput(editBranchName); if (sanitizedName === currentBranch) { setIsEditing(false); return; } setIsRenaming(true); try { await onRename(currentBranch, sanitizedName); setIsEditing(false); setEditBranchName(''); } finally { setIsRenaming(false); } }; const handleCancelEdit = () => { setIsEditing(false); setEditBranchName(''); }; // Handle Enter key to save, Escape to cancel const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { e.preventDefault(); handleSaveEdit(); } else if (e.key === 'Escape') { e.preventDefault(); handleCancelEdit(); } }; if (isEditing) { return (
{ e.preventDefault(); handleSaveEdit(); }} > setEditBranchName(e.target.value)} className="flex-1 min-w-0 bg-transparent typography-ui-label outline-none placeholder:text-muted-foreground" placeholder="Branch name" onKeyDown={handleKeyDown} autoFocus />
); } return (
{currentBranch || 'Detached HEAD'}
{onRename && currentBranch && ( )}
); };