diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/BackendConnections.tsx b/frontend/src/component/admin/network/NetworkTrafficUsage/BackendConnections.tsx index 2c0c4dfdfb..675a7929ed 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/BackendConnections.tsx +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/BackendConnections.tsx @@ -21,6 +21,7 @@ import { import annotationPlugin from 'chartjs-plugin-annotation'; import { useChartDataSelection } from './hooks/useChartDataSelection'; +// TODO: consider renaming to Connection Consumption export const BackendConnections: FC = () => { usePageTitle('Network - Backend Connections'); diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.test.ts b/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.test.ts index dbf00b29f7..05ef1fdee1 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.test.ts +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.test.ts @@ -1,4 +1,7 @@ -import type { TrafficUsageDataSegmentedCombinedSchema } from 'openapi'; +import type { + MeteredConnectionsSchema, + TrafficUsageDataSegmentedCombinedSchema, +} from 'openapi'; import { toConnectionChartData, toTrafficUsageChartData, @@ -152,9 +155,9 @@ describe('toTrafficUsageChartData', () => { }); describe('toConnectionChartData', () => { - const dataPoint = (period: string, count: number) => ({ + const dataPoint = (period: string, connections: number) => ({ period, - trafficTypes: [{ count, group: 'successful-requests' }], + connections, }); const fromEndpointInfo = (endpoint: keyof typeof endpointsInfo) => { @@ -167,7 +170,7 @@ describe('toConnectionChartData', () => { }; test('monthly data conversion', () => { - const input: TrafficUsageDataSegmentedCombinedSchema = { + const input: MeteredConnectionsSchema = { grouping: 'monthly', dateRange: { from: '2025-01-01', @@ -175,16 +178,12 @@ describe('toConnectionChartData', () => { }, apiData: [ { - apiPath: '/api/admin', // filter out - dataPoints: [dataPoint('2025-06', 5)], - }, - { - apiPath: '/api/client', + meteredGroup: 'default', dataPoints: [ - dataPoint('2025-06', 10 * 5 * 60 * 24 * 30), - dataPoint('2025-01', 7 * 5 * 60 * 24 * 31), - dataPoint('2025-03', 11 * 5 * 60 * 24 * 31), - dataPoint('2025-04', 13 * 5 * 60 * 24 * 30), + dataPoint('2025-06', 10), + dataPoint('2025-01', 7), + dataPoint('2025-03', 11), + dataPoint('2025-04', 13), ], }, ], @@ -194,7 +193,9 @@ describe('toConnectionChartData', () => { datasets: [ { data: [7, 0, 11, 13, 0, 10], - ...fromEndpointInfo('/api/client'), + hoverBackgroundColor: '#6D66D9', + label: 'Connections', + backgroundColor: '#6D66D9', }, ], labels: [ @@ -211,7 +212,7 @@ describe('toConnectionChartData', () => { }); test('daily data conversion', () => { - const input: TrafficUsageDataSegmentedCombinedSchema = { + const input: MeteredConnectionsSchema = { grouping: 'daily', dateRange: { from: '2025-01-01', @@ -219,16 +220,12 @@ describe('toConnectionChartData', () => { }, apiData: [ { - apiPath: '/api/admin', // filter out - dataPoints: [dataPoint('2025-01-01', 5)], - }, - { - apiPath: '/api/client', + meteredGroup: 'default', dataPoints: [ - dataPoint('2025-01-02', 2 * 5 * 60 * 24), - dataPoint('2025-01-17', 6 * 5 * 60 * 24), - dataPoint('2025-01-19', 4 * 5 * 60 * 24), - dataPoint('2025-01-06', 8 * 5 * 60 * 24), + dataPoint('2025-01-02', 2), + dataPoint('2025-01-17', 6), + dataPoint('2025-01-19', 4), + dataPoint('2025-01-06', 8), ], }, ], @@ -241,7 +238,9 @@ describe('toConnectionChartData', () => { 0, 2, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], - ...fromEndpointInfo('/api/client'), + hoverBackgroundColor: '#6D66D9', + label: 'Connections', + backgroundColor: '#6D66D9', }, ], labels: Array.from({ length: 31 }).map((_, index) => diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.ts b/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.ts index 985b30c082..56af65ab67 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.ts +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.ts @@ -1,13 +1,14 @@ import type { ChartDataset } from 'chart.js'; -import type { TrafficUsageDataSegmentedCombinedSchema } from 'openapi'; +import type { + MeteredConnectionsSchema, + TrafficUsageDataSegmentedCombinedSchema, +} from 'openapi'; import { endpointsInfo } from './endpoint-info'; import { addDays, addMonths, differenceInCalendarDays, differenceInCalendarMonths, - getDaysInMonth, - parseISO, } from 'date-fns'; import { formatDay, formatMonth } from './dates'; import type { ChartDataSelection } from './chart-data-selection'; @@ -45,51 +46,38 @@ export const toTrafficUsageChartData = ( }; export const toConnectionChartData = ( - traffic: TrafficUsageDataSegmentedCombinedSchema, + traffic: MeteredConnectionsSchema, ): { datasets: ChartDatasetType[]; labels: string[] } => { const { newRecord, labels } = getLabelsAndRecords(traffic); - const datasets = traffic.apiData - .filter((apiData) => apiData.apiPath === '/api/client') - .sort( - (item1, item2) => - endpointsInfo[item1.apiPath].order - - endpointsInfo[item2.apiPath].order, - ) - .map((item) => { - const record = newRecord(); - for (const dataPoint of Object.values(item.dataPoints)) { - const date = parseISO(dataPoint.period); - const requestCount = dataPoint.trafficTypes[0].count; + const datasets = traffic.apiData.map((item) => { + const record = newRecord(); + for (const dataPoint of Object.values(item.dataPoints)) { + const requestCount = dataPoint.connections; + record[dataPoint.period] = requestCount; + } - if (traffic.grouping === 'monthly') { - // 1 connections = 7200 * days in month requests per day - const daysInMonth = getDaysInMonth(date); - record[dataPoint.period] = Number( - (requestCount / (daysInMonth * 7200)).toFixed(1), - ); - } else { - // 1 connection = 7200 requests per day - record[dataPoint.period] = Number( - (requestCount / 7200).toFixed(1), - ); - } - } + const epInfo = { + label: 'Connections', + color: '#6D66D9', + order: 1, + }; - const epInfo = endpointsInfo[item.apiPath]; - - return { - label: epInfo.label, - data: Object.values(record), - backgroundColor: epInfo.color, - hoverBackgroundColor: epInfo.color, - }; - }); + return { + label: epInfo.label, + data: Object.values(record), + backgroundColor: epInfo.color, + hoverBackgroundColor: epInfo.color, + }; + }); return { datasets, labels }; }; const getLabelsAndRecords = ( - traffic: TrafficUsageDataSegmentedCombinedSchema, + traffic: Pick< + TrafficUsageDataSegmentedCombinedSchema, + 'dateRange' | 'grouping' + >, ) => { if (traffic.grouping === 'monthly') { const from = new Date(traffic.dateRange.from); diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/hooks/useStats.ts b/frontend/src/component/admin/network/NetworkTrafficUsage/hooks/useStats.ts index c83916e5af..36bd85e58a 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/hooks/useStats.ts +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/hooks/useStats.ts @@ -13,6 +13,7 @@ import { } from 'utils/traffic-calculations'; import { BILLING_TRAFFIC_BUNDLE_PRICE } from '../../../billing/BillingDashboard/BillingPlan/BillingPlan'; import { averageTrafficPreviousMonths } from '../average-traffic-previous-months'; +import { useConnectionsConsumption } from 'hooks/api/getters/useConnectionsConsumption/useConnectionsConsumption'; export const useTrafficStats = ( includedTraffic: number, @@ -72,7 +73,7 @@ export const useTrafficStats = ( }; export const useConsumptionStats = (chartDataSelection: ChartDataSelection) => { - const { result } = useTrafficSearch( + const { result } = useConnectionsConsumption( chartDataSelection.grouping, toDateRange(chartDataSelection, currentDate), ); @@ -80,10 +81,6 @@ export const useConsumptionStats = (chartDataSelection: ChartDataSelection) => { if (result.state !== 'success') { return { chartData: { datasets: [], labels: [] }, - usageTotal: 0, - overageCost: 0, - estimatedMonthlyCost: 0, - requestSummaryUsage: 0, }; } const traffic = result.data; diff --git a/frontend/src/hooks/api/getters/useConnectionsConsumption/useConnectionsConsumption.ts b/frontend/src/hooks/api/getters/useConnectionsConsumption/useConnectionsConsumption.ts new file mode 100644 index 0000000000..3435ff22f1 --- /dev/null +++ b/frontend/src/hooks/api/getters/useConnectionsConsumption/useConnectionsConsumption.ts @@ -0,0 +1,46 @@ +import useSWR from 'swr'; +import { useMemo } from 'react'; +import { formatApiPath } from 'utils/formatPath'; +import handleErrorResponses from '../httpErrorResponseHandler'; +import type { MeteredConnectionsSchema } from 'openapi'; + +export type MeteredConnectionsResponse = { + refetch: () => void; + result: + | { state: 'success'; data: MeteredConnectionsSchema } + | { state: 'error'; error: Error } + | { state: 'loading' }; +}; + +export const useConnectionsConsumption = ( + grouping: 'monthly' | 'daily', + { + from, + to, + }: { + from: string; + to: string; + }, +): MeteredConnectionsResponse => { + const apiPath = `api/admin/metrics/connection?grouping=${grouping}&from=${from}&to=${to}`; + + const { data, error, mutate } = useSWR(formatApiPath(apiPath), fetcher); + + return useMemo(() => { + const result = data + ? { state: 'success' as const, data: data } + : error + ? { state: 'error' as const, error } + : { state: 'loading' as const }; + return { + refetch: () => mutate(), + result, + }; + }, [data, error, mutate]); +}; + +const fetcher = (path: string) => { + return fetch(path) + .then(handleErrorResponses('Metered Connections Metrics')) + .then((res) => res.json()); +};