1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-23 13:46:45 +02:00

chore: use union type for traffic search data (#9221)

Makes the data returned from the traffic search a union type to avoid
nasty object-is-undefined errors at runtime.

It requires more explicit handling, sure, but it means we don't need
to accept undefined.
This commit is contained in:
Thomas Heartman 2025-02-05 11:50:39 +01:00 committed by GitHub
parent a11c965bec
commit 90e5adb695
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 91 additions and 80 deletions

View File

@ -30,16 +30,19 @@ const useNewOverageCostCalculation = (includedTraffic: number) => {
const from = formatDate(startOfMonth(now));
const to = formatDate(endOfMonth(now));
const { usage } = useTrafficSearch('daily', { from, to });
const { result } = useTrafficSearch('daily', { from, to });
const overageCost = useMemo(() => {
const totalUsage = calculateTotalUsage(usage);
if (result.state !== 'success') {
return 0;
}
const totalUsage = calculateTotalUsage(result.data);
return calculateOverageCost(
totalUsage,
includedTraffic,
BILLING_TRAFFIC_BUNDLE_PRICE,
);
}, [includedTraffic, usage]);
}, [includedTraffic, JSON.stringify(result)]);
return overageCost;
};

View File

@ -178,6 +178,62 @@ const BoldText = styled('span')(({ theme }) => ({
fontWeight: 'bold',
}));
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;
};
const NewNetworkTrafficUsage: FC = () => {
usePageTitle('Network - Data Usage');
const theme = useTheme();
@ -233,25 +289,13 @@ const NewNetworkTrafficUsage: FC = () => {
);
}, [theme, chartDataSelection]);
const traffic = useTrafficSearch(
chartDataSelection.grouping,
toDateRange(chartDataSelection, currentDate),
);
const data = newToChartData(traffic.usage);
const usageTotal = calculateTotalUsage(traffic.usage);
const overageCost = calculateOverageCost(
const {
chartData,
usageTotal,
includedTraffic,
BILLING_TRAFFIC_BUNDLE_PRICE,
);
const estimatedMonthlyCost = calculateEstimatedMonthlyCost(
traffic.usage?.apiData,
includedTraffic,
currentDate,
BILLING_TRAFFIC_BUNDLE_PRICE,
);
overageCost,
estimatedMonthlyCost,
requestSummaryUsage,
} = useTrafficStats(includedTraffic, chartDataSelection);
const showOverageCalculations =
chartDataSelection.grouping === 'daily' &&
@ -296,13 +340,7 @@ const NewNetworkTrafficUsage: FC = () => {
<TrafficInfoBoxes>
<RequestSummary
period={chartDataSelection}
usageTotal={
chartDataSelection.grouping === 'daily'
? usageTotal
: averageTrafficPreviousMonths(
traffic.usage,
)
}
usageTotal={requestSummaryUsage}
includedTraffic={includedTraffic}
/>
{showOverageCalculations && (
@ -321,7 +359,7 @@ const NewNetworkTrafficUsage: FC = () => {
/>
</TopRow>
<Bar
data={data}
data={chartData}
plugins={[customHighlightPlugin()]}
options={options}
aria-label={getChartLabel(chartDataSelection)}

View File

@ -5,7 +5,7 @@ import { currentMonth } from './dates';
export const averageTrafficPreviousMonths = (
traffic: TrafficUsageDataSegmentedCombinedSchema,
) => {
if (!traffic || traffic.grouping === 'daily') {
if (traffic.grouping === 'daily') {
return 0;
}

View File

@ -148,11 +148,4 @@ describe('toChartData', () => {
expect(toChartData(input)).toMatchObject(expectedOutput);
});
test('returns empty data if traffic is undefined', () => {
expect(toChartData(undefined)).toStrictEqual({
labels: [],
datasets: [],
});
});
});

View File

@ -12,12 +12,8 @@ import type { ChartDataSelection } from './chart-data-selection';
export type ChartDatasetType = ChartDataset<'bar'>;
export const toChartData = (
traffic?: TrafficUsageDataSegmentedCombinedSchema,
traffic: TrafficUsageDataSegmentedCombinedSchema,
): { datasets: ChartDatasetType[]; labels: string[] } => {
if (!traffic) {
return { labels: [], datasets: [] };
}
const { newRecord, labels } = getLabelsAndRecords(traffic);
const datasets = traffic.apiData
.sort(

View File

@ -38,13 +38,11 @@ export const useInstanceTrafficMetrics = (
};
export type InstanceTrafficMetricsResponse2 = {
usage: TrafficUsageDataSegmentedCombinedSchema;
refetch: () => void;
loading: boolean;
error?: Error;
result:
| { state: 'success'; data: TrafficUsageDataSegmentedCombinedSchema }
| { state: 'error'; error: Error }
| { state: 'loading' };
};
export const useTrafficSearch = (
@ -61,15 +59,17 @@ export const useTrafficSearch = (
const { data, error, mutate } = useSWR(formatApiPath(apiPath), fetcher);
return useMemo(
() => ({
usage: cleanTrafficData(data) as any,
loading: !error && !data,
return useMemo(() => {
const result = data
? { state: 'success' as const, data: cleanTrafficData(data) }
: error
? { state: 'error' as const, error }
: { state: 'loading' as const };
return {
refetch: () => mutate(),
error,
}),
[data, error, mutate],
);
result,
};
}, [data, error, mutate]);
};
const fetcher = (path: string) => {

View File

@ -171,16 +171,6 @@ describe('traffic overage calculation', () => {
expect(result2).toBe(result);
});
it("doesn't die if traffic is undefined", () => {
expect(
calculateEstimatedMonthlyCost(
undefined,
500_000,
new Date('2024-05-15'),
),
).toBe(0);
});
it('supports custom price and unit size', () => {
const dataUsage = 54_000_000;
const includedTraffic = 53_000_000;

View File

@ -16,12 +16,8 @@ export const METERED_TRAFFIC_ENDPOINTS = [
];
export const cleanTrafficData = (
data?: TrafficUsageDataSegmentedCombinedSchema,
): TrafficUsageDataSegmentedCombinedSchema | undefined => {
if (!data) {
return;
}
data: TrafficUsageDataSegmentedCombinedSchema,
): TrafficUsageDataSegmentedCombinedSchema => {
const { apiData, ...rest } = data;
const cleanedApiData = apiData
.filter((item) => METERED_TRAFFIC_ENDPOINTS.includes(item.apiPath))
@ -67,11 +63,8 @@ const dailyTrafficDataToCurrentUsage = (
// Return the total number of requests for the selected month if showing daily
// data, or the total for the most recent month if showing monthly data
export const calculateTotalUsage = (
data?: TrafficUsageDataSegmentedCombinedSchema,
data: TrafficUsageDataSegmentedCombinedSchema,
): number => {
if (!data) {
return 0;
}
const { grouping, apiData } = data;
if (grouping === 'monthly') {
const latestMonth = format(new Date(data.dateRange.to), 'yyyy-MM');
@ -135,9 +128,7 @@ export const calculateProjectedUsage = ({
};
export const calculateEstimatedMonthlyCost = (
trafficData:
| TrafficUsageDataSegmentedCombinedSchemaApiDataItem[]
| undefined,
trafficData: TrafficUsageDataSegmentedCombinedSchemaApiDataItem[],
includedTraffic: number,
currentDate: Date,
trafficUnitCost = DEFAULT_TRAFFIC_DATA_UNIT_COST,