Skip to content

Commit 1b7f91c

Browse files
authored
feat: read backend connections UI (#9526)
1 parent 22f51df commit 1b7f91c

File tree

5 files changed

+100
-69
lines changed

5 files changed

+100
-69
lines changed

frontend/src/component/admin/network/NetworkTrafficUsage/BackendConnections.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
import annotationPlugin from 'chartjs-plugin-annotation';
2222
import { useChartDataSelection } from './hooks/useChartDataSelection';
2323

24+
// TODO: consider renaming to Connection Consumption
2425
export const BackendConnections: FC = () => {
2526
usePageTitle('Network - Backend Connections');
2627

frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.test.ts

+24-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import type { TrafficUsageDataSegmentedCombinedSchema } from 'openapi';
1+
import type {
2+
MeteredConnectionsSchema,
3+
TrafficUsageDataSegmentedCombinedSchema,
4+
} from 'openapi';
25
import {
36
toConnectionChartData,
47
toTrafficUsageChartData,
@@ -152,9 +155,9 @@ describe('toTrafficUsageChartData', () => {
152155
});
153156

154157
describe('toConnectionChartData', () => {
155-
const dataPoint = (period: string, count: number) => ({
158+
const dataPoint = (period: string, connections: number) => ({
156159
period,
157-
trafficTypes: [{ count, group: 'successful-requests' }],
160+
connections,
158161
});
159162

160163
const fromEndpointInfo = (endpoint: keyof typeof endpointsInfo) => {
@@ -167,24 +170,20 @@ describe('toConnectionChartData', () => {
167170
};
168171

169172
test('monthly data conversion', () => {
170-
const input: TrafficUsageDataSegmentedCombinedSchema = {
173+
const input: MeteredConnectionsSchema = {
171174
grouping: 'monthly',
172175
dateRange: {
173176
from: '2025-01-01',
174177
to: '2025-06-30',
175178
},
176179
apiData: [
177180
{
178-
apiPath: '/api/admin', // filter out
179-
dataPoints: [dataPoint('2025-06', 5)],
180-
},
181-
{
182-
apiPath: '/api/client',
181+
meteredGroup: 'default',
183182
dataPoints: [
184-
dataPoint('2025-06', 10 * 5 * 60 * 24 * 30),
185-
dataPoint('2025-01', 7 * 5 * 60 * 24 * 31),
186-
dataPoint('2025-03', 11 * 5 * 60 * 24 * 31),
187-
dataPoint('2025-04', 13 * 5 * 60 * 24 * 30),
183+
dataPoint('2025-06', 10),
184+
dataPoint('2025-01', 7),
185+
dataPoint('2025-03', 11),
186+
dataPoint('2025-04', 13),
188187
],
189188
},
190189
],
@@ -194,7 +193,9 @@ describe('toConnectionChartData', () => {
194193
datasets: [
195194
{
196195
data: [7, 0, 11, 13, 0, 10],
197-
...fromEndpointInfo('/api/client'),
196+
hoverBackgroundColor: '#6D66D9',
197+
label: 'Connections',
198+
backgroundColor: '#6D66D9',
198199
},
199200
],
200201
labels: [
@@ -211,24 +212,20 @@ describe('toConnectionChartData', () => {
211212
});
212213

213214
test('daily data conversion', () => {
214-
const input: TrafficUsageDataSegmentedCombinedSchema = {
215+
const input: MeteredConnectionsSchema = {
215216
grouping: 'daily',
216217
dateRange: {
217218
from: '2025-01-01',
218219
to: '2025-01-31',
219220
},
220221
apiData: [
221222
{
222-
apiPath: '/api/admin', // filter out
223-
dataPoints: [dataPoint('2025-01-01', 5)],
224-
},
225-
{
226-
apiPath: '/api/client',
223+
meteredGroup: 'default',
227224
dataPoints: [
228-
dataPoint('2025-01-02', 2 * 5 * 60 * 24),
229-
dataPoint('2025-01-17', 6 * 5 * 60 * 24),
230-
dataPoint('2025-01-19', 4 * 5 * 60 * 24),
231-
dataPoint('2025-01-06', 8 * 5 * 60 * 24),
225+
dataPoint('2025-01-02', 2),
226+
dataPoint('2025-01-17', 6),
227+
dataPoint('2025-01-19', 4),
228+
dataPoint('2025-01-06', 8),
232229
],
233230
},
234231
],
@@ -241,7 +238,9 @@ describe('toConnectionChartData', () => {
241238
0, 2, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 4,
242239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
243240
],
244-
...fromEndpointInfo('/api/client'),
241+
hoverBackgroundColor: '#6D66D9',
242+
label: 'Connections',
243+
backgroundColor: '#6D66D9',
245244
},
246245
],
247246
labels: Array.from({ length: 31 }).map((_, index) =>

frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.ts

+27-39
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import type { ChartDataset } from 'chart.js';
2-
import type { TrafficUsageDataSegmentedCombinedSchema } from 'openapi';
2+
import type {
3+
MeteredConnectionsSchema,
4+
TrafficUsageDataSegmentedCombinedSchema,
5+
} from 'openapi';
36
import { endpointsInfo } from './endpoint-info';
47
import {
58
addDays,
69
addMonths,
710
differenceInCalendarDays,
811
differenceInCalendarMonths,
9-
getDaysInMonth,
10-
parseISO,
1112
} from 'date-fns';
1213
import { formatDay, formatMonth } from './dates';
1314
import type { ChartDataSelection } from './chart-data-selection';
@@ -45,51 +46,38 @@ export const toTrafficUsageChartData = (
4546
};
4647

4748
export const toConnectionChartData = (
48-
traffic: TrafficUsageDataSegmentedCombinedSchema,
49+
traffic: MeteredConnectionsSchema,
4950
): { datasets: ChartDatasetType[]; labels: string[] } => {
5051
const { newRecord, labels } = getLabelsAndRecords(traffic);
51-
const datasets = traffic.apiData
52-
.filter((apiData) => apiData.apiPath === '/api/client')
53-
.sort(
54-
(item1, item2) =>
55-
endpointsInfo[item1.apiPath].order -
56-
endpointsInfo[item2.apiPath].order,
57-
)
58-
.map((item) => {
59-
const record = newRecord();
60-
for (const dataPoint of Object.values(item.dataPoints)) {
61-
const date = parseISO(dataPoint.period);
62-
const requestCount = dataPoint.trafficTypes[0].count;
63-
64-
if (traffic.grouping === 'monthly') {
65-
// 1 connections = 7200 * days in month requests per day
66-
const daysInMonth = getDaysInMonth(date);
67-
record[dataPoint.period] = Number(
68-
(requestCount / (daysInMonth * 7200)).toFixed(1),
69-
);
70-
} else {
71-
// 1 connection = 7200 requests per day
72-
record[dataPoint.period] = Number(
73-
(requestCount / 7200).toFixed(1),
74-
);
75-
}
76-
}
52+
const datasets = traffic.apiData.map((item) => {
53+
const record = newRecord();
54+
for (const dataPoint of Object.values(item.dataPoints)) {
55+
const requestCount = dataPoint.connections;
56+
record[dataPoint.period] = requestCount;
57+
}
7758

78-
const epInfo = endpointsInfo[item.apiPath];
59+
const epInfo = {
60+
label: 'Connections',
61+
color: '#6D66D9',
62+
order: 1,
63+
};
7964

80-
return {
81-
label: epInfo.label,
82-
data: Object.values(record),
83-
backgroundColor: epInfo.color,
84-
hoverBackgroundColor: epInfo.color,
85-
};
86-
});
65+
return {
66+
label: epInfo.label,
67+
data: Object.values(record),
68+
backgroundColor: epInfo.color,
69+
hoverBackgroundColor: epInfo.color,
70+
};
71+
});
8772

8873
return { datasets, labels };
8974
};
9075

9176
const getLabelsAndRecords = (
92-
traffic: TrafficUsageDataSegmentedCombinedSchema,
77+
traffic: Pick<
78+
TrafficUsageDataSegmentedCombinedSchema,
79+
'dateRange' | 'grouping'
80+
>,
9381
) => {
9482
if (traffic.grouping === 'monthly') {
9583
const from = new Date(traffic.dateRange.from);

frontend/src/component/admin/network/NetworkTrafficUsage/hooks/useStats.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
} from 'utils/traffic-calculations';
1414
import { BILLING_TRAFFIC_BUNDLE_PRICE } from '../../../billing/BillingDashboard/BillingPlan/BillingPlan';
1515
import { averageTrafficPreviousMonths } from '../average-traffic-previous-months';
16+
import { useConnectionsConsumption } from 'hooks/api/getters/useConnectionsConsumption/useConnectionsConsumption';
1617

1718
export const useTrafficStats = (
1819
includedTraffic: number,
@@ -72,18 +73,14 @@ export const useTrafficStats = (
7273
};
7374

7475
export const useConsumptionStats = (chartDataSelection: ChartDataSelection) => {
75-
const { result } = useTrafficSearch(
76+
const { result } = useConnectionsConsumption(
7677
chartDataSelection.grouping,
7778
toDateRange(chartDataSelection, currentDate),
7879
);
7980
const results = useMemo(() => {
8081
if (result.state !== 'success') {
8182
return {
8283
chartData: { datasets: [], labels: [] },
83-
usageTotal: 0,
84-
overageCost: 0,
85-
estimatedMonthlyCost: 0,
86-
requestSummaryUsage: 0,
8784
};
8885
}
8986
const traffic = result.data;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import useSWR from 'swr';
2+
import { useMemo } from 'react';
3+
import { formatApiPath } from 'utils/formatPath';
4+
import handleErrorResponses from '../httpErrorResponseHandler';
5+
import type { MeteredConnectionsSchema } from 'openapi';
6+
7+
export type MeteredConnectionsResponse = {
8+
refetch: () => void;
9+
result:
10+
| { state: 'success'; data: MeteredConnectionsSchema }
11+
| { state: 'error'; error: Error }
12+
| { state: 'loading' };
13+
};
14+
15+
export const useConnectionsConsumption = (
16+
grouping: 'monthly' | 'daily',
17+
{
18+
from,
19+
to,
20+
}: {
21+
from: string;
22+
to: string;
23+
},
24+
): MeteredConnectionsResponse => {
25+
const apiPath = `api/admin/metrics/connection?grouping=${grouping}&from=${from}&to=${to}`;
26+
27+
const { data, error, mutate } = useSWR(formatApiPath(apiPath), fetcher);
28+
29+
return useMemo(() => {
30+
const result = data
31+
? { state: 'success' as const, data: data }
32+
: error
33+
? { state: 'error' as const, error }
34+
: { state: 'loading' as const };
35+
return {
36+
refetch: () => mutate(),
37+
result,
38+
};
39+
}, [data, error, mutate]);
40+
};
41+
42+
const fetcher = (path: string) => {
43+
return fetch(path)
44+
.then(handleErrorResponses('Metered Connections Metrics'))
45+
.then((res) => res.json());
46+
};

0 commit comments

Comments
 (0)