1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-04 00:18:01 +01:00

feat: add selected month summary card for data usage (#6891)

## About the changes

Adds a summary card that sums up data usage for selected month, and for
Pro shows monthly quota and badge color according to monthly quota
This commit is contained in:
David Leek 2024-04-19 09:33:19 +02:00 committed by GitHub
parent e6764a43c0
commit 2cb9ceaa72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 187 additions and 50 deletions

View File

@ -29,6 +29,7 @@ import {
import type { Theme } from '@mui/material/styles/createTheme'; import type { Theme } from '@mui/material/styles/createTheme';
import Grid from '@mui/material/Grid'; import Grid from '@mui/material/Grid';
import { useUiFlag } from 'hooks/useUiFlag'; import { useUiFlag } from 'hooks/useUiFlag';
import { NetworkTrafficUsagePlanSummary } from './NetworkTrafficUsagePlanSummary';
type ChartDatasetType = ChartDataset<'bar'>; type ChartDatasetType = ChartDataset<'bar'>;
@ -46,14 +47,9 @@ type EndpointInfo = {
order: number; order: number;
}; };
const StyledHeader = styled('h3')(({ theme }) => ({ const StyledBox = styled(Box)(({ theme }) => ({
display: 'flex', display: 'grid',
gap: theme.spacing(1), gap: theme.spacing(5),
alignItems: 'center',
fontSize: theme.fontSizes.bodySize,
margin: 0,
marginTop: theme.spacing(1),
fontWeight: theme.fontWeight.bold,
})); }));
const padMonth = (month: number): string => const padMonth = (month: number): string =>
@ -156,7 +152,7 @@ const toChartData = (
const customHighlightPlugin = { const customHighlightPlugin = {
id: 'customLine', id: 'customLine',
beforeDraw: (chart: Chart) => { beforeDraw: (chart: Chart) => {
const width = 36; const width = 46;
if (chart.tooltip?.opacity && chart.tooltip.x) { if (chart.tooltip?.opacity && chart.tooltip.x) {
const x = chart.tooltip.caretX; const x = chart.tooltip.caretX;
const yAxis = chart.scales.y; const yAxis = chart.scales.y;
@ -268,10 +264,6 @@ const createBarChartOptions = (
}, },
}); });
export const NetworkTrafficUsage: VFC = () => {
usePageTitle('Network - Data Usage');
const theme = useTheme();
const endpointsInfo: Record<string, EndpointInfo> = { const endpointsInfo: Record<string, EndpointInfo> = {
'/api/admin': { '/api/admin': {
label: 'Admin', label: 'Admin',
@ -290,6 +282,12 @@ export const NetworkTrafficUsage: VFC = () => {
}, },
}; };
const proPlanIncludedRequests = 53000000;
export const NetworkTrafficUsage: VFC = () => {
usePageTitle('Network - Data Usage');
const theme = useTheme();
const selectablePeriods = getSelectablePeriods(); const selectablePeriods = getSelectablePeriods();
const record = toPeriodsRecord(selectablePeriods); const record = toPeriodsRecord(selectablePeriods);
const [period, setPeriod] = useState<string>(selectablePeriods[0].key); const [period, setPeriod] = useState<string>(selectablePeriods[0].key);
@ -316,6 +314,8 @@ export const NetworkTrafficUsage: VFC = () => {
const [datasets, setDatasets] = useState<ChartDatasetType[]>([]); const [datasets, setDatasets] = useState<ChartDatasetType[]>([]);
const [usageTotal, setUsageTotal] = useState<number>(0);
const data = { const data = {
labels, labels,
datasets, datasets,
@ -335,17 +335,42 @@ export const NetworkTrafficUsage: VFC = () => {
} }
}, [period]); }, [period]);
useEffect(() => {
if (data) {
const usage = data.datasets.reduce(
(acc: number, current: ChartDatasetType) => {
return (
acc +
current.data.reduce(
(acc_inner, current_inner) =>
acc_inner + current_inner,
0,
)
);
},
0,
);
setUsageTotal(usage);
}
}, [data]);
return ( return (
<ConditionallyRender <ConditionallyRender
condition={isOss() || !flagEnabled} condition={isOss() || !flagEnabled}
show={<Alert severity='warning'>No data available.</Alert>} show={<Alert severity='warning'>No data available.</Alert>}
elseShow={ elseShow={
<> <>
<StyledBox>
<Grid container component='header' spacing={2}> <Grid container component='header' spacing={2}>
<Grid item xs={12} md={10}> <Grid item xs={12} md={10}>
<StyledHeader> <Grid item xs={7} md={5.5}>
Number of requests to Unleash <NetworkTrafficUsagePlanSummary
</StyledHeader> usageTotal={usageTotal}
planIncludedRequests={
proPlanIncludedRequests
}
/>
</Grid>
</Grid> </Grid>
<Grid item xs={12} md={2}> <Grid item xs={12} md={2}>
<Select <Select
@ -362,16 +387,15 @@ export const NetworkTrafficUsage: VFC = () => {
/> />
</Grid> </Grid>
</Grid> </Grid>
<Box sx={{ display: 'grid', gap: 4 }}> <Grid item xs={12} md={2}>
<div>
<Bar <Bar
data={data} data={data}
plugins={[customHighlightPlugin]} plugins={[customHighlightPlugin]}
options={options} options={options}
aria-label='An instance metrics line chart with two lines: requests per second for admin API and requests per second for client API' aria-label='An instance metrics line chart with two lines: requests per second for admin API and requests per second for client API'
/> />
</div> </Grid>
</Box> </StyledBox>
</> </>
} }
/> />

View File

@ -0,0 +1,113 @@
import styled from '@mui/material/styles/styled';
import Box from '@mui/system/Box';
import Grid from '@mui/material/Grid';
import { flexRow } from 'themes/themeStyles';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Badge } from 'component/common/Badge/Badge';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
padding: theme.spacing(3),
border: `2px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadiusLarge,
}));
const StyledCardTitleRow = styled(Box)(() => ({
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
}));
const StyledCardDescription = styled(Box)(({ theme }) => ({
flex: 1,
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2.5),
color: theme.palette.text.secondary,
fontSize: theme.fontSizes.smallBody,
marginTop: theme.spacing(2),
}));
const RowContainer = styled(Box)(({ theme }) => ({
...flexRow,
}));
const StyledNumbersDiv = styled('div')(({ theme }) => ({
marginLeft: 'auto',
display: 'flex',
justifyContent: 'space-between',
textDecoration: 'none',
color: theme.palette.text.primary,
}));
interface INetworkTrafficUsagePlanSummary {
usageTotal: number;
planIncludedRequests: number;
}
export const NetworkTrafficUsagePlanSummary = ({
usageTotal,
planIncludedRequests,
}: INetworkTrafficUsagePlanSummary) => {
const { isPro } = useUiConfig();
return (
<StyledContainer>
<Grid item>
<StyledCardTitleRow>
<b>Number of requests to Unleash</b>
</StyledCardTitleRow>
<StyledCardDescription>
<RowContainer>
Incoming requests for selection{' '}
<StyledNumbersDiv>
<ConditionallyRender
condition={isPro()}
show={
<ConditionallyRender
condition={
usageTotal <= planIncludedRequests
}
show={
<Badge color='success'>
{usageTotal.toLocaleString()}{' '}
requests
</Badge>
}
elseShow={
<Badge color='error'>
{usageTotal.toLocaleString()}{' '}
requests
</Badge>
}
/>
}
elseShow={
<Badge color='neutral'>
{usageTotal.toLocaleString()} requests
</Badge>
}
/>
</StyledNumbersDiv>
</RowContainer>
</StyledCardDescription>
<ConditionallyRender
condition={isPro()}
show={
<StyledCardDescription>
<RowContainer>
Included in your plan monthly
<StyledNumbersDiv>
{planIncludedRequests.toLocaleString()}{' '}
requests
</StyledNumbersDiv>
</RowContainer>
</StyledCardDescription>
}
/>
</Grid>
</StyledContainer>
);
};