mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Grafana/ui: display all selected levels for Cascader (#31729)
* add support for displaying all selected levels for cascader * add story for Cascader with display all selected levels * add tests for Cascader with displayAllSelectedLevels prop * replace enzyme test with RTL for cascader
This commit is contained in:
parent
d09afbda18
commit
6819a25add
@ -59,6 +59,7 @@ export const Simple = Template.bind({});
|
|||||||
Simple.args = {
|
Simple.args = {
|
||||||
separator: '',
|
separator: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WithInitialValue = Template.bind({});
|
export const WithInitialValue = Template.bind({});
|
||||||
WithInitialValue.args = {
|
WithInitialValue.args = {
|
||||||
initialValue: '3',
|
initialValue: '3',
|
||||||
@ -70,3 +71,9 @@ WithCustomValue.args = {
|
|||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
formatCreateLabel: (val) => 'Custom Label' + val,
|
formatCreateLabel: (val) => 'Custom Label' + val,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const WithDisplayAllSelectedLevels = Template.bind({});
|
||||||
|
WithDisplayAllSelectedLevels.args = {
|
||||||
|
displayAllSelectedLevels: true,
|
||||||
|
separator: ',',
|
||||||
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Cascader } from './Cascader';
|
import { Cascader } from './Cascader';
|
||||||
import { shallow } from 'enzyme';
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
@ -27,36 +28,73 @@ const options = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const flatOptions = [
|
|
||||||
{
|
|
||||||
singleLabel: 'Second',
|
|
||||||
label: 'First / Second',
|
|
||||||
value: ['1', '2'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
singleLabel: 'Third',
|
|
||||||
label: 'First / Third',
|
|
||||||
value: ['1', '3'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
singleLabel: 'Fourth',
|
|
||||||
label: 'First / Fourth',
|
|
||||||
value: ['1', '4'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
singleLabel: 'FirstFirst',
|
|
||||||
label: 'FirstFirst',
|
|
||||||
value: ['5'],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
describe('Cascader', () => {
|
describe('Cascader', () => {
|
||||||
let cascader: any;
|
const placeholder = 'cascader-placeholder';
|
||||||
beforeEach(() => {
|
|
||||||
cascader = shallow(<Cascader options={options} onSelect={() => {}} />);
|
it('filters results when searching', () => {
|
||||||
|
render(<Cascader placeholder={placeholder} options={options} onSelect={() => {}} />);
|
||||||
|
|
||||||
|
userEvent.type(screen.getByPlaceholderText(placeholder), 'Third');
|
||||||
|
|
||||||
|
expect(screen.queryByText('Second')).not.toBeInTheDocument();
|
||||||
|
expect(screen.getByText('First / Third')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should convert options to searchable strings', () => {
|
it('displays all levels selected with default separator when displayAllSelectedLevels is true', () => {
|
||||||
expect(cascader.state('searchableOptions')).toEqual(flatOptions);
|
render(
|
||||||
|
<Cascader displayAllSelectedLevels={true} placeholder={placeholder} options={options} onSelect={() => {}} />
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByDisplayValue('First/Second')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(screen.getByPlaceholderText(placeholder));
|
||||||
|
userEvent.click(screen.getByText('First'));
|
||||||
|
userEvent.click(screen.getByText('Second'));
|
||||||
|
|
||||||
|
expect(screen.getByDisplayValue('First/Second')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays all levels selected with separator passed in when displayAllSelectedLevels is true', () => {
|
||||||
|
const separator = ',';
|
||||||
|
|
||||||
|
render(
|
||||||
|
<Cascader
|
||||||
|
displayAllSelectedLevels={true}
|
||||||
|
separator={separator}
|
||||||
|
placeholder={placeholder}
|
||||||
|
options={options}
|
||||||
|
onSelect={() => {}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByDisplayValue('First/Second')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(screen.getByPlaceholderText(placeholder));
|
||||||
|
userEvent.click(screen.getByText('First'));
|
||||||
|
userEvent.click(screen.getByText('Second'));
|
||||||
|
|
||||||
|
expect(screen.getByDisplayValue(`First${separator}Second`)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays last level selected when displayAllSelectedLevels is false', () => {
|
||||||
|
render(
|
||||||
|
<Cascader displayAllSelectedLevels={false} placeholder={placeholder} options={options} onSelect={() => {}} />
|
||||||
|
);
|
||||||
|
|
||||||
|
userEvent.click(screen.getByPlaceholderText(placeholder));
|
||||||
|
userEvent.click(screen.getByText('First'));
|
||||||
|
userEvent.click(screen.getByText('Second'));
|
||||||
|
|
||||||
|
expect(screen.getByDisplayValue('Second')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays last level selected when displayAllSelectedLevels is not passed in', () => {
|
||||||
|
render(<Cascader placeholder={placeholder} options={options} onSelect={() => {}} />);
|
||||||
|
|
||||||
|
userEvent.click(screen.getByPlaceholderText(placeholder));
|
||||||
|
userEvent.click(screen.getByText('First'));
|
||||||
|
userEvent.click(screen.getByText('Second'));
|
||||||
|
|
||||||
|
expect(screen.getByDisplayValue('Second')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -22,6 +22,7 @@ export interface CascaderProps {
|
|||||||
allowCustomValue?: boolean;
|
allowCustomValue?: boolean;
|
||||||
/** A function for formatting the message for custom value creation. Only applies when allowCustomValue is set to true*/
|
/** A function for formatting the message for custom value creation. Only applies when allowCustomValue is set to true*/
|
||||||
formatCreateLabel?: (val: string) => string;
|
formatCreateLabel?: (val: string) => string;
|
||||||
|
displayAllSelectedLevels?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CascaderState {
|
interface CascaderState {
|
||||||
@ -57,6 +58,8 @@ const disableDivFocus = css(`
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
const DEFAULT_SEPARATOR = '/';
|
||||||
|
|
||||||
export class Cascader extends React.PureComponent<CascaderProps, CascaderState> {
|
export class Cascader extends React.PureComponent<CascaderProps, CascaderState> {
|
||||||
constructor(props: CascaderProps) {
|
constructor(props: CascaderProps) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -81,7 +84,7 @@ export class Cascader extends React.PureComponent<CascaderProps, CascaderState>
|
|||||||
if (!option.items) {
|
if (!option.items) {
|
||||||
selectOptions.push({
|
selectOptions.push({
|
||||||
singleLabel: cpy[cpy.length - 1].label,
|
singleLabel: cpy[cpy.length - 1].label,
|
||||||
label: cpy.map((o) => o.label).join(this.props.separator || ' / '),
|
label: cpy.map((o) => o.label).join(this.props.separator || ` ${DEFAULT_SEPARATOR} `),
|
||||||
value: cpy.map((o) => o.value),
|
value: cpy.map((o) => o.value),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -116,7 +119,9 @@ export class Cascader extends React.PureComponent<CascaderProps, CascaderState>
|
|||||||
this.setState({
|
this.setState({
|
||||||
rcValue: value,
|
rcValue: value,
|
||||||
focusCascade: true,
|
focusCascade: true,
|
||||||
activeLabel: selectedOptions[selectedOptions.length - 1].label,
|
activeLabel: this.props.displayAllSelectedLevels
|
||||||
|
? selectedOptions.map((option) => option.label).join(this.props.separator || DEFAULT_SEPARATOR)
|
||||||
|
: selectedOptions[selectedOptions.length - 1].label,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.props.onSelect(selectedOptions[selectedOptions.length - 1].value);
|
this.props.onSelect(selectedOptions[selectedOptions.length - 1].value);
|
||||||
|
Loading…
Reference in New Issue
Block a user