mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 20:35:07 +03:00
235 lines
7.0 KiB
TypeScript
235 lines
7.0 KiB
TypeScript
import { useBranchesQuery } from 'data/branches/branches-query'
|
|
import { useEdgeFunctionServiceStatusQuery } from 'data/service-status/edge-functions-status-query'
|
|
import { useProjectServiceStatusQuery } from 'data/service-status/service-status-query'
|
|
import dayjs from 'dayjs'
|
|
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
|
|
import { DOCS_URL } from 'lib/constants'
|
|
|
|
import { extractDbSchema, type ProjectServiceStatus } from '../Home/ServiceStatus'
|
|
|
|
export const SERVICE_STATUS_THRESHOLD_MINUTES = 5
|
|
|
|
export type ProjectHomeServiceStatusProject = {
|
|
ref: string
|
|
parentRef: string
|
|
status?: string
|
|
inserted_at?: string
|
|
} | undefined
|
|
|
|
export type ProjectHomeServiceRow = {
|
|
name: string
|
|
error?: string
|
|
docsUrl?: string
|
|
isLoading: boolean
|
|
status: ProjectServiceStatus
|
|
logsUrl: string
|
|
}
|
|
|
|
export type ProjectHomeServiceStatusModel = {
|
|
services: ProjectHomeServiceRow[]
|
|
isLoadingChecks: boolean
|
|
allServicesOperational: boolean
|
|
isProjectNew: boolean
|
|
isProjectComingUp: boolean
|
|
overallStatusLabel: string
|
|
}
|
|
|
|
export function useProjectHomeServiceStatusModel(
|
|
projectRef: string | undefined,
|
|
project: ProjectHomeServiceStatusProject
|
|
): ProjectHomeServiceStatusModel {
|
|
const {
|
|
projectAuthAll: authEnabled,
|
|
projectEdgeFunctionAll: edgeFunctionsEnabled,
|
|
realtimeAll: realtimeEnabled,
|
|
projectStorageAll: storageEnabled,
|
|
} = useIsFeatureEnabled([
|
|
'project_auth:all',
|
|
'project_edge_function:all',
|
|
'realtime:all',
|
|
'project_storage:all',
|
|
])
|
|
|
|
const isBranch = Boolean(project && project.parentRef !== project.ref)
|
|
|
|
const { data: branches, isPending: isBranchesLoading } = useBranchesQuery(
|
|
{ projectRef: isBranch ? project?.parentRef : undefined },
|
|
{ enabled: isBranch && Boolean(projectRef) }
|
|
)
|
|
|
|
const currentBranch = isBranch
|
|
? branches?.find((branch) => branch.project_ref === projectRef)
|
|
: undefined
|
|
|
|
const { data: status, isPending: isLoading } = useProjectServiceStatusQuery(
|
|
{ projectRef },
|
|
{
|
|
enabled: Boolean(projectRef),
|
|
refetchInterval: (query) => {
|
|
const data = query.state.data
|
|
const isServiceUnhealthy = data?.some((service) => {
|
|
if (service.name === 'rest' && extractDbSchema(service) === '') {
|
|
return false
|
|
}
|
|
if (service.status === 'ACTIVE_HEALTHY') {
|
|
return false
|
|
}
|
|
return true
|
|
})
|
|
|
|
return isServiceUnhealthy ? 5000 : false
|
|
},
|
|
}
|
|
)
|
|
|
|
const { data: edgeFunctionsStatus } = useEdgeFunctionServiceStatusQuery(
|
|
{ projectRef },
|
|
{
|
|
enabled: Boolean(projectRef),
|
|
refetchInterval: (query) => (!query.state.data?.healthy ? 5000 : false),
|
|
}
|
|
)
|
|
|
|
const authStatus = status?.find((service) => service.name === 'auth')
|
|
const restStatus = status?.find((service) => service.name === 'rest')
|
|
const realtimeStatus = status?.find((service) => service.name === 'realtime')
|
|
const storageStatus = status?.find((service) => service.name === 'storage')
|
|
const dbStatus = status?.find((service) => service.name === 'db')
|
|
|
|
const isMigrationLoading =
|
|
project?.status === 'COMING_UP' ||
|
|
(isBranch &&
|
|
(isBranchesLoading ||
|
|
currentBranch?.status === 'CREATING_PROJECT' ||
|
|
currentBranch?.status === 'RUNNING_MIGRATIONS'))
|
|
|
|
const services: ProjectHomeServiceRow[] = [
|
|
{
|
|
name: 'Database',
|
|
error: undefined,
|
|
docsUrl: undefined,
|
|
isLoading: isLoading,
|
|
status: dbStatus?.status ?? 'UNHEALTHY',
|
|
logsUrl: '/logs/postgres-logs',
|
|
},
|
|
{
|
|
name: 'PostgREST',
|
|
error: restStatus?.error,
|
|
docsUrl: undefined,
|
|
isLoading,
|
|
status: extractDbSchema(restStatus) === '' ? 'DISABLED' : (restStatus?.status ?? 'UNHEALTHY'),
|
|
logsUrl: '/logs/postgrest-logs',
|
|
},
|
|
...(authEnabled
|
|
? [
|
|
{
|
|
name: 'Auth',
|
|
error: authStatus?.error,
|
|
docsUrl: undefined,
|
|
isLoading,
|
|
status: authStatus?.status ?? 'UNHEALTHY',
|
|
logsUrl: '/logs/auth-logs',
|
|
},
|
|
]
|
|
: []),
|
|
...(realtimeEnabled
|
|
? [
|
|
{
|
|
name: 'Realtime',
|
|
error: realtimeStatus?.error,
|
|
docsUrl: undefined,
|
|
isLoading,
|
|
status: realtimeStatus?.status ?? 'UNHEALTHY',
|
|
logsUrl: '/logs/realtime-logs',
|
|
},
|
|
]
|
|
: []),
|
|
...(storageEnabled
|
|
? [
|
|
{
|
|
name: 'Storage',
|
|
error: storageStatus?.error,
|
|
docsUrl: undefined,
|
|
isLoading,
|
|
status: storageStatus?.status ?? 'UNHEALTHY',
|
|
logsUrl: '/logs/storage-logs',
|
|
},
|
|
]
|
|
: []),
|
|
...(edgeFunctionsEnabled
|
|
? [
|
|
{
|
|
name: 'Edge Functions',
|
|
error: undefined,
|
|
docsUrl: `${DOCS_URL}/guides/functions/troubleshooting`,
|
|
isLoading,
|
|
status: edgeFunctionsStatus?.healthy
|
|
? ('ACTIVE_HEALTHY' as const)
|
|
: isLoading
|
|
? ('COMING_UP' as const)
|
|
: ('UNHEALTHY' as const),
|
|
logsUrl: '/logs/edge-functions-logs',
|
|
},
|
|
]
|
|
: []),
|
|
...(isBranch
|
|
? [
|
|
{
|
|
name: 'Migrations',
|
|
error: undefined,
|
|
docsUrl: undefined,
|
|
isLoading: isBranchesLoading,
|
|
status: isBranch
|
|
? currentBranch?.status === 'FUNCTIONS_DEPLOYED'
|
|
? ('ACTIVE_HEALTHY' as const)
|
|
: currentBranch?.status === 'FUNCTIONS_FAILED' ||
|
|
currentBranch?.status === 'MIGRATIONS_FAILED'
|
|
? ('UNHEALTHY' as const)
|
|
: ('COMING_UP' as const)
|
|
: isMigrationLoading
|
|
? 'COMING_UP'
|
|
: 'ACTIVE_HEALTHY',
|
|
logsUrl: isBranch ? '/branches' : '/logs/database-logs',
|
|
},
|
|
]
|
|
: []),
|
|
]
|
|
|
|
const isLoadingChecks = services.some((service) => service.isLoading)
|
|
const allServicesOperational = services.every(
|
|
(service) => service.status === 'ACTIVE_HEALTHY' || service.status === 'DISABLED'
|
|
)
|
|
|
|
const isProjectNew =
|
|
(project?.inserted_at != null &&
|
|
dayjs.utc().diff(dayjs.utc(project.inserted_at), 'minute') <
|
|
SERVICE_STATUS_THRESHOLD_MINUTES) ||
|
|
project?.status === 'COMING_UP' ||
|
|
(isBranch &&
|
|
(currentBranch?.status === 'CREATING_PROJECT' ||
|
|
currentBranch?.status === 'RUNNING_MIGRATIONS' ||
|
|
isMigrationLoading))
|
|
|
|
const isProjectComingUp = ['COMING_UP', 'UNKNOWN'].includes(project?.status ?? '')
|
|
|
|
const anyUnhealthy = services.some((service) => service.status === 'UNHEALTHY')
|
|
const anyComingUp =
|
|
isProjectComingUp || services.some((service) => service.status === 'COMING_UP')
|
|
|
|
const getOverallStatusLabel = (): string => {
|
|
if (isLoadingChecks) return 'Checking...'
|
|
if (anyComingUp) return 'Coming up...'
|
|
if (anyUnhealthy) return 'Unhealthy'
|
|
return 'Healthy'
|
|
}
|
|
|
|
return {
|
|
services,
|
|
isLoadingChecks,
|
|
allServicesOperational,
|
|
isProjectNew,
|
|
isProjectComingUp,
|
|
overallStatusLabel: getOverallStatusLabel(),
|
|
}
|
|
}
|