fix: sidebar dropdown works properly for sub-sessions
This commit is contained in:
@@ -130,6 +130,30 @@ const treeContainsSessionId = (node: SessionNode, sessionId: string | null): boo
|
||||
return false;
|
||||
};
|
||||
|
||||
const treeContainsMenuKey = (
|
||||
node: SessionNode,
|
||||
menuKey: string | null,
|
||||
renderContext: 'project' | 'recent',
|
||||
archivedBucket: boolean,
|
||||
): boolean => {
|
||||
if (!menuKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const nodeMenuKey = `${renderContext}:${archivedBucket ? 'archived' : 'active'}:${node.session.id}`;
|
||||
if (nodeMenuKey === menuKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const child of node.children) {
|
||||
if (treeContainsMenuKey(child, menuKey, renderContext, archivedBucket)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const areEqual = (prev: Props, next: Props): boolean => {
|
||||
const prevSession = prev.node.session;
|
||||
const nextSession = next.node.session;
|
||||
@@ -159,9 +183,9 @@ const areEqual = (prev: Props, next: Props): boolean => {
|
||||
if (prev.editTitle !== next.editTitle && ((prev.editingId === prevSessionId) || (next.editingId === nextSessionId))) return false;
|
||||
if ((prev.copiedSessionId === prevSessionId) !== (next.copiedSessionId === nextSessionId)) return false;
|
||||
|
||||
const prevMenuKey = `${prev.renderContext ?? 'project'}:${prev.archivedBucket ? 'archived' : 'active'}:${prevSessionId}`;
|
||||
const nextMenuKey = `${next.renderContext ?? 'project'}:${next.archivedBucket ? 'archived' : 'active'}:${nextSessionId}`;
|
||||
if ((prev.openSidebarMenuKey === prevMenuKey) !== (next.openSidebarMenuKey === nextMenuKey)) return false;
|
||||
const prevMenuInTree = treeContainsMenuKey(prev.node, prev.openSidebarMenuKey, prev.renderContext ?? 'project', prev.archivedBucket ?? false);
|
||||
const nextMenuInTree = treeContainsMenuKey(next.node, next.openSidebarMenuKey, next.renderContext ?? 'project', next.archivedBucket ?? false);
|
||||
if (prevMenuInTree !== nextMenuInTree) return false;
|
||||
|
||||
const prevDirectory = normalizePath((prevSession as Session & { directory?: string | null }).directory ?? null)
|
||||
?? normalizePath(prev.groupDirectory ?? null);
|
||||
@@ -426,6 +450,18 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
||||
};
|
||||
|
||||
const handleMenuTriggerClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setOpenSidebarMenuKey(isMenuOpen ? null : menuInstanceKey);
|
||||
};
|
||||
|
||||
const handleMenuTriggerPointerDown = (event: React.PointerEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const handleMenuTriggerMouseDown = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
@@ -568,7 +604,7 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
||||
'flex min-w-0 flex-1 cursor-pointer flex-col gap-0 overflow-hidden rounded-sm text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 text-foreground select-none disabled:cursor-not-allowed transition-[padding]',
|
||||
mobileVariant
|
||||
? (isVSCode ? revealPaddingClass : 'pr-7')
|
||||
: '',
|
||||
: revealPaddingClass,
|
||||
)}
|
||||
>
|
||||
<div className={cn('flex w-full items-center min-w-0 flex-1 overflow-hidden', isMinimalMode ? 'gap-1' : 'gap-1')}>
|
||||
@@ -585,25 +621,6 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
||||
)}>
|
||||
{sessionCompactUpdatedLabel}
|
||||
</span>
|
||||
<DropdownMenu open={isMenuOpen} onOpenChange={handleMenuOpenChange}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'absolute inset-y-0 right-0 inline-flex h-4 w-4 items-center justify-center rounded-md text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 transition-opacity',
|
||||
isMenuOpen
|
||||
? 'opacity-100 pointer-events-auto'
|
||||
: cn('opacity-0 pointer-events-none', revealOnHoverClass),
|
||||
)}
|
||||
aria-label="Session menu"
|
||||
onClick={handleMenuTriggerClick}
|
||||
onKeyDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<RiMore2Line className="h-2.5 w-2.5" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
{sessionMenuContent}
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
) : null}
|
||||
{pendingPermissionCount > 0 ? (
|
||||
@@ -683,41 +700,38 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{!isMinimalMode || mobileVariant ? (
|
||||
<div className={cn(
|
||||
'absolute right-0 top-1/2 z-10 -translate-y-1/2',
|
||||
cn(
|
||||
'transition-opacity',
|
||||
isMenuOpen
|
||||
? 'opacity-100 pointer-events-auto'
|
||||
: (mobileVariant && !isVSCode)
|
||||
? 'opacity-100 pointer-events-auto'
|
||||
: cn('opacity-0 pointer-events-none', revealOnHoverClass),
|
||||
),
|
||||
)}>
|
||||
<DropdownMenu open={isMenuOpen} onOpenChange={handleMenuOpenChange}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'inline-flex items-center justify-center rounded-md text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 transition-opacity',
|
||||
isMinimalMode && !mobileVariant
|
||||
? (isMenuOpen
|
||||
? 'h-4 w-4 opacity-100 pointer-events-auto'
|
||||
: cn('h-4 w-4 opacity-0 pointer-events-none', revealOnHoverClass))
|
||||
: 'h-6 w-6 opacity-100',
|
||||
)}
|
||||
aria-label="Session menu"
|
||||
onClick={handleMenuTriggerClick}
|
||||
onKeyDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<RiMore2Line className={cn(isMinimalMode && !mobileVariant ? 'h-2.5 w-2.5' : 'h-3.5 w-3.5')} />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
{sessionMenuContent}
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
) : null}
|
||||
<div className={cn(
|
||||
'absolute right-0 top-1/2 z-10 -translate-y-1/2 transition-opacity',
|
||||
isMenuOpen
|
||||
? 'opacity-100'
|
||||
: (mobileVariant && !isVSCode)
|
||||
? 'opacity-100'
|
||||
: cn('opacity-0', revealOnHoverClass),
|
||||
)}>
|
||||
<DropdownMenu open={isMenuOpen} onOpenChange={handleMenuOpenChange}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'inline-flex items-center justify-center rounded-md text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 transition-opacity',
|
||||
isMinimalMode && !mobileVariant
|
||||
? (isMenuOpen
|
||||
? 'h-4 w-4 opacity-100'
|
||||
: cn('h-4 w-4 opacity-0', revealOnHoverClass))
|
||||
: 'h-6 w-6 opacity-100',
|
||||
)}
|
||||
aria-label="Session menu"
|
||||
onPointerDown={handleMenuTriggerPointerDown}
|
||||
onMouseDown={handleMenuTriggerMouseDown}
|
||||
onClick={handleMenuTriggerClick}
|
||||
onKeyDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<RiMore2Line className={cn(isMinimalMode && !mobileVariant ? 'h-2.5 w-2.5' : 'h-3.5 w-3.5')} />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
{sessionMenuContent}
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
</DraggableSessionRow>
|
||||
{hasChildren && isExpanded
|
||||
|
||||
@@ -118,6 +118,14 @@ export const SortableProjectItem: React.FC<SortableProjectItemProps> = ({
|
||||
event.stopPropagation();
|
||||
}, []);
|
||||
|
||||
const handleMenuTriggerPointerDown = React.useCallback((event: React.PointerEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation();
|
||||
}, []);
|
||||
|
||||
const handleMenuTriggerMouseDown = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation();
|
||||
}, []);
|
||||
|
||||
const handleToggleMouseDown = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
if (event.button === 2 || (event.button === 0 && event.ctrlKey)) {
|
||||
suppressNextToggleRef.current = true;
|
||||
@@ -250,6 +258,8 @@ export const SortableProjectItem: React.FC<SortableProjectItemProps> = ({
|
||||
: 'opacity-0 pointer-events-none group-hover/project:opacity-100 group-hover/project:pointer-events-auto group-focus-within/project:opacity-100 group-focus-within/project:pointer-events-auto',
|
||||
)}
|
||||
aria-label="Project menu"
|
||||
onPointerDown={handleMenuTriggerPointerDown}
|
||||
onMouseDown={handleMenuTriggerMouseDown}
|
||||
onClick={handleMenuTriggerClick}
|
||||
>
|
||||
<RiMore2Line className="h-3.5 w-3.5" />
|
||||
|
||||
Reference in New Issue
Block a user