Browse Source

SONAR-16191 Improve ITs for react-select and remove legacy css

tags/9.5.0.56709
Philippe Perrin 2 years ago
parent
commit
b3421b53d4
33 changed files with 115 additions and 817 deletions
  1. 1
    1
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/BadgeParams.tsx
  2. 1
    1
      server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/__tests__/__snapshots__/BadgeParams-test.tsx.snap
  3. 2
    4
      server/sonar-web/src/main/js/app/styles/init/forms.css
  4. 0
    9
      server/sonar-web/src/main/js/app/styles/style.css
  5. 3
    3
      server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx
  6. 0
    1
      server/sonar-web/src/main/js/apps/coding-rules/components/SeveritySelect.tsx
  7. 15
    15
      server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/ActivationFormModal-test.tsx.snap
  8. 1
    10
      server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx
  9. 0
    11
      server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx
  10. 0
    16
      server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/ApplyTemplate-test.tsx.snap
  11. 1
    2
      server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx
  12. 2
    6
      server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
  13. 0
    17
      server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx
  14. 0
    23
      server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx
  15. 0
    17
      server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchableFilterFooter-test.tsx.snap
  16. 0
    7
      server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx
  17. 3
    10
      server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx
  18. 0
    22
      server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx
  19. 0
    34
      server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap
  20. 3
    14
      server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap
  21. 4
    4
      server/sonar-web/src/main/js/apps/quality-gates/components/MetricSelect.tsx
  22. 6
    14
      server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx
  23. 10
    6
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModalRenderer-test.tsx.snap
  24. 0
    12
      server/sonar-web/src/main/js/apps/quality-gates/styles.css
  25. 9
    14
      server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsFormSelect.tsx
  26. 25
    18
      server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap
  27. 0
    9
      server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListHeader.tsx
  28. 0
    9
      server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx
  29. 0
    16
      server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap
  30. 23
    14
      server/sonar-web/src/main/js/components/controls/Select.tsx
  31. 0
    477
      server/sonar-web/src/main/js/components/controls/SelectLegacy.css
  32. 0
    1
      server/sonar-web/src/main/js/components/controls/SelectLegacy.tsx
  33. 6
    0
      server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Select-test.tsx.snap

+ 1
- 1
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/BadgeParams.tsx View File

@@ -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}

+ 1
- 1
server/sonar-web/src/main/js/app/components/nav/component/projectInformation/badges/__tests__/__snapshots__/BadgeParams-test.tsx.snap View File

@@ -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]}

+ 2
- 4
server/sonar-web/src/main/js/app/styles/init/forms.css View File

@@ -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);
}


+ 0
- 9
server/sonar-web/src/main/js/app/styles/style.css View File

@@ -232,15 +232,6 @@ code.rule {
margin: 10px;
}

.width100 {
width: 100%;
}

textarea.width100 {
width: 100%;
box-sizing: border-box;
}

.property {
margin-bottom: 10px;
}

+ 3
- 3
server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx View File

@@ -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}

+ 0
- 1
server/sonar-web/src/main/js/apps/coding-rules/components/SeveritySelect.tsx View File

@@ -56,7 +56,6 @@ export function SeveritySelect(props: SeveritySelectProps) {

return (
<Select
className="js-severity"
aria-labelledby={ariaLabelledby}
isDisabled={isDisabled}
onChange={props.onChange}

+ 15
- 15
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/ActivationFormModal-test.tsx.snap View File

@@ -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]}

+ 1
- 10
server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx View File

@@ -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)}
/>

+ 0
- 11
server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/ApplyTemplate-test.tsx View File

@@ -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');
});

+ 0
- 16
server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/__snapshots__/ApplyTemplate-test.tsx.snap View File

@@ -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",
}
}
/>
`;

+ 1
- 2
server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx View File

@@ -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}

+ 2
- 6
server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap View File

@@ -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"

+ 0
- 17
server/sonar-web/src/main/js/apps/projects/filters/SearchableFilterFooter.tsx View File

@@ -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')}
/>

+ 0
- 23
server/sonar-web/src/main/js/apps/projects/filters/__tests__/SearchableFilterFooter-test.tsx View File

@@ -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'
);
});

+ 0
- 17
server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchableFilterFooter-test.tsx.snap View File

@@ -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 {

+ 0
- 7
server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx View File

@@ -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)}
/>

+ 3
- 10
server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx View File

@@ -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'))}

+ 0
- 22
server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx View File

@@ -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 }));

+ 0
- 34
server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap View File

@@ -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",
}
}
/>
`;

+ 3
- 14
server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap View File

@@ -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",

+ 4
- 4
server/sonar-web/src/main/js/apps/quality-gates/components/MetricSelect.tsx View File

@@ -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);

+ 6
- 14
server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx View File

@@ -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>
);

+ 10
- 6
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModalRenderer-test.tsx.snap View File

@@ -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>
`;

+ 0
- 12
server/sonar-web/src/main/js/apps/quality-gates/styles.css View File

@@ -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);
}

+ 9
- 14
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsFormSelect.tsx View File

@@ -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>
);
}

+ 25
- 18
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap View File

@@ -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>
`;

+ 0
- 9
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListHeader.tsx View File

@@ -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)}

+ 0
- 9
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx View File

@@ -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

+ 0
- 16
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap View File

@@ -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",
}
}
/>
`;

+ 23
- 14
server/sonar-web/src/main/js/components/controls/Select.tsx View File

@@ -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,

+ 0
- 477
server/sonar-web/src/main/js/components/controls/SelectLegacy.css View File

@@ -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);
}
}

+ 0
- 1
server/sonar-web/src/main/js/components/controls/SelectLegacy.tsx View File

@@ -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);

+ 6
- 0
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Select-test.tsx.snap View File

@@ -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={

Loading…
Cancel
Save