From: Ambroise C Date: Tue, 7 Feb 2023 14:35:50 +0000 (+0100) Subject: SONAR-16746 Upgrade react-select major frontend dependency X-Git-Tag: 10.0.0.68432~253 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8de5e9f1d721daa75ba0e09512f3a0014bd48fb4;p=sonarqube.git SONAR-16746 Upgrade react-select major frontend dependency - Remove package from core-extension-license as it's not used in it - Update related components and tests - Add some CSS helper classes - Remove some code smells - Update integration testing ReactSelect JAVA class definition --------- Co-authored-by: Philippe Perrin --- diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index 6d8fdaecb6a..62a5f9addda 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -30,7 +30,7 @@ "react-intl": "3.12.1", "react-modal": "3.16.1", "react-router-dom": "6.7.0", - "react-select": "4.3.1", + "react-select": "5.7.0", "react-virtualized": "9.22.3", "regenerator-runtime": "0.13.11", "valid-url": "1.0.9" @@ -61,7 +61,6 @@ "@types/react-dom": "16.9.17", "@types/react-helmet": "6.1.6", "@types/react-modal": "3.13.1", - "@types/react-select": "4.0.18", "@types/react-virtualized": "9.21.21", "@types/valid-url": "1.0.3", "@typescript-eslint/eslint-plugin": "5.49.0", diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx index 5ad1bdb1493..3da859b87b9 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx @@ -18,20 +18,20 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import classNames from 'classnames'; +import { orderBy } from 'lodash'; import * as React from 'react'; -import { BranchLike } from '../../../../../../types/branch-like'; import { getBranches } from '../../../../../../api/branches'; import { getRegulatoryReportUrl } from '../../../../../../api/regulatory-report'; import { ButtonLink } from '../../../../../../components/controls/buttons'; -import Select, { BasicSelectOption } from '../../../../../../components/controls/Select'; +import Select, { LabelValueSelectOption } from '../../../../../../components/controls/Select'; import { getBranchLikeDisplayName, isBranch, isMainBranch, } from '../../../../../../helpers/branch-like'; import { translate } from '../../../../../../helpers/l10n'; +import { BranchLike } from '../../../../../../types/branch-like'; import { Component } from '../../../../../../types/types'; -import { orderBy } from 'lodash'; interface Props { component: Pick; @@ -42,7 +42,7 @@ interface Props { interface State { downloadStarted: boolean; selectedBranch: string; - branchLikesOptions: BasicSelectOption[]; + branchLikesOptions: LabelValueSelectOption[]; } export default class RegulatoryReport extends React.PureComponent { @@ -87,7 +87,7 @@ export default class RegulatoryReport extends React.PureComponent }); } - onBranchSelect = (newOption: BasicSelectOption) => { + onBranchSelect = (newOption: LabelValueSelectOption) => { this.setState({ selectedBranch: newOption.value, downloadStarted: false }); }; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/__tests__/RegulatoryReport-it.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/__tests__/RegulatoryReport-it.tsx index 63d784551b0..76072770120 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/__tests__/RegulatoryReport-it.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/projectRegulatoryReport/__tests__/RegulatoryReport-it.tsx @@ -41,7 +41,7 @@ it('should open the regulatory report page', async () => { expect(screen.getByText('regulatory_report.description1')).toBeInTheDocument(); expect(screen.getByText('regulatory_report.description2')).toBeInTheDocument(); - const branchSelect = screen.getByRole('textbox'); + const branchSelect = screen.getByRole('combobox', { name: 'regulatory_page.select_branch' }); expect(branchSelect).toBeInTheDocument(); await user.click(branchSelect); diff --git a/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx b/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx index e3bcc746f78..02ec79d5a74 100644 --- a/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx +++ b/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx @@ -292,16 +292,24 @@ describe('security page', () => { // eslint-disable-next-line jest/no-conditional-in-test if (tokenTypeOption === TokenType.Project) { - await selectEvent.select(screen.getAllByRole('textbox')[1], [tokenTypeLabel]); + await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.type' }), [ + tokenTypeLabel, + ]); // eslint-disable-next-line jest/no-conditional-expect expect(generateButton).toBeDisabled(); // eslint-disable-next-line jest/no-conditional-expect - expect(screen.getAllByRole('textbox')).toHaveLength(4); - await selectEvent.select(screen.getAllByRole('textbox')[2], ['Project Name 1']); + expect(screen.getByRole('textbox', { name: 'users.tokens.name' })).toBeInTheDocument(); + // eslint-disable-next-line jest/no-conditional-expect + expect(screen.getAllByRole('combobox')).toHaveLength(3); + await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.project' }), [ + 'Project Name 1', + ]); // eslint-disable-next-line jest/no-conditional-expect expect(generateButton).toBeEnabled(); } else { - await selectEvent.select(screen.getAllByRole('textbox')[1], [tokenTypeLabel]); + await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.type' }), [ + tokenTypeLabel, + ]); // eslint-disable-next-line jest/no-conditional-expect expect(generateButton).toBeEnabled(); } @@ -389,7 +397,7 @@ describe('security page', () => { securityPagePath ); - selectEvent.openMenu(screen.getAllByRole('textbox')[1]); + selectEvent.openMenu(screen.getByRole('combobox', { name: 'users.tokens.type' })); expect(screen.queryByText(`users.tokens.${TokenType.Project}`)).not.toBeInTheDocument(); }); @@ -417,7 +425,7 @@ describe('security page', () => { securityPagePath ); - await selectEvent.select(screen.getAllByRole('textbox')[1], [ + await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.type' }), [ `users.tokens.${TokenType.Project}`, ]); diff --git a/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx b/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx index 9e435c7e46d..d5a391828aa 100644 --- a/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx @@ -67,6 +67,8 @@ const ui = { downloadSentenceStart: byText('audit_logs.download_start.sentence.1'), startDateInput: byPlaceholderText('start_date'), endDateInput: byPlaceholderText('end_date'), + dateInputMonthSelect: byRole('combobox', { name: 'select_month' }), + dateInputYearSelect: byRole('combobox', { name: 'select_year' }), }; let handler: SettingsServiceMock; @@ -115,21 +117,13 @@ it('should handle download button click', async () => { expect(ui.downloadButton.get()).toHaveAttribute('aria-disabled', 'true'); await user.click(ui.startDateInput.get()); - await selectEvent.select(screen.getByRole('textbox', { name: 'select_month' }), [ - getShortMonthName(getMonth(startDay)), - ]); - await selectEvent.select(screen.getByRole('textbox', { name: 'select_year' }), [ - getYear(startDay), - ]); + await selectEvent.select(ui.dateInputMonthSelect.get(), [getShortMonthName(getMonth(startDay))]); + await selectEvent.select(ui.dateInputYearSelect.get(), [getYear(startDay)]); await user.click(screen.getByText(getDate(startDay))); await user.click(ui.endDateInput.get()); - await selectEvent.select(screen.getByRole('textbox', { name: 'select_month' }), [ - getShortMonthName(getMonth(endDate)), - ]); - await selectEvent.select(screen.getByRole('textbox', { name: 'select_year' }), [ - getYear(endDate), - ]); + await selectEvent.select(ui.dateInputMonthSelect.get(), [getShortMonthName(getMonth(endDate))]); + await selectEvent.select(ui.dateInputYearSelect.get(), [getYear(endDate)]); await user.click(screen.getByText(getDate(endDate))); expect(await ui.downloadButton.find()).toHaveAttribute('aria-disabled', 'false'); diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.tsx index c1bac2d34ae..2c6d4d0278d 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.tsx @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import Select, { BasicSelectOption } from '../../../components/controls/Select'; +import Select, { LabelValueSelectOption } from '../../../components/controls/Select'; import { translate } from '../../../helpers/l10n'; import { TaskStatuses } from '../../../types/tasks'; import { STATUSES } from '../constants'; @@ -32,7 +32,7 @@ interface StatusFilterProps { export default function StatusFilter(props: StatusFilterProps) { const { id, value, onChange } = props; - const options: BasicSelectOption[] = [ + const options: LabelValueSelectOption[] = [ { value: STATUSES.ALL, label: translate('background_task.status.ALL') }, { value: STATUSES.ALL_EXCEPT_PENDING, @@ -46,7 +46,7 @@ export default function StatusFilter(props: StatusFilterProps) { ]; const handleChange = React.useCallback( - ({ value }: BasicSelectOption) => { + ({ value }: LabelValueSelectOption) => { onChange(value); }, [onChange] diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.tsx index 36f94f7008d..c5fe7304c50 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.tsx @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import Select, { BasicSelectOption } from '../../../components/controls/Select'; +import Select, { LabelValueSelectOption } from '../../../components/controls/Select'; import { translate } from '../../../helpers/l10n'; import { ALL_TYPES } from '../constants'; @@ -30,7 +30,7 @@ interface Props { } export default class TypesFilter extends React.PureComponent { - handleChange = ({ value }: BasicSelectOption) => { + handleChange = ({ value }: LabelValueSelectOption) => { this.props.onChange(value); }; @@ -43,7 +43,7 @@ export default class TypesFilter extends React.PureComponent { }; }); - const allOptions: BasicSelectOption[] = [ + const allOptions: LabelValueSelectOption[] = [ { value: ALL_TYPES, label: translate('background_task.type.ALL') }, ...options, ]; diff --git a/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts b/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts index 900194d53cd..00fe9b0ff43 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts +++ b/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts @@ -19,6 +19,7 @@ */ import { fireEvent, screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { byRole } from 'testing-library-selector'; import CodingRulesMock from '../../../api/mocks/CodingRulesMock'; import { mockCurrentUser, mockLoggedInUser } from '../../../helpers/testMocks'; import { renderAppRoutes } from '../../../helpers/testReactTestingUtils'; @@ -30,6 +31,11 @@ jest.mock('../../../api/issues'); jest.mock('../../../api/users'); jest.mock('../../../api/quality-profiles'); +const ui = { + activateInSelectOption: byRole('combobox', { name: 'coding_rules.activate_in' }), + deactivateInSelectOption: byRole('combobox', { name: 'coding_rules.deactivate_in' }), +}; + let handler: CodingRulesMock; beforeAll(() => { @@ -276,7 +282,7 @@ it('no quality profile for bulk cahnge base on language search', async () => { expect(dialog).toBeInTheDocument(); const dialogScreen = within(dialog); - await user.click(dialogScreen.getByRole('textbox', { name: 'coding_rules.activate_in' })); + await user.click(ui.activateInSelectOption.get()); expect(dialogScreen.getByText('coding_rules.bulk_change.no_quality_profile')).toBeInTheDocument(); }); @@ -297,7 +303,7 @@ it('should be able to bulk activate quality profile', async () => { expect(dialog).toBeInTheDocument(); let dialogScreen = within(dialog); - await user.click(dialogScreen.getByRole('textbox', { name: 'coding_rules.activate_in' })); + await user.click(ui.activateInSelectOption.get()); await user.click( dialogScreen.getByText(`${selectQPSuccess.name} - ${selectQPSuccess.languageName}`) ); @@ -326,7 +332,7 @@ it('should be able to bulk activate quality profile', async () => { name: `coding_rules.activate_in_quality_profile (${handler.allRulesCount()} coding_rules._rules)`, }) ); - await user.click(dialogScreen.getByRole('textbox', { name: 'coding_rules.activate_in' })); + await user.click(ui.activateInSelectOption.get()); await user.click( dialogScreen.getByText(`${selectQPWarning.name} - ${selectQPWarning.languageName}`) ); @@ -354,7 +360,7 @@ it('should be able to bulk deactivate quality profile', async () => { name: `coding_rules.deactivate_in_quality_profile (${handler.allRulesCount()} coding_rules._rules)`, }) ); - await user.click(dialogScreen.getByRole('textbox', { name: 'coding_rules.deactivate_in' })); + await user.click(ui.deactivateInSelectOption.get()); await user.click(dialogScreen.getByText(`${selectQP.name} - ${selectQP.languageName}`)); await user.click(dialogScreen.getByRole('button', { name: 'apply' })); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx index 45c035e444c..98031fd3254 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx @@ -19,11 +19,10 @@ */ import classNames from 'classnames'; import * as React from 'react'; -import { OptionTypeBase } from 'react-select'; import { activateRule, Profile } from '../../../api/quality-profiles'; import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons'; import Modal from '../../../components/controls/Modal'; -import Select from '../../../components/controls/Select'; +import Select, { LabelValueSelectOption } from '../../../components/controls/Select'; import { Alert } from '../../../components/ui/Alert'; import { translate } from '../../../helpers/l10n'; import { sanitizeString } from '../../../helpers/sanitize'; @@ -141,7 +140,7 @@ export default class ActivationFormModal extends React.PureComponent { + handleSeverityChange = ({ value }: LabelValueSelectOption) => { this.setState({ severity: value }); }; @@ -176,7 +175,7 @@ export default class ActivationFormModal extends React.PureComponent ' '.repeat(p.depth) + p.name} + getOptionLabel={(p: ProfileWithDeph) => ' '.repeat(p.depth) + p.name} options={profilesWithDepth} value={profile} /> diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx index b1702f45b07..aab3d76897b 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx @@ -18,12 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { components, OptionProps, OptionTypeBase, SingleValueProps } from 'react-select'; +import { components, OptionProps, SingleValueProps } from 'react-select'; import { createRule, updateRule } from '../../../api/rules'; import FormattingTips from '../../../components/common/FormattingTips'; import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons'; import Modal from '../../../components/controls/Modal'; -import Select from '../../../components/controls/Select'; +import Select, { LabelValueSelectOption } from '../../../components/controls/Select'; import TypeHelper from '../../../components/shared/TypeHelper'; import { Alert } from '../../../components/ui/Alert'; import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker'; @@ -33,7 +33,7 @@ import { csvEscape } from '../../../helpers/csv'; import { translate } from '../../../helpers/l10n'; import { sanitizeString } from '../../../helpers/sanitize'; import { latinize } from '../../../helpers/strings'; -import { Dict, RuleDetails, RuleParameter } from '../../../types/types'; +import { Dict, RuleDetails, RuleParameter, RuleType } from '../../../types/types'; import { SeveritySelect } from './SeveritySelect'; interface Props { @@ -144,11 +144,12 @@ export default class CustomRuleFormModal extends React.PureComponent) => this.setState({ description: event.currentTarget.value }); - handleTypeChange = ({ value }: { value: string }) => this.setState({ type: value }); + handleTypeChange = ({ value }: LabelValueSelectOption) => + this.setState({ type: value }); handleSeverityChange = ({ value }: { value: string }) => this.setState({ severity: value }); - handleStatusChange = ({ value }: { value: string }) => this.setState({ status: value }); + handleStatusChange = ({ value }: LabelValueSelectOption) => this.setState({ status: value }); handleParameterChange = (event: React.SyntheticEvent) => { const { name, value } = event.currentTarget; @@ -213,7 +214,7 @@ export default class CustomRuleFormModal extends React.PureComponent ); - renderTypeOption = (props: OptionProps) => { + renderTypeOption = (props: OptionProps, false>) => { return ( @@ -221,7 +222,7 @@ export default class CustomRuleFormModal extends React.PureComponent) => { + renderTypeSingleValue = (props: SingleValueProps, false>) => { return ( @@ -230,7 +231,7 @@ export default class CustomRuleFormModal extends React.PureComponent { - const ruleTypeOption = RULE_TYPES.map((type) => ({ + const ruleTypeOption: LabelValueSelectOption[] = RULE_TYPES.map((type) => ({ label: translate('issue.type', type), value: type, })); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/SeveritySelect.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/SeveritySelect.tsx index daf1f69c15e..ff27e2ac8c5 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/SeveritySelect.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/SeveritySelect.tsx @@ -18,8 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { components, OptionProps, OptionTypeBase, SingleValueProps } from 'react-select'; -import Select from '../../../components/controls/Select'; +import { components, OptionProps, SingleValueProps } from 'react-select'; +import Select, { LabelValueSelectOption } from '../../../components/controls/Select'; import SeverityHelper from '../../../components/shared/SeverityHelper'; import { SEVERITIES } from '../../../helpers/constants'; import { translate } from '../../../helpers/l10n'; @@ -28,7 +28,23 @@ export interface SeveritySelectProps { isDisabled: boolean; severity: string; ariaLabelledby: string; - onChange: (value: OptionTypeBase) => void; + onChange: (value: LabelValueSelectOption) => void; +} + +function Option(props: OptionProps) { + return ( + + + + ); +} + +function SingleValue(props: SingleValueProps) { + return ( + + + + ); } export function SeveritySelect(props: SeveritySelectProps) { @@ -38,22 +54,6 @@ export function SeveritySelect(props: SeveritySelectProps) { value: severity, })); - function Option(props: OptionProps) { - return ( - - - - ); - } - - function SingleValue(props: SingleValueProps) { - return ( - - - - ); - } - return ( { isClearable={true} isSearchable={false} components={{ - Option: (props: OptionProps) => ( - {typeRenderer(props.data)} - ), - SingleValue: (props: SingleValueProps) => ( - {typeRenderer(props.data)} - ), + Option: TypeFieldOptionComponent, + SingleValue: TypeFieldSingleValueComponent, }} onChange={this.handleSelectFieldChange('type')} options={options} @@ -346,7 +371,7 @@ export default class BulkChangeModal extends React.PureComponent { } const severities = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']; - const options: BasicSelectOption[] = severities.map((severity) => ({ + const options: LabelValueSelectOption[] = severities.map((severity) => ({ label: translate('severity', severity), value: severity, })); @@ -359,16 +384,8 @@ export default class BulkChangeModal extends React.PureComponent { isSearchable={false} onChange={this.handleSelectFieldChange('severity')} components={{ - Option: (props: OptionProps) => ( - - {} - - ), - SingleValue: (props: SingleValueProps) => ( - - {} - - ), + Option: SeverityFieldOptionComponent, + SingleValue: SeverityFieldSingleValueComponent, }} options={options} /> diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/AssigneeSelect-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/AssigneeSelect-test.tsx index b446d59933a..af11d1b37f6 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/AssigneeSelect-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/AssigneeSelect-test.tsx @@ -19,7 +19,8 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { Props as ReactSelectAsyncProps } from 'react-select/async'; +import { GroupBase } from 'react-select'; +import { AsyncProps } from 'react-select/async'; import { SearchSelect } from '../../../../components/controls/Select'; import Avatar from '../../../../components/ui/Avatar'; import { mockCurrentUser, mockIssue, mockLoggedInUser } from '../../../../helpers/testMocks'; @@ -97,12 +98,12 @@ it('should render options correctly', () => { it('should render noOptionsMessage correctly', () => { const wrapper = shallowRender(); expect( - wrapper.find>(SearchSelect).props() + wrapper.find>>(SearchSelect).props() .noOptionsMessage!({ inputValue: 'a' }) ).toBe(`select2.tooShort.${MIN_QUERY_LENGTH}`); expect( - wrapper.find>(SearchSelect).props() + wrapper.find>>(SearchSelect).props() .noOptionsMessage!({ inputValue: 'droids' }) ).toBe('select2.noMatches'); }); diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx index 4ec31762871..f71b1122431 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx @@ -20,7 +20,6 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { Props as ReactSelectProps } from 'react-select'; -import { SelectComponentsProps } from 'react-select/src/Select'; import { searchIssueTags } from '../../../../api/issues'; import { SubmitButton } from '../../../../components/controls/buttons'; import Select, { CreatableSelect, SearchSelect } from '../../../../components/controls/Select'; @@ -72,7 +71,7 @@ it.each([ const wrapper = getWrapper([mockIssue(false, { actions: [action] })]); await waitAndUpdate(wrapper); - const { Option, SingleValue } = wrapper.find(Select).props().components; + const { Option, SingleValue } = wrapper.find(Select).props().components; expect(Option({ data: { label: 'label', value: 'value' } })).toMatchSnapshot('Option'); expect(SingleValue({ data: { label: 'label', value: 'value' } })).toMatchSnapshot('SingleValue'); diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingReferenceBranch-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingReferenceBranch-test.tsx index b4e983875f4..c240643795d 100644 --- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingReferenceBranch-test.tsx +++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingReferenceBranch-test.tsx @@ -95,7 +95,7 @@ describe('renderOption', () => { expect( renderBranchOption({ ...props, - data: { value: 'branch-nope', isMain: false, isInvalid: true }, + data: { label: 'branch-nope', value: 'branch-nope', isMain: false, isInvalid: true }, }) ).toMatchSnapshot("branch doesn't exist"); }); diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/BaselineSettingReferenceBranch-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/BaselineSettingReferenceBranch-test.tsx.snap index 3f0251dba3a..e2eb5c63fdc 100644 --- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/BaselineSettingReferenceBranch-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/BaselineSettingReferenceBranch-test.tsx.snap @@ -24,6 +24,7 @@ exports[`renderOption should render correctly: branch doesn't exist 1`] = ` { "isInvalid": true, "isMain": false, + "label": "branch-nope", "value": "branch-nope", } } diff --git a/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx b/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx index d177ea7a804..1568592b95e 100644 --- a/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx @@ -27,7 +27,7 @@ import Link from '../../components/common/Link'; import { SubmitButton } from '../../components/controls/buttons'; import HelpTooltip from '../../components/controls/HelpTooltip'; import Radio from '../../components/controls/Radio'; -import Select, { BasicSelectOption } from '../../components/controls/Select'; +import Select, { LabelValueSelectOption } from '../../components/controls/Select'; import Suggestions from '../../components/embed-docs-modal/Suggestions'; import { Alert } from '../../components/ui/Alert'; import { translate } from '../../helpers/l10n'; @@ -51,7 +51,7 @@ function hasConditionOnNewCode(qualityGate: QualityGate): boolean { return !!qualityGate.conditions?.some((condition) => isDiffMetric(condition.metric)); } -interface QualityGateOption extends BasicSelectOption { +interface QualityGateOption extends LabelValueSelectOption { isDisabled: boolean; } diff --git a/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/ProjectQualityGateApp-it.tsx b/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/ProjectQualityGateApp-it.tsx index 847fb98c4ac..72f27addb65 100644 --- a/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/ProjectQualityGateApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/ProjectQualityGateApp-it.tsx @@ -42,7 +42,7 @@ const ui = { name: /project_quality_gate.always_use_default/, }), specificRadioQualityGate: byRole('radio', { name: /project_quality_gate.always_use_specific/ }), - qualityGatesSelect: byRole('textbox', { name: 'project_quality_gate.select_specific_qg' }), + qualityGatesSelect: byRole('combobox', { name: 'project_quality_gate.select_specific_qg' }), QGWithoutConditionsOptionLabel: byRole('radio', { name: /option QG without conditions selected/, }), diff --git a/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/AddLanguageModal.tsx b/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/AddLanguageModal.tsx index 4601712346b..9c1839d1b46 100644 --- a/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/AddLanguageModal.tsx +++ b/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/AddLanguageModal.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import { Profile } from '../../../api/quality-profiles'; import withLanguagesContext from '../../../app/components/languages/withLanguagesContext'; import { ButtonLink, SubmitButton } from '../../../components/controls/buttons'; -import Select, { BasicSelectOption } from '../../../components/controls/Select'; +import Select, { LabelValueSelectOption } from '../../../components/controls/Select'; import SimpleModal from '../../../components/controls/SimpleModal'; import { translate } from '../../../helpers/l10n'; import { Languages } from '../../../types/languages'; @@ -47,7 +47,7 @@ export function AddLanguageModal(props: AddLanguageModalProps) { const header = translate('project_quality_profile.add_language_modal.title'); - const languageOptions: BasicSelectOption[] = difference( + const languageOptions: LabelValueSelectOption[] = difference( Object.keys(profilesByLanguage), unavailableLanguages ).map((l) => ({ value: l, label: languages[l].name })); @@ -90,7 +90,7 @@ export function AddLanguageModal(props: AddLanguageModalProps) { className="abs-width-300" isDisabled={submitting} id="language" - onChange={({ value }: BasicSelectOption) => { + onChange={({ value }: LabelValueSelectOption) => { setSelected({ language: value, key: undefined }); }} options={languageOptions} diff --git a/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/LanguageProfileSelectOption.tsx b/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/LanguageProfileSelectOption.tsx index b90369d81fb..d45c08fcc6b 100644 --- a/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/LanguageProfileSelectOption.tsx +++ b/server/sonar-web/src/main/js/apps/projectQualityProfiles/components/LanguageProfileSelectOption.tsx @@ -21,11 +21,11 @@ import * as React from 'react'; import { components, OptionProps } from 'react-select'; import DisableableSelectOption from '../../../components/common/DisableableSelectOption'; import Link from '../../../components/common/Link'; -import { BasicSelectOption } from '../../../components/controls/Select'; +import { LabelValueSelectOption } from '../../../components/controls/Select'; import { translate } from '../../../helpers/l10n'; import { getQualityProfileUrl } from '../../../helpers/urls'; -export interface ProfileOption extends BasicSelectOption { +export interface ProfileOption extends LabelValueSelectOption { language: string; isDisabled: boolean; } diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.tsx index c176a8d91de..4fde70375e6 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.tsx @@ -19,7 +19,7 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { GroupTypeBase } from 'react-select'; +import { GroupBase } from 'react-select'; import { mockReactSelectOptionProps } from '../../../../helpers/mocks/react-select'; import { click } from '../../../../helpers/testUtils'; import ProjectsSortingSelect, { Option } from '../ProjectsSortingSelect'; @@ -44,7 +44,7 @@ it('should render option correctly', () => { expect( shallow( >({ + {...mockReactSelectOptionProps>({ label: 'foo', value: 'foo', short: 'fo', @@ -55,7 +55,7 @@ it('should render option correctly', () => { expect( shallow( >({ + {...mockReactSelectOptionProps>({ label: 'foo', value: 'foo', })} diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx index 20d042e7387..a4190c94c74 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx @@ -19,7 +19,6 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { SelectComponentsProps } from 'react-select/src/Select'; import Select from '../../../../components/controls/Select'; import SearchableFilterFooter from '../SearchableFilterFooter'; @@ -38,7 +37,7 @@ it('should render items without the ones in the facet', () => { query={{ languages: ['java'] }} /> ); - expect(wrapper.find(Select).props().options).toMatchSnapshot(); + expect(wrapper.find(Select).props().options).toMatchSnapshot(); }); it('should properly handle a change of the facet value', () => { diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx index bf1bce7b499..c231ca1f3c6 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx @@ -27,7 +27,7 @@ import Checkbox from '../../components/controls/Checkbox'; import DateInput from '../../components/controls/DateInput'; import HelpTooltip from '../../components/controls/HelpTooltip'; import SearchBox from '../../components/controls/SearchBox'; -import Select from '../../components/controls/Select'; +import Select, { LabelValueSelectOption } from '../../components/controls/Select'; import QualifierIcon from '../../components/icons/QualifierIcon'; import { translate } from '../../helpers/l10n'; import { AppState } from '../../types/appstate'; @@ -64,7 +64,6 @@ interface State { const QUALIFIERS_ORDER = ['TRK', 'VW', 'APP']; export class Search extends React.PureComponent { - mounted = false; state: State = { bulkApplyTemplateModal: false, deleteModal: false }; getQualifierOptions = () => { @@ -104,17 +103,19 @@ export class Search extends React.PureComponent { this.setState({ bulkApplyTemplateModal: false }); }; - handleQualifierChange = ({ value }: { value: string }) => this.props.onQualifierChanged(value); + handleQualifierChange = ({ value }: LabelValueSelectOption) => + this.props.onQualifierChanged(value); - handleVisibilityChange = ({ value }: { value: string }) => this.props.onVisibilityChanged(value); + handleVisibilityChange = ({ value }: LabelValueSelectOption) => + this.props.onVisibilityChanged(value); - optionRenderer = (props: OptionProps<{ value: string }, false>) => ( + optionRenderer = (props: OptionProps) => ( {this.renderQualifierOption(props.data)} ); - singleValueRenderer = (props: SingleValueProps<{ value: string }>) => ( + singleValueRenderer = (props: SingleValueProps) => ( - {this.renderQualifierOption(props.data as { value: string; label: string })} + {this.renderQualifierOption(props.data)} ); @@ -137,7 +138,7 @@ export class Search extends React.PureComponent { ); }; - renderQualifierOption = (option: { label: string; value: string }) => ( + renderQualifierOption = (option: LabelValueSelectOption) => (
{option.label} diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/Search-test.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/Search-test.tsx index a891ccfecfd..f059a49c50f 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/Search-test.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/Search-test.tsx @@ -63,10 +63,12 @@ it('renders optionrenderer and singlevaluerenderer', () => { const OptionRendererer = wrapper.instance().optionRenderer; const SingleValueRendererer = wrapper.instance().singleValueRenderer; expect( - shallow() + shallow() ).toMatchSnapshot('option renderer'); expect( - shallow() + shallow( + + ) ).toMatchSnapshot('single value renderer'); }); diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap index 4dd30d3fa72..9179058e21c 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap @@ -309,6 +309,7 @@ exports[`renders optionrenderer and singlevaluerenderer: option renderer 1`] = `
`; @@ -328,6 +330,7 @@ exports[`renders optionrenderer and singlevaluerenderer: single value renderer 1 + Val `; diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx index 32cfa51a0c4..7949b8447c7 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx @@ -56,8 +56,11 @@ export default function QualityGatePermissionsAddModalRenderer(
- + ) { return {customOptions(props.data)}; } -function singleValueRenderer(props: SingleValueProps) { +function singleValueRenderer(props: SingleValueProps) { return {customOptions(props.data)}; } diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx index c50a17e3ce7..d98d0b873e9 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx @@ -189,7 +189,7 @@ it('should be able to add a condition', async () => { let dialog = within(screen.getByRole('dialog')); await user.click(dialog.getByRole('radio', { name: 'quality_gates.conditions.new_code' })); - await selectEvent.select(dialog.getByRole('textbox'), ['Issues']); + await selectEvent.select(dialog.getByRole('combobox'), ['Issues']); await user.click(dialog.getByRole('textbox', { name: 'quality_gates.conditions.value' })); await user.keyboard('12{Enter}'); @@ -201,7 +201,7 @@ it('should be able to add a condition', async () => { await user.click(await screen.findByText('quality_gates.add_condition')); dialog = within(screen.getByRole('dialog')); - await selectEvent.select(dialog.getByRole('textbox'), ['Info Issues']); + await selectEvent.select(dialog.getByRole('combobox'), ['Info Issues']); await user.click(dialog.getByRole('radio', { name: 'quality_gates.conditions.overall_code' })); await user.click(dialog.getByLabelText('quality_gates.conditions.operator')); @@ -219,7 +219,7 @@ it('should be able to add a condition', async () => { dialog = within(screen.getByRole('dialog')); await user.click(dialog.getByRole('radio', { name: 'quality_gates.conditions.overall_code' })); - await selectEvent.select(dialog.getByRole('textbox'), ['Maintainability Rating']); + await selectEvent.select(dialog.getByRole('combobox'), ['Maintainability Rating']); await user.click(dialog.getByLabelText('quality_gates.conditions.value')); await user.click(dialog.getByText('B')); await user.click(dialog.getByRole('button', { name: 'quality_gates.add_condition' })); @@ -555,7 +555,9 @@ describe('The Permissions section', () => { }); await user.click(grantPermissionButton); const popup = screen.getByRole('dialog'); - const searchUserInput = within(popup).getByRole('textbox'); + const searchUserInput = within(popup).getByRole('combobox', { + name: 'quality_gates.permissions.search', + }); expect(searchUserInput).toBeInTheDocument(); const addUserButton = screen.getByRole('button', { name: 'add_verb', @@ -603,7 +605,9 @@ describe('The Permissions section', () => { }); await user.click(grantPermissionButton); const popup = screen.getByRole('dialog'); - const searchUserInput = within(popup).getByRole('textbox'); + const searchUserInput = within(popup).getByRole('combobox', { + name: 'quality_gates.permissions.search', + }); const addUserButton = screen.getByRole('button', { name: 'add_verb', }); @@ -635,7 +639,9 @@ describe('The Permissions section', () => { }); await user.click(grantPermissionButton); const popup = screen.getByRole('dialog'); - const searchUserInput = within(popup).getByRole('textbox'); + const searchUserInput = within(popup).getByRole('combobox', { + name: 'quality_gates.permissions.search', + }); await user.click(searchUserInput); expect(screen.getByText('no_results')).toBeInTheDocument(); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx index 78c0d9ab5e6..b63ffbf6ff6 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx @@ -50,7 +50,7 @@ const ui = { }), createButton: byRole('button', { name: 'create' }), compareButton: byRole('link', { name: 'compare' }), - compareDropdown: byRole('textbox', { name: 'quality_profiles.compare_with' }), + compareDropdown: byRole('combobox', { name: 'quality_profiles.compare_with' }), changelogLink: byRole('link', { name: 'changelog' }), popup: byRole('dialog'), copyRadio: byRole('radio', { @@ -65,7 +65,7 @@ const ui = { }), activateConfirmButton: byRole('button', { name: 'coding_rules.activate' }), namePropupInput: byRole('textbox', { name: 'quality_profiles.new_name field_required' }), - filterByLang: byRole('textbox', { name: 'quality_profiles.filter_by:' }), + filterByLang: byRole('combobox', { name: 'quality_profiles.filter_by:' }), listLinkCQualityProfile: byRole('link', { name: 'c quality profile' }), listLinkNewCQualityProfile: byRole('link', { name: 'New c quality profile' }), listLinkNewCQualityProfileFromCreateButton: byRole('link', { @@ -73,11 +73,11 @@ const ui = { }), listLinkJavaQualityProfile: byRole('link', { name: 'java quality profile' }), returnToList: byRole('link', { name: 'quality_profiles.page' }), - languageSelect: byRole('textbox', { name: 'language field_required' }), - profileExtendSelect: byRole('textbox', { + languageSelect: byRole('combobox', { name: 'language field_required' }), + profileExtendSelect: byRole('combobox', { name: 'quality_profiles.creation.choose_parent_quality_profile field_required', }), - profileCopySelect: byRole('textbox', { + profileCopySelect: byRole('combobox', { name: 'quality_profiles.creation.choose_copy_quality_profile field_required', }), nameCreatePopupInput: byRole('textbox', { name: 'name field_required' }), diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonForm.tsx index fd45c725dca..3f1aefd4892 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonForm.tsx @@ -51,7 +51,7 @@ export default class ComparisonForm extends React.PureComponent { singleValueRenderer = ( options: Option[], - props: SingleValueProps> + props: SingleValueProps, false> ) => ( {renderValue(props.data, options)} ); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsFormSelect.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsFormSelect.tsx index e0a1bf62bcf..d5416291ba7 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsFormSelect.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsFormSelect.tsx @@ -53,7 +53,7 @@ export default class ProfilePermissionsFormSelect extends React.PureComponent{customOptions(data)}; } - singleValueRenderer = (props: SingleValueProps) => ( + singleValueRenderer = (props: SingleValueProps) => ( {customOptions(props.data)} ); diff --git a/server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx b/server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx index 6231711692f..0f0c017aea4 100644 --- a/server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx @@ -23,7 +23,7 @@ import { getScannableProjects } from '../../../api/components'; import { generateToken, getTokens } from '../../../api/user-tokens'; import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import { SubmitButton } from '../../../components/controls/buttons'; -import Select, { BasicSelectOption } from '../../../components/controls/Select'; +import Select, { LabelValueSelectOption } from '../../../components/controls/Select'; import DeferredSpinner from '../../../components/ui/DeferredSpinner'; import { translate } from '../../../helpers/l10n'; import { @@ -53,8 +53,8 @@ interface State { newTokenName: string; newTokenType?: TokenType; tokens: UserToken[]; - projects: BasicSelectOption[]; - selectedProject?: BasicSelectOption; + projects: LabelValueSelectOption[]; + selectedProject?: LabelValueSelectOption; newTokenExpiration: TokenExpiration; tokenExpirationOptions: { value: TokenExpiration; label: string }[]; tokenTypeOptions: Array<{ label: string; value: TokenType }>; @@ -128,7 +128,7 @@ export class TokensForm extends React.PureComponent { return projects; }; - constructTokenTypeOptions = (projects: BasicSelectOption[]) => { + constructTokenTypeOptions = (projects: LabelValueSelectOption[]) => { const { currentUser } = this.props; const tokenTypeOptions = [ @@ -256,7 +256,7 @@ export class TokensForm extends React.PureComponent { this.setState({ newTokenType: value }); }; - handleProjectChange = (selectedProject: BasicSelectOption) => { + handleProjectChange = (selectedProject: LabelValueSelectOption) => { this.setState({ selectedProject }); }; @@ -300,7 +300,7 @@ export class TokensForm extends React.PureComponent { {translate('users.tokens.type')} { {translate('users.tokens.expires_in')} ); } diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Select-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Select-test.tsx.snap index bca0cddafdf..8413389018c 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Select-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Select-test.tsx.snap @@ -1,18 +1,22 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Select should render clearIndicator correctly 1`] = ` - + + /> +
`; exports[`Select should render complex select component: other props 1`] = ` - + × -
+ `; exports[`should render CreatableSelect correctly 1`] = ` - + setValue={[Function]} + theme={ + { + "borderRadius": 4, + "colors": { + "danger": "#DE350B", + "dangerLight": "#FFBDAD", + "neutral0": "hsl(0, 0%, 100%)", + "neutral10": "hsl(0, 0%, 90%)", + "neutral20": "hsl(0, 0%, 80%)", + "neutral30": "hsl(0, 0%, 70%)", + "neutral40": "hsl(0, 0%, 60%)", + "neutral5": "hsl(0, 0%, 95%)", + "neutral50": "hsl(0, 0%, 50%)", + "neutral60": "hsl(0, 0%, 40%)", + "neutral70": "hsl(0, 0%, 30%)", + "neutral80": "hsl(0, 0%, 20%)", + "neutral90": "hsl(0, 0%, 10%)", + "primary": "#2684FF", + "primary25": "#DEEBFF", + "primary50": "#B2D4FF", + "primary75": "#4C9AFF", + }, + "spacing": { + "baseUnit": 4, + "controlHeight": 38, + "menuGutter": 8, + }, + } + } +> + + + + + Select... + + + + + + + + + `; exports[`should render SearchSelect correctly 1`] = ` - + + + + + + + `; diff --git a/server/sonar-web/src/main/js/components/devops-platform/AlmSettingsInstanceSelector.tsx b/server/sonar-web/src/main/js/components/devops-platform/AlmSettingsInstanceSelector.tsx index fd758f2a066..88d013e2a73 100644 --- a/server/sonar-web/src/main/js/components/devops-platform/AlmSettingsInstanceSelector.tsx +++ b/server/sonar-web/src/main/js/components/devops-platform/AlmSettingsInstanceSelector.tsx @@ -27,7 +27,7 @@ function optionRenderer(props: OptionProps) { return {customOptions(props.data)}; } -function singleValueRenderer(props: SingleValueProps) { +function singleValueRenderer(props: SingleValueProps) { return {customOptions(props.data)}; } diff --git a/server/sonar-web/src/main/js/helpers/mocks/react-select.ts b/server/sonar-web/src/main/js/helpers/mocks/react-select.ts index 8b33e117c13..0b7e44c87dc 100644 --- a/server/sonar-web/src/main/js/helpers/mocks/react-select.ts +++ b/server/sonar-web/src/main/js/helpers/mocks/react-select.ts @@ -18,18 +18,18 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { + ClearIndicatorProps, ControlProps, - GroupTypeBase, - IndicatorProps, + DropdownIndicatorProps, + GroupBase, InputProps, OptionProps, - OptionTypeBase, } from 'react-select'; export function mockReactSelectOptionProps< - OptionType extends OptionTypeBase, - IsMulti extends boolean, - GroupType extends GroupTypeBase = GroupTypeBase + OptionType = unknown, + IsMulti extends boolean = boolean, + GroupType extends GroupBase = GroupBase >( data: OptionType, overrides?: OptionProps @@ -45,17 +45,25 @@ export function mockReactSelectInputProps(): InputProps { } export function mockReactSelectControlProps< - OptionType extends OptionTypeBase, - IsMulti extends boolean, - GroupType extends GroupTypeBase = GroupTypeBase + OptionType = unknown, + IsMulti extends boolean = boolean, + GroupType extends GroupBase = GroupBase >(): ControlProps { return {} as ControlProps; } -export function mockReactSelectIndicatorProps< - OptionType extends OptionTypeBase, - IsMulti extends boolean, - GroupType extends GroupTypeBase = GroupTypeBase ->(_option: OptionType): IndicatorProps { - return {} as IndicatorProps; +export function mockReactSelectClearIndicatorProps< + OptionType = unknown, + IsMulti extends boolean = boolean, + GroupType extends GroupBase = GroupBase +>(_option: OptionType): ClearIndicatorProps { + return { getStyles: () => {} } as unknown as ClearIndicatorProps; +} + +export function mockReactSelectDropdownIndicatorProps< + OptionType = unknown, + IsMulti extends boolean = boolean, + GroupType extends GroupBase = GroupBase +>(_option: OptionType): DropdownIndicatorProps { + return {} as DropdownIndicatorProps; } diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock index a35c81616c1..c1d43e4a636 100644 --- a/server/sonar-web/yarn.lock +++ b/server/sonar-web/yarn.lock @@ -681,7 +681,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7": +"@babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7": version: 7.16.3 resolution: "@babel/runtime@npm:7.16.3" dependencies: @@ -918,7 +918,7 @@ __metadata: languageName: node linkType: hard -"@emotion/cache@npm:^11.4.0, @emotion/cache@npm:^11.6.0": +"@emotion/cache@npm:^11.4.0": version: 11.6.0 resolution: "@emotion/cache@npm:11.6.0" dependencies: @@ -941,13 +941,6 @@ __metadata: languageName: node linkType: hard -"@emotion/hash@npm:^0.8.0": - version: 0.8.0 - resolution: "@emotion/hash@npm:0.8.0" - checksum: 4b35d88a97e67275c1d990c96d3b0450451d089d1508619488fc0acb882cb1ac91e93246d471346ebd1b5402215941ef4162efe5b51534859b39d8b3a0e3ffaa - languageName: node - linkType: hard - "@emotion/hash@npm:^0.9.0": version: 0.9.0 resolution: "@emotion/hash@npm:0.9.0" @@ -999,7 +992,7 @@ __metadata: languageName: node linkType: hard -"@emotion/react@npm:11.10.5": +"@emotion/react@npm:11.10.5, @emotion/react@npm:^11.8.1": version: 11.10.5 resolution: "@emotion/react@npm:11.10.5" dependencies: @@ -1023,42 +1016,6 @@ __metadata: languageName: node linkType: hard -"@emotion/react@npm:^11.1.1": - version: 11.6.0 - resolution: "@emotion/react@npm:11.6.0" - dependencies: - "@babel/runtime": ^7.13.10 - "@emotion/cache": ^11.6.0 - "@emotion/serialize": ^1.0.2 - "@emotion/sheet": ^1.1.0 - "@emotion/utils": ^1.0.0 - "@emotion/weak-memoize": ^0.2.5 - hoist-non-react-statics: ^3.3.1 - peerDependencies: - "@babel/core": ^7.0.0 - react: ">=16.8.0" - peerDependenciesMeta: - "@babel/core": - optional: true - "@types/react": - optional: true - checksum: 4fb2d108dc32716d1f162026ac5fdbd0662e3b435a34fb324629d72bb6bff61b18ac8975b51457c16ffa41543bade5d07558566ab76420b3926fbb9159441232 - languageName: node - linkType: hard - -"@emotion/serialize@npm:^1.0.0, @emotion/serialize@npm:^1.0.2": - version: 1.0.2 - resolution: "@emotion/serialize@npm:1.0.2" - dependencies: - "@emotion/hash": ^0.8.0 - "@emotion/memoize": ^0.7.4 - "@emotion/unitless": ^0.7.5 - "@emotion/utils": ^1.0.0 - csstype: ^3.0.2 - checksum: ff84fbe09ec06e7ad3deaef5c5b5ea6af6a522e8efe49c2b398b875d06872626284a83b6b18b7f777750c94264a61e7924157d869d9bca2f675731bbb91a6055 - languageName: node - linkType: hard - "@emotion/serialize@npm:^1.1.1": version: 1.1.1 resolution: "@emotion/serialize@npm:1.1.1" @@ -1109,13 +1066,6 @@ __metadata: languageName: node linkType: hard -"@emotion/unitless@npm:^0.7.5": - version: 0.7.5 - resolution: "@emotion/unitless@npm:0.7.5" - checksum: f976e5345b53fae9414a7b2e7a949aa6b52f8bdbcc84458b1ddc0729e77ba1d1dfdff9960e0da60183877873d3a631fa24d9695dd714ed94bcd3ba5196586a6b - languageName: node - linkType: hard - "@emotion/unitless@npm:^0.8.0": version: 0.8.0 resolution: "@emotion/unitless@npm:0.8.0" @@ -1331,6 +1281,22 @@ __metadata: languageName: node linkType: hard +"@floating-ui/core@npm:^1.1.0": + version: 1.1.1 + resolution: "@floating-ui/core@npm:1.1.1" + checksum: a8497bf981eedf652d275f7207342a9b24c1a67909dca9e042e2379b24321e6688c7774415f3ea607c466adf82b02d8779513f449376c46b2982f2380c80cd35 + languageName: node + linkType: hard + +"@floating-ui/dom@npm:^1.0.1": + version: 1.1.1 + resolution: "@floating-ui/dom@npm:1.1.1" + dependencies: + "@floating-ui/core": ^1.1.0 + checksum: 8b7f3b98ed7ec0b634e4a0b735253b0442358c5cea8302935fc185b2bd882202a053622abe9248c76d0908645dd35f93adeaed2d64371b2ab76b36725ce3f7d3 + languageName: node + linkType: hard + "@formatjs/intl-displaynames@npm:^1.2.0": version: 1.2.10 resolution: "@formatjs/intl-displaynames@npm:1.2.10" @@ -2466,24 +2432,12 @@ __metadata: languageName: node linkType: hard -"@types/react-select@npm:4.0.18": - version: 4.0.18 - resolution: "@types/react-select@npm:4.0.18" - dependencies: - "@emotion/serialize": ^1.0.0 - "@types/react": "*" - "@types/react-dom": "*" - "@types/react-transition-group": "*" - checksum: c247c7fe45cc1d1db1fb0e5a569e288037081ed05d17f377376de82a58a5d334bb7282922ee5eaf3c30957437b028097235be81cb0bed905b3b73f9a5b8c7b58 - languageName: node - linkType: hard - -"@types/react-transition-group@npm:*": - version: 4.4.4 - resolution: "@types/react-transition-group@npm:4.4.4" +"@types/react-transition-group@npm:^4.4.0": + version: 4.4.5 + resolution: "@types/react-transition-group@npm:4.4.5" dependencies: "@types/react": "*" - checksum: 86e9ff9731798e12bc2afe0304678918769633b531dcf6397f86af81718fb7930ef8648e894eeb3718fc6eab6eb885cfb9b82a44d1d74e10951ee11ebc4643ae + checksum: 265f1c74061556708ffe8d15559e35c60d6c11478c9950d3735575d2c116ca69f461d85effa06d73a613eb8b73c84fd32682feb57cf7c5f9e4284021dbca25b0 languageName: node linkType: hard @@ -2859,7 +2813,6 @@ __metadata: "@types/react-dom": 16.9.17 "@types/react-helmet": 6.1.6 "@types/react-modal": 3.13.1 - "@types/react-select": 4.0.18 "@types/react-virtualized": 9.21.21 "@types/valid-url": 1.0.3 "@typescript-eslint/eslint-plugin": 5.49.0 @@ -2914,7 +2867,7 @@ __metadata: react-intl: 3.12.1 react-modal: 3.16.1 react-router-dom: 6.7.0 - react-select: 4.3.1 + react-select: 5.7.0 react-select-event: 5.5.1 react-virtualized: 9.22.3 regenerator-runtime: 0.13.11 @@ -7480,10 +7433,10 @@ __metadata: languageName: node linkType: hard -"memoize-one@npm:^5.0.0": - version: 5.2.1 - resolution: "memoize-one@npm:5.2.1" - checksum: a3cba7b824ebcf24cdfcd234aa7f86f3ad6394b8d9be4c96ff756dafb8b51c7f71320785fbc2304f1af48a0467cbbd2a409efc9333025700ed523f254cb52e3d +"memoize-one@npm:^6.0.0": + version: 6.0.0 + resolution: "memoize-one@npm:6.0.0" + checksum: f185ea69f7cceae5d1cb596266dcffccf545e8e7b4106ec6aa93b71ab9d16460dd118ac8b12982c55f6d6322fcc1485de139df07eacffaae94888b9b3ad7675f languageName: node linkType: hard @@ -8395,7 +8348,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:^15.5.8, prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2": +"prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2": version: 15.7.2 resolution: "prop-types@npm:15.7.2" dependencies: @@ -8531,17 +8484,6 @@ __metadata: languageName: node linkType: hard -"react-input-autosize@npm:^3.0.0": - version: 3.0.0 - resolution: "react-input-autosize@npm:3.0.0" - dependencies: - prop-types: ^15.5.8 - peerDependencies: - react: ^16.3.0 || ^17.0.0 - checksum: cc3309ddc87446ade742c7d0e88ef089dd8b6981f21506a2bb27daf01a8803ac697f64157c4ffc7e81dfcf3892b54a4072dbc3652fd9addcf6d22dd0b87ab723 - languageName: node - linkType: hard - "react-intl@npm:3.12.1": version: 3.12.1 resolution: "react-intl@npm:3.12.1" @@ -8654,21 +8596,23 @@ __metadata: languageName: node linkType: hard -"react-select@npm:4.3.1": - version: 4.3.1 - resolution: "react-select@npm:4.3.1" +"react-select@npm:5.7.0": + version: 5.7.0 + resolution: "react-select@npm:5.7.0" dependencies: "@babel/runtime": ^7.12.0 "@emotion/cache": ^11.4.0 - "@emotion/react": ^11.1.1 - memoize-one: ^5.0.0 + "@emotion/react": ^11.8.1 + "@floating-ui/dom": ^1.0.1 + "@types/react-transition-group": ^4.4.0 + memoize-one: ^6.0.0 prop-types: ^15.6.0 - react-input-autosize: ^3.0.0 react-transition-group: ^4.3.0 + use-isomorphic-layout-effect: ^1.1.2 peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - checksum: e87e0b42a662ddce7957a69a3029ea769b22264c197cbd1d8bde1ce631e49c5c5f42414773364674a7a6a8431340e1ede49220583bf1dcd966b63e9bd25cfc12 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 3d29f7bb6dd66ad55396d820f05da6112f1d21b67526422a8ff5aa6cd47c783804c1b73042ac2949ba0871056a3dc68c06a73a8281abb61571e475d72bbd80dc languageName: node linkType: hard @@ -9907,6 +9851,18 @@ __metadata: languageName: node linkType: hard +"use-isomorphic-layout-effect@npm:^1.1.2": + version: 1.1.2 + resolution: "use-isomorphic-layout-effect@npm:1.1.2" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: a6532f7fc9ae222c3725ff0308aaf1f1ddbd3c00d685ef9eee6714fd0684de5cb9741b432fbf51e61a784e2955424864f7ea9f99734a02f237b17ad3e18ea5cb + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2"