diff --git a/frontend/src/component/common/Input/Input.tsx b/frontend/src/component/common/Input/Input.tsx index 7afcaed430..546896a924 100644 --- a/frontend/src/component/common/Input/Input.tsx +++ b/frontend/src/component/common/Input/Input.tsx @@ -1,4 +1,4 @@ -import { InputLabelProps, TextField } from '@material-ui/core'; +import { InputLabelProps, InputProps, TextField } from '@material-ui/core'; import { INPUT_ERROR_TEXT } from '../../../testIds'; import { useStyles } from './Input.styles'; import React from 'react'; @@ -15,6 +15,7 @@ interface IInputProps extends React.InputHTMLAttributes { onBlur?: (e: any) => any; multiline?: boolean; rows?: number; + InputProps?: Partial; InputLabelProps?: Partial; } @@ -27,6 +28,7 @@ const Input = ({ className, value, onChange, + InputProps, ...rest }: IInputProps) => { const styles = useStyles(); diff --git a/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.styles.ts b/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.styles.ts new file mode 100644 index 0000000000..0aba375799 --- /dev/null +++ b/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.styles.ts @@ -0,0 +1,29 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export const useStyles = makeStyles(theme => ({ + error: { + color: theme.palette.error.main, + fontSize: theme.fontSizes.smallBody, + position: 'relative', + }, + input: { + maxWidth: 350, + width: '100%', + }, + grid: { + marginBottom: '0.5rem', + }, + weightInput: { + marginRight: '0.8rem', + }, + label: { marginBottom: '1rem' }, + info: { + width: '18.5px', + height: '18.5px', + color: 'grey', + }, + select: { + minWidth: '100px', + width: '100%', + }, +})); diff --git a/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.tsx b/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.tsx index a8eb0ad990..b97fb5832b 100644 --- a/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.tsx @@ -5,24 +5,26 @@ import { FormControlLabel, Grid, InputAdornment, - TextField, Tooltip, } from '@material-ui/core'; import { Info } from '@material-ui/icons'; import { weightTypes } from './enums'; import { OverrideConfig } from './OverrideConfig/OverrideConfig'; -import ConditionallyRender from '../../../../../common/ConditionallyRender'; +import ConditionallyRender from 'component/common/ConditionallyRender'; import { useCommonStyles } from 'common.styles'; -import Dialogue from '../../../../../common/Dialogue'; +import Dialogue from 'component/common/Dialogue'; import { modalStyles, trim } from 'component/common/util'; -import PermissionSwitch from '../../../../../common/PermissionSwitch/PermissionSwitch'; +import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch'; import { UPDATE_FEATURE_VARIANTS } from 'component/providers/AccessProvider/permissions'; -import useFeature from '../../../../../../hooks/api/getters/useFeature/useFeature'; +import useFeature from 'hooks/api/getters/useFeature/useFeature'; import { useParams } from 'react-router-dom'; import { IFeatureViewParams } from 'interfaces/params'; import { IFeatureVariant, IOverride } from 'interfaces/featureToggle'; import cloneDeep from 'lodash.clonedeep'; import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect'; +import { useStyles } from './AddFeatureVariant.styles'; +import Input from 'component/common/Input/Input'; +import { formatUnknownError } from 'utils/format-unknown-error'; const payloadOptions = [ { key: 'string', label: 'string' }, @@ -43,7 +45,7 @@ interface IAddVariantProps { editing: boolean; } -const AddVariant = ({ +export const AddVariant = ({ showDialog, closeDialog, save, @@ -53,6 +55,7 @@ const AddVariant = ({ title, editing, }: IAddVariantProps) => { + const styles = useStyles(); const [data, setData] = useState>({}); const [payload, setPayload] = useState(EMPTY_PAYLOAD); const [overrides, setOverrides] = useState([]); @@ -62,6 +65,18 @@ const AddVariant = ({ const { feature } = useFeature(projectId, featureId); const [variants, setVariants] = useState([]); + const isValidJSON = (input: string): boolean => { + try { + JSON.parse(input); + return true; + } catch (e: unknown) { + setError({ + payload: 'Invalid JSON', + }); + return false; + } + }; + const clear = () => { if (editVariant) { setData({ @@ -136,6 +151,11 @@ const AddVariant = ({ setError(weightValidation); return; } + const validJSON = + payload.type === 'json' && !isValidJSON(payload.value); + if (validJSON) { + return; + } try { const variant: IFeatureVariant = { @@ -154,19 +174,14 @@ const AddVariant = ({ await save(variant); clear(); closeDialog(); - } catch (error) { - // @ts-expect-error - if (error?.body?.details[0]?.message?.includes('duplicate value')) { + } catch (e: unknown) { + const error = formatUnknownError(e); + if (error.includes('duplicate value')) { setError({ name: 'A variant with that name already exists.' }); - } else if ( - // @ts-expect-error - error?.body?.details[0]?.message?.includes('must be a number') - ) { + } else if (error.includes('must be a number')) { setError({ weight: 'Weight must be a number' }); } else { - const msg = - // @ts-expect-error - error?.body?.details[0]?.message || 'Could not add variant'; + const msg = error || 'Could not add variant'; setError({ general: msg }); } } @@ -174,6 +189,7 @@ const AddVariant = ({ const onPayload = (e: ChangeEvent<{ name?: string; value: unknown }>) => { e.preventDefault(); + setError({ payload: '' }); setPayload({ ...payload, // @ts-expect-error @@ -248,20 +264,16 @@ const AddVariant = ({ onSubmit={submit} className={commonStyles.contentSpacingY} > -

{error.general}

- {error.general}

+ 0) } show={ - + - ), }} - style={{ marginRight: '0.8rem' }} + className={styles.weightInput} value={data.weight} error={Boolean(error.weight)} - helperText={error.weight} + errorText={error.weight} type="number" disabled={!isFixWeight} onChange={e => { @@ -339,19 +344,13 @@ const AddVariant = ({ } /> -

+

Payload - +

@@ -360,40 +359,37 @@ const AddVariant = ({ id="variant-payload-type" name="type" label="Type" - className={commonStyles.fullWidth} + className={styles.select} value={payload.type} options={payloadOptions} onChange={onPayload} - style={{ minWidth: '100px', width: '100%' }} /> -
0} show={ -

+

Overrides - +

} @@ -410,10 +406,8 @@ const AddVariant = ({ color="primary" > Add override - {' '} + ); }; - -export default AddVariant; diff --git a/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/FeatureVariantsList.tsx b/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/FeatureVariantsList.tsx index 129624d4f4..56a6c44acc 100644 --- a/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/FeatureVariantsList.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureVariants/FeatureVariantsList/FeatureVariantsList.tsx @@ -10,7 +10,7 @@ import { TableRow, Typography, } from '@material-ui/core'; -import AddVariant from './AddFeatureVariant/AddFeatureVariant'; +import { AddVariant } from './AddFeatureVariant/AddFeatureVariant'; import { useContext, useEffect, useState } from 'react'; import useFeature from '../../../../../hooks/api/getters/useFeature/useFeature';