From 6ddad7c6256d38730615495b0bf8e189fba147cc Mon Sep 17 00:00:00 2001 From: philippe-perrin-sonarsource Date: Wed, 17 Jul 2019 11:52:13 +0200 Subject: [PATCH] Moved SelectList to sonar-ui-common --- server/sonar-vsts/package.json | 2 +- server/sonar-vsts/yarn.lock | 8 +- server/sonar-web/package.json | 2 +- .../components/extensions/exposeLibraries.ts | 8 +- .../groups/components/EditMembersModal.tsx | 6 +- .../__tests__/EditMembersModal-test.tsx | 6 +- .../quality-gates/components/Projects.tsx | 6 +- .../components/__tests__/Projects-test.tsx | 6 +- .../details/ChangeProjectsForm.tsx | 6 +- .../__tests__/ChangeProjectsForm-test.tsx | 6 +- .../js/apps/users/components/GroupsForm.tsx | 6 +- .../components/__tests__/GroupsForm-test.tsx | 6 +- .../js/components/SelectList/SelectList.tsx | 184 ------ .../SelectList/SelectListListContainer.tsx | 129 ---- .../SelectList/SelectListListElement.tsx | 76 --- .../SelectList/__tests__/SelectList-test.tsx | 148 ----- .../SelectListListContainer-test.tsx | 39 -- .../__tests__/SelectListListElement-test.tsx | 47 -- .../__snapshots__/SelectList-test.tsx.snap | 558 ------------------ .../SelectListListContainer-test.tsx.snap | 60 -- .../SelectListListElement-test.tsx.snap | 41 -- .../main/js/components/SelectList/styles.css | 62 -- server/sonar-web/yarn.lock | 8 +- 23 files changed, 40 insertions(+), 1380 deletions(-) delete mode 100644 server/sonar-web/src/main/js/components/SelectList/SelectList.tsx delete mode 100644 server/sonar-web/src/main/js/components/SelectList/SelectListListContainer.tsx delete mode 100644 server/sonar-web/src/main/js/components/SelectList/SelectListListElement.tsx delete mode 100644 server/sonar-web/src/main/js/components/SelectList/__tests__/SelectList-test.tsx delete mode 100644 server/sonar-web/src/main/js/components/SelectList/__tests__/SelectListListContainer-test.tsx delete mode 100644 server/sonar-web/src/main/js/components/SelectList/__tests__/SelectListListElement-test.tsx delete mode 100644 server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectList-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListContainer-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListElement-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/components/SelectList/styles.css diff --git a/server/sonar-vsts/package.json b/server/sonar-vsts/package.json index bbeecefabc0..d354a4e921c 100644 --- a/server/sonar-vsts/package.json +++ b/server/sonar-vsts/package.json @@ -12,7 +12,7 @@ "react": "16.8.6", "react-dom": "16.8.6", "regenerator-runtime": "0.13.2", - "sonar-ui-common": "0.0.13", + "sonar-ui-common": "0.0.14", "whatwg-fetch": "2.0.4" }, "devDependencies": { diff --git a/server/sonar-vsts/yarn.lock b/server/sonar-vsts/yarn.lock index cdb38f45a8e..528ea02c2fd 100644 --- a/server/sonar-vsts/yarn.lock +++ b/server/sonar-vsts/yarn.lock @@ -8416,10 +8416,10 @@ sockjs@0.3.19: faye-websocket "^0.10.0" uuid "^3.0.1" -sonar-ui-common@0.0.13: - version "0.0.13" - resolved "https://repox.jfrog.io/repox/api/npm/npm/sonar-ui-common/-/sonar-ui-common-0.0.13.tgz#b01255f32d7863e529117bfe715890edfcdb8c97" - integrity sha1-sBJV8y14Y+UpEXv+cViQ7fzbjJc= +sonar-ui-common@0.0.14: + version "0.0.14" + resolved "https://repox.jfrog.io/repox/api/npm/npm/sonar-ui-common/-/sonar-ui-common-0.0.14.tgz#56faa2ba62503c206e9894f55f36bd9ff4934257" + integrity sha1-VvqiumJQPCBumJT1Xza9n/STQlc= dependencies: "@types/react-select" "1.2.6" classnames "2.2.6" diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index 5c55d499fec..e5514be444a 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -35,7 +35,7 @@ "regenerator-runtime": "0.13.2", "remark-custom-blocks": "2.3.0", "remark-slug": "5.1.0", - "sonar-ui-common": "0.0.13", + "sonar-ui-common": "0.0.14", "unist-util-visit": "1.4.0", "valid-url": "1.0.9", "whatwg-fetch": "2.0.4" diff --git a/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts b/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts index 991d3375ce3..288a9ca2001 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts +++ b/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts @@ -63,6 +63,7 @@ import ActionsDropdown, { import RadioToggle from 'sonar-ui-common/components/controls/RadioToggle'; import ReloadButton from 'sonar-ui-common/components/controls/ReloadButton'; import Select from 'sonar-ui-common/components/controls/Select'; +import SelectList from 'sonar-ui-common/components/controls/SelectList'; import SearchSelect from 'sonar-ui-common/components/controls/SearchSelect'; import throwGlobalError from '../../utils/throwGlobalError'; import addGlobalSuccessMessage from '../../utils/addGlobalSuccessMessage'; @@ -88,7 +89,6 @@ import DateTimeFormatter from '../../../components/intl/DateTimeFormatter'; import Favorite from '../../../components/controls/Favorite'; import HomePageSelect from '../../../components/controls/HomePageSelect'; import BranchIcon from '../../../components/icons-components/BranchIcon'; -import SelectList from '../../../components/SelectList/SelectList'; import CoverageRating from '../../../components/ui/CoverageRating'; import NotFound from '../../../app/components/NotFound'; import A11ySkipTarget from '../a11y/A11ySkipTarget'; @@ -112,7 +112,11 @@ const exposeLibraries = () => { getRulesUrl }; global.SonarMeasures = { ...measures, formatMeasure }; - global.SonarRequest = { ...request, throwGlobalError, addGlobalSuccessMessage }; + global.SonarRequest = { + ...request, + throwGlobalError, + addGlobalSuccessMessage + }; global.SonarComponents = { A11ySkipTarget, ActionsDropdown, diff --git a/server/sonar-web/src/main/js/apps/groups/components/EditMembersModal.tsx b/server/sonar-web/src/main/js/apps/groups/components/EditMembersModal.tsx index 5bfeb5e20bf..71ef68106b4 100644 --- a/server/sonar-web/src/main/js/apps/groups/components/EditMembersModal.tsx +++ b/server/sonar-web/src/main/js/apps/groups/components/EditMembersModal.tsx @@ -23,9 +23,9 @@ import { translate } from 'sonar-ui-common/helpers/l10n'; import { ResetButtonLink } from 'sonar-ui-common/components/controls/buttons'; import Modal from 'sonar-ui-common/components/controls/Modal'; import SelectList, { - Filter, + SelectListFilter, SelectListSearchParams -} from '../../../components/SelectList/SelectList'; +} from 'sonar-ui-common/components/controls/SelectList'; import { addUserToGroup, getUsersInGroup, removeUserFromGroup } from '../../../api/user_groups'; interface Props { @@ -154,7 +154,7 @@ export default class EditMembersModal extends React.PureComponent needToReload={ this.state.needToReload && this.state.lastSearchParams && - this.state.lastSearchParams.filter !== Filter.All + this.state.lastSearchParams.filter !== SelectListFilter.All } onSearch={this.fetchUsers} onSelect={this.handleSelect} diff --git a/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditMembersModal-test.tsx b/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditMembersModal-test.tsx index ed9e065877c..24e6f464d85 100644 --- a/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditMembersModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditMembersModal-test.tsx @@ -19,9 +19,9 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; +import SelectList, { SelectListFilter } from 'sonar-ui-common/components/controls/SelectList'; import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; import EditMembersModal from '../EditMembersModal'; -import SelectList, { Filter } from '../../../../components/SelectList/SelectList'; import { getUsersInGroup, addUserToGroup, removeUserFromGroup } from '../../../../api/user_groups'; const organization = 'orga'; @@ -53,7 +53,7 @@ it('should render modal properly', async () => { .props() .onSearch({ query: '', - filter: Filter.Selected, + filter: SelectListFilter.Selected, page: 1, pageSize: 100 }); @@ -72,7 +72,7 @@ it('should render modal properly', async () => { p: 1, ps: 100, q: undefined, - selected: Filter.Selected + selected: SelectListFilter.Selected }) ); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx index a64bf9ece87..05bb7d8e7d7 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx @@ -21,9 +21,9 @@ import * as React from 'react'; import { find, without } from 'lodash'; import { translate } from 'sonar-ui-common/helpers/l10n'; import SelectList, { - Filter, + SelectListFilter, SelectListSearchParams -} from '../../../components/SelectList/SelectList'; +} from 'sonar-ui-common/components/controls/SelectList'; import { associateGateWithProject, dissociateGateWithProject, @@ -153,7 +153,7 @@ export default class Projects extends React.PureComponent { needToReload={ this.state.needToReload && this.state.lastSearchParams && - this.state.lastSearchParams.filter !== Filter.All + this.state.lastSearchParams.filter !== SelectListFilter.All } onSearch={this.fetchProjects} onSelect={this.handleSelect} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx index 572808e4466..fa12351ea98 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx @@ -20,8 +20,8 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; +import SelectList, { SelectListFilter } from 'sonar-ui-common/components/controls/SelectList'; import Projects from '../Projects'; -import SelectList, { Filter } from '../../../../components/SelectList/SelectList'; import { mockQualityGate } from '../../../../helpers/testMocks'; import { searchProjects, @@ -56,7 +56,7 @@ it('should render correctly', async () => { .props() .onSearch({ query: '', - filter: Filter.Selected, + filter: SelectListFilter.Selected, page: 1, pageSize: 100 }); @@ -74,7 +74,7 @@ it('should render correctly', async () => { page: 1, pageSize: 100, query: undefined, - selected: Filter.Selected + selected: SelectListFilter.Selected }) ); expect(wrapper.state().needToReload).toBe(false); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeProjectsForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeProjectsForm.tsx index 5119c0a0b0d..d7ec7959131 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeProjectsForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeProjectsForm.tsx @@ -22,9 +22,9 @@ import { find, without } from 'lodash'; import { translate } from 'sonar-ui-common/helpers/l10n'; import Modal from 'sonar-ui-common/components/controls/Modal'; import SelectList, { - Filter, + SelectListFilter, SelectListSearchParams -} from '../../../components/SelectList/SelectList'; +} from 'sonar-ui-common/components/controls/SelectList'; import { Profile } from '../types'; import { associateProject, @@ -162,7 +162,7 @@ export default class ChangeProjectsForm extends React.PureComponent { .props() .onSearch({ query: '', - filter: Filter.Selected, + filter: SelectListFilter.Selected, page: 1, pageSize: 100 }); @@ -73,7 +73,7 @@ it('should render correctly', async () => { p: 1, ps: 100, q: undefined, - selected: Filter.Selected + selected: SelectListFilter.Selected }) ); expect(wrapper.state().needToReload).toBe(false); diff --git a/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx b/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx index 697c533e387..3de11517160 100644 --- a/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx @@ -22,9 +22,9 @@ import { find, without } from 'lodash'; import { translate } from 'sonar-ui-common/helpers/l10n'; import Modal from 'sonar-ui-common/components/controls/Modal'; import SelectList, { - Filter, + SelectListFilter, SelectListSearchParams -} from '../../../components/SelectList/SelectList'; +} from 'sonar-ui-common/components/controls/SelectList'; import { getUserGroups, UserGroup } from '../../../api/users'; import { addUserToGroup, removeUserFromGroup } from '../../../api/user_groups'; @@ -162,7 +162,7 @@ export default class GroupsForm extends React.PureComponent { needToReload={ this.state.needToReload && this.state.lastSearchParams && - this.state.lastSearchParams.filter !== Filter.All + this.state.lastSearchParams.filter !== SelectListFilter.All } onSearch={this.fetchUsers} onSelect={this.handleSelect} diff --git a/server/sonar-web/src/main/js/apps/users/components/__tests__/GroupsForm-test.tsx b/server/sonar-web/src/main/js/apps/users/components/__tests__/GroupsForm-test.tsx index e6cbf910c64..61c721b4ea8 100644 --- a/server/sonar-web/src/main/js/apps/users/components/__tests__/GroupsForm-test.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/__tests__/GroupsForm-test.tsx @@ -19,9 +19,9 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; +import SelectList, { SelectListFilter } from 'sonar-ui-common/components/controls/SelectList'; import { waitAndUpdate, click } from 'sonar-ui-common/helpers/testUtils'; import GroupsForm from '../GroupsForm'; -import SelectList, { Filter } from '../../../../components/SelectList/SelectList'; import { getUserGroups } from '../../../../api/users'; import { addUserToGroup, removeUserFromGroup } from '../../../../api/user_groups'; import { mockUser } from '../../../../helpers/testMocks'; @@ -70,7 +70,7 @@ it('should render correctly', async () => { .props() .onSearch({ query: '', - filter: Filter.Selected, + filter: SelectListFilter.Selected, page: 1, pageSize: 100 }); @@ -88,7 +88,7 @@ it('should render correctly', async () => { p: 1, ps: 100, q: undefined, - selected: Filter.Selected + selected: SelectListFilter.Selected }) ); expect(wrapper.state().needToReload).toBe(false); diff --git a/server/sonar-web/src/main/js/components/SelectList/SelectList.tsx b/server/sonar-web/src/main/js/components/SelectList/SelectList.tsx deleted file mode 100644 index 7cafc36df69..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/SelectList.tsx +++ /dev/null @@ -1,184 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 * as React from 'react'; -import { translate } from 'sonar-ui-common/helpers/l10n'; -import SearchBox from 'sonar-ui-common/components/controls/SearchBox'; -import RadioToggle from 'sonar-ui-common/components/controls/RadioToggle'; -import ListFooter from 'sonar-ui-common/components/controls/ListFooter'; -import SelectListListContainer from './SelectListListContainer'; -import './styles.css'; - -export enum Filter { - All = 'all', - Selected = 'selected', - Unselected = 'deselected' -} - -interface Props { - allowBulkSelection?: boolean; - elements: string[]; - elementsTotalCount?: number; - disabledElements?: string[]; - labelSelected?: string; - labelUnselected?: string; - labelAll?: string; - needToReload?: boolean; - onSearch: (searchParams: SelectListSearchParams) => Promise; - onSelect: (element: string) => Promise; - onUnselect: (element: string) => Promise; - pageSize?: number; - readOnly?: boolean; - renderElement: (element: string) => React.ReactNode; - selectedElements: string[]; - withPaging?: boolean; -} - -export interface SelectListSearchParams { - filter: Filter; - page?: number; - pageSize?: number; - query: string; -} - -interface State { - lastSearchParams: SelectListSearchParams; - loading: boolean; -} - -const DEFAULT_PAGE_SIZE = 100; - -export default class SelectList extends React.PureComponent { - mounted = false; - - constructor(props: Props) { - super(props); - - this.state = { - lastSearchParams: { - filter: Filter.Selected, - page: 1, - pageSize: props.pageSize ? props.pageSize : DEFAULT_PAGE_SIZE, - query: '' - }, - loading: false - }; - } - - componentDidMount() { - this.mounted = true; - this.search({}); - } - - componentWillUnmount() { - this.mounted = false; - } - - getFilter = () => - this.state.lastSearchParams.query === '' ? this.state.lastSearchParams.filter : Filter.All; - - search = (searchParams: Partial) => - this.setState( - prevState => ({ - loading: true, - lastSearchParams: { ...prevState.lastSearchParams, ...searchParams } - }), - () => - this.props - .onSearch({ - filter: this.getFilter(), - page: this.props.withPaging ? this.state.lastSearchParams.page : undefined, - pageSize: this.props.withPaging ? this.state.lastSearchParams.pageSize : undefined, - query: this.state.lastSearchParams.query - }) - .finally(() => { - if (this.mounted) { - this.setState({ loading: false }); - } - }) - ); - - changeFilter = (filter: Filter) => this.search({ filter, page: 1 }); - - handleQueryChange = (query: string) => this.search({ page: 1, query }); - - onLoadMore = () => - this.search({ - page: - this.state.lastSearchParams.page != null ? this.state.lastSearchParams.page + 1 : undefined - }); - - onReload = () => this.search({ page: 1 }); - - render() { - const { - labelSelected = translate('selected'), - labelUnselected = translate('unselected'), - labelAll = translate('all') - } = this.props; - const { filter } = this.state.lastSearchParams; - - const disabled = this.state.lastSearchParams.query !== ''; - - return ( -
-
- - -
- - {!!this.props.elementsTotalCount && ( - - )} -
- ); - } -} diff --git a/server/sonar-web/src/main/js/components/SelectList/SelectListListContainer.tsx b/server/sonar-web/src/main/js/components/SelectList/SelectListListContainer.tsx deleted file mode 100644 index 1398d3eb9f9..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/SelectListListContainer.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 * as React from 'react'; -import * as classNames from 'classnames'; -import { translate } from 'sonar-ui-common/helpers/l10n'; -import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; -import Checkbox from 'sonar-ui-common/components/controls/Checkbox'; -import { Filter } from './SelectList'; -import SelectListListElement from './SelectListListElement'; - -interface Props { - allowBulkSelection?: boolean; - elements: string[]; - disabledElements: string[]; - filter: Filter; - onSelect: (element: string) => Promise; - onUnselect: (element: string) => Promise; - readOnly?: boolean; - renderElement: (element: string) => React.ReactNode; - selectedElements: string[]; -} - -interface State { - loading: boolean; -} - -export default class SelectListListContainer extends React.PureComponent { - mounted = false; - state: State = { loading: false }; - - componentDidMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; - } - - stopLoading = () => { - if (this.mounted) { - this.setState({ loading: false }); - } - }; - - isDisabled = (element: string): boolean => { - return this.props.readOnly || this.props.disabledElements.includes(element); - }; - - isSelected = (element: string): boolean => { - return this.props.selectedElements.includes(element); - }; - - handleBulkChange = (checked: boolean) => { - this.setState({ loading: true }); - if (checked) { - Promise.all(this.props.elements.map(element => this.props.onSelect(element))) - .then(this.stopLoading) - .catch(this.stopLoading); - } else { - Promise.all(this.props.selectedElements.map(element => this.props.onUnselect(element))) - .then(this.stopLoading) - .catch(this.stopLoading); - } - }; - - renderBulkSelector() { - const { elements, readOnly, selectedElements } = this.props; - return ( - <> -
  • - 0} - disabled={this.state.loading || readOnly} - onCheck={this.handleBulkChange} - thirdState={selectedElements.length > 0 && elements.length !== selectedElements.length}> - - {translate('bulk_change')} - - - -
  • -
  • - - ); - } - - render() { - const { allowBulkSelection, elements, filter } = this.props; - - return ( -
    -
      - {allowBulkSelection && - elements.length > 0 && - filter === Filter.All && - this.renderBulkSelector()} - {elements.map(element => ( - - ))} -
    -
    - ); - } -} diff --git a/server/sonar-web/src/main/js/components/SelectList/SelectListListElement.tsx b/server/sonar-web/src/main/js/components/SelectList/SelectListListElement.tsx deleted file mode 100644 index 2991f8b4f28..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/SelectListListElement.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 * as React from 'react'; -import * as classNames from 'classnames'; -import Checkbox from 'sonar-ui-common/components/controls/Checkbox'; - -interface Props { - active?: boolean; - disabled?: boolean; - element: string; - onSelect: (element: string) => Promise; - onUnselect: (element: string) => Promise; - renderElement: (element: string) => React.ReactNode; - selected: boolean; -} - -interface State { - loading: boolean; -} - -export default class SelectListListElement extends React.PureComponent { - mounted = false; - state: State = { loading: false }; - - componentDidMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; - } - - stopLoading = () => { - if (this.mounted) { - this.setState({ loading: false }); - } - }; - - handleCheck = (checked: boolean) => { - this.setState({ loading: true }); - const request = checked ? this.props.onSelect : this.props.onUnselect; - request(this.props.element).then(this.stopLoading, this.stopLoading); - }; - - render() { - return ( -
  • - - {this.props.renderElement(this.props.element)} - -
  • - ); - } -} diff --git a/server/sonar-web/src/main/js/components/SelectList/__tests__/SelectList-test.tsx b/server/sonar-web/src/main/js/components/SelectList/__tests__/SelectList-test.tsx deleted file mode 100644 index 2d1ab5a0c99..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/__tests__/SelectList-test.tsx +++ /dev/null @@ -1,148 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 * as React from 'react'; -import { shallow } from 'enzyme'; -import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; -import SelectList, { Filter } from '../SelectList'; - -const elements = ['foo', 'bar', 'baz']; -const selectedElements = [elements[0]]; -const disabledElements = [elements[1]]; - -it('should display properly with basics features', async () => { - const wrapper = shallowRender(); - await waitAndUpdate(wrapper); - expect(wrapper.instance().mounted).toBe(true); - - expect(wrapper).toMatchSnapshot(); - - wrapper.instance().componentWillUnmount(); - expect(wrapper.instance().mounted).toBe(false); -}); - -it('should display properly with advanced features', async () => { - const wrapper = shallowRender({ - allowBulkSelection: true, - elementsTotalCount: 125, - pageSize: 10, - readOnly: true, - withPaging: true - }); - await waitAndUpdate(wrapper); - - expect(wrapper).toMatchSnapshot(); -}); - -it('should display a loader when searching', async () => { - const wrapper = shallowRender(); - await waitAndUpdate(wrapper); - expect(wrapper.state().loading).toBe(false); - - wrapper.instance().search({}); - expect(wrapper.state().loading).toBe(true); - expect(wrapper).toMatchSnapshot(); - - await waitAndUpdate(wrapper); - expect(wrapper.state().loading).toBe(false); -}); - -it('should cancel filter selection when search is active', async () => { - const spy = jest.fn().mockResolvedValue({}); - const wrapper = shallowRender({ onSearch: spy }); - wrapper.instance().changeFilter(Filter.Unselected); - await waitAndUpdate(wrapper); - - expect(spy).toHaveBeenCalledWith({ - query: '', - filter: Filter.Unselected, - page: undefined, - pageSize: undefined - }); - expect(wrapper).toMatchSnapshot(); - - const query = 'test'; - wrapper.instance().handleQueryChange(query); - expect(spy).toHaveBeenCalledWith({ - query, - filter: Filter.All, - page: undefined, - pageSize: undefined - }); - - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); - - wrapper.instance().handleQueryChange(''); - expect(spy).toHaveBeenCalledWith({ - query: '', - filter: Filter.Unselected, - page: undefined, - pageSize: undefined - }); - - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); -}); - -it('should display pagination element properly and call search method with correct parameters', () => { - const spy = jest.fn().mockResolvedValue({}); - const wrapper = shallowRender({ elementsTotalCount: 100, onSearch: spy, withPaging: true }); - expect(wrapper).toMatchSnapshot(); - expect(spy).toHaveBeenCalledWith({ - query: '', - filter: Filter.Selected, - page: 1, - pageSize: 100 - }); // Basic default call - - wrapper.instance().onLoadMore(); - expect(spy).toHaveBeenCalledWith({ - query: '', - filter: Filter.Selected, - page: 2, - pageSize: 100 - }); // Load more call - - wrapper.instance().onReload(); - expect(spy).toHaveBeenCalledWith({ - query: '', - filter: Filter.Selected, - page: 1, - pageSize: 100 - }); // Reload call - - wrapper.setProps({ needToReload: true }); - expect(wrapper).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - Promise.resolve())} - onSelect={jest.fn(() => Promise.resolve())} - onUnselect={jest.fn(() => Promise.resolve())} - renderElement={(foo: string) => foo} - selectedElements={selectedElements} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/SelectList/__tests__/SelectListListContainer-test.tsx b/server/sonar-web/src/main/js/components/SelectList/__tests__/SelectListListContainer-test.tsx deleted file mode 100644 index 496b9b49a9a..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/__tests__/SelectListListContainer-test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 * as React from 'react'; -import { shallow } from 'enzyme'; -import SelectListListContainer from '../SelectListListContainer'; -import { Filter } from '../SelectList'; - -it('should render correctly', () => { - const wrapper = shallow( - Promise.resolve())} - onUnselect={jest.fn(() => Promise.resolve())} - renderElement={(foo: string) => foo} - selectedElements={['foo']} - /> - ); - expect(wrapper).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/SelectList/__tests__/SelectListListElement-test.tsx b/server/sonar-web/src/main/js/components/SelectList/__tests__/SelectListListElement-test.tsx deleted file mode 100644 index 59569846591..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/__tests__/SelectListListElement-test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 * as React from 'react'; -import { shallow } from 'enzyme'; -import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; -import SelectListListElement from '../SelectListListElement'; - -const listElement = ( - Promise.resolve())} - onUnselect={jest.fn(() => Promise.resolve())} - renderElement={(foo: string) => foo} - selected={false} - /> -); - -it('should display a loader when checking', async () => { - const wrapper = shallow(listElement); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.state().loading).toBe(false); - - (wrapper.instance() as SelectListListElement).handleCheck(true); - expect(wrapper.state().loading).toBe(true); - expect(wrapper).toMatchSnapshot(); - - await waitAndUpdate(wrapper); - expect(wrapper.state().loading).toBe(false); -}); diff --git a/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectList-test.tsx.snap b/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectList-test.tsx.snap deleted file mode 100644 index f68fa52b1bf..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectList-test.tsx.snap +++ /dev/null @@ -1,558 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should cancel filter selection when search is active 1`] = ` -
    -
    - - -
    - -
    -`; - -exports[`should cancel filter selection when search is active 2`] = ` -
    -
    - - -
    - -
    -`; - -exports[`should cancel filter selection when search is active 3`] = ` -
    -
    - - -
    - -
    -`; - -exports[`should display a loader when searching 1`] = ` -
    -
    - - -
    - -
    -`; - -exports[`should display pagination element properly and call search method with correct parameters 1`] = ` -
    -
    - - -
    - - -
    -`; - -exports[`should display pagination element properly and call search method with correct parameters 2`] = ` -
    -
    - - -
    - - -
    -`; - -exports[`should display properly with advanced features 1`] = ` -
    -
    - - -
    - - -
    -`; - -exports[`should display properly with basics features 1`] = ` -
    -
    - - -
    - -
    -`; diff --git a/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListContainer-test.tsx.snap b/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListContainer-test.tsx.snap deleted file mode 100644 index 04b0553b72a..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListContainer-test.tsx.snap +++ /dev/null @@ -1,60 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -
    -
      -
    • - - - bulk_change - - - -
    • -
    • - - - -
    -
    -`; diff --git a/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListElement-test.tsx.snap b/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListElement-test.tsx.snap deleted file mode 100644 index e5d4ba3601f..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListElement-test.tsx.snap +++ /dev/null @@ -1,41 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display a loader when checking 1`] = ` -
  • - - - foo - - -
  • -`; - -exports[`should display a loader when checking 2`] = ` -
  • - - - foo - - -
  • -`; diff --git a/server/sonar-web/src/main/js/components/SelectList/styles.css b/server/sonar-web/src/main/js/components/SelectList/styles.css deleted file mode 100644 index 40401ec06dd..00000000000 --- a/server/sonar-web/src/main/js/components/SelectList/styles.css +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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. - */ -.select-list { -} - -.select-list-container { - min-width: 500px; - box-sizing: border-box; -} - -.select-list-control { - margin-bottom: 10px; - box-sizing: border-box; -} - -.select-list-list-container { - border: 1px solid #bfbfbf; - box-sizing: border-box; - height: 400px; - overflow: auto; -} - -.select-list-list-checkbox { - display: flex !important; - align-items: center; -} - -.select-list-list-checkbox i { - display: inline-block; - vertical-align: middle; - margin-right: 10px; -} - -.select-list-list-disabled { - cursor: not-allowed; -} - -.select-list-list-disabled > a { - pointer-events: none; -} - -.select-list-list-item { - display: inline-block; - vertical-align: middle; -} diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock index ede9c74a051..ec251b4e4e0 100644 --- a/server/sonar-web/yarn.lock +++ b/server/sonar-web/yarn.lock @@ -9263,10 +9263,10 @@ sockjs@0.3.19: faye-websocket "^0.10.0" uuid "^3.0.1" -sonar-ui-common@0.0.13: - version "0.0.13" - resolved "https://repox.jfrog.io/repox/api/npm/npm/sonar-ui-common/-/sonar-ui-common-0.0.13.tgz#b01255f32d7863e529117bfe715890edfcdb8c97" - integrity sha1-sBJV8y14Y+UpEXv+cViQ7fzbjJc= +sonar-ui-common@0.0.14: + version "0.0.14" + resolved "https://repox.jfrog.io/repox/api/npm/npm/sonar-ui-common/-/sonar-ui-common-0.0.14.tgz#56faa2ba62503c206e9894f55f36bd9ff4934257" + integrity sha1-VvqiumJQPCBumJT1Xza9n/STQlc= dependencies: "@types/react-select" "1.2.6" classnames "2.2.6" -- 2.39.5