mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-28 00:17:12 +01:00
feat: backend connections tab (#9381)
This commit is contained in:
parent
359b7cc4c0
commit
f46ec293df
@ -14,6 +14,9 @@ const NetworkTraffic = lazy(() => import('./NetworkTraffic/NetworkTraffic'));
|
||||
const NetworkTrafficUsage = lazy(
|
||||
() => import('./NetworkTrafficUsage/NetworkTrafficUsage'),
|
||||
);
|
||||
const BackendConnections = lazy(
|
||||
() => import('./NetworkTrafficUsage/BackendConnections'),
|
||||
);
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
@ -28,17 +31,31 @@ const tabs = [
|
||||
label: 'Connected Edges',
|
||||
path: '/admin/network/connected-edges',
|
||||
},
|
||||
];
|
||||
|
||||
const seatModelTabs = [
|
||||
{
|
||||
label: 'Data Usage',
|
||||
path: '/admin/network/data-usage',
|
||||
},
|
||||
];
|
||||
|
||||
const consumptionModelTabs = [
|
||||
{
|
||||
label: 'Backend Connections',
|
||||
path: '/admin/network/backend-connections',
|
||||
},
|
||||
];
|
||||
|
||||
export const Network = () => {
|
||||
const { pathname } = useLocation();
|
||||
const edgeObservabilityEnabled = useUiFlag('edgeObservability');
|
||||
const consumptionModelEnabled = useUiFlag('consumptionModel');
|
||||
const allTabs = consumptionModelEnabled
|
||||
? [...tabs, ...consumptionModelTabs]
|
||||
: [...tabs, ...seatModelTabs];
|
||||
|
||||
const filteredTabs = tabs.filter(
|
||||
const filteredTabs = allTabs.filter(
|
||||
({ label }) => label !== 'Connected Edges' || edgeObservabilityEnabled,
|
||||
);
|
||||
|
||||
@ -82,6 +99,10 @@ export const Network = () => {
|
||||
path='data-usage'
|
||||
element={<NetworkTrafficUsage />}
|
||||
/>
|
||||
<Route
|
||||
path='backend-connections'
|
||||
element={<BackendConnections />}
|
||||
/>
|
||||
</Routes>
|
||||
</PageContent>
|
||||
</div>
|
||||
|
@ -0,0 +1,75 @@
|
||||
import type { FC } from 'react';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { Alert, Box } from '@mui/material';
|
||||
import { PeriodSelector } from './PeriodSelector';
|
||||
import { Bar } from 'react-chartjs-2';
|
||||
import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin';
|
||||
import { getChartLabel } from './chart-functions';
|
||||
import { useConsumptionStats } from './hooks/useStats';
|
||||
import { StyledBox, TopRow } from './SharedComponents';
|
||||
import {
|
||||
BarElement,
|
||||
CategoryScale,
|
||||
Chart as ChartJS,
|
||||
Legend,
|
||||
LinearScale,
|
||||
Title,
|
||||
Tooltip,
|
||||
} from 'chart.js';
|
||||
import annotationPlugin from 'chartjs-plugin-annotation';
|
||||
import { useChartDataSelection } from './hooks/useChartDataSelection';
|
||||
|
||||
export const BackendConnections: FC = () => {
|
||||
usePageTitle('Network - Backend Connections');
|
||||
|
||||
const { isOss } = useUiConfig();
|
||||
|
||||
const { chartDataSelection, setChartDataSelection, options } =
|
||||
useChartDataSelection();
|
||||
|
||||
const { chartData } = useConsumptionStats(chartDataSelection);
|
||||
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={isOss()}
|
||||
show={<Alert severity='warning'>Not enabled.</Alert>}
|
||||
elseShow={
|
||||
<>
|
||||
<StyledBox>
|
||||
<TopRow>
|
||||
<Box>
|
||||
1 connection = 7200 backend SDK requests per day
|
||||
</Box>
|
||||
<PeriodSelector
|
||||
selectedPeriod={chartDataSelection}
|
||||
setPeriod={setChartDataSelection}
|
||||
/>
|
||||
</TopRow>
|
||||
<Bar
|
||||
data={chartData}
|
||||
plugins={[customHighlightPlugin()]}
|
||||
options={options}
|
||||
aria-label={getChartLabel(chartDataSelection)}
|
||||
/>
|
||||
</StyledBox>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// Register dependencies that we need to draw the chart.
|
||||
ChartJS.register(
|
||||
annotationPlugin,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
);
|
||||
|
||||
// Use a default export to lazy-load the charting library.
|
||||
export default BackendConnections;
|
@ -1,172 +1,45 @@
|
||||
import { useMemo, useState, useEffect, type FC } from 'react';
|
||||
import { type FC, useEffect, useMemo, useState } from 'react';
|
||||
import useTheme from '@mui/material/styles/useTheme';
|
||||
import styled from '@mui/material/styles/styled';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
import Select from 'component/common/select';
|
||||
import Box from '@mui/system/Box';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { Alert, Link } from '@mui/material';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
type ChartOptions,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
CategoryScale,
|
||||
Chart as ChartJS,
|
||||
Legend,
|
||||
LinearScale,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
} from 'chart.js';
|
||||
|
||||
import { Bar } from 'react-chartjs-2';
|
||||
import {
|
||||
useInstanceTrafficMetrics,
|
||||
useTrafficSearch,
|
||||
} from 'hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics';
|
||||
import type { Theme } from '@mui/material/styles/createTheme';
|
||||
import { useInstanceTrafficMetrics } from 'hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import { NetworkTrafficUsagePlanSummary } from './NetworkTrafficUsagePlanSummary';
|
||||
import annotationPlugin from 'chartjs-plugin-annotation';
|
||||
import {
|
||||
useTrafficDataEstimation,
|
||||
calculateEstimatedMonthlyCost as deprecatedCalculateEstimatedMonthlyCost,
|
||||
useTrafficDataEstimation,
|
||||
} from 'hooks/useTrafficData';
|
||||
import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin';
|
||||
import { formatTickValue } from 'component/common/Chart/formatTickValue';
|
||||
import { useTrafficLimit } from './hooks/useTrafficLimit';
|
||||
import { BILLING_TRAFFIC_BUNDLE_PRICE } from 'component/admin/billing/BillingDashboard/BillingPlan/BillingPlan';
|
||||
import { useLocationSettings } from 'hooks/useLocationSettings';
|
||||
import { PeriodSelector } from './PeriodSelector';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { OverageInfo, RequestSummary } from './RequestSummary';
|
||||
import { averageTrafficPreviousMonths } from './average-traffic-previous-months';
|
||||
import {
|
||||
calculateTotalUsage,
|
||||
calculateOverageCost,
|
||||
calculateEstimatedMonthlyCost,
|
||||
} from 'utils/traffic-calculations';
|
||||
import { currentDate, currentMonth } from './dates';
|
||||
import { type ChartDataSelection, toDateRange } from './chart-data-selection';
|
||||
import {
|
||||
type ChartDatasetType,
|
||||
getChartLabel,
|
||||
toChartData as newToChartData,
|
||||
toConnectionChartData,
|
||||
} from './chart-functions';
|
||||
import { periodsRecord, selectablePeriods } from './selectable-periods';
|
||||
|
||||
const StyledBox = styled(Box)(({ theme }) => ({
|
||||
display: 'grid',
|
||||
gap: theme.spacing(5),
|
||||
}));
|
||||
|
||||
const createBarChartOptions = (
|
||||
theme: Theme,
|
||||
tooltipTitleCallback: (tooltipItems: any) => string,
|
||||
includedTraffic?: number,
|
||||
): ChartOptions<'bar'> => ({
|
||||
plugins: {
|
||||
annotation: {
|
||||
clip: false,
|
||||
annotations: {
|
||||
line: {
|
||||
type: 'line',
|
||||
borderDash: [5, 5],
|
||||
yMin: includedTraffic ? includedTraffic / 30 : 0,
|
||||
yMax: includedTraffic ? includedTraffic / 30 : 0,
|
||||
borderColor: 'gray',
|
||||
borderWidth: 1,
|
||||
display: !!includedTraffic,
|
||||
|
||||
label: {
|
||||
backgroundColor: 'rgba(192, 192, 192, 0.8)',
|
||||
color: 'black',
|
||||
padding: {
|
||||
top: 10,
|
||||
bottom: 10,
|
||||
left: 10,
|
||||
right: 10,
|
||||
},
|
||||
content: 'Average daily requests included in your plan',
|
||||
display: !!includedTraffic,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
color: theme.palette.text.primary,
|
||||
pointStyle: 'circle',
|
||||
usePointStyle: true,
|
||||
boxHeight: 6,
|
||||
padding: 15,
|
||||
boxPadding: 5,
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
titleColor: theme.palette.text.primary,
|
||||
bodyColor: theme.palette.text.primary,
|
||||
bodySpacing: 6,
|
||||
padding: {
|
||||
top: 20,
|
||||
bottom: 20,
|
||||
left: 30,
|
||||
right: 30,
|
||||
},
|
||||
borderColor: 'rgba(0, 0, 0, 0.05)',
|
||||
borderWidth: 3,
|
||||
usePointStyle: true,
|
||||
caretSize: 0,
|
||||
boxPadding: 10,
|
||||
callbacks: {
|
||||
title: tooltipTitleCallback,
|
||||
},
|
||||
},
|
||||
},
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true,
|
||||
ticks: {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
ticks: {
|
||||
color: theme.palette.text.secondary,
|
||||
maxTicksLimit: 5,
|
||||
callback: formatTickValue,
|
||||
},
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
elements: {
|
||||
bar: {
|
||||
borderRadius: 5,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
});
|
||||
|
||||
const TopRow = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexFlow: 'row wrap',
|
||||
justifyContent: 'space-between',
|
||||
gap: theme.spacing(2, 4),
|
||||
alignItems: 'start',
|
||||
}));
|
||||
import { calculateOverageCost } from 'utils/traffic-calculations';
|
||||
import { currentMonth } from './dates';
|
||||
import { type ChartDatasetType, getChartLabel } from './chart-functions';
|
||||
import { createBarChartOptions } from './bar-chart-options';
|
||||
import { useTrafficStats } from './hooks/useStats';
|
||||
import { BoldText, StyledBox, TopRow } from './SharedComponents';
|
||||
import { useChartDataSelection } from './hooks/useChartDataSelection';
|
||||
|
||||
const TrafficInfoBoxes = styled('div')(({ theme }) => ({
|
||||
display: 'grid',
|
||||
@ -175,123 +48,17 @@ const TrafficInfoBoxes = styled('div')(({ theme }) => ({
|
||||
gap: theme.spacing(2, 4),
|
||||
}));
|
||||
|
||||
const BoldText = styled('span')(({ theme }) => ({
|
||||
fontWeight: 'bold',
|
||||
}));
|
||||
|
||||
const useTrafficStats = (
|
||||
includedTraffic: number,
|
||||
chartDataSelection: ChartDataSelection,
|
||||
) => {
|
||||
const consumptionModelEnabled = useUiFlag('consumptionModel');
|
||||
const { result } = useTrafficSearch(
|
||||
chartDataSelection.grouping,
|
||||
toDateRange(chartDataSelection, currentDate),
|
||||
);
|
||||
const results = useMemo(() => {
|
||||
if (result.state !== 'success') {
|
||||
return {
|
||||
chartData: { datasets: [], labels: [] },
|
||||
usageTotal: 0,
|
||||
overageCost: 0,
|
||||
estimatedMonthlyCost: 0,
|
||||
requestSummaryUsage: 0,
|
||||
};
|
||||
}
|
||||
const traffic = result.data;
|
||||
|
||||
const chartData = consumptionModelEnabled
|
||||
? toConnectionChartData(traffic)
|
||||
: newToChartData(traffic);
|
||||
const usageTotal = calculateTotalUsage(traffic);
|
||||
const overageCost = calculateOverageCost(
|
||||
usageTotal,
|
||||
includedTraffic,
|
||||
BILLING_TRAFFIC_BUNDLE_PRICE,
|
||||
);
|
||||
|
||||
const estimatedMonthlyCost = calculateEstimatedMonthlyCost(
|
||||
traffic.apiData,
|
||||
includedTraffic,
|
||||
currentDate,
|
||||
BILLING_TRAFFIC_BUNDLE_PRICE,
|
||||
);
|
||||
|
||||
const requestSummaryUsage =
|
||||
chartDataSelection.grouping === 'daily'
|
||||
? usageTotal
|
||||
: averageTrafficPreviousMonths(traffic);
|
||||
|
||||
return {
|
||||
chartData,
|
||||
usageTotal,
|
||||
overageCost,
|
||||
estimatedMonthlyCost,
|
||||
requestSummaryUsage,
|
||||
};
|
||||
}, [
|
||||
JSON.stringify(result),
|
||||
includedTraffic,
|
||||
JSON.stringify(chartDataSelection),
|
||||
]);
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
const NewNetworkTrafficUsage: FC = () => {
|
||||
usePageTitle('Network - Data Usage');
|
||||
const theme = useTheme();
|
||||
|
||||
const estimateTrafficDataCost = useUiFlag('estimateTrafficDataCost');
|
||||
|
||||
const { isOss } = useUiConfig();
|
||||
|
||||
const { locationSettings } = useLocationSettings();
|
||||
|
||||
const [chartDataSelection, setChartDataSelection] =
|
||||
useState<ChartDataSelection>({
|
||||
grouping: 'daily',
|
||||
month: selectablePeriods[0].key,
|
||||
});
|
||||
|
||||
const includedTraffic = useTrafficLimit();
|
||||
|
||||
const options = useMemo(() => {
|
||||
return createBarChartOptions(
|
||||
theme,
|
||||
(tooltipItems: any) => {
|
||||
if (chartDataSelection.grouping === 'daily') {
|
||||
const periodItem = periodsRecord[chartDataSelection.month];
|
||||
const tooltipDate = new Date(
|
||||
periodItem.year,
|
||||
periodItem.month,
|
||||
Number.parseInt(tooltipItems[0].label),
|
||||
);
|
||||
return tooltipDate.toLocaleDateString(
|
||||
locationSettings?.locale ?? 'en-US',
|
||||
{
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const timestamp = Date.parse(tooltipItems[0].label);
|
||||
if (Number.isNaN(timestamp)) {
|
||||
return 'Current month to date';
|
||||
}
|
||||
return new Date(timestamp).toLocaleDateString(
|
||||
locationSettings?.locale ?? 'en-US',
|
||||
{
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
includedTraffic,
|
||||
);
|
||||
}, [theme, chartDataSelection]);
|
||||
const { chartDataSelection, setChartDataSelection, options } =
|
||||
useChartDataSelection(includedTraffic);
|
||||
|
||||
const {
|
||||
chartData,
|
||||
|
@ -0,0 +1,19 @@
|
||||
import styled from '@mui/material/styles/styled';
|
||||
import Box from '@mui/system/Box';
|
||||
|
||||
export const StyledBox = styled(Box)(({ theme }) => ({
|
||||
display: 'grid',
|
||||
gap: theme.spacing(5),
|
||||
}));
|
||||
|
||||
export const TopRow = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexFlow: 'row wrap',
|
||||
justifyContent: 'space-between',
|
||||
gap: theme.spacing(2, 4),
|
||||
alignItems: 'start',
|
||||
}));
|
||||
|
||||
export const BoldText = styled('span')(({ theme }) => ({
|
||||
fontWeight: 'bold',
|
||||
}));
|
@ -0,0 +1,102 @@
|
||||
import type { Theme } from '@mui/material/styles/createTheme';
|
||||
import type { ChartOptions } from 'chart.js';
|
||||
import { formatTickValue } from 'component/common/Chart/formatTickValue';
|
||||
|
||||
export const createBarChartOptions = (
|
||||
theme: Theme,
|
||||
tooltipTitleCallback: (tooltipItems: any) => string,
|
||||
includedTraffic?: number,
|
||||
): ChartOptions<'bar'> => ({
|
||||
plugins: {
|
||||
annotation: {
|
||||
clip: false,
|
||||
annotations: {
|
||||
line: {
|
||||
type: 'line',
|
||||
borderDash: [5, 5],
|
||||
yMin: includedTraffic ? includedTraffic / 30 : 0,
|
||||
yMax: includedTraffic ? includedTraffic / 30 : 0,
|
||||
borderColor: 'gray',
|
||||
borderWidth: 1,
|
||||
display: !!includedTraffic,
|
||||
|
||||
label: {
|
||||
backgroundColor: 'rgba(192, 192, 192, 0.8)',
|
||||
color: 'black',
|
||||
padding: {
|
||||
top: 10,
|
||||
bottom: 10,
|
||||
left: 10,
|
||||
right: 10,
|
||||
},
|
||||
content: 'Average daily requests included in your plan',
|
||||
display: !!includedTraffic,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
color: theme.palette.text.primary,
|
||||
pointStyle: 'circle',
|
||||
usePointStyle: true,
|
||||
boxHeight: 6,
|
||||
padding: 15,
|
||||
boxPadding: 5,
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
titleColor: theme.palette.text.primary,
|
||||
bodyColor: theme.palette.text.primary,
|
||||
bodySpacing: 6,
|
||||
padding: {
|
||||
top: 20,
|
||||
bottom: 20,
|
||||
left: 30,
|
||||
right: 30,
|
||||
},
|
||||
borderColor: 'rgba(0, 0, 0, 0.05)',
|
||||
borderWidth: 3,
|
||||
usePointStyle: true,
|
||||
caretSize: 0,
|
||||
boxPadding: 10,
|
||||
callbacks: {
|
||||
title: tooltipTitleCallback,
|
||||
},
|
||||
},
|
||||
},
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true,
|
||||
ticks: {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
ticks: {
|
||||
color: theme.palette.text.secondary,
|
||||
maxTicksLimit: 5,
|
||||
callback: formatTickValue,
|
||||
},
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
elements: {
|
||||
bar: {
|
||||
borderRadius: 5,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
import type { TrafficUsageDataSegmentedCombinedSchema } from 'openapi';
|
||||
import { toChartData } from './chart-functions';
|
||||
import { toTrafficUsageChartData } from './chart-functions';
|
||||
import { endpointsInfo } from './endpoint-info';
|
||||
|
||||
describe('toChartData', () => {
|
||||
@ -67,7 +67,7 @@ describe('toChartData', () => {
|
||||
],
|
||||
};
|
||||
|
||||
expect(toChartData(input)).toMatchObject(expectedOutput);
|
||||
expect(toTrafficUsageChartData(input)).toMatchObject(expectedOutput);
|
||||
});
|
||||
|
||||
test('daily data conversion', () => {
|
||||
@ -121,7 +121,7 @@ describe('toChartData', () => {
|
||||
),
|
||||
};
|
||||
|
||||
expect(toChartData(input)).toMatchObject(expectedOutput);
|
||||
expect(toTrafficUsageChartData(input)).toMatchObject(expectedOutput);
|
||||
});
|
||||
|
||||
test('sorts endpoints according to endpoint data spec', () => {
|
||||
@ -146,6 +146,6 @@ describe('toChartData', () => {
|
||||
],
|
||||
};
|
||||
|
||||
expect(toChartData(input)).toMatchObject(expectedOutput);
|
||||
expect(toTrafficUsageChartData(input)).toMatchObject(expectedOutput);
|
||||
});
|
||||
});
|
||||
|
@ -13,7 +13,7 @@ import { formatDay, formatMonth } from './dates';
|
||||
import type { ChartDataSelection } from './chart-data-selection';
|
||||
export type ChartDatasetType = ChartDataset<'bar'>;
|
||||
|
||||
export const toChartData = (
|
||||
export const toTrafficUsageChartData = (
|
||||
traffic: TrafficUsageDataSegmentedCombinedSchema,
|
||||
): { datasets: ChartDatasetType[]; labels: string[] } => {
|
||||
const { newRecord, labels } = getLabelsAndRecords(traffic);
|
||||
@ -47,6 +47,7 @@ export const toConnectionChartData = (
|
||||
): { 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 -
|
||||
@ -61,11 +62,14 @@ export const toConnectionChartData = (
|
||||
if (traffic.grouping === 'monthly') {
|
||||
// 1 connections = 7200 * days in month requests per day
|
||||
const daysInMonth = getDaysInMonth(date);
|
||||
record[dataPoint.period] =
|
||||
requestCount / (daysInMonth * 7200);
|
||||
record[dataPoint.period] = Number(
|
||||
(requestCount / (daysInMonth * 7200)).toFixed(1),
|
||||
);
|
||||
} else {
|
||||
// 1 connection = 7200 requests per day
|
||||
record[dataPoint.period] = requestCount / 7200;
|
||||
record[dataPoint.period] = Number(
|
||||
(requestCount / 7200).toFixed(1),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import type { ChartDataSelection } from '../chart-data-selection';
|
||||
import { periodsRecord, selectablePeriods } from '../selectable-periods';
|
||||
import { createBarChartOptions } from '../bar-chart-options';
|
||||
import useTheme from '@mui/material/styles/useTheme';
|
||||
import { useLocationSettings } from 'hooks/useLocationSettings';
|
||||
|
||||
export const useChartDataSelection = (includedTraffic?: number) => {
|
||||
const theme = useTheme();
|
||||
const { locationSettings } = useLocationSettings();
|
||||
|
||||
const [chartDataSelection, setChartDataSelection] =
|
||||
useState<ChartDataSelection>({
|
||||
grouping: 'daily',
|
||||
month: selectablePeriods[0].key,
|
||||
});
|
||||
|
||||
const options = useMemo(() => {
|
||||
return createBarChartOptions(
|
||||
theme,
|
||||
(tooltipItems: any) => {
|
||||
if (chartDataSelection.grouping === 'daily') {
|
||||
const periodItem = periodsRecord[chartDataSelection.month];
|
||||
const tooltipDate = new Date(
|
||||
periodItem.year,
|
||||
periodItem.month,
|
||||
Number.parseInt(tooltipItems[0].label),
|
||||
);
|
||||
return tooltipDate.toLocaleDateString(
|
||||
locationSettings?.locale ?? 'en-US',
|
||||
{
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const timestamp = Date.parse(tooltipItems[0].label);
|
||||
if (Number.isNaN(timestamp)) {
|
||||
return 'Current month to date';
|
||||
}
|
||||
return new Date(timestamp).toLocaleDateString(
|
||||
locationSettings?.locale ?? 'en-US',
|
||||
{
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
includedTraffic,
|
||||
);
|
||||
}, [theme, chartDataSelection]);
|
||||
|
||||
return { chartDataSelection, setChartDataSelection, options };
|
||||
};
|
@ -0,0 +1,98 @@
|
||||
import { type ChartDataSelection, toDateRange } from '../chart-data-selection';
|
||||
import { useTrafficSearch } from 'hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics';
|
||||
import { currentDate } from '../dates';
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
toTrafficUsageChartData as newToChartData,
|
||||
toConnectionChartData,
|
||||
} from '../chart-functions';
|
||||
import {
|
||||
calculateEstimatedMonthlyCost,
|
||||
calculateOverageCost,
|
||||
calculateTotalUsage,
|
||||
} from 'utils/traffic-calculations';
|
||||
import { BILLING_TRAFFIC_BUNDLE_PRICE } from '../../../billing/BillingDashboard/BillingPlan/BillingPlan';
|
||||
import { averageTrafficPreviousMonths } from '../average-traffic-previous-months';
|
||||
|
||||
export const useTrafficStats = (
|
||||
includedTraffic: number,
|
||||
chartDataSelection: ChartDataSelection,
|
||||
) => {
|
||||
const { result } = useTrafficSearch(
|
||||
chartDataSelection.grouping,
|
||||
toDateRange(chartDataSelection, currentDate),
|
||||
);
|
||||
const results = useMemo(() => {
|
||||
if (result.state !== 'success') {
|
||||
return {
|
||||
chartData: { datasets: [], labels: [] },
|
||||
usageTotal: 0,
|
||||
overageCost: 0,
|
||||
estimatedMonthlyCost: 0,
|
||||
requestSummaryUsage: 0,
|
||||
};
|
||||
}
|
||||
const traffic = result.data;
|
||||
|
||||
const chartData = newToChartData(traffic);
|
||||
const usageTotal = calculateTotalUsage(traffic);
|
||||
const overageCost = calculateOverageCost(
|
||||
usageTotal,
|
||||
includedTraffic,
|
||||
BILLING_TRAFFIC_BUNDLE_PRICE,
|
||||
);
|
||||
|
||||
const estimatedMonthlyCost = calculateEstimatedMonthlyCost(
|
||||
traffic.apiData,
|
||||
includedTraffic,
|
||||
currentDate,
|
||||
BILLING_TRAFFIC_BUNDLE_PRICE,
|
||||
);
|
||||
|
||||
const requestSummaryUsage =
|
||||
chartDataSelection.grouping === 'daily'
|
||||
? usageTotal
|
||||
: averageTrafficPreviousMonths(traffic);
|
||||
|
||||
return {
|
||||
chartData,
|
||||
usageTotal,
|
||||
overageCost,
|
||||
estimatedMonthlyCost,
|
||||
requestSummaryUsage,
|
||||
};
|
||||
}, [
|
||||
JSON.stringify(result),
|
||||
includedTraffic,
|
||||
JSON.stringify(chartDataSelection),
|
||||
]);
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
export const useConsumptionStats = (chartDataSelection: ChartDataSelection) => {
|
||||
const { result } = useTrafficSearch(
|
||||
chartDataSelection.grouping,
|
||||
toDateRange(chartDataSelection, currentDate),
|
||||
);
|
||||
const results = useMemo(() => {
|
||||
if (result.state !== 'success') {
|
||||
return {
|
||||
chartData: { datasets: [], labels: [] },
|
||||
usageTotal: 0,
|
||||
overageCost: 0,
|
||||
estimatedMonthlyCost: 0,
|
||||
requestSummaryUsage: 0,
|
||||
};
|
||||
}
|
||||
const traffic = result.data;
|
||||
|
||||
const chartData = toConnectionChartData(traffic);
|
||||
|
||||
return {
|
||||
chartData,
|
||||
};
|
||||
}, [JSON.stringify(result), JSON.stringify(chartDataSelection)]);
|
||||
|
||||
return results;
|
||||
};
|
Loading…
Reference in New Issue
Block a user