Files
supabase/apps/studio/components/ui/Charts/AreaChart.tsx
f65884f341 Reports consolidation 1: Edge Functions (#38129)
* wip

* add formatTimestamp for reports

* add tests for formatTimestamp

* fix type err

* rm old chart logic

* do not retry replication sources

* update report config schema

* use report config

* fix charts, simplify config

* sync charts

* rm comment

* usefilltimeseries

* move chart upsell to its own component

* cleanup v2 chart component

* fix chartheader function format bug

* make attributes dynamic

* move types to its own file

* update reportv2chart types

* update reportv2 chart type

* use new edgefn report

* rm mock

* rm old code

* fix type err

* fix type err

* rename hook

* return sql in dataprovider

* add button to open in log explorer in chart header

* fix type

* fix chart type toggle

* fix type error

* export data transformation for testing

* add tests for data transformation

* rm dupped code

* add report settings to edge fn report

* rm mocked data

* rename

* fix type err

* Apply suggestion from @joshenlim

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>

* rm unnecessary div

* rm unnecessary props from report upsell

* cleaner query keys

* move loadin/error/empty states to inside panel content to prevent layout shift

* use card instead of panel

* use buttontooltip in chartheader

* use buttontooltips in buttons with tooltips

* rm export default

* rm export defualt

* rm i from key

* fix status code transformation

* fix filltimeseries

* add tests for filltimeseries

* fix data transform

* pass xaxis key to chart

* refactor hover state to use timestamp not index

* fix tests

* fix areachart

* fix barchart

* fix chartheader

* fix composedchart

* fix stacked

* fix type missing xaxiskey

* type fix

* Revert "refactor hover state to use timestamp not index"

This reverts commit cfd7886460.

* undo charthover changes, fix data aggregation

* Revert "fix tests"

This reverts commit e5200a2035.

* move transforms to testable functions, add tests

* nit refactors and clean up

* feat: add aws nimbus cloud provider (#38312)

* feat: add aws nimbus cloud provider

* Fix return type of useCustomContent hook

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>

* add utc plugin to dayjs

* move plugins to vitest setup

* rm customparser plugin

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Alaister Young <alaister@users.noreply.github.com>
2025-09-01 11:10:30 +02:00

161 lines
4.9 KiB
TypeScript

import dayjs from 'dayjs'
import { useState } from 'react'
import { Area, AreaChart as RechartAreaChart, Tooltip, XAxis } from 'recharts'
import { useChartHoverState } from './useChartHoverState'
import { CHART_COLORS, DateTimeFormats } from 'components/ui/Charts/Charts.constants'
import { ChartHeader } from './ChartHeader'
import type { CommonChartProps, Datum } from './Charts.types'
import { numberFormatter, useChartSize } from './Charts.utils'
import NoDataPlaceholder from './NoDataPlaceholder'
export interface AreaChartProps<D = Datum> extends CommonChartProps<D> {
yAxisKey: string
xAxisKey: string
format?: string
customDateFormat?: string
displayDateInUtc?: boolean
syncId?: string
}
const AreaChart = ({
data,
yAxisKey,
xAxisKey,
format,
customDateFormat = DateTimeFormats.FULL,
title,
highlightedValue,
highlightedLabel,
displayDateInUtc,
minimalHeader,
className = '',
valuePrecision,
size = 'normal',
syncId,
}: AreaChartProps) => {
const { Container } = useChartSize(size)
const { hoveredIndex, syncTooltip, setHover, clearHover } = useChartHoverState(
syncId || 'default'
)
const [focusDataIndex, setFocusDataIndex] = useState<number | null>(null)
const day = (value: number | string) => (displayDateInUtc ? dayjs(value).utc() : dayjs(value))
const resolvedHighlightedLabel =
(focusDataIndex !== null &&
data &&
data[focusDataIndex] !== undefined &&
day(data[focusDataIndex][xAxisKey]).format(customDateFormat)) ||
highlightedLabel
const resolvedHighlightedValue =
focusDataIndex !== null ? data[focusDataIndex]?.[yAxisKey] : highlightedValue
if (data.length === 0) {
return (
<NoDataPlaceholder
description="It may take up to 24 hours for data to refresh"
size={size}
className={className}
attribute={title}
format={format}
/>
)
}
return (
<div className={['flex flex-col gap-3', className].join(' ')}>
<ChartHeader
title={title}
format={format}
customDateFormat={customDateFormat}
highlightedValue={
typeof resolvedHighlightedValue === 'number'
? numberFormatter(resolvedHighlightedValue, valuePrecision)
: resolvedHighlightedValue
}
highlightedLabel={resolvedHighlightedLabel}
minimalHeader={minimalHeader}
syncId={syncId}
data={data}
xAxisKey={xAxisKey}
yAxisKey={yAxisKey}
xAxisIsDate={true}
displayDateInUtc={displayDateInUtc}
valuePrecision={valuePrecision}
attributes={[]}
/>
<Container>
<RechartAreaChart
data={data}
margin={{
top: 0,
right: 0,
left: 0,
bottom: 0,
}}
className="overflow-visible"
onMouseMove={(e: any) => {
if (e.activeTooltipIndex !== focusDataIndex) {
setFocusDataIndex(e.activeTooltipIndex)
}
setHover(e.activeTooltipIndex)
}}
onMouseLeave={() => {
setFocusDataIndex(null)
clearHover()
}}
>
<defs>
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={CHART_COLORS.GREEN_1} stopOpacity={0.8} />
<stop offset="95%" stopColor={CHART_COLORS.GREEN_1} stopOpacity={0} />
</linearGradient>
</defs>
<XAxis
dataKey={xAxisKey}
interval={data.length - 2}
angle={0}
// hide the tick
tick={false}
// color the axis
axisLine={{ stroke: CHART_COLORS.AXIS }}
tickLine={{ stroke: CHART_COLORS.AXIS }}
/>
<Tooltip
content={(props) =>
syncId && syncTooltip && hoveredIndex !== null ? (
<div className="bg-black/90 text-white p-2 rounded text-xs">
<div className="font-medium">
{dayjs(data[hoveredIndex]?.[xAxisKey]).format(customDateFormat)}
</div>
<div>
{numberFormatter(Number(data[hoveredIndex]?.[yAxisKey]) || 0, valuePrecision)}
{format}
</div>
</div>
) : null
}
/>
<Area
type="monotone"
dataKey={yAxisKey}
stroke={CHART_COLORS.GREEN_1}
fillOpacity={1}
fill="url(#colorUv)"
/>
</RechartAreaChart>
</Container>
{data && (
<div className="text-foreground-lighter -mt-8 flex items-center justify-between text-xs">
<span>{dayjs(data[0][xAxisKey]).format(customDateFormat)}</span>
<span>{dayjs(data[data?.length - 1]?.[xAxisKey]).format(customDateFormat)}</span>
</div>
)}
</div>
)
}
export default AreaChart