import { DndContext, DragEndEvent, DragOverlay, PointerSensor, useSensor, useSensors, } from '@dnd-kit/core' import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable' import { useParams } from 'common' import { AnimatePresence, motion } from 'framer-motion' import { Plus, X } from 'lucide-react' import { useRouter } from 'next/router' import { cn, ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger, Tabs_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_, } from 'ui' import { useEditorType } from '../editors/EditorsLayout.hooks' import { CollapseButton } from './CollapseButton' import { SortableTab } from './SortableTab' import { TabPreview } from './TabPreview' import { useTabsScroll } from './Tabs.utils' import { useDashboardHistory } from '@/hooks/misc/useDashboardHistory' import { editorEntityTypes, useTabsStateSnapshot, type Tab } from '@/state/tabs' export const EditorTabs = () => { const { ref, id } = useParams() const router = useRouter() const { setLastVisitedSnippet, setLastVisitedTable } = useDashboardHistory() const editor = useEditorType() const tabs = useTabsStateSnapshot() const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 1, // Start with a very small distance }, }) ) const openTabs = tabs.openTabs .map((id) => tabs.tabsMap[id]) .filter((tab) => tab !== undefined) as Tab[] const hasNewTab = router.asPath.includes('/new') // Filter by editor type - only show SQL tabs for SQL editor and table tabs for table editor const editorTabs = !!editor ? openTabs.filter((tab) => editorEntityTypes[editor]?.includes(tab.type)) : [] const handleDragEnd = (event: DragEndEvent) => { const { active, over } = event if (!over || active.id === over.id) return const oldIndex = tabs.openTabs.indexOf(active.id.toString()) const newIndex = tabs.openTabs.indexOf(over.id.toString()) if (oldIndex !== newIndex) { tabs.handleTabDragEnd(oldIndex, newIndex, active.id.toString(), router) } } const onClearDashboardHistory = () => { if (editor === 'table') { setLastVisitedTable(undefined) } else if (editor === 'sql') { setLastVisitedSnippet(undefined) } } const handleClose = (tabId: string) => { tabs.handleTabClose({ id: tabId, router, editor, onClearDashboardHistory }) } const handleCloseAll = () => { if (editor) { const tabsToClose = editor === 'table' ? tabs.openTabs.filter((x) => !x.startsWith('sql')) : tabs.openTabs.filter((x) => x.startsWith('sql')) tabs.removeTabs(tabsToClose) onClearDashboardHistory() router.push(`/project/${ref}/${editor === 'table' ? 'editor' : 'sql'}`) } } const handleCloseOthers = (tabId: string) => { if (editor) { const tabsToClose = editor === 'table' ? tabs.openTabs.filter((x) => !x.startsWith('sql') && x !== tabId) : tabs.openTabs.filter((x) => x.startsWith('sql') && x !== tabId) tabs.removeTabs(tabsToClose) onClearDashboardHistory() const entityId = editor === 'table' ? tabId.split('-')[1] : tabId.split('sql-')[1] if (id !== entityId) { router.push(`/project/${ref}/${editor === 'table' ? 'editor' : 'sql'}/${entityId}`) } } } const handleCloseRight = (tabId: string) => { if (editor) { const openedTabs = editor === 'table' ? tabs.openTabs.filter((x) => !x.startsWith('sql')) : tabs.openTabs.filter((x) => x.startsWith('sql')) const tabIdx = openedTabs.indexOf(tabId) const activeTabIdx = openedTabs.indexOf(tabs.activeTab!) const tabsToClose = openedTabs.slice(tabIdx + 1) tabs.removeTabs(tabsToClose) const isActiveTabClosed = tabIdx < activeTabIdx if (isActiveTabClosed) { const id = editor === 'table' ? tabId.split('-')[1] : tabId.split('sql-')[1] router.push(`/project/${ref}/${editor === 'table' ? 'editor' : 'sql'}/${id}`) } } } const handleTabChange = (id: string) => { tabs.handleTabNavigation(id, router) } const { tabsListRef } = useTabsScroll({ activeTab: tabs.activeTab, tabCount: editorTabs.length }) return ( tab.id)} strategy={horizontalListSortingStrategy} > {editorTabs.map((tab, index) => ( handleClose(tab.id)} /> handleClose(tab.id)}>Close handleCloseOthers(tab.id)}> Close Others handleCloseRight(tab.id)}> Close to the Right Close All ))} {/* Non-draggable new tab */} {hasNewTab && (
New
{ e.preventDefault() e.stopPropagation() }} className="ml-1 opacity-0 group-hover:opacity-100 hover:bg-200 rounded-xs cursor-pointer" onMouseDown={(e) => { e.preventDefault() e.stopPropagation() }} onPointerDown={(e) => { e.preventDefault() e.stopPropagation() handleClose('new') }} > {' '}
)} {!hasNewTab && ( router.push( `/project/${router.query.ref}/${editor === 'table' ? 'editor' : 'sql'}/new?skip=true` ) } initial={{ opacity: 0, scale: 0.8, x: -10 }} animate={{ opacity: 1, scale: 1, x: 0 }} transition={{ duration: 0.2 }} > )}
{tabs.activeTab ? : null} ) }