aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2018-02-22 12:08:16 +0100
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2018-02-23 16:34:13 +0100
commit5b3eaeebc6e69dc03d794cc0febcacb48408cf10 (patch)
tree05912182ccdf41d7c1d2ddf738c106988db52849 /server/sonar-web
parent1ecbb0ef85da06d61cfda9f19568f3311f795d8e (diff)
downloadsonarqube-5b3eaeebc6e69dc03d794cc0febcacb48408cf10.tar.gz
sonarqube-5b3eaeebc6e69dc03d794cc0febcacb48408cf10.zip
SONAR-10207 Show a loading spinner in tags selector
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/api/issues.ts5
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsTagsPopup.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.tsx24
-rw-r--r--server/sonar-web/src/main/js/components/common/MultiSelect.tsx39
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/components/controls/SearchBox.css6
-rw-r--r--server/sonar-web/src/main/js/components/controls/SearchBox.tsx10
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SearchBox-test.tsx.snap11
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueTags.js1
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTags-test.js.snap2
-rw-r--r--server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.tsx (renamed from server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.js)62
-rw-r--r--server/sonar-web/src/main/js/components/issue/popups/__tests__/SetIssueTagsPopup-test.tsx (renamed from server/sonar-web/src/main/js/components/issue/popups/__tests__/SetIssueTagsPopup-test.js)6
-rw-r--r--server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/SetIssueTagsPopup-test.tsx.snap (renamed from server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/SetIssueTagsPopup-test.js.snap)7
-rw-r--r--server/sonar-web/src/main/js/components/tags/TagsSelector.tsx16
-rw-r--r--server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.tsx12
16 files changed, 131 insertions, 87 deletions
diff --git a/server/sonar-web/src/main/js/api/issues.ts b/server/sonar-web/src/main/js/api/issues.ts
index 9830e627e54..f5ec6453bcc 100644
--- a/server/sonar-web/src/main/js/api/issues.ts
+++ b/server/sonar-web/src/main/js/api/issues.ts
@@ -20,6 +20,7 @@
import { FacetValue } from '../app/types';
import { getJSON, post, postJSON, RequestData } from '../helpers/request';
import { RawIssue } from '../helpers/issues';
+import throwGlobalError from '../app/utils/throwGlobalError';
export interface IssueResponse {
components?: Array<{}>;
@@ -117,7 +118,9 @@ export function getIssuesCount(query: RequestData): Promise<any> {
export function searchIssueTags(
data: { organization?: string; ps?: number; q?: string } = { ps: 100 }
): Promise<string[]> {
- return getJSON('/api/issues/tags', data).then(r => r.tags);
+ return getJSON('/api/issues/tags', data)
+ .then(r => r.tags)
+ .catch(throwGlobalError);
}
export function getIssueChangelog(issue: string): Promise<any> {
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsTagsPopup.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsTagsPopup.tsx
index d6064752070..ddd9a5d54ed 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsTagsPopup.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsTagsPopup.tsx
@@ -32,7 +32,7 @@ interface Props {
}
interface State {
- searchResult: any[];
+ searchResult: string[];
}
const LIST_SIZE = 10;
@@ -43,7 +43,6 @@ export default class RuleDetailsTagsPopup extends React.PureComponent<Props, Sta
componentDidMount() {
this.mounted = true;
- this.onSearch('');
}
componentWillUnmount() {
@@ -51,7 +50,7 @@ export default class RuleDetailsTagsPopup extends React.PureComponent<Props, Sta
}
onSearch = (query: string) => {
- getRuleTags({
+ return getRuleTags({
q: query,
ps: Math.min(this.props.tags.length + LIST_SIZE, 100),
organization: this.props.organization
@@ -77,13 +76,13 @@ export default class RuleDetailsTagsPopup extends React.PureComponent<Props, Sta
render() {
return (
<TagsSelector
- position={this.props.popupPosition || {}}
- tags={this.state.searchResult}
- selectedTags={this.props.tags}
listSize={LIST_SIZE}
onSearch={this.onSearch}
onSelect={this.onSelect}
onUnselect={this.onUnselect}
+ position={this.props.popupPosition || {}}
+ selectedTags={this.props.tags}
+ tags={this.state.searchResult}
/>
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.tsx
index 2e2bb774a80..2fdd9fe1f6e 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.tsx
@@ -37,17 +37,29 @@ interface State {
const LIST_SIZE = 10;
export default class MetaTagsSelector extends React.PureComponent<Props, State> {
+ mounted = false;
state: State = { searchResult: [] };
componentDidMount() {
- this.onSearch('');
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
}
onSearch = (query: string) => {
- searchProjectTags({
+ return searchProjectTags({
q: query,
ps: Math.min(this.props.selectedTags.length - 1 + LIST_SIZE, 100)
- }).then(result => this.setState({ searchResult: result.tags }), () => {});
+ }).then(
+ ({ tags }) => {
+ if (this.mounted) {
+ this.setState({ searchResult: tags });
+ }
+ },
+ () => {}
+ );
};
onSelect = (tag: string) => {
@@ -61,13 +73,13 @@ export default class MetaTagsSelector extends React.PureComponent<Props, State>
render() {
return (
<TagsSelector
- position={this.props.position}
- tags={this.state.searchResult}
- selectedTags={this.props.selectedTags}
listSize={LIST_SIZE}
onSearch={this.onSearch}
onSelect={this.onSelect}
onUnselect={this.onUnselect}
+ position={this.props.position}
+ selectedTags={this.props.selectedTags}
+ tags={this.state.searchResult}
/>
);
}
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 bc235e5a1af..91a68f25fe8 100644
--- a/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
+++ b/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
@@ -23,21 +23,22 @@ import MultiSelectOption from './MultiSelectOption';
import SearchBox from '../controls/SearchBox';
interface Props {
- selectedElements: Array<string>;
- elements: Array<string>;
+ elements: string[];
listSize?: number;
- onSearch: (query: string) => void;
+ onSearch: (query: string) => Promise<void>;
onSelect: (item: string) => void;
onUnselect: (item: string) => void;
- validateSearchInput?: (value: string) => string;
placeholder: string;
+ selectedElements: string[];
+ validateSearchInput?: (value: string) => string;
}
interface State {
- query: string;
- selectedElements: Array<string>;
- unselectedElements: Array<string>;
activeIdx: number;
+ loading: boolean;
+ query: string;
+ selectedElements: string[];
+ unselectedElements: string[];
}
interface DefaultProps {
@@ -50,6 +51,7 @@ type PropsWithDefault = Props & DefaultProps;
export default class MultiSelect extends React.PureComponent<Props, State> {
container?: HTMLDivElement | null;
searchInput?: HTMLInputElement | null;
+ mounted = false;
static defaultProps: DefaultProps = {
listSize: 10,
@@ -59,14 +61,17 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
+ activeIdx: 0,
+ loading: true,
query: '',
selectedElements: [],
- unselectedElements: [],
- activeIdx: 0
+ unselectedElements: []
};
}
componentDidMount() {
+ this.mounted = true;
+ this.onSearchQuery('');
this.updateSelectedElements(this.props);
this.updateUnselectedElements(this.props as PropsWithDefault);
if (this.container) {
@@ -96,6 +101,7 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
}
componentWillUnmount() {
+ this.mounted = false;
if (this.container) {
this.container.removeEventListener('keydown', this.handleKeyboard);
}
@@ -122,14 +128,14 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
handleKeyboard = (evt: KeyboardEvent) => {
switch (evt.keyCode) {
case 40: // down
- this.setState(this.selectNextElement);
evt.stopPropagation();
evt.preventDefault();
+ this.setState(this.selectNextElement);
break;
case 38: // up
- this.setState(this.selectPreviousElement);
evt.stopPropagation();
evt.preventDefault();
+ this.setState(this.selectPreviousElement);
break;
case 37: // left
case 39: // right
@@ -144,8 +150,8 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
};
onSearchQuery = (query: string) => {
- this.setState({ query, activeIdx: 0 });
- this.props.onSearch(query);
+ this.setState({ activeIdx: 0, loading: true, query });
+ this.props.onSearch(query).then(this.stopLoading, this.stopLoading);
};
onSelectItem = (item: string) => {
@@ -218,6 +224,12 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
}
};
+ stopLoading = () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ };
+
toggleSelect = (item: string) => {
if (this.props.selectedElements.indexOf(item) === -1) {
this.onSelectItem(item);
@@ -236,6 +248,7 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
<SearchBox
autoFocus={true}
className="little-spacer-top"
+ loading={this.state.loading}
onChange={this.handleSearchChange}
placeholder={this.props.placeholder}
value={query}
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 13bb1651866..097fd543c36 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
@@ -24,7 +24,7 @@ import MultiSelect from '../MultiSelect';
const props = {
selectedElements: ['bar'],
elements: [],
- onSearch: () => {},
+ onSearch: () => Promise.resolve(),
onSelect: () => {},
onUnselect: () => {},
placeholder: ''
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
index 15c17fc74ad..69b2384f396 100644
--- 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
@@ -10,6 +10,7 @@ exports[`should render multiselect with selected elements 1`] = `
<SearchBox
autoFocus={true}
className="little-spacer-top"
+ loading={true}
onChange={[Function]}
placeholder=""
value=""
@@ -40,6 +41,7 @@ exports[`should render multiselect with selected elements 2`] = `
<SearchBox
autoFocus={true}
className="little-spacer-top"
+ loading={true}
onChange={[Function]}
placeholder=""
value=""
@@ -84,6 +86,7 @@ exports[`should render multiselect with selected elements 3`] = `
<SearchBox
autoFocus={true}
className="little-spacer-top"
+ loading={true}
onChange={[Function]}
placeholder=""
value=""
@@ -128,6 +131,7 @@ exports[`should render multiselect with selected elements 4`] = `
<SearchBox
autoFocus={true}
className="little-spacer-top"
+ loading={true}
onChange={[Function]}
placeholder=""
value="test"
diff --git a/server/sonar-web/src/main/js/components/controls/SearchBox.css b/server/sonar-web/src/main/js/components/controls/SearchBox.css
index daecb042ac0..7c5d32ecae4 100644
--- a/server/sonar-web/src/main/js/components/controls/SearchBox.css
+++ b/server/sonar-web/src/main/js/components/controls/SearchBox.css
@@ -85,6 +85,12 @@
transition: color 0.3s ease;
}
+.search-box > .spinner {
+ position: absolute;
+ top: 4px;
+ left: 5px;
+}
+
.search-box-clear {
position: absolute;
top: 4px;
diff --git a/server/sonar-web/src/main/js/components/controls/SearchBox.tsx b/server/sonar-web/src/main/js/components/controls/SearchBox.tsx
index b5b29941883..84329946fed 100644
--- a/server/sonar-web/src/main/js/components/controls/SearchBox.tsx
+++ b/server/sonar-web/src/main/js/components/controls/SearchBox.tsx
@@ -20,8 +20,9 @@
import * as React from 'react';
import * as classNames from 'classnames';
import { debounce, Cancelable } from 'lodash';
-import SearchIcon from '../icons-components/SearchIcon';
import ClearIcon from '../icons-components/ClearIcon';
+import SearchIcon from '../icons-components/SearchIcon';
+import DeferredSpinner from '../common/DeferredSpinner';
import { ButtonIcon } from '../ui/buttons';
import * as theme from '../../app/theme';
import { translateWithParameters } from '../../helpers/l10n';
@@ -32,6 +33,7 @@ interface Props {
className?: string;
innerRef?: (node: HTMLInputElement | null) => void;
id?: string;
+ loading?: boolean;
minLength?: number;
onChange: (value: string) => void;
onClick?: React.MouseEventHandler<HTMLInputElement>;
@@ -119,7 +121,7 @@ export default class SearchBox extends React.PureComponent<Props, State> {
};
render() {
- const { minLength } = this.props;
+ const { loading, minLength } = this.props;
const { value } = this.state;
const inputClassName = classNames('search-box-input', {
@@ -145,7 +147,9 @@ export default class SearchBox extends React.PureComponent<Props, State> {
value={value}
/>
- <SearchIcon className="search-box-magnifier" />
+ <DeferredSpinner loading={loading !== undefined ? loading : false}>
+ <SearchIcon className="search-box-magnifier" />
+ </DeferredSpinner>
{value && (
<ButtonIcon
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SearchBox-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SearchBox-test.tsx.snap
index d69e12de1e3..25b226be5a2 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SearchBox-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SearchBox-test.tsx.snap
@@ -14,9 +14,14 @@ exports[`renders 1`] = `
type="search"
value="foo"
/>
- <SearchIcon
- className="search-box-magnifier"
- />
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ >
+ <SearchIcon
+ className="search-box-magnifier"
+ />
+ </DeferredSpinner>
<ButtonIcon
className="button-tiny search-box-clear"
color="#999"
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTags.js b/server/sonar-web/src/main/js/components/issue/components/IssueTags.js
index e4ba9ab9968..e40a85b71af 100644
--- a/server/sonar-web/src/main/js/components/issue/components/IssueTags.js
+++ b/server/sonar-web/src/main/js/components/issue/components/IssueTags.js
@@ -68,7 +68,6 @@ export default class IssueTags extends React.PureComponent {
togglePopup={this.toggleSetTags}
popup={
<SetIssueTagsPopup
- onFail={this.props.onFail}
organization={issue.projectOrganization}
selectedTags={issue.tags}
setTags={this.setTags}
diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTags-test.js.snap b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTags-test.js.snap
index 178f8b75e19..fa30aff7c20 100644
--- a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTags-test.js.snap
+++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTags-test.js.snap
@@ -23,7 +23,6 @@ exports[`should open the popup when the button is clicked 2`] = `
isOpen={true}
popup={
<SetIssueTagsPopup
- onFail={[MockFunction]}
organization="foo"
selectedTags={
Array [
@@ -59,7 +58,6 @@ exports[`should render with the action 1`] = `
isOpen={false}
popup={
<SetIssueTagsPopup
- onFail={[MockFunction]}
organization="foo"
selectedTags={
Array [
diff --git a/server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.js b/server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.tsx
index c334412d5c0..7aa3bebba62 100644
--- a/server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.js
+++ b/server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.tsx
@@ -17,74 +17,70 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-//@flow
-import React from 'react';
+import * as React from 'react';
import { without } from 'lodash';
+import { BubblePopupPosition } from '../../../components/common/BubblePopup';
import TagsSelector from '../../../components/tags/TagsSelector';
import { searchIssueTags } from '../../../api/issues';
-/*::
-type Props = {
- popupPosition?: {},
- onFail: Error => void,
- organization: string,
- selectedTags: Array<string>,
- setTags: (Array<string>) => void
-};
-*/
+interface Props {
+ popupPosition: BubblePopupPosition;
+ organization: string;
+ selectedTags: string[];
+ setTags: (tags: string[]) => void;
+}
-/*::
-type State = {
- searchResult: Array<string>
-};
-*/
+interface State {
+ searchResult: string[];
+}
const LIST_SIZE = 10;
-export default class SetIssueTagsPopup extends React.PureComponent {
- /*:: mounted: boolean; */
- /*:: props: Props; */
- state /*: State */ = { searchResult: [] };
+export default class SetIssueTagsPopup extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = { searchResult: [] };
componentDidMount() {
this.mounted = true;
- this.onSearch('');
}
componentWillUnmount() {
this.mounted = false;
}
- onSearch = (query /*: string */) => {
- searchIssueTags({
+ onSearch = (query: string) => {
+ return searchIssueTags({
q: query,
ps: Math.min(this.props.selectedTags.length - 1 + LIST_SIZE, 100),
organization: this.props.organization
- }).then((tags /*: Array<string> */) => {
- if (this.mounted) {
- this.setState({ searchResult: tags });
- }
- }, this.props.onFail);
+ }).then(
+ (tags: string[]) => {
+ if (this.mounted) {
+ this.setState({ searchResult: tags });
+ }
+ },
+ () => {}
+ );
};
- onSelect = (tag /*: string */) => {
+ onSelect = (tag: string) => {
this.props.setTags([...this.props.selectedTags, tag]);
};
- onUnselect = (tag /*: string */) => {
+ onUnselect = (tag: string) => {
this.props.setTags(without(this.props.selectedTags, tag));
};
render() {
return (
<TagsSelector
- position={this.props.popupPosition}
- tags={this.state.searchResult}
- selectedTags={this.props.selectedTags}
listSize={LIST_SIZE}
onSearch={this.onSearch}
onSelect={this.onSelect}
onUnselect={this.onUnselect}
+ position={this.props.popupPosition}
+ selectedTags={this.props.selectedTags}
+ tags={this.state.searchResult}
/>
);
}
diff --git a/server/sonar-web/src/main/js/components/issue/popups/__tests__/SetIssueTagsPopup-test.js b/server/sonar-web/src/main/js/components/issue/popups/__tests__/SetIssueTagsPopup-test.tsx
index d2cdf422054..f66e329ec87 100644
--- a/server/sonar-web/src/main/js/components/issue/popups/__tests__/SetIssueTagsPopup-test.js
+++ b/server/sonar-web/src/main/js/components/issue/popups/__tests__/SetIssueTagsPopup-test.tsx
@@ -17,16 +17,16 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import * as React from 'react';
import { shallow } from 'enzyme';
-import React from 'react';
import SetIssueTagsPopup from '../SetIssueTagsPopup';
it('should render tags popup correctly', () => {
const element = shallow(
<SetIssueTagsPopup
- onFail={jest.fn()}
organization="foo"
- selectedTags="mytag"
+ popupPosition={{}}
+ selectedTags={['mytag']}
setTags={jest.fn()}
/>
);
diff --git a/server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/SetIssueTagsPopup-test.js.snap b/server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/SetIssueTagsPopup-test.tsx.snap
index 3eee8429326..36d73b1a4cf 100644
--- a/server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/SetIssueTagsPopup-test.js.snap
+++ b/server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/SetIssueTagsPopup-test.tsx.snap
@@ -6,7 +6,12 @@ exports[`should render tags popup correctly 1`] = `
onSearch={[Function]}
onSelect={[Function]}
onUnselect={[Function]}
- selectedTags="mytag"
+ position={Object {}}
+ selectedTags={
+ Array [
+ "mytag",
+ ]
+ }
tags={
Array [
"mytag",
diff --git a/server/sonar-web/src/main/js/components/tags/TagsSelector.tsx b/server/sonar-web/src/main/js/components/tags/TagsSelector.tsx
index 82d42c93710..120f7cdeef5 100644
--- a/server/sonar-web/src/main/js/components/tags/TagsSelector.tsx
+++ b/server/sonar-web/src/main/js/components/tags/TagsSelector.tsx
@@ -24,29 +24,29 @@ import { translate } from '../../helpers/l10n';
import './TagsList.css';
interface Props {
- position: BubblePopupPosition;
- tags: string[];
- selectedTags: string[];
listSize: number;
- onSearch: (query: string) => void;
+ onSearch: (query: string) => Promise<void>;
onSelect: (item: string) => void;
onUnselect: (item: string) => void;
+ position: BubblePopupPosition;
+ selectedTags: string[];
+ tags: string[];
}
export default function TagsSelector(props: Props) {
return (
<BubblePopup
- position={props.position}
- customClass="bubble-popup-bottom-right bubble-popup-menu abs-width-300">
+ customClass="bubble-popup-bottom-right bubble-popup-menu abs-width-300"
+ position={props.position}>
<MultiSelect
elements={props.tags}
- selectedElements={props.selectedTags}
listSize={props.listSize}
onSearch={props.onSearch}
onSelect={props.onSelect}
onUnselect={props.onUnselect}
- validateSearchInput={validateTag}
placeholder={translate('search.search_for_tags')}
+ selectedElements={props.selectedTags}
+ validateSearchInput={validateTag}
/>
</BubblePopup>
);
diff --git a/server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.tsx b/server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.tsx
index 1b5169a2940..f2dd87eda02 100644
--- a/server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.tsx
+++ b/server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.tsx
@@ -22,13 +22,13 @@ import { shallow } from 'enzyme';
import TagsSelector, { validateTag } from '../TagsSelector';
const props = {
- position: { right: 0, top: 0 },
listSize: 10,
- tags: ['foo', 'bar', 'baz'],
- selectedTags: ['bar'],
- onSearch: () => {},
+ onSearch: () => Promise.resolve(),
onSelect: () => {},
- onUnselect: () => {}
+ onUnselect: () => {},
+ position: { right: 0, top: 0 },
+ selectedTags: ['bar'],
+ tags: ['foo', 'bar', 'baz']
};
it('should render with selected tags', () => {
@@ -37,7 +37,7 @@ it('should render with selected tags', () => {
});
it('should render without tags at all', () => {
- expect(shallow(<TagsSelector {...props} tags={[]} selectedTags={[]} />)).toMatchSnapshot();
+ expect(shallow(<TagsSelector {...props} selectedTags={[]} tags={[]} />)).toMatchSnapshot();
});
it('should validate tags correctly', () => {