[Lens] Show validation feedback on top values out of bounds number of values (#110222)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
c568a433f3
commit
3b81205a23
|
@ -348,13 +348,6 @@ export const termsOperation: OperationDefinition<TermsIndexPatternColumn, 'field
|
|||
});
|
||||
return (
|
||||
<>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.lens.indexPattern.terms.size', {
|
||||
defaultMessage: 'Number of values',
|
||||
})}
|
||||
display="columnCompressed"
|
||||
fullWidth
|
||||
>
|
||||
<ValuesInput
|
||||
value={currentColumn.params.size}
|
||||
onChange={(value) => {
|
||||
|
@ -368,7 +361,6 @@ export const termsOperation: OperationDefinition<TermsIndexPatternColumn, 'field
|
|||
);
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
label={
|
||||
<>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { shallow } from 'enzyme';
|
||||
import { EuiFieldNumber } from '@elastic/eui';
|
||||
import { EuiFieldNumber, EuiFormRow } from '@elastic/eui';
|
||||
import { ValuesInput } from './values_input';
|
||||
|
||||
jest.mock('react-use/lib/useDebounce', () => (fn: () => void) => fn());
|
||||
|
@ -41,7 +41,7 @@ describe('Values', () => {
|
|||
expect(onChangeSpy.mock.calls[0][0]).toBe(7);
|
||||
});
|
||||
|
||||
it('should not run onChange function on update when value is out of 1-100 range', () => {
|
||||
it('should not run onChange function on update when value is out of 1-1000 range', () => {
|
||||
const onChangeSpy = jest.fn();
|
||||
const instance = shallow(<ValuesInput value={5} onChange={onChangeSpy} />);
|
||||
act(() => {
|
||||
|
@ -54,4 +54,56 @@ describe('Values', () => {
|
|||
expect(onChangeSpy.mock.calls.length).toBe(1);
|
||||
expect(onChangeSpy.mock.calls[0][0]).toBe(1000);
|
||||
});
|
||||
|
||||
it('should show an error message when the value is out of bounds', () => {
|
||||
const instance = shallow(<ValuesInput value={-5} onChange={jest.fn()} />);
|
||||
|
||||
expect(instance.find(EuiFieldNumber).prop('isInvalid')).toBeTruthy();
|
||||
expect(instance.find(EuiFormRow).prop('error')).toEqual(
|
||||
expect.arrayContaining([expect.stringMatching('Value is lower')])
|
||||
);
|
||||
|
||||
act(() => {
|
||||
instance.find(EuiFieldNumber).prop('onChange')!({
|
||||
currentTarget: { value: '1007' },
|
||||
} as React.ChangeEvent<HTMLInputElement>);
|
||||
});
|
||||
instance.update();
|
||||
|
||||
expect(instance.find(EuiFieldNumber).prop('isInvalid')).toBeTruthy();
|
||||
expect(instance.find(EuiFormRow).prop('error')).toEqual(
|
||||
expect.arrayContaining([expect.stringMatching('Value is higher')])
|
||||
);
|
||||
});
|
||||
|
||||
it('should fallback to last valid value on input blur', () => {
|
||||
const instance = shallow(<ValuesInput value={123} onChange={jest.fn()} />);
|
||||
|
||||
function changeAndBlur(newValue: string) {
|
||||
act(() => {
|
||||
instance.find(EuiFieldNumber).prop('onChange')!({
|
||||
currentTarget: { value: newValue },
|
||||
} as React.ChangeEvent<HTMLInputElement>);
|
||||
});
|
||||
instance.update();
|
||||
act(() => {
|
||||
instance.find(EuiFieldNumber).prop('onBlur')!({} as React.FocusEvent<HTMLInputElement>);
|
||||
});
|
||||
instance.update();
|
||||
}
|
||||
|
||||
changeAndBlur('-5');
|
||||
|
||||
expect(instance.find(EuiFieldNumber).prop('isInvalid')).toBeFalsy();
|
||||
expect(instance.find(EuiFieldNumber).prop('value')).toBe('1');
|
||||
|
||||
changeAndBlur('5000');
|
||||
|
||||
expect(instance.find(EuiFieldNumber).prop('isInvalid')).toBeFalsy();
|
||||
expect(instance.find(EuiFieldNumber).prop('value')).toBe('1000');
|
||||
|
||||
changeAndBlur('');
|
||||
// as we're not handling the onChange state, it fallbacks to the value prop
|
||||
expect(instance.find(EuiFieldNumber).prop('value')).toBe('123');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import React, { useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiFieldNumber } from '@elastic/eui';
|
||||
import { EuiFieldNumber, EuiFormRow } from '@elastic/eui';
|
||||
import { useDebounceWithOptions } from '../../../../shared_components';
|
||||
|
||||
export const ValuesInput = ({
|
||||
|
@ -35,17 +35,63 @@ export const ValuesInput = ({
|
|||
[inputValue]
|
||||
);
|
||||
|
||||
const isEmptyString = inputValue === '';
|
||||
const isHigherThanMax = !isEmptyString && Number(inputValue) > MAX_NUMBER_OF_VALUES;
|
||||
const isLowerThanMin = !isEmptyString && Number(inputValue) < MIN_NUMBER_OF_VALUES;
|
||||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.lens.indexPattern.terms.size', {
|
||||
defaultMessage: 'Number of values',
|
||||
})}
|
||||
display="columnCompressed"
|
||||
fullWidth
|
||||
isInvalid={isHigherThanMax || isLowerThanMin}
|
||||
error={
|
||||
isHigherThanMax
|
||||
? [
|
||||
i18n.translate('xpack.lens.indexPattern.terms.sizeLimitMax', {
|
||||
defaultMessage:
|
||||
'Value is higher than the maximum {max}, the maximum value is used instead.',
|
||||
values: {
|
||||
max: MAX_NUMBER_OF_VALUES,
|
||||
},
|
||||
}),
|
||||
]
|
||||
: isLowerThanMin
|
||||
? [
|
||||
i18n.translate('xpack.lens.indexPattern.terms.sizeLimitMin', {
|
||||
defaultMessage:
|
||||
'Value is lower than the minimum {min}, the minimum value is used instead.',
|
||||
values: {
|
||||
min: MIN_NUMBER_OF_VALUES,
|
||||
},
|
||||
}),
|
||||
]
|
||||
: null
|
||||
}
|
||||
>
|
||||
<EuiFieldNumber
|
||||
min={MIN_NUMBER_OF_VALUES}
|
||||
max={MAX_NUMBER_OF_VALUES}
|
||||
step={1}
|
||||
value={inputValue}
|
||||
compressed
|
||||
isInvalid={isHigherThanMax || isLowerThanMin}
|
||||
onChange={({ currentTarget }) => setInputValue(currentTarget.value)}
|
||||
aria-label={i18n.translate('xpack.lens.indexPattern.terms.size', {
|
||||
defaultMessage: 'Number of values',
|
||||
})}
|
||||
onBlur={() => {
|
||||
if (inputValue === '') {
|
||||
return setInputValue(String(value));
|
||||
}
|
||||
const inputNumber = Number(inputValue);
|
||||
setInputValue(
|
||||
String(Math.min(MAX_NUMBER_OF_VALUES, Math.max(inputNumber, MIN_NUMBER_OF_VALUES)))
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue