feat(sidebar): add worktree session button to project header (#159)

Add a dedicated button to create new worktree sessions directly from the
project header. The button appears on hover (alongside the existing menu)
for git repositories, making the worktree feature more discoverable.

- Add onNewWorktreeSession prop to SortableProjectItem
- Show git branch icon button between menu and new session button
- Button only visible for git repositories
- Uses same hover behavior as the existing project menu
This commit is contained in:
Nils
2026-01-16 18:49:46 +02:00
committed by GitHub
parent 288f0ff29f
commit 195355ae8b
@@ -134,6 +134,7 @@ interface SortableProjectItemProps {
onToggle: () => void; onToggle: () => void;
onHoverChange: (hovered: boolean) => void; onHoverChange: (hovered: boolean) => void;
onNewSession: () => void; onNewSession: () => void;
onNewWorktreeSession?: () => void;
onOpenMultiRunLauncher: () => void; onOpenMultiRunLauncher: () => void;
onClose: () => void; onClose: () => void;
sentinelRef: (el: HTMLDivElement | null) => void; sentinelRef: (el: HTMLDivElement | null) => void;
@@ -155,6 +156,7 @@ const SortableProjectItem: React.FC<SortableProjectItemProps> = ({
onToggle, onToggle,
onHoverChange, onHoverChange,
onNewSession, onNewSession,
onNewWorktreeSession,
onOpenMultiRunLauncher, onOpenMultiRunLauncher,
onClose, onClose,
sentinelRef, sentinelRef,
@@ -253,18 +255,47 @@ const SortableProjectItem: React.FC<SortableProjectItemProps> = ({
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
{/* New session button */} {isRepo && onNewWorktreeSession && (
<button <Tooltip>
type="button" <TooltipTrigger asChild>
onClick={(e) => { <button
e.stopPropagation(); type="button"
onNewSession(); onClick={(e) => {
}} e.stopPropagation();
className="inline-flex h-6 w-6 items-center justify-center text-muted-foreground hover:text-foreground flex-shrink-0 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50" onNewWorktreeSession();
aria-label="New session" }}
> className={cn(
<RiAddLine className="h-4 w-4" /> 'inline-flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 hover:text-foreground',
</button> mobileVariant ? 'opacity-70' : 'opacity-0 group-hover/project:opacity-100',
)}
aria-label="New session in worktree"
>
<RiGitBranchLine className="h-4 w-4" />
</button>
</TooltipTrigger>
<TooltipContent side="bottom" sideOffset={4}>
<p>New session in worktree</p>
</TooltipContent>
</Tooltip>
)}
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
onClick={(e) => {
e.stopPropagation();
onNewSession();
}}
className="inline-flex h-6 w-6 items-center justify-center text-muted-foreground hover:text-foreground flex-shrink-0 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
aria-label="New session"
>
<RiAddLine className="h-4 w-4" />
</button>
</TooltipTrigger>
<TooltipContent side="bottom" sideOffset={4}>
<p>New session</p>
</TooltipContent>
</Tooltip>
</div> </div>
</div> </div>
@@ -1549,6 +1580,16 @@ export const SessionSidebar: React.FC<SessionSidebarProps> = ({
openNewSessionDraft({ directoryOverride: project.normalizedPath }); openNewSessionDraft({ directoryOverride: project.normalizedPath });
} }
}} }}
onNewWorktreeSession={() => {
if (projectKey !== activeProjectId) {
setActiveProject(projectKey);
}
setActiveMainTab('chat');
if (mobileVariant) {
setSessionSwitcherOpen(false);
}
createWorktreeSession();
}}
onOpenMultiRunLauncher={() => { onOpenMultiRunLauncher={() => {
if (projectKey !== activeProjectId) { if (projectKey !== activeProjectId) {
setActiveProject(projectKey); setActiveProject(projectKey);