mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-04 00:18:01 +01:00
feat: limit component (#7538)
This commit is contained in:
parent
30073d527a
commit
c93bfafb7f
67
frontend/src/component/common/Limit/Limit.test.tsx
Normal file
67
frontend/src/component/common/Limit/Limit.test.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
import { screen } from '@testing-library/react';
|
||||
import { render } from 'utils/testRenderer';
|
||||
import { Limit } from './Limit';
|
||||
|
||||
test('Render approaching limit variant', () => {
|
||||
render(
|
||||
<Limit
|
||||
name='strategies in this environment'
|
||||
shortName='strategies'
|
||||
limit={10}
|
||||
currentValue={8}
|
||||
/>,
|
||||
);
|
||||
|
||||
screen.getByText(
|
||||
'You are nearing the limit for strategies in this environment',
|
||||
);
|
||||
screen.getByText('80%');
|
||||
screen.getByText('Limit: 10');
|
||||
});
|
||||
|
||||
test('Render reached limit variant', () => {
|
||||
render(
|
||||
<Limit
|
||||
name='strategies in this environment'
|
||||
shortName='strategies'
|
||||
limit={10}
|
||||
currentValue={10}
|
||||
/>,
|
||||
);
|
||||
|
||||
screen.getByText(
|
||||
'You have reached the limit for strategies in this environment',
|
||||
);
|
||||
screen.getByText('100%');
|
||||
screen.getByText('Limit: 10');
|
||||
});
|
||||
|
||||
test('Render exceeded limit variant', () => {
|
||||
render(
|
||||
<Limit
|
||||
name='strategies in this environment'
|
||||
shortName='strategies'
|
||||
limit={10}
|
||||
currentValue={20}
|
||||
/>,
|
||||
);
|
||||
|
||||
screen.getByText(
|
||||
'You have reached the limit for strategies in this environment',
|
||||
);
|
||||
screen.getByText('200%');
|
||||
screen.getByText('Limit: 10');
|
||||
});
|
||||
|
||||
test('Do not render any limit below threshold', () => {
|
||||
render(
|
||||
<Limit
|
||||
name='strategies in this environment'
|
||||
shortName='strategies'
|
||||
limit={10}
|
||||
currentValue={7}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.queryByText('Limit: 10')).not.toBeInTheDocument();
|
||||
});
|
144
frontend/src/component/common/Limit/Limit.tsx
Normal file
144
frontend/src/component/common/Limit/Limit.tsx
Normal file
@ -0,0 +1,144 @@
|
||||
import { Box, IconButton, styled, Tooltip, Typography } from '@mui/material';
|
||||
import LinearProgress from '@mui/material/LinearProgress';
|
||||
import { Link } from 'react-router-dom';
|
||||
import WarningIcon from '@mui/icons-material/ErrorOutlined';
|
||||
import ErrorIcon from '@mui/icons-material/Cancel';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import type { FC } from 'react';
|
||||
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
|
||||
|
||||
const StyledBox = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
border: `2px solid ${theme.palette.background.application}`,
|
||||
borderRadius: `${theme.shape.borderRadiusMedium}px`,
|
||||
}));
|
||||
|
||||
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
|
||||
height: theme.spacing(1.5),
|
||||
borderRadius: theme.shape.borderRadiusMedium,
|
||||
}));
|
||||
|
||||
const StyledWarningIcon = styled(WarningIcon)(({ theme }) => ({
|
||||
color: theme.palette.warning.border,
|
||||
}));
|
||||
|
||||
const StyledErrorIcon = styled(ErrorIcon)(({ theme }) => ({
|
||||
color: theme.palette.error.main,
|
||||
}));
|
||||
|
||||
const Header = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
gap: theme.spacing(1),
|
||||
alignItems: 'center',
|
||||
fontWeight: 'bold',
|
||||
borderBottom: `2px solid ${theme.palette.background.application}`,
|
||||
padding: theme.spacing(3, 4),
|
||||
fontSize: theme.typography.h2.fontSize,
|
||||
}));
|
||||
|
||||
const Footer = styled(Box)(({ theme }) => ({
|
||||
padding: theme.spacing(3, 4),
|
||||
}));
|
||||
|
||||
const Main = styled(Box)(({ theme }) => ({
|
||||
borderBottom: `2px solid ${theme.palette.background.application}`,
|
||||
padding: theme.spacing(3, 4),
|
||||
}));
|
||||
|
||||
const LimitStats = styled(Box)(({ theme }) => ({
|
||||
marginBottom: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const LimitExplanation = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
marginTop: theme.spacing(1.5),
|
||||
}));
|
||||
|
||||
const ExpandableBox = styled(Box)(({ theme }) => ({
|
||||
flex: 1,
|
||||
}));
|
||||
|
||||
export const Limit: FC<{
|
||||
name: string;
|
||||
shortName?: string;
|
||||
limit: number;
|
||||
currentValue: number;
|
||||
onClose?: () => void;
|
||||
}> = ({ name, shortName, limit, currentValue, onClose }) => {
|
||||
const percentageLimit = Math.round((currentValue / limit) * 100);
|
||||
const belowLimit = currentValue < limit;
|
||||
const threshold = 80;
|
||||
|
||||
if (percentageLimit < threshold) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledBox>
|
||||
<Header>
|
||||
<ConditionallyRender
|
||||
condition={belowLimit}
|
||||
show={<StyledWarningIcon fontSize='large' />}
|
||||
elseShow={<StyledErrorIcon fontSize='large' />}
|
||||
/>
|
||||
|
||||
<ConditionallyRender
|
||||
condition={belowLimit}
|
||||
show={
|
||||
<ExpandableBox>
|
||||
You are nearing the limit for {name}
|
||||
</ExpandableBox>
|
||||
}
|
||||
elseShow={
|
||||
<ExpandableBox>
|
||||
You have reached the limit for {name}
|
||||
</ExpandableBox>
|
||||
}
|
||||
/>
|
||||
|
||||
<ConditionallyRender
|
||||
condition={typeof onClose === 'function'}
|
||||
show={
|
||||
<Tooltip title='Close' arrow describeChild>
|
||||
<IconButton onClick={onClose}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
</Header>
|
||||
<Main>
|
||||
<LimitStats>
|
||||
You have added {currentValue} {shortName ?? name}, which is
|
||||
equivalent to{' '}
|
||||
<Typography component='span' color='primary'>
|
||||
{percentageLimit}%
|
||||
</Typography>{' '}
|
||||
of the limit.
|
||||
</LimitStats>
|
||||
<BorderLinearProgress
|
||||
variant='determinate'
|
||||
value={Math.min(100, percentageLimit)}
|
||||
/>
|
||||
<LimitExplanation>
|
||||
<Link
|
||||
target='_blank'
|
||||
to={'https://docs.getunleash.io/reference/limits'}
|
||||
>
|
||||
Read more about limits
|
||||
</Link>
|
||||
<Typography fontWeight='bold'>Limit: {limit}</Typography>
|
||||
</LimitExplanation>
|
||||
</Main>
|
||||
<Footer>
|
||||
If you need more than <strong>{limit}</strong>{' '}
|
||||
{shortName ?? name}, please reach out to us at{' '}
|
||||
<a href='mailto:cs@getunleash.io?subject=Increase limit'>
|
||||
cs@getunleash.io
|
||||
</a>
|
||||
</Footer>
|
||||
</StyledBox>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user