import React, { useState, useCallback, useEffect, useMemo } from "react" import { GitBranch, Check, ChevronDown, Plus } from "lucide-react" import type { Worktree, WorktreeListResponse } from "@roo-code/types" import { cn } from "@/lib/utils" import { useRooPortal } from "@/components/ui/hooks/useRooPortal" import { Popover, PopoverContent, PopoverTrigger, StandardTooltip, Button } from "@/components/ui" import { useAppTranslation } from "@/i18n/TranslationContext" import { vscode } from "@/utils/vscode" import { CreateWorktreeModal } from "../worktrees/CreateWorktreeModal" import { IconButton } from "./IconButton" interface WorktreeSelectorProps { disabled?: boolean } export const WorktreeSelector = ({ disabled = false }: WorktreeSelectorProps) => { const { t } = useAppTranslation() const [open, setOpen] = useState(false) const [worktrees, setWorktrees] = useState([]) const [isGitRepo, setIsGitRepo] = useState(true) const [showCreateModal, setShowCreateModal] = useState(false) const portalContainer = useRooPortal("roo-portal") // Find current worktree const currentWorktree = useMemo(() => worktrees.find((w) => w.isCurrent), [worktrees]) // Fetch worktrees when popover opens const fetchWorktrees = useCallback(() => { vscode.postMessage({ type: "listWorktrees" }) }, []) // Handle messages from extension useEffect(() => { const handleMessage = (event: MessageEvent) => { const message = event.data if (message.type === "worktreeList") { const response: WorktreeListResponse = message setWorktrees(response.worktrees || []) setIsGitRepo(response.isGitRepo) } } window.addEventListener("message", handleMessage) return () => window.removeEventListener("message", handleMessage) }, []) // Initial fetch and refresh on open useEffect(() => { fetchWorktrees() }, [fetchWorktrees]) useEffect(() => { if (open) { fetchWorktrees() } }, [open, fetchWorktrees]) const handleSelect = useCallback((worktreePath: string) => { vscode.postMessage({ type: "switchWorktree", worktreePath: worktreePath, worktreeNewWindow: false, }) setOpen(false) }, []) const handleSettingsClick = useCallback(() => { vscode.postMessage({ type: "switchTab", tab: "settings", values: { section: "worktrees" }, }) setOpen(false) }, []) // Don't render if not a git repo or only one worktree if (!isGitRepo || worktrees.length <= 1) { return null } const title = t("worktrees:selector.tooltip") return ( {t("worktrees:selector.worktree")}: {currentWorktree?.branch || t("worktrees:noBranch")}
{/* Bottom bar with settings cog and title */}

{t("worktrees:selector.title")}

{t("worktrees:selector.description")}

{/* Worktree list */}
{worktrees.map((worktree) => { const isSelected = worktree.isCurrent return (
!isSelected && handleSelect(worktree.path)} data-testid="worktree-selector-item" className={cn( "px-3 py-1.5 text-sm cursor-pointer flex items-center", "hover:bg-vscode-list-hoverBackground", isSelected && "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground", )}>
{worktree.branch || t("worktrees:noBranch")} {worktree.isBare && ( {t("worktrees:primary")} )}
{worktree.path}
{isSelected && }
) })}
{/* New worktree button */}
{/* Create Worktree Modal */} {showCreateModal && ( setShowCreateModal(false)} openAfterCreate={true} onSuccess={() => { setShowCreateModal(false) fetchWorktrees() }} /> )}
) }