"use client"; import { memo, useCallback } from "react"; import Link from "next/link"; import { IconBug, IconHome, IconSettings } from "@tabler/icons-react"; import { Button } from "@kandev/ui/button"; import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, } from "@kandev/ui/breadcrumb"; import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip"; import { CommitStatBadge } from "@/components/diff-stat"; import { useSessionGit } from "@/hooks/domains/session/use-session-git"; import { EditorsMenu } from "@/components/task/editors-menu"; import { BranchPathPopover } from "@/components/task/branch-path-popover"; import { LayoutPresetSelector } from "@/components/task/layout-preset-selector"; import { DocumentControls } from "@/components/task/document/document-controls"; import { VcsSplitButton } from "@/components/vcs-split-button"; import { PRTopbarButton } from "@/components/github/pr-topbar-button"; import { PortForwardButton } from "@/components/task/port-forward-dialog"; import { WorkflowStepper, type WorkflowStepperStep } from "@/components/task/workflow-stepper"; import { RemoteCloudTooltip } from "@/components/task/remote-cloud-tooltip"; import { QuickChatButton } from "@/components/task/quick-chat-button"; import { DEBUG_UI } from "@/lib/config"; import { toast } from "sonner"; type TaskTopBarProps = { taskId?: string | null; activeSessionId?: string | null; taskTitle?: string; baseBranch?: string; onStartAgent?: (agentProfileId: string) => void; onStopAgent?: () => void; isAgentRunning?: boolean; isAgentLoading?: boolean; worktreePath?: string | null; worktreeBranch?: string | null; repositoryPath?: string | null; repositoryName?: string | null; showDebugOverlay?: boolean; onToggleDebugOverlay?: () => void; workflowSteps?: WorkflowStepperStep[]; currentStepId?: string | null; workflowId?: string | null; workspaceId?: string | null; isArchived?: boolean; isRemoteExecutor?: boolean; isAgentctlReady?: boolean; remoteExecutorName?: string | null; remoteExecutorType?: string | null; remoteState?: string | null; remoteCreatedAt?: string | null; remoteCheckedAt?: string | null; remoteStatusError?: string | null; }; const TaskTopBar = memo(function TaskTopBar({ taskId, activeSessionId, taskTitle, baseBranch, worktreePath, worktreeBranch, repositoryPath, repositoryName, showDebugOverlay, onToggleDebugOverlay, workflowSteps, currentStepId, workflowId, workspaceId, isArchived, isRemoteExecutor, isAgentctlReady, remoteExecutorName, remoteExecutorType, remoteState, remoteCreatedAt, remoteCheckedAt, remoteStatusError, }: TaskTopBarProps) { const git = useSessionGit(activeSessionId); // Prefer live git status branch (updates after rename), fallback to session worktree branch const displayBranch = git.branch || worktreeBranch || baseBranch; // Callback for renaming branch const handleRenameBranch = useCallback( async (newName: string) => { const result = await git.renameBranch(newName); if (result.success) { toast.success(`Branch renamed to "${newName}"`); } else { const msg = result.error || "Failed to rename branch"; toast.error(msg); throw new Error(msg); } }, [git], ); return (
{workflowSteps && workflowSteps.length > 0 && ( )}
); }); /** Left section: breadcrumbs, branch pill */ function TopBarLeft({ taskId, activeSessionId, taskTitle, repositoryName, displayBranch, repositoryPath, worktreePath, isRemoteExecutor, remoteExecutorName, remoteExecutorType, remoteState, remoteCreatedAt, remoteCheckedAt, remoteStatusError, onRenameBranch, }: { taskId?: string | null; activeSessionId?: string | null; taskTitle?: string; repositoryName?: string | null; displayBranch?: string; repositoryPath?: string | null; worktreePath?: string | null; isRemoteExecutor?: boolean; remoteExecutorName?: string | null; remoteExecutorType?: string | null; remoteState?: string | null; remoteCreatedAt?: string | null; remoteCheckedAt?: string | null; remoteStatusError?: string | null; onRenameBranch?: (newName: string) => Promise; }) { return (
{repositoryName && ( <> {repositoryName} {repositoryName} )} {taskTitle ?? "Task details"} {taskTitle ?? "Task details"}
{isRemoteExecutor && ( )}
); } /** Ahead/Behind commit status badges */ function GitAheadBehindBadges({ gitStatus, baseBranch, }: { gitStatus: { ahead: number; behind: number }; baseBranch?: string; }) { const ahead = gitStatus?.ahead ?? 0; const behind = gitStatus?.behind ?? 0; if (ahead === 0 && behind === 0) return null; const compareRef = baseBranch || "main"; return (
{ahead > 0 && ( {ahead} commit{ahead !== 1 ? "s" : ""} ahead of {compareRef} )} {behind > 0 && ( {behind} commit{behind !== 1 ? "s" : ""} behind {compareRef} )}
); } /** Right section: git badges, debug toggle, document controls, editors, VCS, settings */ function TopBarRight({ activeSessionId, baseBranch, gitStatus, showDebugOverlay, onToggleDebugOverlay, isArchived, workspaceId, isRemoteExecutor, isAgentctlReady, }: { activeSessionId?: string | null; baseBranch?: string; gitStatus: { ahead: number; behind: number }; showDebugOverlay?: boolean; onToggleDebugOverlay?: () => void; isArchived?: boolean; workspaceId?: string | null; isRemoteExecutor?: boolean; isAgentctlReady?: boolean; }) { return (
{DEBUG_UI && onToggleDebugOverlay && ( {showDebugOverlay ? "Hide Debug Info" : "Show Debug Info"} )} {!isArchived && ( <> )} Settings
); } export { TaskTopBar };