import { useParams } from 'common' import dayjs from 'dayjs' import { Activity, BarChart2, Database } from 'lucide-react' import { useMemo } from 'react' import type { ChartConfig } from 'ui' import { cn } from 'ui' import { Chart, ChartCard, ChartContent, ChartEmptyState, ChartHeader, ChartLine, ChartLoadingState, ChartMetric, } from 'ui-patterns/Chart' import { buildUsageChartData, formatUsagePercent, getComputeUsageSummary, getDiskUsageSummary, getUsageMetricStatus, type UsageMetricStatus, } from './ComputeAndDiskUsageCharts.utils' import { hasBurstableIO } from './DiskManagement.utils' import type { InfraMonitoringAttribute } from '@/data/analytics/infra-monitoring-query' import { getInfraMonitoringAttributes, useInfraMonitoringAttributesQuery, } from '@/data/analytics/infra-monitoring-query' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { formatBytes } from '@/lib/helpers' const USAGE_ATTRIBUTES = [ 'max_cpu_usage', 'ram_usage', 'disk_io_consumption', 'disk_fs_used_system', 'disk_fs_used_wal', 'pg_database_size', 'disk_fs_size', ] satisfies InfraMonitoringAttribute[] const ROLLING_WINDOW_DAYS = 7 const getRollingWindow = () => { const now = dayjs() return { startDate: now.subtract(ROLLING_WINDOW_DAYS, 'day').toISOString(), endDate: now.toISOString(), } } const COMPUTE_CHART_CONFIG = { maxCpuUsage: { label: 'CPU', color: 'var(--primary-bright)', }, ramUsage: { label: 'Memory', color: 'hsl(var(--warning-default))', }, diskIoConsumption: { label: 'Disk IO', color: 'hsl(var(--destructive-500))', }, } satisfies ChartConfig const DISK_CHART_CONFIG = { databaseUsagePercent: { label: 'Database', color: 'var(--primary-bright)', }, walUsagePercent: { label: 'WAL', color: 'hsl(var(--warning-default))', }, systemUsagePercent: { label: 'System', color: 'hsl(var(--destructive-500))', }, } satisfies ChartConfig const PERCENTAGE_Y_AXIS_PROPS = { domain: [0, 100] as [number, number], allowDataOverflow: true, ticks: [0, 25, 50, 75, 100], tickFormatter: (value: number) => `${Math.round(Number(value))}%`, width: 64, } const getUsageCardClassName = (status: UsageMetricStatus) => cn( 'h-full flex flex-col transition-colors', status === 'warning' && 'border-warning-400 bg-warning-200/30', status === 'negative' && 'border-destructive-400 bg-destructive-200/30' ) export const ComputeAndDiskUsageCharts = ({ className }: { className?: string }) => { const { ref: projectRef } = useParams() const { data: project } = useSelectedProjectQuery() const supportsBurstableIO = hasBurstableIO(project?.infra_compute_size) // Anchor query key dates to mount time; fetch uses a rolling 7-day window on each refetch. const { startDate, endDate } = useMemo(getRollingWindow, []) const { data: usageData, isLoading, isError, } = useInfraMonitoringAttributesQuery( { projectRef, attributes: USAGE_ATTRIBUTES, startDate, endDate, interval: '1d', }, { queryFn: ({ signal }) => getInfraMonitoringAttributes( { projectRef, attributes: USAGE_ATTRIBUTES, ...getRollingWindow(), interval: '1d', }, signal ), } ) const { computeChartData, diskChartData } = useMemo( () => buildUsageChartData(usageData), [usageData] ) const { peakCpuUsage, peakMemoryUsage, peakDiskIoUsage, peakComputeUsage, status: computeUsageStatus, } = useMemo( () => getComputeUsageSummary(computeChartData, supportsBurstableIO), [computeChartData, supportsBurstableIO] ) const { latestDataPoint: latestDiskDataPoint, usagePercent: latestDiskUsage, status: diskUsageStatus, } = useMemo(() => getDiskUsageSummary(diskChartData), [diskChartData]) const isComputeEmpty = computeChartData.length === 0 const isDiskEmpty = diskChartData.length === 0 return (