From 0ab80061f017f5caf55a2d297d94cf7c2d6697e5 Mon Sep 17 00:00:00 2001 From: Mathieu Suen Date: Wed, 17 Nov 2021 17:06:55 +0100 Subject: [PATCH] SONAR-15655 Change Project perspective and sorting to use react-select@v5 --- server/sonar-web/package.json | 6 +- .../components/extensions/exposeLibraries.ts | 4 +- .../projectInformation/badges/BadgeParams.tsx | 6 +- .../__snapshots__/BadgeParams-test.tsx.snap | 6 +- .../application-console/ProjectBranchRow.tsx | 4 +- .../ProjectBranchRow-test.tsx.snap | 2 +- .../ReportFrequencyForm.tsx | 4 +- .../__tests__/ReportFrequencyForm-test.tsx | 4 +- .../ReportFrequencyForm-test.tsx.snap | 6 +- .../components/StatusFilter.tsx | 4 +- .../components/TypesFilter.tsx | 4 +- .../components/WorkersForm.tsx | 4 +- .../components/__tests__/WorkersForm-test.tsx | 5 +- .../__snapshots__/WorkersForm-test.tsx.snap | 4 +- .../components/ActivationFormModal.tsx | 6 +- .../components/BulkChangeModal.tsx | 4 +- .../components/CustomRuleFormModal.tsx | 8 +- .../ActivationFormModal-test.tsx.snap | 20 +- .../BulkChangeModal-test.tsx.snap | 2 +- .../CustomRuleFormModal-test.tsx.snap | 12 +- .../components/MeasureViewSelect.tsx | 4 +- .../MeasureViewSelect-test.tsx.snap | 6 +- .../issues/components/BulkChangeModal.tsx | 6 +- .../__tests__/BulkChangeModal-test.tsx | 4 +- .../project/components/ApplyTemplate.tsx | 4 +- .../__snapshots__/ApplyTemplate-test.tsx.snap | 2 +- .../components/ProjectActivityPageHeader.tsx | 4 +- .../ProjectActivityPageHeader-test.tsx.snap | 2 +- .../components/BranchAnalysisListRenderer.tsx | 4 +- .../BranchAnalysisListRenderer-test.tsx.snap | 6 +- .../ProjectQualityGateAppRenderer.tsx | 4 +- .../ProjectQualityGateAppRenderer-test.tsx | 6 +- ...rojectQualityGateAppRenderer-test.tsx.snap | 12 +- .../components/AddLanguageModal.tsx | 6 +- .../components/SetQualityProfileModal.tsx | 4 +- .../__tests__/AddLanguageModal-test.tsx | 6 +- .../__tests__/SetQualityProfileModal-test.tsx | 6 +- .../AddLanguageModal-test.tsx.snap | 4 +- .../SetQualityProfileModal-test.tsx.snap | 6 +- .../projects/components/PerspectiveSelect.tsx | 47 +++- .../components/PerspectiveSelectOption.tsx | 74 ------- .../components/ProjectsSortingSelect.tsx | 59 +++-- .../ProjectsSortingSelectOption.tsx | 70 ------ .../__tests__/PerspectiveSelect-test.tsx | 35 ++- .../PerspectiveSelectOption-test.tsx | 80 ------- .../__tests__/ProjectsSortingSelect-test.tsx | 78 +++---- .../ProjectsSortingSelectOption-test.tsx | 80 ------- .../PerspectiveSelect-test.tsx.snap | 50 +++-- .../PerspectiveSelectOption-test.tsx.snap | 33 --- .../ProjectsSortingSelect-test.tsx.snap | 152 +++++++++---- .../ProjectsSortingSelectOption-test.tsx.snap | 25 --- .../filters/SearchableFilterFooter.tsx | 4 +- .../__tests__/SearchableFilterFooter-test.tsx | 5 +- .../BulkApplyTemplateModal.tsx | 4 +- .../js/apps/projectsManagement/Search.tsx | 6 +- .../__tests__/Search-test.tsx | 4 +- .../BulkApplyTemplateModal-test.tsx.snap | 8 +- .../__snapshots__/Search-test.tsx.snap | 6 +- .../components/ConditionOperator.tsx | 4 +- .../quality-gates/components/MetricSelect.tsx | 4 +- ...QualityGatePermissionsAddModalRenderer.tsx | 4 +- .../components/ThresholdInput.tsx | 4 +- ...tyGatePermissionsAddModalRenderer-test.tsx | 4 +- .../__tests__/ThresholdInput-test.tsx | 7 +- .../ConditionOperator-test.tsx.snap | 2 +- .../__snapshots__/MetricSelect-test.tsx.snap | 2 +- ...ePermissionsAddModalRenderer-test.tsx.snap | 10 +- .../compare/ComparisonForm.tsx | 4 +- .../compare/__tests__/ComparisonForm-test.tsx | 4 +- .../details/ChangeParentForm.tsx | 4 +- .../details/ProfilePermissionsFormSelect.tsx | 4 +- .../ChangeParentForm-test.tsx.snap | 2 +- ...ProfilePermissionsFormSelect-test.tsx.snap | 2 +- .../home/CreateProfileForm.tsx | 6 +- .../home/ProfilesListHeader.tsx | 4 +- .../CreateProfileForm-test.tsx.snap | 8 +- .../ProfilesListHeader-test.tsx.snap | 2 +- .../components/FilterBar.tsx | 6 +- .../components/__tests__/FilterBar-test.tsx | 6 +- .../__snapshots__/FilterBar-test.tsx.snap | 18 +- .../js/apps/settings/components/Languages.tsx | 4 +- .../components/__tests__/Languages-test.tsx | 4 +- .../__snapshots__/Languages-test.tsx.snap | 4 +- .../inputs/InputForSingleSelectList.tsx | 4 +- .../InputForSingleSelectList-test.tsx | 5 +- .../PRDecorationBindingRenderer.tsx | 4 +- .../PRDecorationBindingRenderer-test.tsx | 4 +- .../PRDecorationBindingRenderer-test.tsx.snap | 12 +- .../users/components/UsersSelectSearch.tsx | 4 +- .../UsersSelectSearch-test.tsx.snap | 4 +- .../activity-graph/GraphsHeader.tsx | 4 +- .../main/js/components/controls/DateInput.tsx | 6 +- .../js/components/controls/SearchSelect.tsx | 4 +- .../main/js/components/controls/Select.tsx | 158 +++++++++++--- .../controls/{Select.css => SelectLegacy.css} | 0 .../js/components/controls/SelectLegacy.tsx | 59 +++++ .../controls/__tests__/Select-test.tsx | 59 +---- .../controls/__tests__/SelectLegacy-test.tsx | 85 ++++++++ .../__snapshots__/DateInput-test.tsx.snap | 4 +- .../__snapshots__/SearchSelect-test.tsx.snap | 2 +- .../__snapshots__/Select-test.tsx.snap | 56 ++--- .../__snapshots__/SelectLegacy-test.tsx.snap | 50 +++++ .../src/main/js/helpers/mocks/react-select.ts | 35 +++ server/sonar-web/yarn.lock | 202 +++++++++++++++++- 104 files changed, 1086 insertions(+), 829 deletions(-) delete mode 100644 server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelectOption.tsx delete mode 100644 server/sonar-web/src/main/js/apps/projects/components/ProjectsSortingSelectOption.tsx delete mode 100644 server/sonar-web/src/main/js/apps/projects/components/__tests__/PerspectiveSelectOption-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelectOption-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PerspectiveSelectOption-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectsSortingSelectOption-test.tsx.snap rename server/sonar-web/src/main/js/components/controls/{Select.css => SelectLegacy.css} (100%) create mode 100644 server/sonar-web/src/main/js/components/controls/SelectLegacy.tsx create mode 100644 server/sonar-web/src/main/js/components/controls/__tests__/SelectLegacy-test.tsx create mode 100644 server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SelectLegacy-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/helpers/mocks/react-select.ts diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index afdd07e8e06..86ff408abfa 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -37,7 +37,8 @@ "react-modal": "3.14.3", "react-redux": "5.1.1", "react-router": "3.2.6", - "react-select": "1.2.1", + "react-select": "4.3.1", + "react-select-legacy": "npm:react-select@1.2.1", "react-virtualized": "9.21.2", "redux": "4.0.5", "redux-thunk": "2.3.0", @@ -80,7 +81,8 @@ "@types/react-modal": "3.12.1", "@types/react-redux": "6.0.6", "@types/react-router": "3.0.20", - "@types/react-select": "1.2.6", + "@types/react-select": "4.0.16", + "@types/react-select-legacy": "npm:@types/react-select@1.2.6", "@types/react-virtualized": "9.21.0", "@types/sanitize-html": "1.22.0", "@types/valid-url": "1.0.2", 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 efa37b2a77a..6ccff0a0c57 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 @@ -40,7 +40,7 @@ import RadioToggle from '../../../components/controls/RadioToggle'; import ReloadButton from '../../../components/controls/ReloadButton'; import SearchBox from '../../../components/controls/SearchBox'; import SearchSelect from '../../../components/controls/SearchSelect'; -import Select from '../../../components/controls/Select'; +import SelectLegacy from '../../../components/controls/SelectLegacy'; import SelectList, { SelectListFilter } from '../../../components/controls/SelectList'; import SimpleModal from '../../../components/controls/SimpleModal'; import Tooltip from '../../../components/controls/Tooltip'; @@ -219,7 +219,7 @@ const exposeLibraries = () => { SearchBox, SearchSelect, SecurityHotspotIcon, - Select, + SelectLegacy, SelectList, SelectListFilter, SimpleModal, diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/BadgeParams.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/BadgeParams.tsx index 92a8e74dbb2..0327f91c636 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/BadgeParams.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/BadgeParams.tsx @@ -20,7 +20,7 @@ import classNames from 'classnames'; import * as React from 'react'; import { fetchWebApi } from '../../../../../../api/web-api'; -import Select from '../../../../../../components/controls/Select'; +import SelectLegacy from '../../../../../../components/controls/SelectLegacy'; import { getLocalizedMetricName, translate } from '../../../../../../helpers/l10n'; import { BadgeFormats, BadgeOptions, BadgeType } from './utils'; @@ -105,7 +105,7 @@ export default class BadgeParams extends React.PureComponent { - - - - { const onSave = jest.fn(); const wrapper = shallowRender({ onSave }); - wrapper.find(Select).simulate('change', { value: 'Daily' }); + wrapper.find(SelectLegacy).simulate('change', { value: 'Daily' }); expect(wrapper.find('.button-success').exists()).toBe(true); expect(wrapper.find(ResetButtonLink).exists()).toBe(true); diff --git a/server/sonar-web/src/main/js/apps/application-settings/__tests__/__snapshots__/ReportFrequencyForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/application-settings/__tests__/__snapshots__/ReportFrequencyForm-test.tsx.snap index dc8322658c5..7ea031a392b 100644 --- a/server/sonar-web/src/main/js/apps/application-settings/__tests__/__snapshots__/ReportFrequencyForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/application-settings/__tests__/__snapshots__/ReportFrequencyForm-test.tsx.snap @@ -13,7 +13,7 @@ exports[`should render correctly: changed 1`] = ` } } /> - application_settings.report.frequency - { ]; return ( - ({ import { shallow } from 'enzyme'; import * as React from 'react'; +import SelectLegacy from '../../../../components/controls/SelectLegacy'; import { submit } from '../../../../helpers/testUtils'; import WorkersForm from '../WorkersForm'; @@ -31,7 +32,7 @@ it('changes select', () => { const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); - wrapper.find('Select').prop('onChange')({ value: 7 }); + wrapper.find(SelectLegacy).prop('onChange')({ value: 7 }); wrapper.update(); expect(wrapper).toMatchSnapshot(); }); @@ -40,7 +41,7 @@ it('returns new worker count', async () => { const onClose = jest.fn(); const wrapper = shallow(); (wrapper.instance() as WorkersForm).mounted = true; - wrapper.find('Select').prop('onChange')({ value: 7 }); + wrapper.find(SelectLegacy).prop('onChange')({ value: 7 }); wrapper.update(); submit(wrapper.find('form')); diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.tsx.snap index 527175beff3..da66d6be96b 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.tsx.snap @@ -18,7 +18,7 @@ exports[`changes select 1`] = `
- - { value: profile.key })); return ( - (
- coding_rules.quality_profile - coding_rules.quality_profile - coding_rules.quality_profile - coding_rules.quality_profile - coding_rules.quality_profile - - severity - type - coding_rules.filters.status - { ); const input = ( - { {this.state.permissionTemplates && ( - {!['VW', 'SVW'].includes(this.props.project.qualifier) && ( -
{translate('baseline.analysis_from')} - baseline.analysis_from -
- - - -
- { it('should render select options correctly', () => { return new Promise((resolve, reject) => { const wrapper = shallowRender(); - const render = wrapper.find(Select).props().optionRenderer; + const render = wrapper.find(SelectLegacy).props().optionRenderer; if (!render) { reject(); return; @@ -66,7 +66,7 @@ it('should correctly handle changes', () => { expect(onSubmit).toHaveBeenLastCalledWith('foo', 'foo'); const change = diveIntoSimpleModal(wrapper) - .find(Select) + .find(SelectLegacy) .props().onChange; expect(change).toBeDefined(); diff --git a/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/AddLanguageModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/AddLanguageModal-test.tsx.snap index 266194051dc..7e6c947970a 100644 --- a/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/AddLanguageModal-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/AddLanguageModal-test.tsx.snap @@ -28,7 +28,7 @@ Array [ project_quality_profile.add_language_modal.choose_language
- - - option.value === perspective)} />
); diff --git a/server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelectOption.tsx b/server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelectOption.tsx deleted file mode 100644 index a9115bc1d14..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelectOption.tsx +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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 BubblesIcon from '../../../components/icons/BubblesIcon'; -import ListIcon from '../../../components/icons/ListIcon'; - -export interface Option { - label: string; - type: string; - value: string; -} - -interface Props { - option: Option; - children?: React.ReactNode; - className?: string; - isFocused?: boolean; - onFocus: (option: Option, event: React.SyntheticEvent) => void; - onSelect: (option: Option, event: React.SyntheticEvent) => void; -} - -export default class PerspectiveSelectOption extends React.PureComponent { - handleMouseDown = (event: React.SyntheticEvent) => { - event.preventDefault(); - event.stopPropagation(); - this.props.onSelect(this.props.option, event); - }; - - handleMouseEnter = (event: React.SyntheticEvent) => { - this.props.onFocus(this.props.option, event); - }; - - handleMouseMove = (event: React.SyntheticEvent) => { - if (this.props.isFocused) { - return; - } - this.props.onFocus(this.props.option, event); - }; - - render() { - const { option } = this.props; - return ( -
-
- {option.type === 'view' && } - {option.type === 'visualization' && } - {this.props.children} -
-
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectsSortingSelect.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectsSortingSelect.tsx index cdf13fbbfac..87814b301c7 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectsSortingSelect.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectsSortingSelect.tsx @@ -17,8 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { sortBy } from 'lodash'; +import { omit, sortBy } from 'lodash'; import * as React from 'react'; +import { components, OptionProps } from 'react-select'; import { colors } from '../../../app/theme'; import { ButtonIcon } from '../../../components/controls/buttons'; import Select from '../../../components/controls/Select'; @@ -27,7 +28,6 @@ import SortAscIcon from '../../../components/icons/SortAscIcon'; import SortDescIcon from '../../../components/icons/SortDescIcon'; import { translate } from '../../../helpers/l10n'; import { parseSorting, SORTING_LEAK_METRICS, SORTING_METRICS } from '../utils'; -import ProjectsSortingSelectOption, { Option } from './ProjectsSortingSelectOption'; interface Props { className?: string; @@ -37,8 +37,19 @@ interface Props { view: string; } +export interface Option { + label: string; + value: string; + className?: string; + short?: string; +} + export default class ProjectsSortingSelect extends React.PureComponent { - getSorting = () => parseSorting(this.props.selectedSort); + getSorting = () => { + const options = this.getOptions(); + const { sortDesc, sortValue } = parseSorting(this.props.selectedSort); + return { sortDesc, value: options.find(o => o.value === sortValue) }; + }; getOptions = () => { const sortMetrics = this.props.view === 'leak' ? SORTING_LEAK_METRICS : SORTING_METRICS; @@ -46,39 +57,59 @@ export default class ProjectsSortingSelect extends React.PureComponent { option => ({ value: option.value, label: translate('projects.sorting', option.value), - class: option.class + className: option.class }) ); }; handleDescToggle = () => { - const sorting = this.getSorting(); - this.props.onChange(sorting.sortValue, !sorting.sortDesc); + const { sortDesc, sortValue } = parseSorting(this.props.selectedSort); + this.props.onChange(sortValue, !sortDesc); }; - handleSortChange = (option: Option) => + handleSortChange = (option: Option) => { this.props.onChange(option.value, this.getSorting().sortDesc); + }; + + projectsSortingSelectOption = (props: OptionProps) => { + const { data, children } = props; + return ( + + {data.short ? data.short : children} + + ); + }; render() { - const { sortDesc, sortValue } = this.getSorting(); + const { sortDesc, value } = this.getSorting(); return (
- +
`; exports[`should render with coverage selected 1`] = `
-
`; + +exports[`should render option correctly 1`] = ` + +`; + +exports[`should render option correctly 2`] = ` +