diff options
author | Guillaume Peoc'h <guillaume.peoch@sonarsource.com> | 2022-04-01 14:10:42 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-04-05 20:03:16 +0000 |
commit | 58bb357d33d2813fd00b7f1345db18df3503a6be (patch) | |
tree | e81707955bf62f0818a218d152c2e41f9fa045b9 /server/sonar-web/src | |
parent | 052a4458e6225349fedb8a6ebd03347cd12a4753 (diff) | |
download | sonarqube-58bb357d33d2813fd00b7f1345db18df3503a6be.tar.gz sonarqube-58bb357d33d2813fd00b7f1345db18df3503a6be.zip |
SONAR-16225 Update SelectLegacy in /quality-gates
Diffstat (limited to 'server/sonar-web/src')
5 files changed, 117 insertions, 73 deletions
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/MetricSelect.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/MetricSelect.tsx index ce6879efa16..7ff3701a4ba 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/MetricSelect.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/MetricSelect.tsx @@ -20,7 +20,7 @@ import { sortBy } from 'lodash'; import * as React from 'react'; import withMetricsContext from '../../../app/components/metrics/withMetricsContext'; -import SelectLegacy from '../../../components/controls/SelectLegacy'; +import Select from '../../../components/controls/Select'; import { getLocalizedMetricDomain, translate } from '../../../helpers/l10n'; import { Dict, Metric } from '../../../types/types'; import { getLocalizedMetricNameNoDiffMetric } from '../utils'; @@ -76,13 +76,13 @@ export class MetricSelectComponent extends React.PureComponent<Props> { }); return ( - <SelectLegacy + <Select className="text-middle quality-gate-metric-select" id="condition-metric" onChange={this.handleChange} options={optionsWithDomains} placeholder={translate('search.search_for_metrics')} - value={metric && metric.key} + value={optionsWithDomains.find(o => o.value === metric?.key)} /> ); } 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 ea2f2fbd70c..47c6190c801 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 @@ -17,10 +17,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { identity, omit } from 'lodash'; import * as React from 'react'; +import { components, ControlProps, OptionProps, SingleValueProps } from 'react-select'; import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons'; import Modal from '../../../components/controls/Modal'; -import SelectLegacy from '../../../components/controls/SelectLegacy'; +import Select from '../../../components/controls/Select'; import GroupIcon from '../../../components/icons/GroupIcon'; import Avatar from '../../../components/ui/Avatar'; import { translate } from '../../../helpers/l10n'; @@ -31,7 +33,7 @@ export interface QualityGatePermissionsAddModalRendererProps { onClose: () => void; onInputChange: (query: string) => void; onSubmit: (event: React.SyntheticEvent<HTMLFormElement>) => void; - onSelection: (selection: UserBase | Group) => void; + onSelection: (selection: Option) => void; submitting: boolean; loading: boolean; query: string; @@ -39,7 +41,7 @@ export interface QualityGatePermissionsAddModalRendererProps { selection?: UserBase | Group; } -type Option = (UserBase | Group) & { value: string }; +export type Option = (UserBase | Group) & { value: string }; export default function QualityGatePermissionsAddModalRenderer( props: QualityGatePermissionsAddModalRendererProps @@ -50,6 +52,8 @@ export default function QualityGatePermissionsAddModalRenderer( const noResultsText = translate('no_results'); + const options = searchResults.map(r => ({ ...r, value: getValue(r) })); + return ( <Modal contentLabel={header} onRequestClose={props.onClose}> <header className="modal-head"> @@ -59,22 +63,24 @@ export default function QualityGatePermissionsAddModalRenderer( <div className="modal-body"> <div className="modal-field"> <label>{translate('quality_gates.permissions.search')}</label> - <SelectLegacy - autoFocus={true} + <Select className="Select-big" - clearable={false} - // disable default react-select filtering - filterOptions={i => i} + autoFocus={true} + isClearable={false} + isSearchable={true} + placeholder="" isLoading={loading} - noResultsText={noResultsText} + filterOptions={identity} + noOptionsMessage={() => noResultsText} onChange={props.onSelection} onInputChange={props.onInputChange} - optionRenderer={optionRenderer} - options={searchResults.map(r => ({ ...r, value: isUser(r) ? r.login : r.name }))} - placeholder="" - searchable={true} - value={selection} - valueRenderer={optionRenderer} + components={{ + Option: optionRenderer, + SingleValue: singleValueRenderer, + Control: controlRenderer + }} + options={options} + value={options.find(o => o.value === (selection && getValue(selection)))} /> </div> </div> @@ -88,7 +94,11 @@ export default function QualityGatePermissionsAddModalRenderer( ); } -function optionRenderer(option: Option) { +function getValue(option: UserBase | Group) { + return isUser(option) ? option.login : option.name; +} + +export function customOptions(option: Option) { return ( <> {isUser(option) ? ( @@ -101,3 +111,27 @@ function optionRenderer(option: Option) { </> ); } + +function optionRenderer(props: OptionProps<Option, false>) { + return ( + <components.Option {...props} className="Select-option"> + {customOptions(props.data)} + </components.Option> + ); +} + +function singleValueRenderer(props: SingleValueProps<Option>) { + return ( + <components.SingleValue {...props} className="Select-value-label"> + {customOptions(props.data)} + </components.SingleValue> + ); +} + +function controlRenderer(props: ControlProps<Option, false>) { + return ( + <components.Control {...omit(props, ['children'])} className="abs-height-100 Select-control"> + {props.children} + </components.Control> + ); +} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App-it.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App-it.tsx index 8aada4ac303..612607f9c19 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App-it.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App-it.tsx @@ -19,6 +19,7 @@ */ import { screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import selectEvent from 'react-select-event'; import { QualityGatesServiceMock } from '../../../../api/mocks/QualityGatesServiceMock'; import { mockAppState } from '../../../../helpers/testMocks'; import { renderApp } from '../../../../helpers/testReactTestingUtils'; @@ -146,8 +147,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 user.click(dialog.getByRole('combobox')); - await user.click(dialog.getByRole('option', { name: 'Issues' })); + await selectEvent.select(dialog.getByRole('textbox'), ['Issues']); await user.click(dialog.getByRole('textbox', { name: 'quality_gates.conditions.value' })); await user.keyboard('12{Enter}'); @@ -161,9 +161,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 user.click(dialog.getByLabelText('quality_gates.conditions.fails_when')); - await user.click(dialog.getByRole('option', { name: 'Info Issues' })); + await selectEvent.select(dialog.getByRole('textbox'), ['Info Issues']); await user.click(dialog.getByRole('radio', { name: 'quality_gates.conditions.overall_code' })); await user.click(dialog.getByLabelText('quality_gates.conditions.operator')); @@ -183,8 +181,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 user.click(dialog.getByLabelText('quality_gates.conditions.fails_when')); - await user.click(dialog.getByRole('option', { name: 'Maintainability Rating' })); + await selectEvent.select(dialog.getByRole('textbox'), ['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' })); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsAddModalRenderer-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsAddModalRenderer-test.tsx index 9e10425c133..da50d58ab68 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsAddModalRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsAddModalRenderer-test.tsx @@ -19,9 +19,9 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import SelectLegacy from '../../../../components/controls/SelectLegacy'; import { mockUserBase } from '../../../../helpers/mocks/users'; import QualityGatePermissionsAddModalRenderer, { + customOptions, QualityGatePermissionsAddModalRendererProps } from '../QualityGatePermissionsAddModalRenderer'; @@ -38,12 +38,10 @@ it('should render correctly', () => { }); it('should render options correctly', () => { - const wrapper = shallowRender(); - - const { optionRenderer = () => null } = wrapper.find(SelectLegacy).props(); - - expect(optionRenderer({ avatar: 'A', name: 'name', login: 'login' })).toMatchSnapshot('user'); - expect(optionRenderer({ name: 'group name' })).toMatchSnapshot('group'); + expect( + customOptions({ avatar: 'A', name: 'name', login: 'login', value: 'login' }) + ).toMatchSnapshot('user'); + expect(customOptions({ name: 'group name', value: 'group name' })).toMatchSnapshot('group'); }); function shallowRender(overrides: Partial<QualityGatePermissionsAddModalRendererProps> = {}) { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModalRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModalRenderer-test.tsx.snap index 5994dbc36f5..f11d813ff89 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModalRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModalRenderer-test.tsx.snap @@ -24,20 +24,25 @@ exports[`should render correctly: default 1`] = ` <label> quality_gates.permissions.search </label> - <SelectLegacy + <Select autoFocus={true} className="Select-big" - clearable={false} + components={ + Object { + "Control": [Function], + "Option": [Function], + "SingleValue": [Function], + } + } filterOptions={[Function]} + isClearable={false} isLoading={false} - noResultsText="no_results" + isSearchable={true} + noOptionsMessage={[Function]} onChange={[MockFunction]} onInputChange={[MockFunction]} - optionRenderer={[Function]} options={Array []} placeholder="" - searchable={true} - valueRenderer={[Function]} /> </div> </div> @@ -83,16 +88,23 @@ exports[`should render correctly: query and results 1`] = ` <label> quality_gates.permissions.search </label> - <SelectLegacy + <Select autoFocus={true} className="Select-big" - clearable={false} + components={ + Object { + "Control": [Function], + "Option": [Function], + "SingleValue": [Function], + } + } filterOptions={[Function]} + isClearable={false} isLoading={false} - noResultsText="no_results" + isSearchable={true} + noOptionsMessage={[Function]} onChange={[MockFunction]} onInputChange={[MockFunction]} - optionRenderer={[Function]} options={ Array [ Object { @@ -106,8 +118,6 @@ exports[`should render correctly: query and results 1`] = ` ] } placeholder="" - searchable={true} - valueRenderer={[Function]} /> </div> </div> @@ -153,25 +163,25 @@ exports[`should render correctly: selection 1`] = ` <label> quality_gates.permissions.search </label> - <SelectLegacy + <Select autoFocus={true} className="Select-big" - clearable={false} + components={ + Object { + "Control": [Function], + "Option": [Function], + "SingleValue": [Function], + } + } filterOptions={[Function]} + isClearable={false} isLoading={false} - noResultsText="no_results" + isSearchable={true} + noOptionsMessage={[Function]} onChange={[MockFunction]} onInputChange={[MockFunction]} - optionRenderer={[Function]} options={Array []} placeholder="" - searchable={true} - value={ - Object { - "login": "userlogin", - } - } - valueRenderer={[Function]} /> </div> </div> @@ -217,20 +227,25 @@ exports[`should render correctly: short query 1`] = ` <label> quality_gates.permissions.search </label> - <SelectLegacy + <Select autoFocus={true} className="Select-big" - clearable={false} + components={ + Object { + "Control": [Function], + "Option": [Function], + "SingleValue": [Function], + } + } filterOptions={[Function]} + isClearable={false} isLoading={false} - noResultsText="no_results" + isSearchable={true} + noOptionsMessage={[Function]} onChange={[MockFunction]} onInputChange={[MockFunction]} - optionRenderer={[Function]} options={Array []} placeholder="" - searchable={true} - valueRenderer={[Function]} /> </div> </div> @@ -276,25 +291,25 @@ exports[`should render correctly: submitting 1`] = ` <label> quality_gates.permissions.search </label> - <SelectLegacy + <Select autoFocus={true} className="Select-big" - clearable={false} + components={ + Object { + "Control": [Function], + "Option": [Function], + "SingleValue": [Function], + } + } filterOptions={[Function]} + isClearable={false} isLoading={false} - noResultsText="no_results" + isSearchable={true} + noOptionsMessage={[Function]} onChange={[MockFunction]} onInputChange={[MockFunction]} - optionRenderer={[Function]} options={Array []} placeholder="" - searchable={true} - value={ - Object { - "login": "userlogin", - } - } - valueRenderer={[Function]} /> </div> </div> |