import { cn } from 'ui' import { MetricCard, MetricCardContent, MetricCardHeader, MetricCardLabel, MetricCardValue, } from 'ui-patterns/MetricCard' import { getConnectionMetrics } from './DatabaseConnections.utils' import { useSelectActivityPid } from './useSelectActivityPid' import { formatDuration } from '@/components/interfaces/QueryPerformance/QueryPerformance.utils' import { useDatabaseRolesQuery } from '@/data/database-roles/database-roles-query' import { useDatabaseActivityQuery } from '@/data/database/activity-query' import { useMaxConnectionsQuery } from '@/data/database/max-connections-query' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { useTrack } from '@/lib/telemetry/track' interface OverviewProps { live?: boolean } export const Overview = ({ live }: OverviewProps) => { const track = useTrack() const { data: project } = useSelectedProjectQuery() const { selectPid } = useSelectActivityPid() const { data, isPending: isLoadingActivity } = useDatabaseActivityQuery( { projectRef: project?.ref, connectionString: project?.connectionString, }, { refetchOnWindowFocus: live, refetchInterval: live ? 3000 : false } ) const { activeQueries, blockedQueries, warnBlockedQueries, longestBlockedQuery, idleInTransactionQueries, longestRunningQuery, warnLongestRunningQuery, queryBlockingTheMostQueries, warnTopBlocker, } = getConnectionMetrics(data ?? []) const { data: roles, isPending: isLoadingRoles } = useDatabaseRolesQuery( { projectRef: project?.ref, connectionString: project?.connectionString, }, { refetchOnWindowFocus: live, refetchInterval: live ? 3000 : false } ) const rolesWithActiveConnections = (roles ?? []).filter((role) => role.activeConnections) const totalActiveConnections = (roles ?? []) .map((role) => role.activeConnections) .reduce((a, b) => a + b, 0) const { data: maxConnectionLimit, isPending: isLoadingMaxConnections } = useMaxConnectionsQuery( { projectRef: project?.ref, connectionString: project?.connectionString, }, { select: (data) => data.maxConnections, refetchInterval: live ? 3000 : false, } ) const onSelectLongestBlocked = () => { if (!longestBlockedQuery) return track('database_connections_overview_metric_card_clicked', { type: 'longest_blocked' }) selectPid(longestBlockedQuery.activity.pid) } const onSelectTopBlocker = () => { if (!queryBlockingTheMostQueries) return track('database_connections_overview_metric_card_clicked', { type: 'top_blocker' }) selectPid(queryBlockingTheMostQueries.activity.pid) } const onSelectLongestRunning = () => { if (!longestRunningQuery) return track('database_connections_overview_metric_card_clicked', { type: 'longest_running' }) selectPid(longestRunningQuery.activity.pid) } return (

Overview

Connections by roles:

{rolesWithActiveConnections.map((role) => ( ))}
{role.name}: {role.activeConnections}
} > Connections {totalActiveConnections} / {maxConnectionLimit} Active queries {activeQueries?.length}

Transactions left open without running a query, which can hold locks and block table cleanup for as long as it stays open

Typically indicates an app issue, such as a forgotten COMMIT or ROLLBACK.

} > Idle in transaction
0 && 'text-warning')} > {idleInTransactionQueries.length}

Queries waiting on a lock held by another session - stalls everything queued behind it.

Typically caused by a slow transaction, a long-running migration, or a stuck idle-in-transaction session.

} > Blocked queries
{blockedQueries.length} {warnBlockedQueries && longestBlockedQuery && ( <> · onSelectLongestBlocked()} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() onSelectLongestBlocked() } }} > PID {longestBlockedQuery.activity.pid} blocked for{' '} {formatDuration(longestBlockedQuery.duration * 1000, 0)} )}
Top blocker {queryBlockingTheMostQueries === null ? ( '-' ) : ( <> onSelectTopBlocker()} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() onSelectTopBlocker() } }} > PID: {queryBlockingTheMostQueries?.activity.pid} · Blocking {queryBlockingTheMostQueries?.count} other{' '} {queryBlockingTheMostQueries?.count > 1 ? 'queries' : 'query'} )} Longest running {longestRunningQuery === null ? ( '-' ) : ( <> onSelectLongestRunning()} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() onSelectLongestRunning() } }} > PID: {longestRunningQuery.activity.pid} · {formatDuration(longestRunningQuery.duration * 1000, 0)} )}
) }