diff options
author | Philippe Perrin <philippe.perrin@sonarsource.com> | 2022-03-31 10:55:12 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-04-13 20:03:17 +0000 |
commit | b3421b53d4da4ae97625a5e147d8f1fe06af0251 (patch) | |
tree | d9502c539669dc7ba394e2c1025e9c4867867f9c /server/sonar-web/src | |
parent | 5c723a09143638c367c18c81a556c7f8d72fa74b (diff) | |
download | sonarqube-b3421b53d4da4ae97625a5e147d8f1fe06af0251.tar.gz sonarqube-b3421b53d4da4ae97625a5e147d8f1fe06af0251.zip |
SONAR-16191 Improve ITs for react-select and remove legacy css
Diffstat (limited to 'server/sonar-web/src')
33 files changed, 115 insertions, 817 deletions
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 e663e2482f2..d2a3fb1e650 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 @@ -109,7 +109,7 @@ export class BadgeParams extends React.PureComponent<Props> { {translate('overview.badges.metric')}: </label> <Select - className="input-medium it__badge-metric" + className="input-medium it__metric-badge-select" name="badge-metric" isSearchable={false} onChange={this.handleMetricChange} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/__tests__/__snapshots__/BadgeParams-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/__tests__/__snapshots__/BadgeParams-test.tsx.snap index 5134dcb90da..d781ec5fd07 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/__tests__/__snapshots__/BadgeParams-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/__tests__/__snapshots__/BadgeParams-test.tsx.snap @@ -10,7 +10,7 @@ exports[`should display measure badge params 1`] = ` : </label> <Select - className="input-medium it__badge-metric" + className="input-medium it__metric-badge-select" isSearchable={false} name="badge-metric" onChange={[Function]} diff --git a/server/sonar-web/src/main/js/app/styles/init/forms.css b/server/sonar-web/src/main/js/app/styles/init/forms.css index 8e0cc9da596..e601bd697e7 100644 --- a/server/sonar-web/src/main/js/app/styles/init/forms.css +++ b/server/sonar-web/src/main/js/app/styles/init/forms.css @@ -81,8 +81,7 @@ input[type='search'].is-valid, input[type='date'].is-valid, input[type='number'].is-valid, textarea.is-valid, -select.is-valid, -.is-valid > .Select-control { +select.is-valid { border-color: var(--green); } @@ -93,8 +92,7 @@ input[type='search'].is-invalid, input[type='date'].is-invalid, input[type='number'].is-invalid, textarea.is-invalid, -select.is-invalid, -.is-invalid > .Select-control { +select.is-invalid { border-color: var(--red); } diff --git a/server/sonar-web/src/main/js/app/styles/style.css b/server/sonar-web/src/main/js/app/styles/style.css index 4244e287433..5fc30094730 100644 --- a/server/sonar-web/src/main/js/app/styles/style.css +++ b/server/sonar-web/src/main/js/app/styles/style.css @@ -232,15 +232,6 @@ code.rule { margin: 10px; } -.width100 { - width: 100%; -} - -textarea.width100 { - width: 100%; - box-sizing: border-box; -} - .property { margin-bottom: 10px; } 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 baab266c94e..a18659665cf 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 @@ -167,12 +167,12 @@ export default class ActivationFormModal extends React.PureComponent<Props, Stat )} <div className="modal-field"> - <label id="coding-rules-quality-profile-select"> + <label id="coding-rules-quality-profile-select-label"> {translate('coding_rules.quality_profile')} </label> <Select - className="js-profile" - aria-labelledby="coding-rules-quality-profile-select" + aria-labelledby="coding-rules-quality-profile-select-label" + id="coding-rules-quality-profile-select" isClearable={false} isDisabled={submitting || profilesWithDepth.length === 1} onChange={this.handleProfileChange} 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 def50c057d9..353da2fbd7f 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 @@ -56,7 +56,6 @@ export function SeveritySelect(props: SeveritySelectProps) { return ( <Select - className="js-severity" aria-labelledby={ariaLabelledby} isDisabled={isDisabled} onChange={props.onChange} diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/ActivationFormModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/ActivationFormModal-test.tsx.snap index 8806948181a..34691d7a35c 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/ActivationFormModal-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/ActivationFormModal-test.tsx.snap @@ -28,14 +28,14 @@ exports[`should render correctly: custom rule 1`] = ` className="modal-field" > <label - id="coding-rules-quality-profile-select" + id="coding-rules-quality-profile-select-label" > coding_rules.quality_profile </label> <Select - aria-labelledby="coding-rules-quality-profile-select" - className="js-profile" + aria-labelledby="coding-rules-quality-profile-select-label" getOptionLabel={[Function]} + id="coding-rules-quality-profile-select" isClearable={false} isDisabled={false} onChange={[Function]} @@ -114,14 +114,14 @@ exports[`should render correctly: default 1`] = ` className="modal-field" > <label - id="coding-rules-quality-profile-select" + id="coding-rules-quality-profile-select-label" > coding_rules.quality_profile </label> <Select - aria-labelledby="coding-rules-quality-profile-select" - className="js-profile" + aria-labelledby="coding-rules-quality-profile-select-label" getOptionLabel={[Function]} + id="coding-rules-quality-profile-select" isClearable={false} isDisabled={false} onChange={[Function]} @@ -235,14 +235,14 @@ exports[`should render correctly: submitting 1`] = ` className="modal-field" > <label - id="coding-rules-quality-profile-select" + id="coding-rules-quality-profile-select-label" > coding_rules.quality_profile </label> <Select - aria-labelledby="coding-rules-quality-profile-select" - className="js-profile" + aria-labelledby="coding-rules-quality-profile-select-label" getOptionLabel={[Function]} + id="coding-rules-quality-profile-select" isClearable={false} isDisabled={true} onChange={[Function]} @@ -354,14 +354,14 @@ exports[`should render correctly: update mode 1`] = ` className="modal-field" > <label - id="coding-rules-quality-profile-select" + id="coding-rules-quality-profile-select-label" > coding_rules.quality_profile </label> <Select - aria-labelledby="coding-rules-quality-profile-select" - className="js-profile" + aria-labelledby="coding-rules-quality-profile-select-label" getOptionLabel={[Function]} + id="coding-rules-quality-profile-select" isClearable={false} isDisabled={false} onChange={[Function]} @@ -470,14 +470,14 @@ exports[`should render correctly: with deep profiles 1`] = ` className="modal-field" > <label - id="coding-rules-quality-profile-select" + id="coding-rules-quality-profile-select-label" > coding_rules.quality_profile </label> <Select - aria-labelledby="coding-rules-quality-profile-select" - className="js-profile" + aria-labelledby="coding-rules-quality-profile-select-label" getOptionLabel={[Function]} + id="coding-rules-quality-profile-select" isClearable={false} isDisabled={true} onChange={[Function]} diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx index 2cf7d042a1a..9ae8fb49949 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx @@ -18,9 +18,9 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import Select from '../../../../components/controls/Select'; import { applyTemplateToProject, getPermissionTemplates } from '../../../../api/permissions'; import { ResetButtonLink, SubmitButton } from '../../../../components/controls/buttons'; +import Select from '../../../../components/controls/Select'; import SimpleModal from '../../../../components/controls/SimpleModal'; import { Alert } from '../../../../components/ui/Alert'; import DeferredSpinner from '../../../../components/ui/DeferredSpinner'; @@ -28,7 +28,6 @@ import MandatoryFieldMarker from '../../../../components/ui/MandatoryFieldMarker import MandatoryFieldsExplanation from '../../../../components/ui/MandatoryFieldsExplanation'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; import { PermissionTemplate } from '../../../../types/types'; -import { components, OptionProps } from 'react-select'; interface Props { onApply?: () => void; @@ -56,11 +55,6 @@ export default class ApplyTemplate extends React.PureComponent<Props, State> { this.mounted = false; } - optionRenderer = (props: OptionProps<{ value: string }, false>) => ( - // This class is added for the integration test. - <components.Option {...props} className="Select-option" /> - ); - fetchPermissionTemplates = () => { getPermissionTemplates().then( ({ permissionTemplates }) => { @@ -144,9 +138,6 @@ export default class ApplyTemplate extends React.PureComponent<Props, State> { className="Select" inputId="project-permissions-template-input" onChange={this.handlePermissionTemplateChange} - components={{ - Option: this.optionRenderer - }} options={options} value={options.filter(o => o.value === this.state.permissionTemplate)} /> diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx index d40525860c5..65edfd756ba 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx @@ -19,7 +19,6 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { mockReactSelectOptionProps } from '../../../../../helpers/mocks/react-select'; import { waitAndUpdate } from '../../../../../helpers/testUtils'; import ApplyTemplate from '../ApplyTemplate'; @@ -52,13 +51,3 @@ it('render correctly', async () => { await waitAndUpdate(wrapper); expect(wrapper.dive()).toMatchSnapshot(); }); - -it('should render option correctly', () => { - const wrapper = shallow<ApplyTemplate>( - <ApplyTemplate onClose={jest.fn()} project={{ key: 'foo', name: 'Foo' }} /> - ); - const OptionRendererer = wrapper.instance().optionRenderer; - expect( - shallow(<OptionRendererer {...mockReactSelectOptionProps({ value: 'val' })} />) - ).toMatchSnapshot('option renderer'); -}); diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/ApplyTemplate-test.tsx.snap b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/ApplyTemplate-test.tsx.snap index 0ceb14c4882..ac0f0a062e0 100644 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/ApplyTemplate-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/ApplyTemplate-test.tsx.snap @@ -45,11 +45,6 @@ exports[`render correctly 2`] = ` </label> <Select className="Select" - components={ - Object { - "Option": [Function], - } - } id="project-permissions-template" inputId="project-permissions-template-input" onChange={[Function]} @@ -86,14 +81,3 @@ exports[`render correctly 2`] = ` </form> </Modal> `; - -exports[`should render option correctly: option renderer 1`] = ` -<Option - className="Select-option" - data={ - Object { - "value": "val", - } - } -/> -`; diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx index 1fc7c467d40..985c9cae082 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx @@ -72,14 +72,13 @@ export default function PageHeader(props: Props) { <div className="display-flex-center"> <PerspectiveSelect - className="projects-topbar-item js-projects-perspective-select" + className="projects-topbar-item" onChange={props.onPerspectiveChange} view={view} /> <div className={classNames('projects-topbar-item')}> <ProjectsSortingSelect - className="js-projects-sorting-select" defaultOption={defaultOption} onChange={props.onSortChange} selectedSort={props.selectedSort} diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap index 7d4af9871aa..d4ebab4d137 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap @@ -56,7 +56,7 @@ exports[`should render correctly 1`] = ` className="display-flex-center" > <PerspectiveSelect - className="projects-topbar-item js-projects-perspective-select" + className="projects-topbar-item" onChange={[MockFunction]} view="overall" /> @@ -64,7 +64,6 @@ exports[`should render correctly 1`] = ` className="projects-topbar-item" > <ProjectsSortingSelect - className="js-projects-sorting-select" defaultOption="analysis_date" onChange={[MockFunction]} selectedSort="size" @@ -132,7 +131,7 @@ exports[`should render correctly while loading 1`] = ` className="display-flex-center" > <PerspectiveSelect - className="projects-topbar-item js-projects-perspective-select" + className="projects-topbar-item" onChange={[MockFunction]} view="overall" /> @@ -140,7 +139,6 @@ exports[`should render correctly while loading 1`] = ` className="projects-topbar-item" > <ProjectsSortingSelect - className="js-projects-sorting-select" defaultOption="analysis_date" onChange={[MockFunction]} selectedSort="size" @@ -154,7 +152,6 @@ exports[`should render correctly while loading 1`] = ` exports[`should render switch the default sorting option for anonymous users 1`] = ` <ProjectsSortingSelect - className="js-projects-sorting-select" defaultOption="name" onChange={[MockFunction]} selectedSort="size" @@ -164,7 +161,6 @@ exports[`should render switch the default sorting option for anonymous users 1`] exports[`should render switch the default sorting option for anonymous users 2`] = ` <ProjectsSortingSelect - className="js-projects-sorting-select" defaultOption="analysis_date" onChange={[MockFunction]} selectedSort="size" diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx index db7a854de11..cfe93e04d91 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx @@ -18,13 +18,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { components, InputProps, OptionProps } from 'react-select'; import Select from '../../../components/controls/Select'; import { translate } from '../../../helpers/l10n'; import { Dict, RawQuery } from '../../../types/types'; interface Props { - isFavorite?: boolean; isLoading?: boolean; onInputChange?: (query: string) => void; onOpen?: () => void; @@ -40,17 +38,6 @@ export default class SearchableFilterFooter extends React.PureComponent<Props> { this.props.onQueryChange({ [this.props.property]: urlOptions }); }; - optionRenderer = (props: OptionProps<{ value: string }, false>) => ( - <components.Option - {...props} - className={'Select-option ' + (props.isFocused ? 'is-focused' : '')} - /> - ); - - inputRenderer = (props: InputProps) => ( - <components.Input {...props} className="it__searchable-footer-select-input" /> - ); - render() { return ( <div className="search-navigator-facet-footer projects-facet-footer"> @@ -60,10 +47,6 @@ export default class SearchableFilterFooter extends React.PureComponent<Props> { onChange={this.handleOptionChange} onInputChange={this.props.onInputChange} onOpen={this.props.onOpen} - components={{ - Option: this.optionRenderer, - Input: this.inputRenderer - }} options={this.props.options} placeholder={translate('search_verb')} /> 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 2568a0ced0e..bb2c4c8e841 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 @@ -20,10 +20,6 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { SelectComponentsProps } from 'react-select/src/Select'; -import { - mockReactSelectInputProps, - mockReactSelectOptionProps -} from '../../../../helpers/mocks/react-select'; import Select from '../../../../components/controls/Select'; import SearchableFilterFooter from '../SearchableFilterFooter'; @@ -58,22 +54,3 @@ it('should properly handle a change of the facet value', () => { wrapper.find(Select).simulate('change', { value: 'js' }); expect(onQueryChange).toBeCalledWith({ languages: 'java,js' }); }); - -it('renders optionrenderer and inputrenderer', () => { - const wrapper = shallow<SearchableFilterFooter>( - <SearchableFilterFooter - onQueryChange={jest.fn()} - options={options} - property="languages" - query={{ languages: ['java'] }} - /> - ); - const OptionRendererer = wrapper.instance().optionRenderer; - const InputRendererer = wrapper.instance().inputRenderer; - expect( - shallow(<OptionRendererer {...mockReactSelectOptionProps({ value: 'val' })} />) - ).toMatchSnapshot('option renderer'); - expect(shallow(<InputRendererer {...mockReactSelectInputProps()} />)).toMatchSnapshot( - 'input renderer' - ); -}); diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchableFilterFooter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchableFilterFooter-test.tsx.snap index 1da4f7f6256..6cf27012dfd 100644 --- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchableFilterFooter-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchableFilterFooter-test.tsx.snap @@ -1,22 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`renders optionrenderer and inputrenderer: input renderer 1`] = ` -<Input - className="it__searchable-footer-select-input" -/> -`; - -exports[`renders optionrenderer and inputrenderer: option renderer 1`] = ` -<Option - className="Select-option " - data={ - Object { - "value": "val", - } - } -/> -`; - exports[`should render items without the ones in the facet 1`] = ` Array [ Object { diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx index 3ff638a1863..825254406b0 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { components, OptionProps } from 'react-select'; import { bulkApplyTemplate, getPermissionTemplates } from '../../api/permissions'; import { ResetButtonLink, SubmitButton } from '../../components/controls/buttons'; import Modal from '../../components/controls/Modal'; @@ -147,14 +146,8 @@ export default class BulkApplyTemplateModal extends React.PureComponent<Props, S <Select id="bulk-apply-template" inputId="bulk-apply-template-input" - className="Select Select-value" isDisabled={this.state.submitting} onChange={this.handlePermissionTemplateChange} - components={{ - Option: (props: OptionProps<{ value: string }, false>) => ( - <components.Option {...props} className="Select-option" /> - ) - }} options={options} value={options.find(option => option.value === this.state.permissionTemplate)} /> 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 a9990336e4d..5ab61ef5a91 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx @@ -109,9 +109,7 @@ export class Search extends React.PureComponent<Props, State> { handleVisibilityChange = ({ value }: { value: string }) => this.props.onVisibilityChanged(value); optionRenderer = (props: OptionProps<{ value: string }, false>) => ( - <components.Option {...props} className="Select-option"> - {this.renderQualifierOption(props.data)} - </components.Option> + <components.Option {...props}>{this.renderQualifierOption(props.data)}</components.Option> ); singleValueRenderer = (props: SingleValueProps<{ value: string }>) => ( @@ -153,7 +151,7 @@ export class Search extends React.PureComponent<Props, State> { return ( <td className="thin nowrap text-middle"> <Select - className="input-medium Select" + className="input-medium it__project-qualifier-select" disabled={!this.props.ready} name="projects-qualifier" onChange={this.handleQualifierChange} @@ -179,15 +177,10 @@ export class Search extends React.PureComponent<Props, State> { return ( <td className="thin nowrap text-middle"> <Select - className="input-small Select" + className="input-small" isDisabled={!this.props.ready} name="projects-visibility" onChange={this.handleVisibilityChange} - components={{ - Option: (props: OptionProps<{ value: string }, false>) => ( - <components.Option {...props} className="Select-option" /> - ) - }} options={options} isSearchable={false} value={options.find(option => option.value === (this.props.visibility || 'all'))} diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx index 7791ca3b046..c99ee490c31 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx @@ -19,9 +19,6 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { SelectComponentsProps } from 'react-select/src/Select'; -import { mockReactSelectOptionProps } from '../../../helpers/mocks/react-select'; -import Select from '../../../components/controls/Select'; import { parseDate } from '../../../helpers/dates'; import { click, waitAndUpdate } from '../../../helpers/testUtils'; import BulkApplyTemplateModal, { Props } from '../BulkApplyTemplateModal'; @@ -102,25 +99,6 @@ it('bulk applies template to selected results', async () => { expect(wrapper).toMatchSnapshot(); }); -it('renders optionrenderer', () => { - const wrapper = shallow(render({ qualifier: 'VW', selection: ['proj1', 'proj2'] })); - wrapper.setState({ - loading: false, - permissionTemplate: 'foo', - permissionTemplates: [ - { id: 'foo', name: 'Foo' }, - { id: 'bar', name: 'Bar' } - ] - }); - const wrapperSelect = wrapper.find<SelectComponentsProps>(Select); - - const { Option } = wrapperSelect.props().components; - - expect(<Option {...mockReactSelectOptionProps({ val: 'val' })} />).toMatchSnapshot( - 'option renderer' - ); -}); - it('closes', () => { const onClose = jest.fn(); const wrapper = shallow(render({ onClose })); diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap index 473486e03c0..07861fbdc29 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap @@ -66,12 +66,6 @@ exports[`bulk applies template to all results 2`] = ` <MandatoryFieldMarker /> </label> <Select - className="Select Select-value" - components={ - Object { - "Option": [Function], - } - } id="bulk-apply-template" inputId="bulk-apply-template-input" isDisabled={false} @@ -149,12 +143,6 @@ exports[`bulk applies template to all results 3`] = ` <MandatoryFieldMarker /> </label> <Select - className="Select Select-value" - components={ - Object { - "Option": [Function], - } - } id="bulk-apply-template" inputId="bulk-apply-template-input" isDisabled={true} @@ -301,12 +289,6 @@ exports[`bulk applies template to selected results 2`] = ` <MandatoryFieldMarker /> </label> <Select - className="Select Select-value" - components={ - Object { - "Option": [Function], - } - } id="bulk-apply-template" inputId="bulk-apply-template-input" isDisabled={false} @@ -384,12 +366,6 @@ exports[`bulk applies template to selected results 3`] = ` <MandatoryFieldMarker /> </label> <Select - className="Select Select-value" - components={ - Object { - "Option": [Function], - } - } id="bulk-apply-template" inputId="bulk-apply-template-input" isDisabled={true} @@ -469,13 +445,3 @@ exports[`bulk applies template to selected results 4`] = ` </footer> </Modal> `; - -exports[`renders optionrenderer: option renderer 1`] = ` -<Option - data={ - Object { - "val": "val", - } - } -/> -`; 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 37f731defa6..124df70931c 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 @@ -51,7 +51,7 @@ exports[`render qualifiers filter 1`] = ` className="thin nowrap text-middle" > <Select - className="input-medium Select" + className="input-medium it__project-qualifier-select" components={ Object { "Option": [Function], @@ -101,12 +101,7 @@ exports[`render qualifiers filter 1`] = ` className="thin nowrap text-middle" > <Select - className="input-small Select" - components={ - Object { - "Option": [Function], - } - } + className="input-small" isDisabled={false} isSearchable={false} name="projects-visibility" @@ -224,12 +219,7 @@ exports[`renders 1`] = ` className="thin nowrap text-middle" > <Select - className="input-small Select" - components={ - Object { - "Option": [Function], - } - } + className="input-small" isDisabled={false} isSearchable={false} name="projects-visibility" @@ -316,7 +306,6 @@ exports[`renders 1`] = ` exports[`renders optionrenderer and singlevaluerenderer: option renderer 1`] = ` <Option - className="Select-option" data={ Object { "value": "val", 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 7ff3701a4ba..5f9a6d21390 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 @@ -33,12 +33,12 @@ interface Props { } interface Option { - disabled?: boolean; + isDisabled?: boolean; label: string; value: string; } -export class MetricSelectComponent extends React.PureComponent<Props> { +export class MetricSelect extends React.PureComponent<Props> { handleChange = (option: Option | null) => { if (option) { const { metricsArray: metrics } = this.props; @@ -69,7 +69,7 @@ export class MetricSelectComponent extends React.PureComponent<Props> { optionsWithDomains.push({ value: '<domain>', label: getLocalizedMetricDomain(option.domain), - disabled: true + isDisabled: true }); } optionsWithDomains.push(option); @@ -88,4 +88,4 @@ export class MetricSelectComponent extends React.PureComponent<Props> { } } -export default withMetricsContext(MetricSelectComponent); +export default withMetricsContext(MetricSelect); 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 dcd3fb8bc29..b06affa7a2a 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 @@ -58,7 +58,6 @@ export default function QualityGatePermissionsAddModalRenderer( <div className="modal-field"> <label>{translate('quality_gates.permissions.search')}</label> <SearchSelect - className="Select-big" autoFocus={true} isClearable={false} placeholder="" @@ -67,6 +66,7 @@ export default function QualityGatePermissionsAddModalRenderer( onChange={props.onSelection} loadOptions={props.handleSearch} getOptionValue={opt => (isUser(opt) ? opt.login : opt.name)} + large={true} components={{ Option: optionRenderer, SingleValue: singleValueRenderer, @@ -87,7 +87,7 @@ export default function QualityGatePermissionsAddModalRenderer( export function customOptions(option: OptionWithValue) { return ( - <> + <span className="display-flex-center"> {isUser(option) ? ( <Avatar hash={option.avatar} name={option.name} size={16} /> ) : ( @@ -95,29 +95,21 @@ export function customOptions(option: OptionWithValue) { )} <strong className="spacer-left">{option.name}</strong> {isUser(option) && <span className="note little-spacer-left">{option.login}</span>} - </> + </span> ); } function optionRenderer(props: OptionProps<OptionWithValue, false>) { - return ( - <components.Option {...props} className="Select-option"> - {customOptions(props.data)} - </components.Option> - ); + return <components.Option {...props}>{customOptions(props.data)}</components.Option>; } function singleValueRenderer(props: SingleValueProps<OptionWithValue>) { - return ( - <components.SingleValue {...props} className="Select-value-label"> - {customOptions(props.data)} - </components.SingleValue> - ); + return <components.SingleValue {...props}>{customOptions(props.data)}</components.SingleValue>; } function controlRenderer(props: ControlProps<OptionWithValue, false>) { return ( - <components.Control {...omit(props, ['children'])} className="abs-height-100 Select-control"> + <components.Control {...omit(props, ['children'])} className="abs-height-100"> {props.children} </components.Control> ); 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 d1d1f01f70b..8abba358be6 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 @@ -26,7 +26,6 @@ exports[`should render correctly: default 1`] = ` </label> <SearchSelect autoFocus={true} - className="Select-big" components={ Object { "Control": [Function], @@ -37,6 +36,7 @@ exports[`should render correctly: default 1`] = ` defaultOptions={true} getOptionValue={[Function]} isClearable={false} + large={true} loadOptions={[MockFunction]} noOptionsMessage={[Function]} onChange={[MockFunction]} @@ -88,7 +88,6 @@ exports[`should render correctly: with selection and submitting 1`] = ` </label> <SearchSelect autoFocus={true} - className="Select-big" components={ Object { "Control": [Function], @@ -99,6 +98,7 @@ exports[`should render correctly: with selection and submitting 1`] = ` defaultOptions={true} getOptionValue={[Function]} isClearable={false} + large={true} loadOptions={[MockFunction]} noOptionsMessage={[Function]} onChange={[MockFunction]} @@ -128,7 +128,9 @@ exports[`should render correctly: with selection and submitting 1`] = ` `; exports[`should render options correctly: group 1`] = ` -<React.Fragment> +<span + className="display-flex-center" +> <GroupIcon size={16} /> @@ -137,11 +139,13 @@ exports[`should render options correctly: group 1`] = ` > group name </strong> -</React.Fragment> +</span> `; exports[`should render options correctly: user 1`] = ` -<React.Fragment> +<span + className="display-flex-center" +> <withAppStateContext(Avatar) hash="A" name="name" @@ -157,5 +161,5 @@ exports[`should render options correctly: user 1`] = ` > login </span> -</React.Fragment> +</span> `; diff --git a/server/sonar-web/src/main/js/apps/quality-gates/styles.css b/server/sonar-web/src/main/js/apps/quality-gates/styles.css index 06f2d9e64b5..00f798d1f51 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/styles.css +++ b/server/sonar-web/src/main/js/apps/quality-gates/styles.css @@ -26,18 +26,6 @@ padding-top: 20px; } -.quality-gate-metric-select .Select-option { - padding-left: calc(2 * var(--gridSize)); -} - -.quality-gate-metric-select .Select-option.is-disabled { - opacity: 1; - font-weight: 600; - color: var(--baseFontColor); - padding-left: var(--gridSize); - font-style: normal; -} - .quality-gate-permissions .permission-list-item:hover { background-color: var(--rowHoverHighlight); } 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 5fb5f97cadc..902b39bec96 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 @@ -50,21 +50,15 @@ export default class ProfilePermissionsFormSelect extends React.PureComponent<Pr optionRenderer(props: OptionProps<OptionWithValue, false>) { const { data } = props; - return ( - <components.Option {...props} className="Select-option"> - {customOptions(data)} - </components.Option> - ); + return <components.Option {...props}>{customOptions(data)}</components.Option>; } singleValueRenderer = (props: SingleValueProps<OptionWithValue>) => ( - <components.SingleValue {...props} className="Select-value-label"> - {customOptions(props.data)} - </components.SingleValue> + <components.SingleValue {...props}>{customOptions(props.data)}</components.SingleValue> ); controlRenderer = (props: ControlProps<OptionWithValue, false>) => ( - <components.Control {...omit(props, ['children'])} className="abs-height-100 Select-control"> + <components.Control {...omit(props, ['children'])} className="abs-height-100"> {props.children} </components.Control> ); @@ -89,7 +83,7 @@ export default class ProfilePermissionsFormSelect extends React.PureComponent<Pr return ( <SearchSelect - className="Select-big width-100" + className="width-100" autoFocus={true} isClearable={false} id="change-profile-permission" @@ -99,6 +93,7 @@ export default class ProfilePermissionsFormSelect extends React.PureComponent<Pr loadOptions={this.handleSearch} placeholder="" noOptionsMessage={() => noResultsText} + large={true} components={{ Option: this.optionRenderer, SingleValue: this.singleValueRenderer, @@ -119,15 +114,15 @@ function getStringValue(option: Option) { function customOptions(option: OptionWithValue) { return isUser(option) ? ( - <> + <span className="display-flex-center"> <Avatar hash={option.avatar} name={option.name} size={16} /> <strong className="spacer-left">{option.name}</strong> <span className="note little-spacer-left">{option.login}</span> - </> + </span> ) : ( - <> + <span className="display-flex-center"> <GroupIcon size={16} /> <strong className="spacer-left">{option.name}</strong> - </> + </span> ); } diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap index 35b8f64412e..3aac863d757 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap @@ -2,14 +2,14 @@ exports[`should render control correctly: control renderer 1`] = ` <Control - className="abs-height-100 Select-control" + className="abs-height-100" /> `; exports[`should render correctly 1`] = ` <SearchSelect autoFocus={true} - className="Select-big width-100" + className="width-100" components={ Object { "Control": [Function], @@ -21,6 +21,7 @@ exports[`should render correctly 1`] = ` id="change-profile-permission" inputId="change-profile-permission-input" isClearable={false} + large={true} loadOptions={[Function]} noOptionsMessage={[Function]} onChange={[MockFunction]} @@ -30,7 +31,6 @@ exports[`should render correctly 1`] = ` exports[`should render option correctly: option renderer 1`] = ` <Option - className="Select-option" data={ Object { "name": "name", @@ -38,20 +38,23 @@ exports[`should render option correctly: option renderer 1`] = ` } } > - <GroupIcon - size={16} - /> - <strong - className="spacer-left" + <span + className="display-flex-center" > - name - </strong> + <GroupIcon + size={16} + /> + <strong + className="spacer-left" + > + name + </strong> + </span> </Option> `; exports[`should render value correctly: value renderer 1`] = ` <SingleValue - className="Select-value-label" data={ Object { "name": "name", @@ -59,13 +62,17 @@ exports[`should render value correctly: value renderer 1`] = ` } } > - <GroupIcon - size={16} - /> - <strong - className="spacer-left" + <span + className="display-flex-center" > - name - </strong> + <GroupIcon + size={16} + /> + <strong + className="spacer-left" + > + name + </strong> + </span> </SingleValue> `; diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListHeader.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListHeader.tsx index 24ba281de89..b605ba81f5b 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListHeader.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListHeader.tsx @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { components, OptionProps } from 'react-select'; import Select from '../../../components/controls/Select'; import { Router, withRouter } from '../../../components/hoc/withRouter'; import { translate } from '../../../helpers/l10n'; @@ -37,11 +36,6 @@ export class ProfilesListHeader extends React.PureComponent<Props> { router.replace(!option ? PROFILE_PATH : getProfilesForLanguagePath(option.value)); }; - optionRenderer = (props: OptionProps<{ value: string }, false>) => ( - // This class is added for the integration test. - <components.Option {...props} className="Select-option" /> - ); - render() { const { currentFilter, languages } = this.props; if (languages.length < 2) { @@ -65,9 +59,6 @@ export class ProfilesListHeader extends React.PureComponent<Props> { inputId="quality-profiles-filter-input" isClearable={true} onChange={this.handleChange} - components={{ - Option: this.optionRenderer - }} options={options} isSearchable={true} value={options.filter(o => o.value === currentFilter)} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx index b44c5630ac9..dcebe81d551 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx @@ -19,7 +19,6 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { mockReactSelectOptionProps } from '../../../../helpers/mocks/react-select'; import { mockRouter } from '../../../../helpers/testMocks'; import { ProfilesListHeader } from '../ProfilesListHeader'; @@ -28,14 +27,6 @@ it('should render correctly', () => { expect(wrapper).toMatchSnapshot(); }); -it('should render option correctly', () => { - const wrapper = shallowRender(); - const OptionRendererer = wrapper.instance().optionRenderer; - expect( - shallow(<OptionRendererer {...mockReactSelectOptionProps({ value: 'val' })} />) - ).toMatchSnapshot('option renderer'); -}); - function shallowRender(props: Partial<ProfilesListHeader['props']> = {}) { return shallow<ProfilesListHeader>( <ProfilesListHeader diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap index ea74d1544c7..9e1043ed52d 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap @@ -14,11 +14,6 @@ exports[`should render correctly 1`] = ` <Select autoFocus={true} className="input-medium" - components={ - Object { - "Option": [Function], - } - } id="quality-profiles-filter" inputId="quality-profiles-filter-input" isClearable={true} @@ -40,14 +35,3 @@ exports[`should render correctly 1`] = ` /> </header> `; - -exports[`should render option correctly: option renderer 1`] = ` -<Option - className="Select-option" - data={ - Object { - "value": "val", - } - } -/> -`; diff --git a/server/sonar-web/src/main/js/components/controls/Select.tsx b/server/sonar-web/src/main/js/components/controls/Select.tsx index 42862806a66..0807f4f6dee 100644 --- a/server/sonar-web/src/main/js/components/controls/Select.tsx +++ b/server/sonar-web/src/main/js/components/controls/Select.tsx @@ -19,6 +19,7 @@ */ import styled from '@emotion/styled'; import classNames from 'classnames'; +import { omit } from 'lodash'; import * as React from 'react'; import ReactSelect, { GroupTypeBase, @@ -50,6 +51,10 @@ export interface BasicSelectOption { value: string; } +interface StyleExtensionProps { + large?: boolean; +} + export function dropdownIndicator< Option extends OptionTypeBase, IsMulti extends boolean = false, @@ -94,12 +99,14 @@ export default class Select< Option, IsMulti extends boolean = false, Group extends GroupTypeBase<Option> = GroupTypeBase<Option> -> extends React.Component<Props<Option, IsMulti, Group>> { +> extends React.Component<Props<Option, IsMulti, Group> & StyleExtensionProps> { render() { return ( <ReactSelect - {...this.props} - styles={selectStyle<Option, IsMulti, Group>()} + {...omit(this.props, 'className', 'large')} + styles={selectStyle<Option, IsMulti, Group>(this.props)} + className={classNames('react-select', this.props.className)} + classNamePrefix="react-select" components={{ ...this.props.components, DropdownIndicator: dropdownIndicator, @@ -133,13 +140,15 @@ export function CreatableSelect< export function SearchSelect< Option, - isMulti extends boolean, + IsMulti extends boolean, Group extends GroupTypeBase<Option> = GroupTypeBase<Option> ->(props: Props<Option, isMulti, Group> & AsyncProps<Option, Group>) { +>(props: Props<Option, IsMulti, Group> & AsyncProps<Option, Group> & StyleExtensionProps) { return ( <AsyncReactSelect - {...props} - styles={selectStyle<Option, isMulti, Group>()} + {...omit(props, 'className', 'large')} + styles={selectStyle<Option, IsMulti, Group>(props)} + className={classNames('react-select', props.className)} + classNamePrefix="react-select" components={{ ...props.components, DropdownIndicator: dropdownIndicator, @@ -151,11 +160,9 @@ export function SearchSelect< ); } -export function selectStyle< - Option, - IsMulti extends boolean, - Group extends GroupTypeBase<Option> ->(): StylesConfig<Option, IsMulti, Group> { +export function selectStyle<Option, IsMulti extends boolean, Group extends GroupTypeBase<Option>>( + props?: Props<Option, IsMulti, Group> & AsyncProps<Option, Group> & StyleExtensionProps +): StylesConfig<Option, IsMulti, Group> { return { container: () => ({ position: 'relative', @@ -178,12 +185,14 @@ export function selectStyle< boxSizing: 'border-box', color: `${colors.baseFontColor}`, cursor: 'default', - outline: 'none' + outline: 'none', + padding: props?.large ? '4px 0px' : '0' }), singleValue: () => ({ bottom: 0, left: 0, lineHeight: '23px', + padding: props?.large ? '4px 8px' : '0 8px', paddingLeft: '8px', paddingRight: '24px', position: 'absolute', @@ -289,7 +298,7 @@ export function selectStyle< option: (_provided, state) => ({ display: 'block', lineHeight: '20px', - padding: '0 8px', + padding: props?.large ? '4px 8px' : '0 8px', boxSizing: 'border-box', color: state.isDisabled ? colors.disableGrayText : colors.baseFontColor, backgroundColor: state.isFocused ? colors.barBackgroundColor : colors.white, diff --git a/server/sonar-web/src/main/js/components/controls/SelectLegacy.css b/server/sonar-web/src/main/js/components/controls/SelectLegacy.css deleted file mode 100644 index c5a6a9c8438..00000000000 --- a/server/sonar-web/src/main/js/components/controls/SelectLegacy.css +++ /dev/null @@ -1,477 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -.Select { - position: relative; - display: inline-block; - vertical-align: middle; - font-size: var(--smallFontSize); - text-align: left; -} - -.Select, -.Select div, -.Select input, -.Select span { - box-sizing: border-box; -} - -.Select.is-disabled > .Select-control { - background-color: var(--disableGrayBg) !important; - border-color: var(--disableGrayBorder) !important; -} - -.Select.is-disabled > .Select-control:hover { - box-shadow: none !important; -} - -.Select.is-disabled .Select-arrow-zone { - cursor: not-allowed !important; - pointer-events: none !important; -} - -.Select.is-disabled .Select-placeholder, -.Select.is-disabled .Select-value { - color: var(--disableGrayText) !important; -} - -.Select-control { - position: relative; - display: table; - width: 100%; - height: var(--controlHeight); - line-height: calc(var(--controlHeight) - 2px); - border: 1px solid var(--gray80); - border-collapse: separate; - border-radius: 2px; - background-color: #fff; - color: var(--baseFontColor); - cursor: default; - outline: none; - overflow: hidden; -} - -.is-searchable.is-open > .Select-control { - cursor: text; -} - -.is-open > .Select-control { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - background: #fff; -} - -.is-open > .Select-control > .Select-arrow { - border-color: transparent transparent #999; - border-width: 0 5px 5px; -} - -.is-searchable.is-focused:not(.is-open) > .Select-control { - cursor: text; -} - -.is-focused:not(.is-open) > .Select-control { - border-color: var(--blue); -} - -.Select-placeholder { - color: var(--secondFontColor); -} - -.Select-placeholder, -:not(.Select--multi) > .Select-control .Select-value { - bottom: 0; - left: 0; - line-height: 23px; - padding-left: 8px; - padding-right: 24px; - position: absolute; - right: 0; - top: 0; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.Select-value [class^='icon-'] { - padding-top: 5px; -} - -.Select-value svg, -.Select-value img { - padding-top: 3px; -} - -.Select-option svg, -.Select-option img, -.Select-option [class^='icon-'] { - padding-top: 2px; -} - -.has-value:not(.Select--multi) > .Select-control > .Select-value .Select-value-label, -.has-value.is-pseudo-focused:not(.Select--multi) - > .Select-control - > .Select-value - .Select-value-label { - color: var(--baseFontColor); -} - -.has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label, -.has-value.is-pseudo-focused:not(.Select--multi) - > .Select-control - > .Select-value - a.Select-value-label { - cursor: pointer; - text-decoration: none; -} - -.has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:hover, -.has-value.is-pseudo-focused:not(.Select--multi) - > .Select-control - > .Select-value - a.Select-value-label:hover, -.has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:focus, -.has-value.is-pseudo-focused:not(.Select--multi) - > .Select-control - > .Select-value - a.Select-value-label:focus { - color: #007eff; - outline: none; - text-decoration: underline; -} - -.Select-input { - vertical-align: top; - height: 22px; - padding-left: 8px; - padding-right: 8px; - outline: none; -} - -.Select-input > input { - background: none transparent; - border: 0 none; - cursor: default; - display: inline-block; - font-family: inherit; - font-size: var(--smallFontSize); - height: 22px; - margin: 0; - outline: none; - padding: 0; - box-shadow: none; - -webkit-appearance: none; -} - -.is-focused .Select-input > input { - cursor: text; -} - -.has-value.is-pseudo-focused .Select-input { - opacity: 0; -} - -.Select-control:not(.is-searchable) > .Select-input { - outline: none; -} - -.Select-loading-zone { - cursor: pointer; - display: table-cell; - position: relative; - text-align: center; - vertical-align: middle; - width: 16px; -} - -.Select-loading { - -webkit-animation: Select-animation-spin 400ms infinite linear; - -o-animation: Select-animation-spin 400ms infinite linear; - animation: Select-animation-spin 400ms infinite linear; - width: 16px; - height: 16px; - box-sizing: border-box; - border-radius: 50%; - border: 2px solid #ccc; - border-right-color: var(--baseFontColor); - display: inline-block; - position: relative; - vertical-align: middle; -} - -.Select-clear-zone { - -webkit-animation: Select-animation-fadeIn 200ms; - -o-animation: Select-animation-fadeIn 200ms; - animation: Select-animation-fadeIn 200ms; - color: #999; - cursor: pointer; - display: table-cell; - position: relative; - text-align: center; - vertical-align: middle; - width: 16px; - height: 16px; - padding-right: 4px; -} - -.Select-clear-zone:hover .Select-clear { - background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj48c3ZnIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxNCAxNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7Ij4gICAgPGcgdHJhbnNmb3JtPSJtYXRyaXgoMC4wMjM0Mzc1LDAsMCwwLjAyMzQzNzUsLTUuMDE1NjIsLTUuMDE1NjIpIj4gICAgICAgIDxwYXRoIGQ9Ik04MTAsMjc0TDU3Miw1MTJMODEwLDc1MEw3NTAsODEwTDUxMiw1NzJMMjc0LDgxMEwyMTQsNzUwTDQ1Miw1MTJMMjE0LDI3NEwyNzQsMjE0TDUxMiw0NTJMNzUwLDIxNEw4MTAsMjc0WiIgc3R5bGU9ImZpbGw6cmdiKDIzMSwyMCw1Nik7ZmlsbC1ydWxlOm5vbnplcm87Ii8+ICAgIDwvZz48L3N2Zz4=); -} - -.Select-clear { - display: block; - width: 9px; - height: 9px; - background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj48c3ZnIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxNCAxNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7Ij4gICAgPGcgdHJhbnNmb3JtPSJtYXRyaXgoMC4wMjM0Mzc1LDAsMCwwLjAyMzQzNzUsLTUuMDE1NjIsLTUuMDE1NjIpIj4gICAgICAgIDxwYXRoIGQ9Ik04MTAsMjc0TDU3Miw1MTJMODEwLDc1MEw3NTAsODEwTDUxMiw1NzJMMjc0LDgxMEwyMTQsNzUwTDQ1Miw1MTJMMjE0LDI3NEwyNzQsMjE0TDUxMiw0NTJMNzUwLDIxNEw4MTAsMjc0WiIgc3R5bGU9ImZpbGw6cmdiKDE1MywxNTMsMTUzKTtmaWxsLXJ1bGU6bm9uemVybzsiLz4gICAgPC9nPjwvc3ZnPg==); - background-size: 9px 9px; - text-indent: -9999px; -} - -.Select--multi .Select-clear-zone { - width: 17px; -} - -.Select-arrow-zone { - cursor: pointer; - display: table-cell; - position: relative; - text-align: center; - vertical-align: middle; - width: 20px; - padding-right: 5px; -} - -.Select-arrow { - border-color: #999 transparent transparent; - border-style: solid; - border-width: 4px 4px 2px; - display: inline-block; - height: 0; - width: 0; -} - -.is-open .Select-arrow, -.Select-arrow-zone:hover > .Select-arrow { - border-top-color: #666; -} - -@-webkit-keyframes Select-animation-fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@keyframes Select-animation-fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -.Select-menu-outer { - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; - background-color: #fff; - border: 1px solid #ccc; - border-top-color: var(--barBorderColor); - box-sizing: border-box; - margin-top: -1px; - max-height: 200px; - position: absolute; - top: 100%; - width: 100%; - z-index: var(--dropdownMenuZIndex); - -webkit-overflow-scrolling: touch; - box-shadow: var(--defaultShadow); -} - -.Select-menu { - max-height: 198px; - padding: 5px 0; - overflow-y: auto; -} - -.Select-option { - display: block; - line-height: 20px; - padding: 0 8px; - box-sizing: border-box; - color: var(--baseFontColor); - font-size: var(--smallFontSize); - cursor: pointer; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.Select-option:last-child { - border-bottom-right-radius: 2px; - border-bottom-left-radius: 2px; -} - -.Select-option.is-focused { - background-color: var(--barBackgroundColor); -} - -.Select-option.is-disabled { - cursor: default; - opacity: 0.4; - font-style: italic; -} - -.Select-noresults { - box-sizing: border-box; - color: var(--gray60); - cursor: default; - display: block; - padding: 8px 10px; -} - -.Select--multi .Select-value { - background-color: rgba(0, 126, 255, 0.08); - border-radius: 2px; - border: 1px solid rgba(0, 126, 255, 0.24); - color: var(--baseFontColor); - display: inline-block; - font-size: var(--smallFontSize); - line-height: 14px; - margin: 1px 4px 1px 1px; - vertical-align: top; -} - -.Select-value-label { - font-size: var(--smallFontSize); -} - -.is-searchable.is-open .Select-value-label { - opacity: 0.5; -} - -.Select-big .Select-control { - padding-top: 4px; - padding-bottom: 4px; -} - -.Select-big .Select-placeholder { - margin-top: 4px; - margin-bottom: 4px; -} - -.Select-big .Select-value-label { - display: inline-block; - margin-top: 7px; - line-height: 16px; -} - -.Select-big .Select-option { - padding: 7px 8px; - line-height: 16px; -} - -.Select-big img, -.Select-big svg { - padding-top: 0; -} - -.Select--multi .Select-value-icon, -.Select--multi .Select-value-label { - display: inline-block; - vertical-align: middle; -} - -.Select--multi .Select-value-label { - display: inline-block; - max-width: 200px; - border-bottom-right-radius: 2px; - border-top-right-radius: 2px; - cursor: default; - padding: 2px 5px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.Select--multi a.Select-value-label { - color: #007eff; - cursor: pointer; - text-decoration: none; -} - -.Select--multi a.Select-value-label:hover { - text-decoration: underline; -} - -.Select--multi .Select-value-icon { - cursor: pointer; - border-bottom-left-radius: 2px; - border-top-left-radius: 2px; - border-right: 1px solid rgba(0, 126, 255, 0.24); - padding: 1px 5px; -} - -.Select--multi .Select-value-icon:hover, -.Select--multi .Select-value-icon:focus { - background-color: rgba(0, 113, 230, 0.08); - color: #0071e6; -} - -.Select--multi .Select-value-icon:active { - background-color: rgba(0, 126, 255, 0.24); -} - -.Select--multi.is-disabled .Select-value { - background-color: #fcfcfc; - border: 1px solid #e3e3e3; - color: var(--baseFontColor); -} - -.Select--multi.is-disabled .Select-value-icon { - cursor: not-allowed; - border-right: 1px solid #e3e3e3; -} - -.Select--multi.is-disabled .Select-value-icon:hover, -.Select--multi.is-disabled .Select-value-icon:focus, -.Select--multi.is-disabled .Select-value-icon:active { - background-color: #fcfcfc; -} - -.Select-aria-only { - display: none; -} - -@keyframes Select-animation-spin { - to { - transform: rotate(1turn); - } -} - -@-webkit-keyframes Select-animation-spin { - to { - -webkit-transform: rotate(1turn); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/SelectLegacy.tsx b/server/sonar-web/src/main/js/components/controls/SelectLegacy.tsx index 36ec973ce17..d4906283a82 100644 --- a/server/sonar-web/src/main/js/components/controls/SelectLegacy.tsx +++ b/server/sonar-web/src/main/js/components/controls/SelectLegacy.tsx @@ -25,7 +25,6 @@ import ReactSelectClass, { } from 'react-select-legacy'; import { lazyLoadComponent } from '../lazyLoadComponent'; import { ClearButton } from './buttons'; -import './SelectLegacy.css'; const ReactSelectLib = import('react-select-legacy'); const ReactSelect = lazyLoadComponent(() => ReactSelectLib); 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 eff8131e9a9..5ae4b935b00 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 @@ -13,6 +13,8 @@ exports[`Select should render clearIndicator correctly 1`] = ` exports[`Select should render complex select component: other props 1`] = ` <StateManager + className="react-select" + classNamePrefix="react-select" components={ Object { "ClearIndicator": [Function], @@ -50,6 +52,8 @@ exports[`Select should render complex select component: other props 1`] = ` exports[`Select should render correctly: default 1`] = ` <StateManager + className="react-select" + classNamePrefix="react-select" components={ Object { "ClearIndicator": [Function], @@ -154,6 +158,8 @@ exports[`should render SearchSelect correctly 1`] = ` blurInputOnSelect={true} cacheOptions={false} captureMenuScroll={false} + className="react-select" + classNamePrefix="react-select" closeMenuOnScroll={false} closeMenuOnSelect={true} components={ |