From 187f265680c801b5bee717d65641dec79888cc49 Mon Sep 17 00:00:00 2001 From: Jaanus Sellin Date: Wed, 16 Apr 2025 11:52:36 +0300 Subject: [PATCH] feat: add values button now actually adds value (#9768) --- .../EditableConstraint.tsx | 1 + .../FeatureStrategyConstraints/ValueList.tsx | 184 +++++++++++++----- 2 files changed, 140 insertions(+), 45 deletions(-) diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint.tsx index 3bbe548b6f..f7d3b141ea 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint.tsx @@ -383,6 +383,7 @@ export const EditableConstraint: FC = ({ )} diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/ValueList.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/ValueList.tsx index c4ce259b04..f7b953d9b6 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/ValueList.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/ValueList.tsx @@ -1,6 +1,13 @@ import Add from '@mui/icons-material/Add'; import Clear from '@mui/icons-material/Clear'; -import { Button, Chip, type ChipProps, Popover, styled } from '@mui/material'; +import { + Button, + Chip, + type ChipProps, + Popover, + styled, + TextField, +} from '@mui/material'; import { type FC, forwardRef, @@ -8,6 +15,7 @@ import { useRef, useState, } from 'react'; +import { parseParameterStrings } from 'utils/parseParameter'; const ValueListWrapper = styled('div')(({ theme }) => ({ display: 'flex', @@ -79,59 +87,136 @@ const StyledPopover = styled(Popover)(({ theme }) => ({ '& .MuiPaper-root': { borderRadius: theme.shape.borderRadiusLarge, border: `1px solid ${theme.palette.divider}`, - padding: theme.spacing(1), + padding: theme.spacing(2), + width: '300px', }, })); -const AddValues = forwardRef((props, ref) => { - const [open, setOpen] = useState(false); - const positioningRef = useRef(null); - useImperativeHandle(ref, () => positioningRef.current as HTMLButtonElement); +const StyledTextField = styled(TextField)(({ theme }) => ({ + width: '100%', + marginBottom: theme.spacing(1), +})); - return ( - <> - setOpen(true)} - type='button' - > - - Add values - - setOpen(false)} - anchorOrigin={{ - vertical: 'bottom', - horizontal: 'center', - }} - transformOrigin={{ - vertical: 'top', - horizontal: 'center', - }} - > -
e.preventDefault()}> - - -
-
- - ); -}); +const ButtonContainer = styled('div')(({ theme }) => ({ + display: 'flex', + justifyContent: 'flex-end', +})); + +const ErrorMessage = styled('div')(({ theme }) => ({ + color: theme.palette.error.main, + fontSize: theme.typography.caption.fontSize, + marginBottom: theme.spacing(1), +})); + +interface AddValuesProps { + onAddValues: (values: string[]) => void; +} + +const AddValues = forwardRef( + ({ onAddValues }, ref) => { + const [open, setOpen] = useState(false); + const [inputValues, setInputValues] = useState(''); + const [error, setError] = useState(''); + const positioningRef = useRef(null); + useImperativeHandle( + ref, + () => positioningRef.current as HTMLButtonElement, + ); + + const handleAdd = () => { + 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; + } + + onAddValues(newValues); + setInputValues(''); + setError(''); + setOpen(false); + }; + + const handleKeyPress = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + event.preventDefault(); + handleAdd(); + } + }; + + return ( + <> + setOpen(true)} + type='button' + > + + Add values + + setOpen(false)} + anchorOrigin={{ + vertical: 'bottom', + horizontal: 'center', + }} + transformOrigin={{ + vertical: 'top', + horizontal: 'center', + }} + > +
+ { + setInputValues(e.target.value); + setError(''); + }} + onKeyPress={handleKeyPress} + error={Boolean(error)} + helperText={error} + size='small' + fullWidth + autoFocus + /> + + + +
+
+ + ); + }, +); type Props = { values: string[] | undefined; removeValue: (index: number) => void; + setValues: (values: string[]) => void; }; -export const ValueList: FC = ({ values = [], removeValue }) => { +export const ValueList: FC = ({ + values = [], + removeValue, + setValues, +}) => { const constraintElementRefs: React.MutableRefObject< (HTMLDivElement | null)[] > = useRef([]); @@ -149,6 +234,11 @@ export const ValueList: FC = ({ values = [], removeValue }) => { } }; + const handleAddValues = (newValues: string[]) => { + const combinedValues = uniqueValues([...(values || []), ...newValues]); + setValues(combinedValues); + }; + return ( @@ -168,7 +258,11 @@ export const ValueList: FC = ({ values = [], removeValue }) => { ))} - + ); }; + +const uniqueValues = (values: T[]): T[] => { + return Array.from(new Set(values)); +};