mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-27 11:02:16 +01:00
Implements client-side validation of constraint values before you can add them to a constraint. I've removed the extra server-side validation that used to happen for each specific constraint, because the surrounding form itself uses server side validation to check every constraint every time there's a change. This is what controls disabling the submit button etc. I wanna make the next PR a bit of a followup cleanup now that it's clearer what properties we do and don't need. <img width="371" alt="image" src="https://github.com/user-attachments/assets/7c98708f-fcbe-40ca-8590-bb0f5b2ad167" /> <img width="361" alt="image" src="https://github.com/user-attachments/assets/503d4841-d910-4e8e-b0ef-a3d725739534" />
93 lines
3.3 KiB
TypeScript
93 lines
3.3 KiB
TypeScript
import Add from '@mui/icons-material/Add';
|
|
import { styled } from '@mui/material';
|
|
import { forwardRef, useImperativeHandle, useRef, useState } from 'react';
|
|
import { parseParameterStrings } from 'utils/parseParameter';
|
|
import { baseChipStyles } from './ValueList';
|
|
import { AddValuesPopover, type OnAddActions } from './AddValuesPopover';
|
|
import type { ConstraintValidatorOutput } from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/useConstraintInput/constraintValidators';
|
|
|
|
// todo: MUI v6 / v7 upgrade: consider changing this to a Chip to align with the rest of the values and the single value selector. There was a fix introduced in v6 that makes you not lose focus on pressing esc: https://mui.com/material-ui/migration/upgrade-to-v6/#chip talk to Thomas for more info.
|
|
const AddValuesButton = styled('button')(({ theme }) => ({
|
|
...baseChipStyles(theme),
|
|
color: theme.palette.primary.main,
|
|
svg: {
|
|
fill: theme.palette.primary.main,
|
|
height: theme.fontSizes.smallerBody,
|
|
width: theme.fontSizes.smallerBody,
|
|
},
|
|
border: 'none',
|
|
borderRadius: theme.shape.borderRadiusExtraLarge,
|
|
display: 'flex',
|
|
flexFlow: 'row nowrap',
|
|
whiteSpace: 'nowrap',
|
|
gap: theme.spacing(0.25),
|
|
alignItems: 'center',
|
|
padding: theme.spacing(0.5, 1.5, 0.5, 1.5),
|
|
height: 'auto',
|
|
cursor: 'pointer',
|
|
}));
|
|
|
|
interface AddValuesProps {
|
|
onAddValues: (newValues: string[]) => void;
|
|
helpText?: string;
|
|
validator: (...values: string[]) => ConstraintValidatorOutput;
|
|
}
|
|
|
|
export const AddValuesWidget = forwardRef<HTMLButtonElement, AddValuesProps>(
|
|
({ onAddValues, helpText, validator }, ref) => {
|
|
const [open, setOpen] = useState(false);
|
|
const positioningRef = useRef<HTMLButtonElement>(null);
|
|
useImperativeHandle(
|
|
ref,
|
|
() => positioningRef.current as HTMLButtonElement,
|
|
);
|
|
|
|
const handleAdd = (
|
|
inputValues: string,
|
|
{ setError, clearInput }: OnAddActions,
|
|
) => {
|
|
const newValues = parseParameterStrings(inputValues);
|
|
|
|
if (newValues.length === 0) {
|
|
setError('Values cannot be empty');
|
|
return;
|
|
}
|
|
|
|
if (newValues.some((v) => v.length > 100)) {
|
|
setError('Values cannot be longer than 100 characters');
|
|
return;
|
|
}
|
|
|
|
const [isValid, errorMessage] = validator(...newValues);
|
|
if (isValid) {
|
|
onAddValues(newValues);
|
|
clearInput();
|
|
setError('');
|
|
} else {
|
|
setError(errorMessage);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<AddValuesButton
|
|
ref={positioningRef}
|
|
onClick={() => setOpen(true)}
|
|
type='button'
|
|
>
|
|
<Add />
|
|
<span>Add values</span>
|
|
</AddValuesButton>
|
|
|
|
<AddValuesPopover
|
|
onAdd={handleAdd}
|
|
helpText={helpText}
|
|
open={open}
|
|
anchorEl={positioningRef.current}
|
|
onClose={() => setOpen(false)}
|
|
/>
|
|
</>
|
|
);
|
|
},
|
|
);
|