aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorMathieu Suen <mathieu.suen@sonarsource.com>2022-10-18 14:36:44 +0200
committersonartech <sonartech@sonarsource.com>2022-10-21 20:03:17 +0000
commit483c51b8401fd096553bf64d946651e5024fd3eb (patch)
treeaca117466e3bfa8577a6b5056db5da4abda26b13 /server
parentd75de0570fc03c35f71569021454aa1d1f326d62 (diff)
downloadsonarqube-483c51b8401fd096553bf64d946651e5024fd3eb.tar.gz
sonarqube-483c51b8401fd096553bf64d946651e5024fd3eb.zip
SONAR-17453 Fixed order when changing selection in nulti select ui
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/components/common/MultiSelect.tsx245
-rw-r--r--server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx30
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx165
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx42
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap208
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap114
6 files changed, 179 insertions, 625 deletions
diff --git a/server/sonar-web/src/main/js/components/common/MultiSelect.tsx b/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
index ff01303af80..efffa6b4851 100644
--- a/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
+++ b/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
@@ -18,20 +18,17 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import classNames from 'classnames';
-import { difference } from 'lodash';
+import { isEmpty, remove, xor } from 'lodash';
import * as React from 'react';
import SearchBox from '../../components/controls/SearchBox';
-import { isShortcut } from '../../helpers/keyboardEventHelpers';
-import { KeyboardKeys } from '../../helpers/keycodes';
import { translateWithParameters } from '../../helpers/l10n';
-import MultiSelectOption from './MultiSelectOption';
+import MultiSelectOption, { Element } from './MultiSelectOption';
export interface MultiSelectProps {
allowNewElements?: boolean;
allowSelection?: boolean;
legend: string;
elements: string[];
- // eslint-disable-next-line react/no-unused-prop-types
filterSelected?: (query: string, selectedElements: string[]) => string[];
footerNode?: React.ReactNode;
listSize?: number;
@@ -45,11 +42,9 @@ export interface MultiSelectProps {
}
interface State {
- activeIdx: number;
loading: boolean;
query: string;
- selectedElements: string[];
- unselectedElements: string[];
+ elements: Element[];
}
interface DefaultProps {
@@ -63,8 +58,6 @@ interface DefaultProps {
type PropsWithDefault = MultiSelectProps & DefaultProps;
export default class MultiSelect extends React.PureComponent<PropsWithDefault, State> {
- container?: HTMLDivElement | null;
- searchInput?: HTMLInputElement | null;
mounted = false;
static defaultProps: DefaultProps = {
@@ -78,51 +71,79 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S
constructor(props: PropsWithDefault) {
super(props);
this.state = {
- activeIdx: 0,
- loading: true,
+ loading: false,
query: '',
- selectedElements: [],
- unselectedElements: []
+ elements: []
};
}
componentDidMount() {
this.mounted = true;
this.onSearchQuery('');
- this.updateSelectedElements(this.props as PropsWithDefault);
- this.updateUnselectedElements(this.props as PropsWithDefault);
- if (this.container) {
- this.container.addEventListener('keydown', this.handleKeyboard, true);
- }
+ this.computeElements();
}
- componentDidUpdate(prevProps: PropsWithDefault) {
+ componentDidUpdate(prevProps: PropsWithDefault, prevState: State) {
if (
- prevProps.elements !== this.props.elements ||
- prevProps.selectedElements !== this.props.selectedElements
+ !isEmpty(
+ xor(
+ [...prevProps.selectedElements, ...prevProps.elements],
+ [...this.props.selectedElements, ...this.props.elements]
+ )
+ )
) {
- this.updateSelectedElements(this.props);
- this.updateUnselectedElements(this.props);
-
- const totalElements = this.getAllElements(this.props, this.state).length;
- if (this.state.activeIdx >= totalElements) {
- this.setState({ activeIdx: totalElements - 1 });
- }
+ this.computeElements();
}
- if (this.searchInput) {
- this.searchInput.focus();
+ if (prevState.query !== this.state.query) {
+ this.setState(({ query, elements }, props) => {
+ const newElements = [...elements];
+ this.appendCreateElelement(newElements, query, props);
+ return { elements: newElements };
+ });
}
}
componentWillUnmount() {
this.mounted = false;
- if (this.container) {
- this.container.removeEventListener('keydown', this.handleKeyboard, true);
+ }
+
+ computeElements() {
+ this.setState(({ query }, props) => {
+ const newStateElement: Element[] = [
+ ...this.props
+ .filterSelected(query, this.props.selectedElements)
+ .map(e => ({ value: e, selected: true })),
+ ...this.props.elements.map(e => ({
+ value: e,
+ selected: false
+ }))
+ ];
+
+ this.appendCreateElelement(newStateElement, query, props);
+ return { elements: newStateElement };
+ });
+ }
+
+ appendCreateElelement(elements: Element[], query: string, props: PropsWithDefault) {
+ const { allowNewElements = true } = props;
+ if (this.isNewElement(query, props) && allowNewElements) {
+ const create = elements.find(e => e.custom);
+ if (create) {
+ create.value = query;
+ } else {
+ elements.push({ value: query, selected: false, custom: true });
+ }
+ } else if (!this.isNewElement(query, props) && allowNewElements) {
+ remove(elements, e => e.custom);
}
}
handleSelectChange = (selected: boolean, item: string) => {
+ this.setState(({ elements }) => {
+ const newElements = elements.map(e => (e.value === item ? { value: e.value, selected } : e));
+ return { elements: newElements };
+ });
if (selected) {
this.onSelectItem(item);
} else {
@@ -134,42 +155,16 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S
this.onSearchQuery((this.props as PropsWithDefault).validateSearchInput(value));
};
- handleElementHover = (element: string) => {
- this.setState((prevState, props) => {
- return { activeIdx: this.getAllElements(props, prevState).indexOf(element) };
- });
- };
-
- handleKeyboard = (event: KeyboardEvent) => {
- if (isShortcut(event)) {
- return true;
- }
- switch (event.key) {
- case KeyboardKeys.DownArrow:
- event.stopPropagation();
- event.preventDefault();
- this.setState(this.selectNextElement);
- break;
- case KeyboardKeys.UpArrow:
- event.stopPropagation();
- event.preventDefault();
- this.setState(this.selectPreviousElement);
- break;
- case KeyboardKeys.LeftArrow:
- case KeyboardKeys.RightArrow:
- event.stopPropagation();
- break;
- case KeyboardKeys.Enter:
- if (this.state.activeIdx >= 0) {
- this.toggleSelect(this.getAllElements(this.props, this.state)[this.state.activeIdx]);
- }
- break;
- }
- };
-
onSearchQuery = (query: string) => {
- this.setState({ activeIdx: 0, loading: true, query });
+ const { allowNewElements = true } = this.props;
+
this.props.onSearch(query).then(this.stopLoading, this.stopLoading);
+ if (allowNewElements) {
+ this.setState({
+ loading: true,
+ query
+ });
+ }
};
onSelectItem = (item: string) => {
@@ -182,67 +177,7 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S
onUnselectItem = (item: string) => this.props.onUnselect(item);
isNewElement = (elem: string, { selectedElements, elements }: PropsWithDefault) =>
- elem.length > 0 && selectedElements.indexOf(elem) === -1 && elements.indexOf(elem) === -1;
-
- updateSelectedElements = (props: PropsWithDefault) => {
- this.setState((state: State) => {
- if (state.query) {
- return {
- selectedElements: props.filterSelected(state.query, props.selectedElements)
- };
- } else {
- return { selectedElements: [...props.selectedElements] };
- }
- });
- };
-
- updateUnselectedElements = (props: PropsWithDefault) => {
- this.setState((state: State) => {
- if (props.listSize === 0) {
- return { unselectedElements: difference(props.elements, props.selectedElements) };
- } else if (props.listSize < state.selectedElements.length) {
- return { unselectedElements: [] };
- } else {
- return {
- unselectedElements: difference(props.elements, props.selectedElements).slice(
- 0,
- props.listSize - state.selectedElements.length
- )
- };
- }
- });
- };
-
- getAllElements = (props: PropsWithDefault, state: State) => {
- if (this.isNewElement(state.query, props)) {
- return [...state.selectedElements, ...state.unselectedElements, state.query];
- } else {
- return [...state.selectedElements, ...state.unselectedElements];
- }
- };
-
- setElementActive = (idx: number) => this.setState({ activeIdx: idx });
-
- selectNextElement = (state: State, props: PropsWithDefault) => {
- const { activeIdx } = state;
- const allElements = this.getAllElements(props, state);
- if (activeIdx < 0 || activeIdx >= allElements.length - 1) {
- return { activeIdx: 0 };
- } else {
- return { activeIdx: activeIdx + 1 };
- }
- };
-
- selectPreviousElement = (state: State, props: PropsWithDefault) => {
- const { activeIdx } = state;
- const allElements = this.getAllElements(props, state);
- if (activeIdx <= 0) {
- const lastIdx = allElements.length - 1;
- return { activeIdx: lastIdx };
- } else {
- return { activeIdx: activeIdx - 1 };
- }
- };
+ !isEmpty(elem) && selectedElements.indexOf(elem) === -1 && elements.indexOf(elem) === -1;
stopLoading = () => {
if (this.mounted) {
@@ -250,20 +185,10 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S
}
};
- toggleSelect = (item: string) => {
- if (this.props.selectedElements.indexOf(item) === -1) {
- this.onSelectItem(item);
- } else {
- this.onUnselectItem(item);
- }
- };
-
render() {
- const { legend, allowSelection = true, allowNewElements = true, footerNode = '' } = this.props;
+ const { legend, allowSelection = true, footerNode = '' } = this.props;
const { renderLabel } = this.props as PropsWithDefault;
- const { query, activeIdx, selectedElements, unselectedElements } = this.state;
- const activeElement = this.getAllElements(this.props, this.state)[activeIdx];
- const showNewElement = allowNewElements && this.isNewElement(query, this.props);
+ const { query, elements } = this.state;
const infiniteList = this.props.listSize === 0;
const listClasses = classNames('menu', {
'menu-vertically-limited': infiniteList,
@@ -273,7 +198,7 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S
});
return (
- <div className="multi-select" ref={div => (this.container = div)}>
+ <div className="multi-select">
<div className="menu-search">
<SearchBox
autoFocus={true}
@@ -286,42 +211,16 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S
</div>
<fieldset aria-label={legend}>
<ul className={listClasses}>
- {selectedElements.length > 0 &&
- selectedElements.map(element => (
- <MultiSelectOption
- active={activeElement === element}
- element={element}
- key={element}
- onHover={this.handleElementHover}
- onSelectChange={this.handleSelectChange}
- renderLabel={renderLabel}
- selected={true}
- />
- ))}
- {unselectedElements.length > 0 &&
- unselectedElements.map(element => (
- <MultiSelectOption
- active={activeElement === element}
- disabled={!allowSelection}
- element={element}
- key={element}
- onHover={this.handleElementHover}
- onSelectChange={this.handleSelectChange}
- renderLabel={renderLabel}
- />
- ))}
- {showNewElement && (
+ {elements.map(e => (
<MultiSelectOption
- active={activeElement === query}
- custom={true}
- element={query}
- key={query}
- onHover={this.handleElementHover}
+ element={e}
+ disabled={!allowSelection && !e.selected}
+ key={e.value}
onSelectChange={this.handleSelectChange}
renderLabel={renderLabel}
/>
- )}
- {!showNewElement && selectedElements.length < 1 && unselectedElements.length < 1 && (
+ ))}
+ {isEmpty(elements) && (
<li className="spacer-left">{translateWithParameters('no_results_for_x', query)}</li>
)}
</ul>
diff --git a/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx b/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx
index f3da85c78e8..70063767fd3 100644
--- a/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx
+++ b/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx
@@ -22,32 +22,38 @@ import * as React from 'react';
import Checkbox from '../../components/controls/Checkbox';
import { translate } from '../../helpers/l10n';
-export interface MultiSelectOptionProps {
- active?: boolean;
+export interface Element {
+ value: string;
+ selected: boolean;
custom?: boolean;
+}
+
+export interface MultiSelectOptionProps {
disabled?: boolean;
- element: string;
- onHover: (element: string) => void;
+ element: Element;
onSelectChange: (selected: boolean, element: string) => void;
renderLabel: (element: string) => React.ReactNode;
- selected?: boolean;
}
export default function MultiSelectOption(props: MultiSelectOptionProps) {
- const { active, custom, disabled, element, selected } = props;
- const onHover = () => props.onHover(element);
+ const { disabled, element } = props;
+ const [active, setActive] = React.useState(false);
const className = classNames({ active, disabled });
- const label = props.renderLabel(element);
+ const label = props.renderLabel(element.value);
return (
- <li onFocus={onHover} onMouseOver={onHover}>
+ <li
+ onFocus={() => setActive(true)}
+ onBlur={() => setActive(false)}
+ onMouseLeave={() => setActive(false)}
+ onMouseOver={() => setActive(true)}>
<Checkbox
- checked={Boolean(selected)}
+ checked={element.selected}
className={className}
disabled={disabled}
- id={element}
+ id={element.value}
onCheck={props.onSelectChange}>
- {custom ? (
+ {element.custom ? (
<span
aria-label={`${translate('create_new_element')}: ${label}`}
className="little-spacer-left">
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx
index a2e5c946cbd..bc8fd239ee0 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx
+++ b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx
@@ -17,92 +17,105 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { mount, shallow } from 'enzyme';
+import { render } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
import * as React from 'react';
-import { KeyboardKeys } from '../../../helpers/keycodes';
-import { mockEvent } from '../../../helpers/testUtils';
-import MultiSelect, { MultiSelectProps } from '../MultiSelect';
+import { byRole, byText } from 'testing-library-selector';
+import MultiSelect from '../MultiSelect';
-const props = {
- selectedElements: ['bar'],
- elements: [],
- onSearch: () => Promise.resolve(),
- onSelect: () => {},
- onUnselect: () => {},
- renderLabel: (element: string) => element,
- placeholder: ''
+const ui = {
+ checkbox: (name: string) => byRole('checkbox', { name }),
+ search: byRole('searchbox', { name: 'search_verb' }),
+ noResult: byText('no_results_for_x.notfound')
};
-const elements = ['foo', 'bar', 'baz'];
+it('should handle selection', async () => {
+ const user = userEvent.setup();
+ const rerender = renderMultiSelect();
+ expect(ui.checkbox('az').get()).toBeChecked();
+ await user.click(ui.checkbox('az').get());
+ expect(ui.checkbox('az').get()).not.toBeChecked();
-it('should render multiselect with selected elements', () => {
- const multiselect = shallowRender();
- // Will not only the selected element
- expect(multiselect).toMatchSnapshot();
+ await user.type(ui.search.get(), 'create');
+ await user.click(ui.checkbox('create_new_element: create').get());
+ expect(ui.checkbox('create').get()).toBeChecked();
- multiselect.setProps({ elements });
- expect(multiselect).toMatchSnapshot();
- multiselect.setState({ activeIdx: 2 });
- expect(multiselect).toMatchSnapshot();
- multiselect.setState({ query: 'test' });
- expect(multiselect).toMatchSnapshot();
+ // Custom label
+ rerender({ renderLabel: label => `prefxed-${label}` });
+ expect(ui.checkbox('prefxed-create').get()).toBeChecked();
});
-it('should render with the focus inside the search input', () => {
- /*
- * Need to attach to document body to have it set to `document.activeElement`
- * See: https://github.com/jsdom/jsdom/issues/2723#issuecomment-580163361
- */
- const container = document.createElement('div');
- document.body.appendChild(container);
- const multiselect = mount(<MultiSelect legend="multi select" {...props} />, {
- attachTo: container
- });
-
- expect(multiselect.find('input').getDOMNode()).toBe(document.activeElement);
-
- multiselect.unmount();
-});
-
-it.each([
- [KeyboardKeys.DownArrow, 1, 1],
- [KeyboardKeys.UpArrow, 1, 1],
- [KeyboardKeys.LeftArrow, 1, 0]
-])('should handle keyboard event: %s', (key, stopPropagationCalls, preventDefaultCalls) => {
- const wrapper = shallowRender();
-
- const stopPropagation = jest.fn();
- const preventDefault = jest.fn();
- const event = mockEvent({ preventDefault, stopPropagation, key });
-
- wrapper.instance().handleKeyboard(event);
-
- expect(stopPropagation).toBeCalledTimes(stopPropagationCalls);
- expect(preventDefault).toBeCalledTimes(preventDefaultCalls);
+it('should handle disable selection', () => {
+ renderMultiSelect({ allowSelection: false });
+ expect(ui.checkbox('az').get()).toBeChecked();
+ expect(ui.checkbox('cx').get()).toHaveAttribute('aria-disabled', 'true');
});
-it('should handle keyboard event: enter', () => {
- const wrapper = shallowRender();
-
- wrapper.instance().toggleSelect = jest.fn();
-
- wrapper.instance().handleKeyboard(mockEvent({ key: KeyboardKeys.Enter }));
-
- expect(wrapper.instance().toggleSelect).toBeCalled();
+it('should handle search', async () => {
+ const user = userEvent.setup();
+ const rerender = renderMultiSelect();
+ expect(ui.checkbox('cx').get()).toBeInTheDocument();
+ await user.type(ui.search.get(), 'az');
+ expect(ui.checkbox('cx').query()).not.toBeInTheDocument();
+ expect(ui.checkbox('az').get()).toBeInTheDocument();
+ expect(ui.checkbox('az-new').get()).toBeInTheDocument();
+
+ await user.clear(ui.search.get());
+ await user.type(ui.search.get(), 'notfound');
+ expect(ui.checkbox('create_new_element: notfound').get()).toBeInTheDocument();
+
+ rerender({ allowNewElements: false });
+ await user.clear(ui.search.get());
+ await user.type(ui.search.get(), 'notfound');
+ expect(ui.noResult.get()).toBeInTheDocument();
});
-function shallowRender(overrides: Partial<MultiSelectProps> = {}) {
- return shallow<MultiSelect>(
- <MultiSelect
- selectedElements={['bar']}
- elements={[]}
- legend="multi select"
- onSearch={() => Promise.resolve()}
- onSelect={jest.fn()}
- onUnselect={jest.fn()}
- renderLabel={(element: string) => element}
- placeholder=""
- {...overrides}
- />
- );
+function renderMultiSelect(override?: Partial<MultiSelect['props']>) {
+ const initial = ['cx', 'dw', 'ev', 'fu', 'gt', 'hs'];
+ const initialSelected = ['az', 'by'];
+
+ function Parent(props?: Partial<MultiSelect['props']>) {
+ const [elements, setElements] = React.useState(initial);
+ const [selected, setSelected] = React.useState(['az', 'by']);
+ const onSearch = (query: string) => {
+ if (query === 'notfound') {
+ setElements([]);
+ setSelected([]);
+ } else if (query === '') {
+ setElements(initial);
+ setSelected(initialSelected);
+ } else {
+ setElements([...elements.filter(e => e.indexOf(query) !== -1), `${query}-new`]);
+ setSelected(selected.filter(e => e.indexOf(query) !== -1));
+ }
+ return Promise.resolve();
+ };
+
+ const onSelect = (element: string) => {
+ setSelected([...selected, element]);
+ setElements(elements.filter(e => e !== element));
+ };
+
+ const onUnselect = (element: string) => {
+ setElements([...elements, element]);
+ setSelected(selected.filter(e => e !== element));
+ };
+ return (
+ <MultiSelect
+ selectedElements={selected}
+ elements={elements}
+ legend="multi select"
+ onSearch={onSearch}
+ onSelect={onSelect}
+ onUnselect={onUnselect}
+ placeholder=""
+ {...props}
+ />
+ );
+ }
+
+ const { rerender } = render(<Parent {...override} />);
+ return function(reoverride?: Partial<MultiSelect['props']>) {
+ rerender(<Parent {...override} {...reoverride} />);
+ };
}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx
deleted file mode 100644
index 28e09b68c5b..00000000000
--- a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import MultiSelectOption, { MultiSelectOptionProps } from '../MultiSelectOption';
-
-it('should render standard element', () => {
- expect(shallowRender()).toMatchSnapshot('default element');
- expect(shallowRender({ selected: true })).toMatchSnapshot('selected element');
- expect(shallowRender({ custom: true })).toMatchSnapshot('custom element');
- expect(shallowRender({ active: true, selected: true })).toMatchSnapshot('active element');
- expect(shallowRender({ disabled: true })).toMatchSnapshot('disabled element');
-});
-
-function shallowRender(props: Partial<MultiSelectOptionProps> = {}) {
- return shallow(
- <MultiSelectOption
- element="mytag"
- onHover={jest.fn()}
- onSelectChange={jest.fn()}
- renderLabel={(element: string) => element}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap
deleted file mode 100644
index 2ec8d126534..00000000000
--- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap
+++ /dev/null
@@ -1,208 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render multiselect with selected elements 1`] = `
-<div
- className="multi-select"
->
- <div
- className="menu-search"
- >
- <SearchBox
- autoFocus={true}
- className="little-spacer-top"
- loading={true}
- onChange={[Function]}
- placeholder=""
- value=""
- />
- </div>
- <fieldset
- aria-label="multi select"
- >
- <ul
- className="menu menu-vertically-limited spacer-top with-top-separator"
- >
- <MultiSelectOption
- active={true}
- element="bar"
- key="bar"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- selected={true}
- />
- </ul>
- </fieldset>
-</div>
-`;
-
-exports[`should render multiselect with selected elements 2`] = `
-<div
- className="multi-select"
->
- <div
- className="menu-search"
- >
- <SearchBox
- autoFocus={true}
- className="little-spacer-top"
- loading={true}
- onChange={[Function]}
- placeholder=""
- value=""
- />
- </div>
- <fieldset
- aria-label="multi select"
- >
- <ul
- className="menu menu-vertically-limited spacer-top with-top-separator"
- >
- <MultiSelectOption
- active={true}
- element="bar"
- key="bar"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- selected={true}
- />
- <MultiSelectOption
- active={false}
- disabled={false}
- element="foo"
- key="foo"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- <MultiSelectOption
- active={false}
- disabled={false}
- element="baz"
- key="baz"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- </ul>
- </fieldset>
-</div>
-`;
-
-exports[`should render multiselect with selected elements 3`] = `
-<div
- className="multi-select"
->
- <div
- className="menu-search"
- >
- <SearchBox
- autoFocus={true}
- className="little-spacer-top"
- loading={true}
- onChange={[Function]}
- placeholder=""
- value=""
- />
- </div>
- <fieldset
- aria-label="multi select"
- >
- <ul
- className="menu menu-vertically-limited spacer-top with-top-separator"
- >
- <MultiSelectOption
- active={false}
- element="bar"
- key="bar"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- selected={true}
- />
- <MultiSelectOption
- active={false}
- disabled={false}
- element="foo"
- key="foo"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- <MultiSelectOption
- active={true}
- disabled={false}
- element="baz"
- key="baz"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- </ul>
- </fieldset>
-</div>
-`;
-
-exports[`should render multiselect with selected elements 4`] = `
-<div
- className="multi-select"
->
- <div
- className="menu-search"
- >
- <SearchBox
- autoFocus={true}
- className="little-spacer-top"
- loading={true}
- onChange={[Function]}
- placeholder=""
- value="test"
- />
- </div>
- <fieldset
- aria-label="multi select"
- >
- <ul
- className="menu menu-vertically-limited spacer-top with-top-separator"
- >
- <MultiSelectOption
- active={false}
- element="bar"
- key="bar"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- selected={true}
- />
- <MultiSelectOption
- active={false}
- disabled={false}
- element="foo"
- key="foo"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- <MultiSelectOption
- active={true}
- disabled={false}
- element="baz"
- key="baz"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- <MultiSelectOption
- active={false}
- custom={true}
- element="test"
- key="test"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- </ul>
- </fieldset>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap
deleted file mode 100644
index ee6ce1bf244..00000000000
--- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap
+++ /dev/null
@@ -1,114 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render standard element: active element 1`] = `
-<li
- onFocus={[Function]}
- onMouseOver={[Function]}
->
- <Checkbox
- checked={true}
- className="active"
- id="mytag"
- onCheck={[MockFunction]}
- thirdState={false}
- >
- <span
- className="little-spacer-left"
- >
- mytag
- </span>
- </Checkbox>
-</li>
-`;
-
-exports[`should render standard element: custom element 1`] = `
-<li
- onFocus={[Function]}
- onMouseOver={[Function]}
->
- <Checkbox
- checked={false}
- className=""
- id="mytag"
- onCheck={[MockFunction]}
- thirdState={false}
- >
- <span
- aria-label="create_new_element: mytag"
- className="little-spacer-left"
- >
- <span
- aria-hidden={true}
- className="little-spacer-right"
- >
- +
- </span>
- mytag
- </span>
- </Checkbox>
-</li>
-`;
-
-exports[`should render standard element: default element 1`] = `
-<li
- onFocus={[Function]}
- onMouseOver={[Function]}
->
- <Checkbox
- checked={false}
- className=""
- id="mytag"
- onCheck={[MockFunction]}
- thirdState={false}
- >
- <span
- className="little-spacer-left"
- >
- mytag
- </span>
- </Checkbox>
-</li>
-`;
-
-exports[`should render standard element: disabled element 1`] = `
-<li
- onFocus={[Function]}
- onMouseOver={[Function]}
->
- <Checkbox
- checked={false}
- className="disabled"
- disabled={true}
- id="mytag"
- onCheck={[MockFunction]}
- thirdState={false}
- >
- <span
- className="little-spacer-left"
- >
- mytag
- </span>
- </Checkbox>
-</li>
-`;
-
-exports[`should render standard element: selected element 1`] = `
-<li
- onFocus={[Function]}
- onMouseOver={[Function]}
->
- <Checkbox
- checked={true}
- className=""
- id="mytag"
- onCheck={[MockFunction]}
- thirdState={false}
- >
- <span
- className="little-spacer-left"
- >
- mytag
- </span>
- </Checkbox>
-</li>
-`;