mirror of
https://github.com/supabase/supabase.git
synced 2026-10-16 22:59:11 +03:00
* test client connections charts * add granularity to database dashboard * add range selection * add selection to area charts * refactor ChartHeader * fix default * fix time preset selected label and add tooltip actions * client connections stacked chart * polish all new chartts * change attribute * fix * add real queries * memory stack * cleanup * precision 1 * update charts * add endpoints * tooltip * format * improve charts * toggle max value * show limit * cleanup * cleanup * update api schema * fix ram_usage_max_available * remove pgbouncer and comments * show total with percentage in chart header * pretty * hide * update reports database * remove client_connections * revert * fix connectionStrings error * restore correct queries and conditions * vertically zoom in to percentage data * add feature flag logic on charts * add feature flag logic to date picker * chore: remove comment * add tooltip to charts metrics * chore: comment new pg endpoints * feat: lazy load ComposedChartHandler queries * feat: dim non-hovered chart values when hovering chart label item * feat: improve dim styling * chore: improve light mode stacked chart colors * chore: remove 15s interval * chore: sync types * chore: remove type * chore: restore type * fix hook error * show chart type toggle * remove console log * temp * keep connections charts as before * restore DateRangePicker * show last aggregate value when not hovering * clean up imports * disk IOps read and write * restore flag * refactor queries * clean up grafana promo banner * Update database-charts.ts | updated language * fix hook error * fix hook error * fix hook error * attempt fix hook error --------- Co-authored-by: TheOtherBrian1 <91111415+TheOtherBrian1@users.noreply.github.com>
196 lines
6.0 KiB
TypeScript
196 lines
6.0 KiB
TypeScript
import { useRouter } from 'next/router'
|
|
import { PropsWithChildren, useState } from 'react'
|
|
import { Button, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
|
|
|
import AreaChart from 'components/ui/Charts/AreaChart'
|
|
import BarChart from 'components/ui/Charts/BarChart'
|
|
import { AnalyticsInterval } from 'data/analytics/constants'
|
|
import {
|
|
InfraMonitoringAttribute,
|
|
useInfraMonitoringQuery,
|
|
} from 'data/analytics/infra-monitoring-query'
|
|
import {
|
|
ProjectDailyStatsAttribute,
|
|
useProjectDailyStatsQuery,
|
|
} from 'data/analytics/project-daily-stats-query'
|
|
import { Activity, BarChartIcon, Loader2 } from 'lucide-react'
|
|
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
|
import { WarningIcon } from 'ui'
|
|
import type { ChartData } from './Charts.types'
|
|
|
|
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
|
|
}
|
|
|
|
/**
|
|
* 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,
|
|
}: PropsWithChildren<ChartHandlerProps>) => {
|
|
const router = useRouter()
|
|
const { ref } = router.query
|
|
|
|
const state = useDatabaseSelectorStateSnapshot()
|
|
const [chartStyle, setChartStyle] = useState<string>(defaultChartStyle)
|
|
|
|
const databaseIdentifier = state.selectedDatabaseId
|
|
|
|
const { data: dailyStatsData, isLoading: isFetchingDailyStats } = useProjectDailyStatsQuery(
|
|
{
|
|
projectRef: ref as string,
|
|
attribute: attribute as ProjectDailyStatsAttribute,
|
|
startDate,
|
|
endDate,
|
|
interval: interval as AnalyticsInterval,
|
|
databaseIdentifier,
|
|
},
|
|
{ enabled: provider === 'daily-stats' && data === undefined }
|
|
)
|
|
|
|
const { data: infraMonitoringData, isLoading: isFetchingInfraMonitoring } =
|
|
useInfraMonitoringQuery(
|
|
{
|
|
projectRef: ref as string,
|
|
attribute: attribute as InfraMonitoringAttribute,
|
|
startDate,
|
|
endDate,
|
|
interval: interval as AnalyticsInterval,
|
|
databaseIdentifier,
|
|
},
|
|
{ enabled: provider === 'infra-monitoring' && data === undefined }
|
|
)
|
|
|
|
const chartData =
|
|
data ||
|
|
(provider === 'infra-monitoring'
|
|
? infraMonitoringData
|
|
: 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 (
|
|
<div className="flex h-52 w-full flex-col items-center justify-center gap-y-2">
|
|
<Loader2 size={18} className="animate-spin text-border-strong" />
|
|
<p className="text-xs text-foreground-lighter">Loading data for {label}</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (chartData === undefined) {
|
|
return (
|
|
<div className="flex h-52 w-full flex-col items-center justify-center gap-y-2">
|
|
<WarningIcon />
|
|
<p className="text-xs text-foreground-lighter">Unable to load data for {label}</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="h-full w-full">
|
|
<div className="absolute right-6 z-10 flex justify-between">
|
|
{!hideChartType && (
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
type="default"
|
|
className="px-1.5"
|
|
icon={chartStyle === 'bar' ? <Activity /> : <BarChartIcon />}
|
|
onClick={() => setChartStyle(chartStyle === 'bar' ? 'line' : 'bar')}
|
|
/>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="left" align="center">
|
|
View as {chartStyle === 'bar' ? 'line chart' : 'bar chart'}
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
)}
|
|
{children}
|
|
</div>
|
|
{chartStyle === 'bar' ? (
|
|
<BarChart
|
|
YAxisProps={{ width: 1 }}
|
|
data={(chartData?.data ?? []) as any}
|
|
format={format || chartData?.format}
|
|
xAxisKey={'period_start'}
|
|
yAxisKey={attribute}
|
|
highlightedValue={_highlightedValue}
|
|
title={label}
|
|
customDateFormat={customDateFormat}
|
|
/>
|
|
) : (
|
|
<AreaChart
|
|
data={(chartData?.data ?? []) as any}
|
|
format={format || chartData?.format}
|
|
xAxisKey="period_start"
|
|
yAxisKey={attribute}
|
|
highlightedValue={_highlightedValue}
|
|
title={label}
|
|
customDateFormat={customDateFormat}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default ChartHandler
|