Files
supabase/apps/studio/components/layouts/ExplorerLayout/ExplorerNavItem.tsx
Joshen Lim 14bda8a5cf Joshenlim/fe 4438 explorer allow deleting notebookchat without first having to (#50701)
### Context

Adds context menu to the explorer nav to allow users to delete notebooks
or chats from there (instead of having to open the notebook / chat
first, then select delete from the header)
<img width="304" height="339" alt="image"
src="https://github.com/user-attachments/assets/2ad0f21c-0d49-407c-97a2-ef11ae59e280"
/>

### Changes involved:
- Consolidates the rendering of explorer nav items into a single
component that both `ExplorerNavNotebook`, `ExplorerNavHome` and
`ExplorerNavChats` use.
- We were previously rendering a link for notebook, and a button for
chats. But chats' button was just calling `router.push` under the hood.
- Opting to use a Context to handle the delete functionality such that
we can render the confirmation modal just once at the layout level since
there's multiple places that have this delete functionality - notebook
tab, chat tab, context menu in each of the explorer navs

### To test
- [ ] Verify that navigating around the explorer is status quo
- [ ] Verify that you can delete a notebook/chat from within the
notebook/chat tab
- [ ] Verify that you can delete a notebook/chat from the explorer nav
- [ ] Verify that after deleting a notebook/chat from either locations,
the tabs should clear

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Unified chat and notebook navigation with direct links and active-item
highlighting.
- Added context-menu options to delete chats and notebooks with
confirmation and status notifications.
- Added double-click support for keeping recently viewed chats and
notebooks open as tabs.
  - Deleted items and their related tabs are removed automatically.

- **Tests**
- Updated Explorer navigation tests for the unified link-based item
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-22 16:21:55 +08:00

58 lines
1.6 KiB
TypeScript

import { MessageSquare, NotebookText, Trash } from 'lucide-react'
import Link from 'next/link'
import { type CSSProperties } from 'react'
import { cn, ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from 'ui'
import { rowClassName } from './ExplorerLayout.constants'
interface ExplorerNavItemProps {
href: string
type: 'notebook' | 'chat'
name: string
description?: string
isActive?: boolean
style?: CSSProperties
onDoubleClick: () => void
onSelectDelete: () => void
}
export const ExplorerNavItem = ({
href,
type,
name,
description,
isActive = false,
style,
onDoubleClick,
onSelectDelete,
}: ExplorerNavItemProps) => {
return (
<ContextMenu modal={false}>
<ContextMenuTrigger asChild>
<Link
href={href}
className={rowClassName(isActive)}
style={style}
onDoubleClick={onDoubleClick}
>
{type === 'notebook' ? (
<NotebookText size={14} className={cn('shrink-0', isActive && 'text-foreground')} />
) : (
<MessageSquare size={14} className={cn('shrink-0', isActive && 'text-foreground')} />
)}
<span className="flex-1 truncate text-left">{name}</span>
{!!description && (
<span className="shrink-0 text-xs text-foreground-lighter">{description}</span>
)}
</Link>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem className="gap-x-2" onSelect={onSelectDelete}>
<Trash size={14} />
<span>Delete {type}</span>
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
)
}