From 832e3f2e79ff91cfacdd644fb0fea83367e2d066 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Fri, 2 May 2025 15:47:29 +0200 Subject: [PATCH] Add input help text (#9883) Adds help text to the popover input for free text values, single numeric and semver values. The help text is in addition to the error text (so you can get both). Also makes the add button a little narrower to better match sketches. ## Rendered Multiple values (free text): image With error image Numeric operators: image SemVer operators: image --- .../AddSingleValueWidget.tsx | 4 ++- .../AddValuesPopover.tsx | 19 ++++++++-- .../AddValuesWidget.tsx | 4 ++- .../EditableConstraint.tsx | 35 +++++++++++++------ 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddSingleValueWidget.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddSingleValueWidget.tsx index a6b1221bf2..545da27372 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddSingleValueWidget.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddSingleValueWidget.tsx @@ -21,10 +21,11 @@ interface AddValuesProps { onAddValue: (newValue: string) => void; removeValue: () => void; currentValue?: string; + helpText?: string; } export const AddSingleValueWidget = forwardRef( - ({ currentValue, onAddValue, removeValue }, ref) => { + ({ currentValue, onAddValue, removeValue, helpText }, ref) => { const [open, setOpen] = useState(false); const positioningRef = useRef(null); useImperativeHandle( @@ -56,6 +57,7 @@ export const AddSingleValueWidget = forwardRef( setOpen(false)} diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddValuesPopover.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddValuesPopover.tsx index 51a21e1ce4..c13d2bf25f 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddValuesPopover.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddValuesPopover.tsx @@ -33,19 +33,31 @@ type AddValuesProps = { open: boolean; anchorEl: HTMLElement | null; onClose: () => void; + helpText?: string; }; +const HelpText = styled('p')(({ theme }) => ({ + color: theme.palette.text.secondary, + fontSize: theme.typography.caption.fontSize, +})); + +const AddButton = styled(Button)(({ theme }) => ({ + minWidth: theme.spacing(4), +})); + export const AddValuesPopover: FC = ({ initialValue, onAdd, anchorEl, open, onClose, + helpText, }) => { const [inputValue, setInputValue] = useState(initialValue || ''); const [error, setError] = useState(''); const inputRef = useRef(null); const inputId = useId(); + const helpTextId = useId(); return ( = ({ autoFocus error={!!error} helperText={error} + aria-describedby={helpTextId} /> - + + {helpText} ); diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddValuesWidget.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddValuesWidget.tsx index 1d43370803..33b154cd65 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddValuesWidget.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/AddValuesWidget.tsx @@ -28,10 +28,11 @@ const AddValuesButton = styled('button')(({ theme }) => ({ interface AddValuesProps { onAddValues: (newValues: string[]) => void; + helpText?: string; } export const AddValuesWidget = forwardRef( - ({ onAddValues }, ref) => { + ({ onAddValues, helpText }, ref) => { const [open, setOpen] = useState(false); const positioningRef = useRef(null); useImperativeHandle( @@ -73,6 +74,7 @@ export const AddValuesWidget = forwardRef( setOpen(false)} diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint.tsx index d34c864915..100c411a51 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint.tsx @@ -146,21 +146,28 @@ const StyledCaseSensitiveIcon = styled(CaseSensitiveIcon)(({ theme }) => ({ fill: 'currentcolor', })); -const getInputType = (input: Input) => { +type InputType = + | { input: 'legal values' } + | { input: 'date' } + | { input: 'single value'; type: 'number' | 'semver' } + | { input: 'multiple values' }; + +const getInputType = (input: Input): InputType => { switch (input) { case 'IN_OPERATORS_LEGAL_VALUES': case 'STRING_OPERATORS_LEGAL_VALUES': case 'NUM_OPERATORS_LEGAL_VALUES': case 'SEMVER_OPERATORS_LEGAL_VALUES': - return 'legal values'; + return { input: 'legal values' }; case 'DATE_OPERATORS_SINGLE_VALUE': - return 'date input'; + return { input: 'date' }; case 'NUM_OPERATORS_SINGLE_VALUE': + return { input: 'single value', type: 'number' }; case 'SEMVER_OPERATORS_SINGLE_VALUE': - return 'single text value'; + return { input: 'single value', type: 'semver' }; case 'IN_OPERATORS_FREETEXT': case 'STRING_OPERATORS_FREETEXT': - return 'free text'; + return { input: 'multiple values' }; } }; @@ -273,8 +280,8 @@ export const EditableConstraint: FC = ({ }; const TopRowInput = () => { - switch (inputType) { - case 'date input': + switch (inputType.input) { + case 'date': return ( = ({ setError={setError} /> ); - case 'single text value': + case 'single value': return ( { @@ -291,11 +298,17 @@ export const EditableConstraint: FC = ({ }} removeValue={() => setValue('')} currentValue={localConstraint.value} + helpText={ + inputType.type === 'number' + ? 'Add a single number' + : 'A semver value should be of the format X.Y.Z' + } /> ); - case 'free text': + case 'multiple values': return ( { // todo (`addEditStrategy`): move deduplication logic higher up in the context handling @@ -400,7 +413,7 @@ export const EditableConstraint: FC = ({ - {inputType === 'legal values' ? ( + {inputType.input === 'legal values' ? ( = ({ values={localConstraint.values || []} setValuesWithRecord={setValuesWithRecord} setValues={setValues} - />{' '} + /> ) : null}