Grafana-UI: Allow <Select /> value to be unset (#32136)

* Fix: Allow <Select /> value to be unset

* clean up

* fix null object in select onChange

* Revert "fix null object in select onChange"

This reverts commit 4b157073884938e5e6a1fac1bbafa7c6017cb361.

* undo onChange arg type change

* fix tests
This commit is contained in:
Josh Hunt 2021-03-22 14:45:27 +00:00 committed by GitHub
parent 4a2ba2a3ab
commit 7389b2ecac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 5 deletions

View File

@ -1,6 +1,7 @@
import React from 'react';
import React, { useState } from 'react';
import { mount, ReactWrapper } from 'enzyme';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import selectEvent from 'react-select-event';
import { SelectBase } from './SelectBase';
import { SelectableValue } from '@grafana/data';
@ -43,6 +44,25 @@ describe('SelectBase', () => {
expect(screen.getByLabelText('My select')).toBeInTheDocument();
});
it('allows the value to be unset', async () => {
const Test = () => {
const option = { value: 'test-value', label: 'Test label' };
const [value, setValue] = useState<SelectableValue<string> | null>(option);
return (
<>
<button onClick={() => setValue(null)}>clear value</button>
<SelectBase value={value} onChange={setValue} options={[option]} />
</>
);
};
render(<Test />);
expect(screen.queryByText('Test label')).toBeInTheDocument();
userEvent.click(screen.getByText('clear value'));
expect(screen.queryByText('Test label')).not.toBeInTheDocument();
});
describe('when openMenuOnFocus prop', () => {
describe('is provided', () => {
it('opens on focus', () => {

View File

@ -60,7 +60,7 @@ export interface SelectCommonProps<T> {
/** Use a custom element to control Select. A proper ref to the renderControl is needed if 'portal' isn't set to null*/
renderControl?: ControlComponent<T>;
tabSelectsValue?: boolean;
value?: SelectValue<T>;
value?: SelectValue<T> | null;
/** Sets the width to a multiple of 8px. Should only be used with inline forms. Setting width of the container is preferred in other cases.*/
width?: number;
isOptionDisabled?: () => boolean;

View File

@ -74,10 +74,14 @@ describe('Select utils', () => {
expect(cleanValue('test1', optGroup)).toEqual([{ label: 'Group 4 - Option 1', value: 'test1' }]);
expect(cleanValue(3, options)).toEqual([{ label: 'Option 3', value: 3 }]);
});
it('should return undefined for null/undefined/empty values', () => {
it('should return null for null values', () => {
expect(cleanValue(null, options)).toEqual([null]);
});
it('should return undefined for undefined/empty values', () => {
expect(cleanValue([undefined], options)).toEqual(undefined);
expect(cleanValue(undefined, options)).toEqual(undefined);
expect(cleanValue(null, options)).toEqual(undefined);
expect(cleanValue('', options)).toEqual(undefined);
});
});

View File

@ -9,7 +9,8 @@ export const cleanValue = (value: any, options: Array<SelectableValue | Selectab
const filtered = value.filter(Boolean);
return filtered?.length ? filtered : undefined;
}
if (typeof value === 'object' && value !== null) {
if (typeof value === 'object') {
// we want to allow null through into here, so the Select value can be unset
return [value];
}
if (typeof value === 'string' || typeof value === 'number') {