mirror of
https://github.com/grafana/grafana.git
synced 2025-01-13 09:32:12 -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 = {
|
||||
separator: '',
|
||||
};
|
||||
|
||||
export const WithInitialValue = Template.bind({});
|
||||
WithInitialValue.args = {
|
||||
initialValue: '3',
|
||||
@ -70,3 +71,9 @@ WithCustomValue.args = {
|
||||
allowCustomValue: true,
|
||||
formatCreateLabel: (val) => 'Custom Label' + val,
|
||||
};
|
||||
|
||||
export const WithDisplayAllSelectedLevels = Template.bind({});
|
||||
WithDisplayAllSelectedLevels.args = {
|
||||
displayAllSelectedLevels: true,
|
||||
separator: ',',
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Cascader } from './Cascader';
|
||||
import { shallow } from 'enzyme';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
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', () => {
|
||||
let cascader: any;
|
||||
beforeEach(() => {
|
||||
cascader = shallow(<Cascader options={options} onSelect={() => {}} />);
|
||||
const placeholder = 'cascader-placeholder';
|
||||
|
||||
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', () => {
|
||||
expect(cascader.state('searchableOptions')).toEqual(flatOptions);
|
||||
it('displays all levels selected with default separator when displayAllSelectedLevels is true', () => {
|
||||
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;
|
||||
/** A function for formatting the message for custom value creation. Only applies when allowCustomValue is set to true*/
|
||||
formatCreateLabel?: (val: string) => string;
|
||||
displayAllSelectedLevels?: boolean;
|
||||
}
|
||||
|
||||
interface CascaderState {
|
||||
@ -57,6 +58,8 @@ const disableDivFocus = css(`
|
||||
}
|
||||
`);
|
||||
|
||||
const DEFAULT_SEPARATOR = '/';
|
||||
|
||||
export class Cascader extends React.PureComponent<CascaderProps, CascaderState> {
|
||||
constructor(props: CascaderProps) {
|
||||
super(props);
|
||||
@ -81,7 +84,7 @@ export class Cascader extends React.PureComponent<CascaderProps, CascaderState>
|
||||
if (!option.items) {
|
||||
selectOptions.push({
|
||||
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),
|
||||
});
|
||||
} else {
|
||||
@ -116,7 +119,9 @@ export class Cascader extends React.PureComponent<CascaderProps, CascaderState>
|
||||
this.setState({
|
||||
rcValue: value,
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user