import dayjs from 'dayjs' import { Activity, BarChartIcon, Loader2 } from 'lucide-react' import { useRouter } from 'next/router' import { PropsWithChildren, useMemo, useState } from 'react' import { Button, Tooltip, TooltipContent, TooltipTrigger, WarningIcon } from 'ui' import type { ChartData } from './Charts.types' import AreaChart from '@/components/ui/Charts/AreaChart' import BarChart from '@/components/ui/Charts/BarChart' import { AnalyticsInterval } from '@/data/analytics/constants' import { mapMultiResponseToAnalyticsData } from '@/data/analytics/infra-monitoring-queries' import { InfraMonitoringAttribute, useInfraMonitoringAttributesQuery, } from '@/data/analytics/infra-monitoring-query' import { ProjectDailyStatsAttribute, useProjectDailyStatsQuery, } from '@/data/analytics/project-daily-stats-query' import { useDatabaseSelectorStateSnapshot } from '@/state/database-selector' interface ChartHandlerProps { id?: string label: string attribute: string provider: 'infra-monitoring' | 'daily-stats' startDate: string endDate: string interval: string customDateFormat?: string defaultChartStyle?: 'bar' | 'line' hideChartType?: boolean data?: ChartData isLoading?: boolean format?: string highlightedValue?: string | number syncId?: string } /** * Controls chart display state. Optionally fetches static chart data if data is not provided. * * If the `data` prop is provided, it will disable automatic chart data fetching and pass the data directly to the chart render. * - loading state can also be provided through the `isLoading` prop, to display loading placeholders. Ignored if `data` key not provided. * - if `isLoading=true` and `data` is `undefined`, loading error message will be shown. * * Provided data must be in the expected chart format. */ const ChartHandler = ({ label, attribute, provider, startDate, endDate, interval, customDateFormat, children = null, defaultChartStyle = 'bar', hideChartType = false, data, isLoading, format, highlightedValue, syncId, ...otherProps }: PropsWithChildren) => { const router = useRouter() const { ref } = router.query const state = useDatabaseSelectorStateSnapshot() const [chartStyle, setChartStyle] = useState(defaultChartStyle) const databaseIdentifier = state.selectedDatabaseId const { data: dailyStatsData, isPending: isFetchingDailyStats } = useProjectDailyStatsQuery( { projectRef: ref as string, attribute: attribute as ProjectDailyStatsAttribute, startDate: dayjs(startDate).format('YYYY-MM-DD'), endDate: dayjs(endDate).format('YYYY-MM-DD'), }, { enabled: provider === 'daily-stats' && data === undefined } ) const { data: infraMonitoringData, isPending: isFetchingInfraMonitoring } = useInfraMonitoringAttributesQuery( { projectRef: ref as string, attributes: [attribute as InfraMonitoringAttribute], startDate, endDate, interval: interval as AnalyticsInterval, databaseIdentifier, }, { enabled: provider === 'infra-monitoring' && data === undefined } ) const transformedInfraData = useMemo(() => { if (!infraMonitoringData) return undefined const mapped = mapMultiResponseToAnalyticsData(infraMonitoringData, [ attribute as InfraMonitoringAttribute, ]) return mapped[attribute] }, [infraMonitoringData, attribute]) const chartData = data || (provider === 'infra-monitoring' ? transformedInfraData : provider === 'daily-stats' ? dailyStatsData : undefined) const loading = isLoading || (provider === 'infra-monitoring' ? isFetchingInfraMonitoring : provider === 'daily-stats' ? isFetchingDailyStats : isLoading) const shouldHighlightMaxValue = provider === 'daily-stats' && !attribute.includes('ingress') && !attribute.includes('egress') && chartData !== undefined && 'maximum' in chartData const shouldHighlightTotalGroupedValue = chartData !== undefined && 'totalGrouped' in chartData const _highlightedValue = highlightedValue !== undefined ? highlightedValue : shouldHighlightMaxValue ? chartData?.maximum : provider === 'daily-stats' ? chartData?.total : shouldHighlightTotalGroupedValue ? chartData?.totalGrouped?.[attribute] : (chartData?.data[chartData?.data.length - 1] as any)?.[attribute as any] if (loading) { return (

Loading data for {label}

) } if (chartData === undefined) { return (

Unable to load data for {label}

) } return (
{!hideChartType && (
{chartStyle === 'bar' ? ( ) : ( )}
) } export default ChartHandler