From 59f23cba81c4d79fe57fc97e27ac76525c56736d Mon Sep 17 00:00:00 2001 From: Duyet Le Date: Thu, 22 Aug 2024 13:45:03 +0700 Subject: [PATCH] chore: fix area breakdown --- app/overview/page.tsx | 45 +++++++++++++------ components/charts/query-count.tsx | 4 +- components/generic-charts/area.cy.tsx | 63 ++++++++++++++++++++++++--- components/generic-charts/area.tsx | 51 ++++++++++++++++------ types/charts.ts | 2 + 5 files changed, 131 insertions(+), 34 deletions(-) diff --git a/app/overview/page.tsx b/app/overview/page.tsx index b4acfeb1..3c0fbf39 100644 --- a/app/overview/page.tsx +++ b/app/overview/page.tsx @@ -28,13 +28,34 @@ export default async function Overview() { Backups +
+ + + + + + + + @@ -44,29 +65,19 @@ export default async function Overview() { - - - - @@ -77,6 +88,7 @@ export default async function Overview() {
- +
diff --git a/components/charts/query-count.tsx b/components/charts/query-count.tsx index cf418edb..997ce752 100644 --- a/components/charts/query-count.tsx +++ b/components/charts/query-count.tsx @@ -49,7 +49,7 @@ export async function ChartQueryCount({ { event_time: string query_count: number - breakdown: Array<[string, number]> + breakdown: Array<[string, number] | Record> }[] >({ query }) @@ -65,6 +65,8 @@ export async function ChartQueryCount({ showLegend={false} colors={['--chart-yellow']} breakdown="breakdown" + breakdownLabel="query_kind" + breakdownValue="count" {...props} /> diff --git a/components/generic-charts/area.cy.tsx b/components/generic-charts/area.cy.tsx index 1a4370df..51df95dc 100644 --- a/components/generic-charts/area.cy.tsx +++ b/components/generic-charts/area.cy.tsx @@ -231,7 +231,28 @@ describe('', () => { }, ] - it('renders with breakdown', () => { + const dataWithBreakdown2 = [ + { + date: '2025-01-01', + query_count: 1000, + query_duration: 1000, + breakdown: [ + { query_kind: 'select', count: '500' }, + { query_kind: 'insert', count: '500' }, + ], + }, + { + date: '2025-01-02', + query_count: 2000, + query_duration: 2000, + breakdown: [ + { query_kind: 'select', count: '1000' }, + { query_kind: 'insert', count: '1000' }, + ], + }, + ] + + it('renders with breakdown as array of array format (old clickhouse)', () => { cy.mount( ', () => { ) }) - it('renders with breakdown custom breakdownLabel', () => { - const breakdownLabel = 'Custom breakdown' + it('renders with breakdown as array of object', () => { + cy.mount( + + ) + cy.screenshot() + + // Render as svg + cy.get('svg:first').as('chart').should('be.visible') + + // Hover to show tooltip + cy.get('@chart').trigger('mouseover') + + // Show breakdown in tooltip + cy.get('.recharts-tooltip-wrapper [role="breakdown"]').should( + 'contain', + 'Breakdown' + ) + cy.get('[role="breakdown"] [role="row"]').should( + 'have.length', + dataWithBreakdown[0].breakdown.length + ) + }) + + it('renders with breakdown custom breakdownHeading', () => { + const breakdownHeading = 'Custom breakdown' cy.mount( ', () => { index="date" showLegend breakdown="breakdown" - breakdownLabel={breakdownLabel} + breakdownHeading={breakdownHeading} tooltipActive={true /* always show tooltip for test/debugging */} /> ) @@ -280,7 +333,7 @@ describe('', () => { // Show breakdown in tooltip cy.get('.recharts-tooltip-wrapper [role="breakdown"]').should( 'contain', - breakdownLabel + breakdownHeading ) }) }) diff --git a/components/generic-charts/area.tsx b/components/generic-charts/area.tsx index de36b546..8ba288c5 100644 --- a/components/generic-charts/area.tsx +++ b/components/generic-charts/area.tsx @@ -34,6 +34,8 @@ export function AreaChart({ tickFormatter, breakdown, breakdownLabel, + breakdownValue, + breakdownHeading, tooltipActive, className, }: AreaChartProps) { @@ -85,6 +87,8 @@ export function AreaChart({ {renderChartTooltip({ breakdown, breakdownLabel, + breakdownValue, + breakdownHeading, tooltipActive, chartConfig, categories, @@ -112,12 +116,19 @@ export function AreaChart({ function renderChartTooltip({ breakdown, breakdownLabel, + breakdownValue, + breakdownHeading, tooltipActive, chartConfig, categories, }: Pick< AreaChartProps, - 'breakdown' | 'breakdownLabel' | 'tooltipActive' | 'categories' + | 'breakdown' + | 'breakdownLabel' + | 'breakdownValue' + | 'breakdownHeading' + | 'tooltipActive' + | 'categories' > & { chartConfig: ChartConfig }) { @@ -173,16 +184,29 @@ function renderChartTooltip({ > - ) => { + formatter={(value, name, item, index, payload: any) => { const breakdownData = payload[ breakdown as keyof typeof payload - ] as any[] + ] as Array + const breakdownDataMap = breakdownData.map((item) => { + // breakdown: [('A', 1000)] + if (Array.isArray(item) && item.length === 2) { + return item + } + + // breakdown: [{ name: 'A', value: 1000 }] + if (typeof item === 'object') { + if (!breakdownLabel || !breakdownValue) { + throw new Error('Missing breakdownLabel or breakdownValue') + } + + return [item[breakdownLabel], item[breakdownValue]] + } + + throw new Error( + 'Invalid breakdown data, expected array(2) or object' + ) + }) return ( <> @@ -209,9 +233,9 @@ function renderChartTooltip({ role="breakdown" >
- {breakdownLabel || 'Breakdown'} + {breakdownHeading || 'Breakdown'}
- {breakdownData.map(([name, value], index) => ( + {breakdownDataMap.map(([name, value], index) => (
({ } /> - {chartConfig[name as keyof typeof chartConfig] - ?.label || name} + {item[breakdownLabel as keyof typeof item] || name}
- {value} + {value.toLocaleString()}
diff --git a/types/charts.ts b/types/charts.ts index 9d4fb5c9..2a884d92 100644 --- a/types/charts.ts +++ b/types/charts.ts @@ -124,6 +124,8 @@ export interface AreaChartProps extends BaseChartProps { opacity?: number breakdown?: string breakdownLabel?: string + breakdownValue?: string + breakdownHeading?: string tooltipActive?: boolean // TODO: support these features