Files
supabase/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.utils.tsx
Joshen Lim 42f1344303 Ensure logs pages are accessible irregardless of project's status (#43010)
## Context

Ensure that project's logs pages are accessible irregardless of
project's status, given that logs are mutually exclusive from the
project's database and doesn't require the database to be online for it
to be functional.

## Other changes
Mainly around simplifying some logic within ProjectLayout
- Remove `disabled` prop in `SideBarNavLink` component, given that
`route` prop already has a `disabled` param
- Define `disabled` within `NavigationBar.utils.tsx` -> just have one
place to define the "configuration" of a route
- Minimize manually declaring specific routes to render specific UI (for
Restore failed)
  - All of these can be grouped under `routesToIgnoreDBConnection`

## To test
- [ ] Verify that you can access the logs page while the project is
coming up
- [ ] Verify that you can access the logs page on a paused project (and
also use it)
2026-02-19 17:53:45 +08:00

207 lines
7.0 KiB
TypeScript

import { ICON_SIZE, ICON_STROKE_WIDTH } from 'components/interfaces/Sidebar'
import { generateAuthMenu } from 'components/layouts/AuthLayout/AuthLayout.utils'
import { generateDatabaseMenu } from 'components/layouts/DatabaseLayout/DatabaseMenu.utils'
import { generateSettingsMenu } from 'components/layouts/ProjectSettingsLayout/SettingsMenu.utils'
import type { Route } from 'components/ui/ui.types'
import { EditorIndexPageLink } from 'data/prefetchers/project.$ref.editor'
import type { Project } from 'data/projects/project-detail-query'
import { Auth, Database, EdgeFunctions, Realtime, SqlEditor, Storage, TableEditor } from 'icons'
import { IS_PLATFORM, PROJECT_STATUS } from 'lib/constants'
import { Blocks, FileText, Lightbulb, List, Settings, Telescope } from 'lucide-react'
export const generateToolRoutes = (ref?: string, project?: Project, features?: {}): Route[] => {
const isProjectActive = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY
const isProjectBuilding = project?.status === PROJECT_STATUS.COMING_UP
const buildingUrl = `/project/${ref}`
return [
{
key: 'editor',
label: 'Table Editor',
disabled: !isProjectActive,
icon: <TableEditor size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/editor`),
linkElement: <EditorIndexPageLink projectRef={ref} />,
},
{
key: 'sql',
label: 'SQL Editor',
disabled: !isProjectActive,
icon: <SqlEditor size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/sql`),
},
]
}
export const generateProductRoutes = (
ref?: string,
project?: Project,
features?: {
auth?: boolean
edgeFunctions?: boolean
storage?: boolean
realtime?: boolean
authOverviewPage?: boolean
}
): Route[] => {
const isProjectActive = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY
const isProjectBuilding = project?.status === PROJECT_STATUS.COMING_UP
const buildingUrl = `/project/${ref}`
const authEnabled = features?.auth ?? true
const edgeFunctionsEnabled = features?.edgeFunctions ?? true
const storageEnabled = features?.storage ?? true
const realtimeEnabled = features?.realtime ?? true
const authOverviewPageEnabled = features?.authOverviewPage ?? false
const databaseMenu = generateDatabaseMenu(project)
const authMenu = generateAuthMenu(ref as string)
return [
{
key: 'database',
label: 'Database',
disabled: !isProjectActive,
icon: <Database size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link:
ref &&
(isProjectBuilding
? buildingUrl
: isProjectActive
? `/project/${ref}/database/schemas`
: `/project/${ref}/database/backups/scheduled`),
items: databaseMenu,
},
...(authEnabled
? [
{
key: 'auth',
label: 'Authentication',
disabled: !isProjectActive,
icon: <Auth size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link:
ref &&
(isProjectBuilding
? buildingUrl
: authOverviewPageEnabled
? `/project/${ref}/auth/overview`
: `/project/${ref}/auth/users`),
items: authMenu,
},
]
: []),
...(storageEnabled
? [
{
key: 'storage',
label: 'Storage',
disabled: !isProjectActive,
icon: <Storage size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/storage/files`),
},
]
: []),
...(edgeFunctionsEnabled
? [
{
key: 'functions',
label: 'Edge Functions',
disabled: false,
icon: <EdgeFunctions size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && `/project/${ref}/functions`,
},
]
: []),
...(realtimeEnabled
? [
{
key: 'realtime',
label: 'Realtime',
disabled: !isProjectActive,
icon: <Realtime size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/realtime/inspector`),
},
]
: []),
]
}
export const generateOtherRoutes = (
ref?: string,
project?: Project,
features?: { unifiedLogs?: boolean; showReports?: boolean; apiDocsSidePanel?: boolean }
): Route[] => {
const isProjectActive = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY
const isProjectBuilding = project?.status === PROJECT_STATUS.COMING_UP
const buildingUrl = `/project/${ref}`
const { unifiedLogs, showReports, apiDocsSidePanel } = features ?? {}
const unifiedLogsEnabled = unifiedLogs ?? false
const reportsEnabled = showReports ?? true
const apiDocsSidePanelEnabled = apiDocsSidePanel ?? false
return [
{
key: 'advisors',
label: 'Advisors',
disabled: !isProjectActive,
icon: <Lightbulb size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/advisors/security`),
},
...(IS_PLATFORM && reportsEnabled
? [
{
key: 'observability',
label: 'Observability',
disabled: !isProjectActive,
icon: <Telescope size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/observability`),
},
]
: []),
{
key: 'logs',
label: 'Logs',
disabled: false,
icon: <List size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && (unifiedLogsEnabled ? `/project/${ref}/logs` : `/project/${ref}/logs/explorer`),
},
...(apiDocsSidePanelEnabled
? [
{
key: 'api',
label: 'API Docs',
disabled: !isProjectActive,
icon: <FileText size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link:
ref &&
(isProjectBuilding ? buildingUrl : `/project/${ref}/integrations/data_api/docs`),
},
]
: []),
{
key: 'integrations',
label: 'Integrations',
disabled: !isProjectActive,
icon: <Blocks size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/integrations`),
},
]
}
export const generateSettingsRoutes = (ref?: string, project?: Project): Route[] => {
const settingsMenu = generateSettingsMenu(ref as string)
return [
{
key: 'settings',
label: 'Project Settings',
icon: <Settings size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link:
ref &&
(IS_PLATFORM ? `/project/${ref}/settings/general` : `/project/${ref}/settings/log-drains`),
items: settingsMenu,
disabled: false,
},
]
}