From 87a84426ec6a4925cc0e46c6538c8cc1e239e0cd Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 29 Jan 2025 10:43:41 +0100 Subject: [PATCH] feat(1-3267): use new API for chart creation (#9149) Adds support for the new /traffic-search API behind a flag. When active, you'll be able to select month ranges as well as specific single months. Largely copies the existing network traffic component, and adds some minor tweaks to make it work with the new data. This is quite rough, but it gives us a base to build on for later. There's still things that we need to solve for in following PRs. --- .../NetworkTrafficUsage.tsx | 229 +++++++++++++++--- .../NetworkTrafficUsage/PeriodSelector.tsx | 38 +-- .../monthly-traffic-data-to-current-usage.ts | 22 ++ .../useInstanceTrafficMetrics.ts | 65 ++++- frontend/src/hooks/useTrafficData.ts | 125 +++++++++- 5 files changed, 413 insertions(+), 66 deletions(-) create mode 100644 frontend/src/component/admin/network/NetworkTrafficUsage/monthly-traffic-data-to-current-usage.ts diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx b/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx index 113ccd5926..bc5b4e489e 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx @@ -20,13 +20,17 @@ import { } from 'chart.js'; import { Bar } from 'react-chartjs-2'; -import { useInstanceTrafficMetrics } from 'hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics'; +import { + useInstanceTrafficMetrics, + useInstanceTrafficMetrics2, +} from 'hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics'; import type { Theme } from '@mui/material/styles/createTheme'; import Grid from '@mui/material/Grid'; import { NetworkTrafficUsagePlanSummary } from './NetworkTrafficUsagePlanSummary'; import annotationPlugin from 'chartjs-plugin-annotation'; import { type ChartDatasetType, + newToChartData, useTrafficDataEstimation, } from 'hooks/useTrafficData'; import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin'; @@ -36,6 +40,8 @@ import { BILLING_TRAFFIC_BUNDLE_PRICE } from 'component/admin/billing/BillingDas import { useLocationSettings } from 'hooks/useLocationSettings'; import { PeriodSelector } from './PeriodSelector'; import { useUiFlag } from 'hooks/useUiFlag'; +import { format } from 'date-fns'; +import { monthlyTrafficDataToCurrentUsage } from './monthly-traffic-data-to-current-usage'; const StyledBox = styled(Box)(({ theme }) => ({ display: 'grid', @@ -148,10 +154,173 @@ const NewHeader = styled('div')(() => ({ alignItems: 'flex-start', })); -export const NetworkTrafficUsage: FC = () => { +const NewNetworkTrafficUsage: FC = () => { + usePageTitle('Network - Data Usage'); + const theme = useTheme(); + + const { isOss } = useUiConfig(); + + const { locationSettings } = useLocationSettings(); + const { + record, + newPeriod, + setNewPeriod, + toTrafficUsageSum, + calculateOverageCost, + calculateEstimatedMonthlyCost, + } = useTrafficDataEstimation(); + + const includedTraffic = useTrafficLimit(); + + const options = useMemo(() => { + return createBarChartOptions( + theme, + (tooltipItems: any) => { + if (newPeriod.grouping === 'daily') { + const periodItem = record[newPeriod.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 { + return new Date(tooltipItems[0].label).toLocaleDateString( + locationSettings?.locale ?? 'en-US', + { + month: 'long', + year: 'numeric', + }, + ); + } + }, + includedTraffic, + ); + }, [theme, newPeriod]); + + const traffic = useInstanceTrafficMetrics2(newPeriod); + + const data = newToChartData(traffic.usage); + + const [usageTotal, setUsageTotal] = useState(0); + + const [overageCost, setOverageCost] = useState(0); + + const [estimatedMonthlyCost, setEstimatedMonthlyCost] = useState(0); + + useEffect(() => { + if (data) { + let usage: number; + if (newPeriod.grouping === 'monthly') { + usage = monthlyTrafficDataToCurrentUsage(traffic.usage); + } else { + usage = toTrafficUsageSum(data.datasets); + } + + setUsageTotal(usage); + if (includedTraffic > 0) { + const calculatedOverageCost = calculateOverageCost( + usage, + includedTraffic, + BILLING_TRAFFIC_BUNDLE_PRICE, + ); + setOverageCost(calculatedOverageCost); + + setEstimatedMonthlyCost( + calculateEstimatedMonthlyCost( + newPeriod.grouping === 'daily' + ? newPeriod.month + : format(new Date(), 'yyyy-MM'), + data.datasets, + includedTraffic, + new Date(), + BILLING_TRAFFIC_BUNDLE_PRICE, + ), + ); + } + } + }, [data]); + + return ( + Not enabled.} + elseShow={ + <> + 0 && overageCost > 0} + show={ + + Heads up! You are currently consuming + more requests than your plan includes and will + be billed according to our terms. Please see{' '} + + this page + {' '} + for more information. In order to reduce your + traffic consumption, you may configure an{' '} + + Unleash Edge instance + {' '} + in your own datacenter. + + } + /> + + + { + // todo: add new usage plan summary that works for monthly data as well as daily + } + + + + + + + + } + /> + ); +}; + +export const NetworkTrafficUsage: FC = () => { + const useNewNetworkTraffic = useUiFlag('dataUsageMultiMonthView'); + return useNewNetworkTraffic ? ( + + ) : ( + + ); +}; + +const OldNetworkTrafficUsage: FC = () => { usePageTitle('Network - Data Usage'); const theme = useTheme(); - const showMultiMonthSelector = useUiFlag('dataUsageMultiMonthView'); const { isOss } = useUiConfig(); @@ -279,49 +448,31 @@ export const NetworkTrafficUsage: FC = () => { } /> - {showMultiMonthSelector ? ( - + + - - - ) : ( - - - - - - setPeriod(e.target.value)} + style={{ + minWidth: '100%', + marginBottom: theme.spacing(2), + }} + formControlStyles={{ width: '100%' }} + /> + + + void; + selectedPeriod: ChartDataSelection; + setPeriod: (period: ChartDataSelection) => void; }; export const PeriodSelector: FC = ({ selectedPeriod, setPeriod }) => { const selectablePeriods = getSelectablePeriods(); - // this is for dev purposes; only to show how the design will work when you select a range. - const [tempOverride, setTempOverride] = useState(); - - const select = (value: Selection) => { - if (value.type === 'month') { - setTempOverride(null); - setPeriod(value.value); - } else { - setTempOverride(value); - } - }; - const rangeOptions = [3, 6, 12].map((monthsBack) => ({ value: monthsBack, label: `Last ${monthsBack} months`, @@ -183,17 +172,17 @@ export const PeriodSelector: FC = ({ selectedPeriod, setPeriod }) => {