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:
parent
a11c965bec
commit
90e5adb695
@ -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;
|
||||
};
|
||||
|
@ -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)}
|
||||
|
@ -5,7 +5,7 @@ import { currentMonth } from './dates';
|
||||
export const averageTrafficPreviousMonths = (
|
||||
traffic: TrafficUsageDataSegmentedCombinedSchema,
|
||||
) => {
|
||||
if (!traffic || traffic.grouping === 'daily') {
|
||||
if (traffic.grouping === 'daily') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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(
|
||||
|
@ -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) => {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user