api-overview.tsx195 lines · main
1import { useCallback } from 'react'
2
3import {
4 ErrorCountsChartRenderer,
5 NetworkTrafficRenderer,
6 RequestsByCountryMapRenderer,
7 ResponseSpeedChartRenderer,
8 TopApiRoutesRenderer,
9 TotalRequestsChartRenderer,
10} from '@/components/interfaces/Reports/renderers/ApiRenderers'
11import ReportFilterBar from '@/components/interfaces/Reports/ReportFilterBar'
12import ReportHeader from '@/components/interfaces/Reports/ReportHeader'
13import ReportPadding from '@/components/interfaces/Reports/ReportPadding'
14import { REPORT_DATERANGE_HELPER_LABELS } from '@/components/interfaces/Reports/Reports.constants'
15import ReportStickyNav from '@/components/interfaces/Reports/ReportStickyNav'
16import ReportWidget from '@/components/interfaces/Reports/ReportWidget'
17import { DatePickerValue } from '@/components/interfaces/Settings/Logs/Logs.DatePickers'
18import UpgradePrompt from '@/components/interfaces/Settings/Logs/UpgradePrompt'
19import DefaultLayout from '@/components/layouts/DefaultLayout'
20import ObservabilityLayout from '@/components/layouts/ObservabilityLayout/ObservabilityLayout'
21import { ObservabilityLink } from '@/components/ui/ObservabilityLink'
22import { useApiReport } from '@/data/reports/api-report-query'
23import { useReportDateRange } from '@/hooks/misc/useReportDateRange'
24import type { NextPageWithLayout } from '@/types'
25
26export const ApiReport: NextPageWithLayout = () => {
27 const report = useApiReport()
28
29 const {
30 data,
31 error,
32 filters,
33 isLoading,
34 params,
35 mergeParams,
36 removeFilters,
37 addFilter,
38 refresh,
39 } = report
40
41 const {
42 datePickerHelpers,
43 datePickerValue,
44 handleDatePickerChange: handleDatePickerChangeFromHook,
45 showUpgradePrompt,
46 setShowUpgradePrompt,
47 } = useReportDateRange(REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES)
48
49 const handleDatepickerChange = useCallback(
50 (vals: DatePickerValue) => {
51 const promptShown = handleDatePickerChangeFromHook(vals)
52 if (!promptShown) {
53 mergeParams({
54 iso_timestamp_start: vals.from ?? '',
55 iso_timestamp_end: vals.to ?? '',
56 })
57 }
58 },
59 [handleDatePickerChangeFromHook, mergeParams]
60 )
61
62 const handleDatepickerChangeForRefresh = useCallback(
63 (vals: DatePickerValue) => {
64 handleDatePickerChangeFromHook(vals)
65 mergeParams({
66 iso_timestamp_start: vals.from ?? '',
67 iso_timestamp_end: vals.to ?? '',
68 })
69 handleDatepickerChange(vals)
70 },
71 [handleDatePickerChangeFromHook, mergeParams, handleDatepickerChange]
72 )
73
74 const refreshWithParams = useCallback(async () => {
75 await new Promise((resolve) => setTimeout(resolve, 0))
76 refresh()
77 }, [refresh])
78
79 const onRefreshReport = useCallback(async () => {
80 if (datePickerValue.isHelper && datePickerValue.text) {
81 const selectedHelper = datePickerHelpers.find((h) => h.text === datePickerValue.text)
82 if (selectedHelper) {
83 handleDatepickerChangeForRefresh({
84 from: selectedHelper.calcFrom(),
85 to: selectedHelper.calcTo(),
86 isHelper: true,
87 text: selectedHelper.text,
88 })
89 }
90 }
91
92 await refreshWithParams()
93 }, [datePickerValue, datePickerHelpers, handleDatepickerChangeForRefresh, refreshWithParams])
94
95 return (
96 <ReportPadding>
97 <ReportHeader title="API Gateway" showDatabaseSelector={false} />
98 <ReportStickyNav
99 content={
100 <div className="flex items-center gap-3">
101 <ReportFilterBar
102 onRemoveFilters={removeFilters}
103 onDatepickerChange={handleDatepickerChange}
104 datepickerFrom={params.totalRequests.iso_timestamp_start}
105 datepickerTo={params.totalRequests.iso_timestamp_end}
106 onAddFilter={addFilter}
107 onRefresh={onRefreshReport}
108 isLoading={isLoading}
109 filters={filters}
110 datepickerHelpers={datePickerHelpers}
111 initialDatePickerValue={datePickerValue}
112 className="w-full"
113 showDatabaseSelector={false}
114 />
115 <UpgradePrompt
116 show={showUpgradePrompt}
117 setShowUpgradePrompt={setShowUpgradePrompt}
118 title="Report date range"
119 description="Report data can be stored for a maximum of 3 months depending on the plan that your project is on."
120 source="apiReportDateRange"
121 />
122 </div>
123 }
124 >
125 <ReportWidget
126 isLoading={isLoading}
127 params={params.requestsByCountry}
128 error={error.requestsByCountry}
129 title="Requests by Geography"
130 tooltip="Number of API Gateway requests per geography"
131 data={data.requestsByCountry || []}
132 renderer={RequestsByCountryMapRenderer}
133 contentClassName="p-0 overflow-hidden"
134 headerClassName="px-4 pt-4"
135 />
136 <ReportWidget
137 isLoading={isLoading}
138 params={params.totalRequests}
139 title="Total Requests"
140 data={data.totalRequests || []}
141 error={error.totalRequest}
142 renderer={TotalRequestsChartRenderer}
143 append={TopApiRoutesRenderer}
144 appendProps={{ data: data.topRoutes || [], params: params.topRoutes }}
145 />
146 <ReportWidget
147 isLoading={isLoading}
148 params={params.errorCounts}
149 title="Response Errors"
150 tooltip="Error responses with 4XX or 5XX status codes"
151 data={data.errorCounts || []}
152 error={error.errorCounts}
153 renderer={ErrorCountsChartRenderer}
154 appendProps={{
155 data: data.topErrorRoutes || [],
156 params: params.topErrorRoutes,
157 }}
158 append={TopApiRoutesRenderer}
159 />
160 <ReportWidget
161 isLoading={isLoading}
162 params={params.responseSpeed}
163 title="Response Speed"
164 tooltip="Average response speed of a request (in ms)"
165 data={data.responseSpeed || []}
166 error={error.responseSpeed}
167 renderer={ResponseSpeedChartRenderer}
168 appendProps={{ data: data.topSlowRoutes || [], params: params.topSlowRoutes }}
169 append={TopApiRoutesRenderer}
170 />
171
172 <ReportWidget
173 isLoading={isLoading}
174 params={params.networkTraffic}
175 error={error.networkTraffic}
176 title="Network Traffic"
177 tooltip="Ingress and egress of requests and responses respectively"
178 data={data.networkTraffic || []}
179 renderer={NetworkTrafficRenderer}
180 />
181 </ReportStickyNav>
182 <div className="py-8">
183 <ObservabilityLink />
184 </div>
185 </ReportPadding>
186 )
187}
188
189ApiReport.getLayout = (page) => (
190 <DefaultLayout>
191 <ObservabilityLayout title="API Gateway">{page}</ObservabilityLayout>
192 </DefaultLayout>
193)
194
195export default ApiReport