EdgeFunctionInvocationsSection.tsx156 lines · main
1import type { ComponentProps } from 'react'
2import { useMemo } from 'react'
3import { Button } from 'ui'
4import { Chart, ChartActions, ChartLoadingState, ChartMetric } from 'ui-patterns/Chart'
5import { PageContainer } from 'ui-patterns/PageContainer'
6import {
7 PageSection,
8 PageSectionAside,
9 PageSectionContent,
10 PageSectionMeta,
11 PageSectionSummary,
12} from 'ui-patterns/PageSection'
13import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
14
15import { EdgeFunctionChartEmptyState } from './EdgeFunctionChartEmptyState'
16import { EdgeFunctionInvocationsChart } from './EdgeFunctionInvocationsChart'
17import {
18 EDGE_FUNCTION_CHART_INTERVALS,
19 formatRate,
20 getChartEmptyStateCopy,
21 getSegmentedButtonClassName,
22} from './EdgeFunctionOverview.utils'
23import type { InvocationChartDatum, InvocationUpdateAnnotation } from './EdgeFunctionOverview.utils'
24import { toAlertError } from './EdgeFunctionRecentErrors.utils'
25import AlertError from '@/components/ui/AlertError'
26import type { ChartIntervals } from '@/types'
27
28interface EdgeFunctionInvocationsSectionProps {
29 interval: string
30 onIntervalChange: (interval: string) => void
31 selectedInterval: ChartIntervals
32 actions?: ComponentProps<typeof ChartActions>['actions']
33 totalInvocationCount: number
34 totalErrorCount: number
35 totalWarningCount: number
36 isLoadingFunction: boolean
37 isErrorFunction: boolean
38 functionError?: unknown
39 isLoadingChart: boolean
40 isErrorChart: boolean
41 chartErrorMessage?: string
42 chartData: InvocationChartDatum[]
43 onChartClick: () => void
44 updateAnnotation?: InvocationUpdateAnnotation
45}
46
47export const EdgeFunctionInvocationsSection = ({
48 interval,
49 onIntervalChange,
50 selectedInterval,
51 actions,
52 totalInvocationCount,
53 totalErrorCount,
54 totalWarningCount,
55 isLoadingFunction,
56 isErrorFunction,
57 functionError,
58 isLoadingChart,
59 isErrorChart,
60 chartErrorMessage,
61 chartData,
62 onChartClick,
63 updateAnnotation,
64}: EdgeFunctionInvocationsSectionProps) => {
65 const dateTimeFormat = selectedInterval.format ?? 'MMM D, h:mma'
66 const emptyStateCopy = useMemo(
67 () => getChartEmptyStateCopy('invocations', isErrorChart, chartErrorMessage),
68 [chartErrorMessage, isErrorChart]
69 )
70
71 return (
72 <PageSection className="bg-surface-100/50 border-b pb-10 pt-8">
73 <PageSectionContent>
74 <PageContainer size="full">
75 <div className="flex flex-col gap-5">
76 <PageSectionMeta className="items-center!">
77 <PageSectionSummary>
78 <div className="flex flex-wrap items-start gap-x-8 gap-y-4">
79 <ChartMetric
80 label="Total Invocations"
81 value={totalInvocationCount}
82 status="default"
83 tooltip="Total number of invocations"
84 />
85 <ChartMetric
86 label="5xx Rate"
87 value={formatRate(totalErrorCount, totalInvocationCount)}
88 status="negative"
89 tooltip="Share of invocations that returned a 5xx status code"
90 />
91 <ChartMetric
92 label="4xx Rate"
93 value={formatRate(totalWarningCount, totalInvocationCount)}
94 status="warning"
95 tooltip="Share of invocations that returned a 4xx status code"
96 />
97 </div>
98 </PageSectionSummary>
99 <PageSectionAside className="flex-wrap @xl:self-center">
100 <div className="flex items-center">
101 {EDGE_FUNCTION_CHART_INTERVALS.map((item, index) => {
102 return (
103 <Button
104 key={`function-filter-${item.key}`}
105 type={interval === item.key ? 'secondary' : 'default'}
106 onClick={() => onIntervalChange(item.key)}
107 className={getSegmentedButtonClassName(
108 index,
109 EDGE_FUNCTION_CHART_INTERVALS.length
110 )}
111 >
112 {item.label}
113 </Button>
114 )
115 })}
116 </div>
117 <ChartActions actions={actions} />
118 </PageSectionAside>
119 </PageSectionMeta>
120
121 <div>
122 {isLoadingFunction && <GenericSkeletonLoader />}
123 {isErrorFunction && (
124 <AlertError
125 error={toAlertError(functionError)}
126 subject="Failed to retrieve edge function details"
127 layout="vertical"
128 />
129 )}
130 </div>
131
132 <div>
133 <Chart isLoading={isLoadingChart}>
134 {isLoadingChart ? (
135 <ChartLoadingState />
136 ) : isErrorChart || chartData.length === 0 ? (
137 <EdgeFunctionChartEmptyState
138 title={emptyStateCopy.title}
139 description={emptyStateCopy.description}
140 />
141 ) : (
142 <EdgeFunctionInvocationsChart
143 chartData={chartData}
144 dateTimeFormat={dateTimeFormat}
145 onChartClick={onChartClick}
146 updateAnnotation={updateAnnotation}
147 />
148 )}
149 </Chart>
150 </div>
151 </div>
152 </PageContainer>
153 </PageSectionContent>
154 </PageSection>
155 )
156}