import type { WritableComputedRef } from '@vue/reactivity' import { navigateTo, useProject, useRoute, useState } from '#imports' import type { RouterConfig } from '@nuxt/schema' export enum TabType { TABLE = 'table', VIEW = 'view', AUTH = 'auth', } export interface TabItem { type: TabType title: string id?: string viewTitle?: string viewId?: string } function getPredicate(key: Partial) { return (tab: TabItem) => (!('id' in key) || tab.id === key.id) && (!('title' in key) || tab.title === key.title) && (!('type' in key) || tab.type === key.type) } export function useTabs() { const tabs = useState('tabs', () => []) const route = useRoute() const router = useRouter() const { tables } = useProject() const projectType = $computed(() => route.params.projectType as string) const activeTabIndex: WritableComputedRef = computed({ get() { if ((route.name as string)?.startsWith('projectType-projectId-index-index-type-title-viewTitle') && tables.value?.length) { const tab: Partial = { type: route.params.type as TabType, title: route.params.title as string } const id = tables.value?.find((t) => t.title === tab.title)?.id if (!id) return -1 tab.id = id as string let index = tabs.value.findIndex((t) => t.id === tab.id) if (index === -1) { tabs.value.push(tab as TabItem) index = tabs.value.length - 1 } return index } else if ((route.name as string)?.startsWith('nc-projectId-index-index-auth')) { return tabs.value.findIndex((t) => t.type === 'auth') } return -1 }, set(index: number) { if (index === -1) { navigateTo(`/${projectType}/${route.params.projectId}`) } else { const tab = tabs.value[index] if (!tab) return return navigateToTab(tab) } }, }) const activeTab = computed(() => tabs.value?.[activeTabIndex.value]) const addTab = (tabMeta: TabItem) => { const tabIndex = tabs.value.findIndex((tab) => tab.id === tabMeta.id) // if tab already found make it active if (tabIndex > -1) { activeTabIndex.value = tabIndex } // if tab not found add it else { tabs.value = [...(tabs.value || []), tabMeta] activeTabIndex.value = tabs.value.length - 1 } } const clearTabs = () => { tabs.value = [] } const closeTab = async (key: number | Partial) => { const index = typeof key === 'number' ? key : tabs.value.findIndex(getPredicate(key)) if (activeTabIndex.value === index) { let newTabIndex = index - 1 if (newTabIndex < 0 && tabs.value?.length > 1) newTabIndex = index + 1 if (newTabIndex === -1) { await navigateTo(`/${projectType}/${route.params.projectId}`) } else { await navigateToTab(tabs.value?.[newTabIndex]) } } tabs.value.splice(index, 1) } function navigateToTab(tab: TabItem) { switch (tab.type) { case TabType.TABLE: return navigateTo( `/${projectType}/${route.params.projectId}/table/${tab?.title}${tab.viewTitle ? `/${tab.viewTitle}` : ''}`, ) case TabType.VIEW: return navigateTo( `/${projectType}/${route.params.projectId}/view/${tab?.title}${tab.viewTitle ? `/${tab.viewTitle}` : ''}`, ) case TabType.AUTH: return navigateTo(`/${projectType}/${route.params.projectId}/auth`) } } const updateTab = (key: number | Partial, newTabItemProps: Partial) => { const tab = typeof key === 'number' ? tabs.value[key] : tabs.value.find(getPredicate(key)) if (tab) { const isActive = tabs.value.indexOf(tab) === activeTabIndex.value Object.assign(tab, newTabItemProps) if (isActive && tab.title) router.replace({ params: { title: tab.title, }, }) } } return { tabs, addTab, activeTabIndex, activeTab, clearTabs, closeTab, updateTab } }