import { useQueryClient } from '@tanstack/react-query' import { useParams } from 'common' import dayjs from 'dayjs' import { RefreshCw } from 'lucide-react' import { useRouter } from 'next/router' import { useCallback, useMemo, useState } from 'react' import { Badge, Button, Tooltip, TooltipContent, TooltipTrigger } from 'ui' import { DatabaseInfrastructureSection } from './DatabaseInfrastructureSection' import { useObservabilityOverviewData } from './ObservabilityOverview.utils' import { ObservabilityOverviewFooter } from './ObservabilityOverviewFooter' import { ServiceHealthTable } from './ServiceHealthTable' import { useSlowQueriesCount } from './useSlowQueriesCount' import ReportHeader from '@/components/interfaces/Reports/ReportHeader' import ReportPadding from '@/components/interfaces/Reports/ReportPadding' import { ChartIntervalDropdown } from '@/components/ui/Logs/ChartIntervalDropdown' import { CHART_INTERVALS } from '@/components/ui/Logs/logs.utils' import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' type ChartIntervalKey = '1hr' | '1day' | '7day' export const ObservabilityOverview = () => { const router = useRouter() const { ref: projectRef } = useParams() const { data: organization } = useSelectedOrganizationQuery() const queryClient = useQueryClient() const { projectStorageAll: storageSupported } = useIsFeatureEnabled(['project_storage:all']) const DEFAULT_INTERVAL: ChartIntervalKey = '1day' const [interval, setInterval] = useState(DEFAULT_INTERVAL) const [refreshKey, setRefreshKey] = useState(0) const selectedInterval = CHART_INTERVALS.find((i) => i.key === interval) || CHART_INTERVALS[1] const { datetimeFormat } = useMemo(() => { const format = selectedInterval.format || 'MMM D, ha' return { datetimeFormat: format } }, [selectedInterval]) const overviewData = useObservabilityOverviewData(projectRef!, interval, refreshKey) const { slowQueriesCount, isLoading: slowQueriesLoading } = useSlowQueriesCount( projectRef, refreshKey ) const handleRefresh = useCallback(() => { setRefreshKey((prev) => prev + 1) queryClient.invalidateQueries({ queryKey: ['project-metrics'] }) queryClient.invalidateQueries({ queryKey: ['postgrest-overview-metrics'] }) queryClient.invalidateQueries({ queryKey: ['infra-monitoring'] }) queryClient.invalidateQueries({ queryKey: ['max-connections'] }) }, [queryClient]) const serviceBase = useMemo( () => [ { key: 'db' as const, name: 'Database', reportUrl: `/project/${projectRef}/observability/database`, logsUrl: `/project/${projectRef}/logs/postgres-logs`, enabled: true, hasReport: true, }, { key: 'auth' as const, name: 'Auth', reportUrl: `/project/${projectRef}/observability/auth`, logsUrl: `/project/${projectRef}/logs/auth-logs`, enabled: true, hasReport: true, }, { key: 'functions' as const, name: 'Edge Functions', reportUrl: `/project/${projectRef}/observability/edge-functions`, logsUrl: `/project/${projectRef}/logs/edge-functions-logs`, enabled: true, hasReport: true, }, { key: 'realtime' as const, name: 'Realtime', reportUrl: `/project/${projectRef}/observability/realtime`, logsUrl: `/project/${projectRef}/logs/realtime-logs`, enabled: true, hasReport: true, }, { key: 'storage' as const, name: 'Storage', reportUrl: `/project/${projectRef}/observability/storage`, logsUrl: `/project/${projectRef}/logs/storage-logs`, enabled: storageSupported, hasReport: true, }, { key: 'postgrest' as const, name: 'Data API', reportUrl: `/project/${projectRef}/observability/postgrest`, logsUrl: `/project/${projectRef}/logs/postgrest-logs`, enabled: true, hasReport: true, }, ], [projectRef, storageSupported] ) const enabledServices = serviceBase.filter((s) => s.enabled) const dbServiceData = overviewData.services.db // Navigate to the log view scoped to the clicked bar's bucket window const handleBarClick = useCallback( (logsUrl: string) => (datum: any) => { if (!datum?.timestamp) return // datum.timestamp is already the UTC-truncated bucket boundary from timestamp_trunc(), // so use it directly to avoid local-timezone startOf() misalignment (e.g. UTC+5:30). const unit = interval === '1hr' ? 'minute' : 'hour' const start = datum.timestamp const end = dayjs.utc(datum.timestamp).add(1, unit).toISOString() const queryParams = new URLSearchParams({ its: start, ite: end }) router.push(`${logsUrl}?${queryParams.toString()}`) }, [router, interval] ) return (
Beta

This page is subject to change

setInterval(interval as ChartIntervalKey)} organizationSlug={organization?.slug} dropdownAlign="end" tooltipSide="left" />
({ key: service.key, name: service.name, description: '', reportUrl: service.hasReport ? service.reportUrl : undefined, logsUrl: service.logsUrl, }))} serviceData={overviewData.services} onBarClick={handleBarClick} datetimeFormat={datetimeFormat} />
) }