import { Home, User } from 'icons'
import { isUndefined } from 'lodash'
import { Command, FileText, FlaskConical, Search, Settings } from 'lucide-react'
import { useTheme } from 'next-themes'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useState } from 'react'
import { useParams } from 'common'
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import { useProjectLintsQuery } from 'data/lint/lint-query'
import { ProjectIndexPageLink } from 'data/prefetchers/project.$ref'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
import { useFlag } from 'hooks/ui/useFlag'
import { useSignOut } from 'lib/auth'
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
import { useProfile } from 'lib/profile'
import { useAppStateSnapshot } from 'state/app-state'
import {
AiIconAnimation,
Button,
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
HoverCardContent_Shadcn_,
HoverCardTrigger_Shadcn_,
HoverCard_Shadcn_,
Separator,
Theme,
Tooltip,
TooltipContent,
TooltipTrigger,
cn,
singleThemes,
} from 'ui'
import { useSetCommandMenuOpen } from 'ui-patterns/CommandMenu'
import { useProjectContext } from '../ProjectContext'
import { CommandOption } from './CommandOption'
import {
generateOtherRoutes,
generateProductRoutes,
generateSettingsRoutes,
generateToolRoutes,
} from './NavigationBar.utils'
import { NavigationIconButton } from './NavigationIconButton'
import NavigationIconLink from './NavigationIconLink'
export const ICON_SIZE = 20
export const ICON_STROKE_WIDTH = 1.5
const NavigationBar = () => {
const snap = useAppStateSnapshot()
const [userDropdownOpen, setUserDropdownOpenState] = useState(false)
const [storedAllowNavPanel] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.EXPAND_NAVIGATION_PANEL,
true
)
// Don't allow the nav panel to expand in playwright tests
const allowNavPanelToExpand = process.env.NEXT_PUBLIC_NODE_ENV !== 'test' && storedAllowNavPanel
return (
)
}
export const NavContent = () => {
const router = useRouter()
const { profile } = useProfile()
const { project } = useProjectContext()
const { theme, setTheme } = useTheme()
const { ref: projectRef } = useParams()
const setCommandMenuOpen = useSetCommandMenuOpen()
const snap = useAppStateSnapshot()
const signOut = useSignOut()
const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled()
const [userDropdownOpen, setUserDropdownOpenState] = useState(false)
const [storedAllowNavPanel] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.EXPAND_NAVIGATION_PANEL,
true
)
// Don't allow the nav panel to expand in playwright tests
const allowNavPanelToExpand = process.env.NEXT_PUBLIC_NODE_ENV !== 'test' && storedAllowNavPanel
const {
projectAuthAll: authEnabled,
projectEdgeFunctionAll: edgeFunctionsEnabled,
projectStorageAll: storageEnabled,
realtimeAll: realtimeEnabled,
} = useIsFeatureEnabled([
'project_auth:all',
'project_edge_function:all',
'project_storage:all',
'realtime:all',
])
const { data } = useProjectLintsQuery({
projectRef: project?.ref,
})
const securityLints = (data ?? []).filter((lint) => lint.categories.includes('SECURITY'))
const errorLints = securityLints.filter((lint) => lint.level === 'ERROR')
const activeRoute = router.pathname.split('/')[3]
const toolRoutes = generateToolRoutes(projectRef, project)
const productRoutes = generateProductRoutes(projectRef, project, {
auth: authEnabled,
edgeFunctions: edgeFunctionsEnabled,
storage: storageEnabled,
realtime: realtimeEnabled,
})
const showWarehouse = useFlag('warehouse')
const otherRoutes = generateOtherRoutes(projectRef, project)
const settingsRoutes = generateSettingsRoutes(projectRef, project)
const onCloseNavigationIconLink = (event: any) => {
snap.setNavigationPanelOpen(
false,
event.target.id === 'icon-link' || ['svg', 'path'].includes(event.target.localName)
)
}
const CommandButton = (
}
>
Commands
}
label="Search"
shortcut="K"
onClick={() => {
setCommandMenuOpen(true)
snap.setNavigationPanelOpen(false)
}}
/>
}
label="Assistant"
shortcut="I"
onClick={() => {
snap.setAiAssistantPanel({ open: !snap.aiAssistantPanel.open })
}}
/>
)
const UserAccountButton = (
)
return (
<>
,
link: `/project/${projectRef}`,
linkElement: ,
}}
onClick={onCloseNavigationIconLink}
/>
{toolRoutes.map((route) => (
))}
{productRoutes.map((route) => (
))}
{otherRoutes.map((route) => {
if (route.key === 'api' && isNewAPIDocsEnabled) {
return (
{
snap.setShowProjectApiDocs(true)
snap.setNavigationPanelOpen(false)
}}
icon={}
>
Project API
)
} else if (route.key === 'advisors') {
return (
{securityLints.length > 0 && (
0 ? 'bg-destructive-600' : 'bg-warning-600'
)}
/>
)}
)
} else if (route.key === 'logs') {
// TODO: Undo this when warehouse flag is removed
const label = showWarehouse ? 'Logs & Analytics' : route.label
const newRoute = { ...route, label }
return (
)
} else {
return (
)
}
})}
{settingsRoutes.map((route) => (
))}
{IS_PLATFORM && (
<>
{!allowNavPanelToExpand && (
{CommandButton}
Commands
)}
{allowNavPanelToExpand && CommandButton}
>
)}
{
setUserDropdownOpenState(open)
if (open === false) snap.setNavigationPanelOpen(false)
}}
>
{allowNavPanelToExpand ? (
{UserAccountButton}
) : (
{UserAccountButton}
Account settings
)}
{IS_PLATFORM && (
<>
{profile && (
<>
{profile.username}
{profile.primary_email !== profile.username && (
{profile.primary_email}
)}
>
)}
Account preferences
snap.setShowFeaturePreviewModal(true)}
onSelect={() => snap.setShowFeaturePreviewModal(true)}
>
Feature previews
>
)}
Theme
{
setTheme(value)
}}
>
{singleThemes.map((theme: Theme) => (
{theme.name}
))}
{IS_PLATFORM && (
<>
{
await signOut()
await router.push('/sign-in')
}}
>
Log out
>
)}
>
)
}
export default NavigationBar