Files
supabase/apps/studio/components/interfaces/Functions/EdgeFunctionOverview/EdgeFunctionInvocationsSection.tsx
T

157 lines
5.4 KiB
TypeScript

import type { ComponentProps } from 'react'
import { useMemo } from 'react'
import { Button } from 'ui'
import { Chart, ChartActions, ChartLoadingState, ChartMetric } from 'ui-patterns/Chart'
import { PageContainer } from 'ui-patterns/PageContainer'
import {
PageSection,
PageSectionAside,
PageSectionContent,
PageSectionMeta,
PageSectionSummary,
} from 'ui-patterns/PageSection'
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
import { EdgeFunctionChartEmptyState } from './EdgeFunctionChartEmptyState'
import { EdgeFunctionInvocationsChart } from './EdgeFunctionInvocationsChart'
import {
EDGE_FUNCTION_CHART_INTERVALS,
formatRate,
getChartEmptyStateCopy,
getSegmentedButtonClassName,
} from './EdgeFunctionOverview.utils'
import type { InvocationChartDatum, InvocationUpdateAnnotation } from './EdgeFunctionOverview.utils'
import { toAlertError } from './EdgeFunctionRecentErrors.utils'
import AlertError from '@/components/ui/AlertError'
import type { ChartIntervals } from '@/types'
interface EdgeFunctionInvocationsSectionProps {
interval: string
onIntervalChange: (interval: string) => void
selectedInterval: ChartIntervals
actions?: ComponentProps<typeof ChartActions>['actions']
totalInvocationCount: number
totalErrorCount: number
totalWarningCount: number
isLoadingFunction: boolean
isErrorFunction: boolean
functionError?: unknown
isLoadingChart: boolean
isErrorChart: boolean
chartErrorMessage?: string
chartData: InvocationChartDatum[]
onChartClick: () => void
updateAnnotation?: InvocationUpdateAnnotation
}
export const EdgeFunctionInvocationsSection = ({
interval,
onIntervalChange,
selectedInterval,
actions,
totalInvocationCount,
totalErrorCount,
totalWarningCount,
isLoadingFunction,
isErrorFunction,
functionError,
isLoadingChart,
isErrorChart,
chartErrorMessage,
chartData,
onChartClick,
updateAnnotation,
}: EdgeFunctionInvocationsSectionProps) => {
const dateTimeFormat = selectedInterval.format ?? 'MMM D, h:mma'
const emptyStateCopy = useMemo(
() => getChartEmptyStateCopy('invocations', isErrorChart, chartErrorMessage),
[chartErrorMessage, isErrorChart]
)
return (
<PageSection className="bg-surface-100/50 border-b pb-10 pt-8">
<PageSectionContent>
<PageContainer size="full">
<div className="flex flex-col gap-5">
<PageSectionMeta className="!items-center">
<PageSectionSummary>
<div className="flex flex-wrap items-start gap-x-8 gap-y-4">
<ChartMetric
label="Total Invocations"
value={totalInvocationCount}
status="default"
tooltip="Total number of invocations"
/>
<ChartMetric
label="5xx Rate"
value={formatRate(totalErrorCount, totalInvocationCount)}
status="negative"
tooltip="Share of invocations that returned a 5xx status code"
/>
<ChartMetric
label="4xx Rate"
value={formatRate(totalWarningCount, totalInvocationCount)}
status="warning"
tooltip="Share of invocations that returned a 4xx status code"
/>
</div>
</PageSectionSummary>
<PageSectionAside className="flex-wrap @xl:self-center">
<div className="flex items-center">
{EDGE_FUNCTION_CHART_INTERVALS.map((item, index) => {
return (
<Button
key={`function-filter-${item.key}`}
type={interval === item.key ? 'secondary' : 'default'}
onClick={() => onIntervalChange(item.key)}
className={getSegmentedButtonClassName(
index,
EDGE_FUNCTION_CHART_INTERVALS.length
)}
>
{item.label}
</Button>
)
})}
</div>
<ChartActions actions={actions} />
</PageSectionAside>
</PageSectionMeta>
<div>
{isLoadingFunction && <GenericSkeletonLoader />}
{isErrorFunction && (
<AlertError
error={toAlertError(functionError)}
subject="Failed to retrieve edge function details"
layout="vertical"
/>
)}
</div>
<div>
<Chart isLoading={isLoadingChart}>
{isLoadingChart ? (
<ChartLoadingState />
) : isErrorChart || chartData.length === 0 ? (
<EdgeFunctionChartEmptyState
title={emptyStateCopy.title}
description={emptyStateCopy.description}
/>
) : (
<EdgeFunctionInvocationsChart
chartData={chartData}
dateTimeFormat={dateTimeFormat}
onChartClick={onChartClick}
updateAnnotation={updateAnnotation}
/>
)}
</Chart>
</div>
</div>
</PageContainer>
</PageSectionContent>
</PageSection>
)
}