Files
supabase/apps/studio/components/interfaces/Functions/EdgeFunctionOverview/EdgeFunctionInvocationsChart.tsx
T
Jordi Enric 24f8549e41 fix(studio): open edge function logs from chart clicks FE-3922 (#50364)
## Problem

Clicking an invocation bar on the Edge Function overview did not
preserve the selected chart segment, so the destination could not open a
focused investigation window.

## Fix

Forward the clicked bar timestamp and navigate to Logs or Invocations
with an encoded, focused time range. Share the existing chart range
calculation and add real Recharts interaction coverage.

## How to test

- Open an Edge Function Overview page with invocation data.
- Click a populated bar in the Total Invocations chart.
- Expected result: Logs or Invocations opens with its and ite query
parameters centered on the clicked bar.
- Repeat with unified logs enabled and disabled to verify both
destinations.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Clicking a bar in the Edge Function invocations chart now opens the
relevant logs or invocations view.
- The destination is focused on a time window surrounding the selected
invocation, making investigation faster.
- Chart bars now provide a pointer cursor to indicate they are
interactive.

- **Bug Fixes**
- Chart clicks without valid invocation data no longer trigger incorrect
navigation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 11:06:37 +02:00

119 lines
3.8 KiB
TypeScript

import { Rocket } from 'lucide-react'
import { useMemo } from 'react'
import {
Bar,
CartesianGrid,
BarChart as RechartBarChart,
ReferenceLine,
XAxis,
YAxis,
} from 'recharts'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from 'ui'
import {
formatChartTimestamp,
getChartTimeRangeLabels,
INVOCATION_CHART_CONFIG,
} from './EdgeFunctionOverview.utils'
import type { InvocationChartDatum, InvocationUpdateAnnotation } from './EdgeFunctionOverview.utils'
interface EdgeFunctionInvocationsChartProps {
chartData: InvocationChartDatum[]
dateTimeFormat: string
onChartClick: (timestamp: string) => void
updateAnnotation?: InvocationUpdateAnnotation
}
export const EdgeFunctionInvocationsChart = ({
chartData,
dateTimeFormat,
onChartClick,
updateAnnotation,
}: EdgeFunctionInvocationsChartProps) => {
const timeRangeLabels = useMemo(
() => getChartTimeRangeLabels(chartData, dateTimeFormat),
[chartData, dateTimeFormat]
)
return (
<div className="flex flex-col gap-1">
<div className="relative h-40 w-full overflow-visible">
<ChartContainer config={INVOCATION_CHART_CONFIG} className="aspect-auto! h-full! w-full!">
<RechartBarChart
data={chartData}
className="cursor-pointer"
margin={{ top: 0, right: 0, left: 0, bottom: 0 }}
onClick={(tooltipData) => {
const timestamp = tooltipData?.activePayload?.[0]?.payload?.timestamp
if (typeof timestamp === 'string') onChartClick(timestamp)
}}
>
<CartesianGrid vertical={false} />
<YAxis hide width={0} />
<XAxis
dataKey="timestamp"
tickLine={false}
axisLine={false}
tick={false}
minTickGap={32}
/>
<ChartTooltip
cursor={false}
content={
<ChartTooltipContent
className="text-foreground-light"
labelFormatter={(value) =>
formatChartTimestamp(value as string | number | undefined, dateTimeFormat)
}
indicator="dot"
/>
}
/>
<Bar
dataKey="error_count"
stackId="invocations"
fill="var(--color-error_count)"
maxBarSize={24}
/>
<Bar
dataKey="warning_count"
stackId="invocations"
fill="var(--color-warning_count)"
maxBarSize={24}
/>
<Bar
dataKey="ok_count"
stackId="invocations"
fill="var(--color-ok_count)"
maxBarSize={24}
/>
{updateAnnotation && (
<ReferenceLine
x={updateAnnotation.timestamp}
stroke="var(--foreground-default)"
strokeDasharray="4 4"
strokeWidth={1.5}
/>
)}
</RechartBarChart>
</ChartContainer>
{updateAnnotation && (
<span
className="pointer-events-none absolute bottom-0 z-10 flex h-6 w-6 -translate-x-1/2 translate-y-1/2 items-center justify-center rounded-full border border-foreground/20 bg-background text-foreground shadow-xs"
style={{ left: `${updateAnnotation.position}%` }}
title={`Updated ${formatChartTimestamp(updateAnnotation.updatedAt, dateTimeFormat)}`}
>
<Rocket size={12} strokeWidth={1.75} />
</span>
)}
</div>
{timeRangeLabels && (
<div className="-mt-6 flex items-center justify-between text-[10px] font-mono text-foreground-lighter">
<span>{timeRangeLabels.start}</span>
<span>{timeRangeLabels.end}</span>
</div>
)}
</div>
)
}