EdgeFunctionInvocationsSection.tsx 5.4 KB

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