mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-31 13:47:02 +02:00
feat: constraints values limit in a strategy UI (#7557)
This commit is contained in:
parent
8f8ff13cc5
commit
46b1eedcc7
@ -10,7 +10,8 @@ import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender'
|
|||||||
const StyledBox = styled(Box)(({ theme }) => ({
|
const StyledBox = styled(Box)(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
border: `2px solid ${theme.palette.background.application}`,
|
backgroundColor: theme.palette.background.default,
|
||||||
|
border: `1px solid ${theme.palette.divider}`,
|
||||||
borderRadius: `${theme.shape.borderRadiusMedium}px`,
|
borderRadius: `${theme.shape.borderRadiusMedium}px`,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}));
|
}));
|
||||||
@ -33,7 +34,7 @@ const Header = styled(Box)(({ theme }) => ({
|
|||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
borderBottom: `1px solid ${theme.palette.background.application}`,
|
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||||
padding: theme.spacing(3, 4),
|
padding: theme.spacing(3, 4),
|
||||||
fontSize: theme.typography.h2.fontSize,
|
fontSize: theme.typography.h2.fontSize,
|
||||||
}));
|
}));
|
||||||
@ -43,7 +44,7 @@ const Footer = styled(Box)(({ theme }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const Main = styled(Box)(({ theme }) => ({
|
const Main = styled(Box)(({ theme }) => ({
|
||||||
borderBottom: `1px solid ${theme.palette.background.application}`,
|
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||||
padding: theme.spacing(3, 4),
|
padding: theme.spacing(3, 4),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -68,7 +69,7 @@ export const Limit: FC<{
|
|||||||
currentValue: number;
|
currentValue: number;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
}> = ({ name, shortName, limit, currentValue, onClose }) => {
|
}> = ({ name, shortName, limit, currentValue, onClose }) => {
|
||||||
const percentageLimit = Math.round((currentValue / limit) * 100);
|
const percentageLimit = Math.floor((currentValue / limit) * 100);
|
||||||
const belowLimit = currentValue < limit;
|
const belowLimit = currentValue < limit;
|
||||||
const threshold = 80;
|
const threshold = 80;
|
||||||
|
|
||||||
|
@ -119,3 +119,20 @@ test('should set values', async () => {
|
|||||||
expect(errors).toEqual(['']);
|
expect(errors).toEqual(['']);
|
||||||
expect(values).toEqual(['1', '2', '3']);
|
expect(values).toEqual(['1', '2', '3']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should show limit reached indicator', async () => {
|
||||||
|
setupApi();
|
||||||
|
render(
|
||||||
|
<FreeTextInput
|
||||||
|
error=''
|
||||||
|
values={['1', '2', '3']}
|
||||||
|
setValues={(newValues) => {}}
|
||||||
|
setError={(newError: string) => {}}
|
||||||
|
removeValue={() => {}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await screen.findByText(
|
||||||
|
'You have reached the limit for single constraint values',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, Chip } from '@mui/material';
|
import { Box, Button, Chip, styled } from '@mui/material';
|
||||||
import { makeStyles } from 'tss-react/mui';
|
import { makeStyles } from 'tss-react/mui';
|
||||||
import Input from 'component/common/Input/Input';
|
import Input from 'component/common/Input/Input';
|
||||||
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
|
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
|
||||||
@ -8,6 +8,8 @@ import { ConstraintFormHeader } from '../ConstraintFormHeader/ConstraintFormHead
|
|||||||
import { parseParameterStrings } from 'utils/parseParameter';
|
import { parseParameterStrings } from 'utils/parseParameter';
|
||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
import { useUiFlag } from 'hooks/useUiFlag';
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { Limit } from 'component/common/Limit/Limit';
|
||||||
|
|
||||||
interface IFreeTextInputProps {
|
interface IFreeTextInputProps {
|
||||||
values: string[];
|
values: string[];
|
||||||
@ -53,6 +55,12 @@ const useStyles = makeStyles()((theme) => ({
|
|||||||
valuesContainer: { marginTop: '1rem' },
|
valuesContainer: { marginTop: '1rem' },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const LimitContainer = styled(Box)(({ theme }) => ({
|
||||||
|
'&:has(*)': {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
const ENTER = 'Enter';
|
const ENTER = 'Enter';
|
||||||
|
|
||||||
export const FreeTextInput = ({
|
export const FreeTextInput = ({
|
||||||
@ -66,6 +74,7 @@ export const FreeTextInput = ({
|
|||||||
const { classes: styles } = useStyles();
|
const { classes: styles } = useStyles();
|
||||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||||
const { uiConfig, loading } = useUiConfig();
|
const { uiConfig, loading } = useUiConfig();
|
||||||
|
const constraintValuesLimit = uiConfig.resourceLimits.constraintValues;
|
||||||
|
|
||||||
const onKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
const onKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (event.key === ENTER) {
|
if (event.key === ENTER) {
|
||||||
@ -80,13 +89,12 @@ export const FreeTextInput = ({
|
|||||||
...parseParameterStrings(inputValues),
|
...parseParameterStrings(inputValues),
|
||||||
]);
|
]);
|
||||||
const limitReached = Boolean(
|
const limitReached = Boolean(
|
||||||
resourceLimitsEnabled &&
|
resourceLimitsEnabled && newValues.length > constraintValuesLimit,
|
||||||
newValues.length > uiConfig.resourceLimits.constraintValues,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (limitReached) {
|
if (limitReached) {
|
||||||
setError(
|
setError(
|
||||||
`constraints cannot have more than ${uiConfig.resourceLimits.constraintValues} values`,
|
`constraints cannot have more than ${constraintValuesLimit} values`,
|
||||||
);
|
);
|
||||||
} else if (newValues.length === 0) {
|
} else if (newValues.length === 0) {
|
||||||
setError('values cannot be empty');
|
setError('values cannot be empty');
|
||||||
@ -139,6 +147,19 @@ export const FreeTextInput = ({
|
|||||||
removeValue={removeValue}
|
removeValue={removeValue}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<LimitContainer>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={resourceLimitsEnabled}
|
||||||
|
show={
|
||||||
|
<Limit
|
||||||
|
name='single constraint values'
|
||||||
|
shortName='values'
|
||||||
|
currentValue={values.length}
|
||||||
|
limit={constraintValuesLimit}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</LimitContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user