* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import SelectLegacy from '../../../components/controls/SelectLegacy';
+import { components, OptionProps, SingleValueProps } from 'react-select';
+import Select from '../../../components/controls/Select';
import Tooltip from '../../../components/controls/Tooltip';
import { translate } from '../../../helpers/l10n';
import { Profile } from '../types';
withKey?: string;
}
+interface Option {
+ value: string;
+ label: string;
+ isDefault: boolean | undefined;
+}
export default class ComparisonForm extends React.PureComponent<Props> {
handleChange = (option: { value: string }) => {
this.props.onCompare(option.value);
};
+ optionRenderer(
+ options: Option[],
+ props: OptionProps<Omit<Option, 'label' | 'isDefault'>, false>
+ ) {
+ const { data } = props;
+ return <components.Option {...props}>{renderValue(data, options)}</components.Option>;
+ }
+
+ singleValueRenderer = (
+ options: Option[],
+ props: SingleValueProps<Omit<typeof options[0], 'label' | 'isDefault'>>
+ ) => (
+ <components.SingleValue {...props}>{renderValue(props.data, options)}</components.SingleValue>
+ );
+
render() {
const { profile, profiles, withKey } = this.props;
const options = profiles
.filter(p => p.language === profile.language && p !== profile)
.map(p => ({ value: p.key, label: p.name, isDefault: p.isDefault }));
- function renderValue(p: typeof options[0]) {
- return (
- <div>
- <span>{p.label}</span>
- {p.isDefault && (
- <Tooltip overlay={translate('quality_profiles.list.default.help')}>
- <span className=" spacer-left badge">{translate('default')}</span>
- </Tooltip>
- )}
- </div>
- );
- }
-
return (
<div className="display-inline-block">
- <label className="spacer-right">{translate('quality_profiles.compare_with')}</label>
- <SelectLegacy
+ <label htmlFor="quality-profiles-comparision-input" className="spacer-right">
+ {translate('quality_profiles.compare_with')}
+ </label>
+ <Select
className="input-large"
- clearable={false}
+ autoFocus={true}
+ isClearable={false}
+ id="quality-profiles-comparision"
+ inputId="quality-profiles-comparision-input"
onChange={this.handleChange}
options={options}
- valueRenderer={renderValue}
- optionRenderer={renderValue}
- placeholder={translate('select_verb')}
- value={withKey}
+ isSearchable={true}
+ components={{
+ Option: this.optionRenderer.bind(this, options),
+ SingleValue: this.singleValueRenderer.bind(null, options)
+ }}
+ value={options.filter(o => o.value === withKey)}
/>
</div>
);
}
}
+
+function renderValue(p: Omit<Option, 'label' | 'isDefault'>, options: Option[]) {
+ const selectedOption = options.find(o => o.value === p.value);
+ if (selectedOption !== undefined) {
+ return (
+ <div>
+ <span>{selectedOption.label}</span>
+ {selectedOption.isDefault && (
+ <Tooltip overlay={translate('quality_profiles.list.default.help')}>
+ <span className="spacer-left badge">{translate('default')}</span>
+ </Tooltip>
+ )}
+ </div>
+ );
+ }
+}
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import SelectLegacy from '../../../../components/controls/SelectLegacy';
+import { mockReactSelectOptionProps } from '../../../../helpers/mocks/react-select';
+import Select from '../../../../components/controls/Select';
import { mockQualityProfile } from '../../../../helpers/testMocks';
import ComparisonForm from '../ComparisonForm';
it('should render Select with right options', () => {
+ const output = shallowRender().find(Select);
+
+ expect(output.length).toBe(1);
+ expect(output.prop('value')).toEqual([
+ { isDefault: true, value: 'another', label: 'another name' }
+ ]);
+ expect(output.prop('options')).toEqual([
+ { isDefault: true, value: 'another', label: 'another name' }
+ ]);
+});
+
+it('should render option correctly', () => {
+ const wrapper = shallowRender();
+ const mockOptions = [
+ {
+ value: 'val',
+ label: 'label',
+ isDefault: undefined
+ }
+ ];
+ const OptionRenderer = wrapper.instance().optionRenderer.bind(null, mockOptions);
+ expect(
+ shallow(<OptionRenderer {...mockReactSelectOptionProps({ value: 'test' })} />)
+ ).toMatchSnapshot('option render');
+});
+
+it('should render value correctly', () => {
+ const wrapper = shallowRender();
+ const mockOptions = [
+ {
+ value: 'val',
+ label: 'label',
+ isDefault: true
+ }
+ ];
+ const ValueRenderer = wrapper.instance().singleValueRenderer.bind(null, mockOptions);
+ expect(
+ shallow(<ValueRenderer {...mockReactSelectOptionProps({ value: 'test' })} />)
+ ).toMatchSnapshot('value render');
+});
+
+function shallowRender(overrides: Partial<ComparisonForm['props']> = {}) {
const profile = mockQualityProfile();
const profiles = [
profile,
- mockQualityProfile({ key: 'another', name: 'another name' }),
+ mockQualityProfile({ key: 'another', name: 'another name', isDefault: true }),
mockQualityProfile({ key: 'java', name: 'java', language: 'java' })
];
- const profileDefault = { value: 'c', label: 'c name', isDefault: true };
-
- const output = shallow(
+ return shallow<ComparisonForm>(
<ComparisonForm
onCompare={() => true}
profile={profile}
profiles={profiles}
withKey="another"
+ {...overrides}
/>
- ).find(SelectLegacy);
- expect(output.props().valueRenderer!(profileDefault)).toMatchSnapshot('Render default for value');
- expect(output.props().valueRenderer!(profile)).toMatchSnapshot('Render for value');
-
- expect(output.props().optionRenderer!(profileDefault)).toMatchSnapshot(
- 'Render default for option'
);
- expect(output.props().optionRenderer!(profile)).toMatchSnapshot('Render for option');
-
- expect(output.length).toBe(1);
- expect(output.prop('value')).toBe('another');
- expect(output.prop('options')).toEqual([
- { isDefault: false, value: 'another', label: 'another name' }
- ]);
-});
+}
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render Select with right options: Render default for option 1`] = `
-<div>
- <span>
- c name
- </span>
- <Tooltip
- overlay="quality_profiles.list.default.help"
- >
- <span
- className=" spacer-left badge"
- >
- default
- </span>
- </Tooltip>
-</div>
+exports[`should render option correctly: option render 1`] = `
+<Option
+ data={
+ Object {
+ "value": "test",
+ }
+ }
+/>
`;
-exports[`should render Select with right options: Render default for value 1`] = `
-<div>
- <span>
- c name
- </span>
- <Tooltip
- overlay="quality_profiles.list.default.help"
- >
- <span
- className=" spacer-left badge"
- >
- default
- </span>
- </Tooltip>
-</div>
-`;
-
-exports[`should render Select with right options: Render for option 1`] = `
-<div>
- <span />
-</div>
-`;
-
-exports[`should render Select with right options: Render for value 1`] = `
-<div>
- <span />
-</div>
+exports[`should render value correctly: value render 1`] = `
+<SingleValue
+ data={
+ Object {
+ "value": "test",
+ }
+ }
+/>
`;
*/
import { sortBy } from 'lodash';
import * as React from 'react';
+import Select from '../../../components/controls/Select';
import { changeProfileParent } from '../../../api/quality-profiles';
import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import Modal from '../../../components/controls/Modal';
-import SelectLegacy from '../../../components/controls/SelectLegacy';
import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
import { translate } from '../../../helpers/l10n';
this.state.selected == null ||
this.state.selected === this.props.profile.parentKey;
+ const selectedValue = this.state.selected ?? (this.props.profile.parentKey || '');
+
return (
<Modal
contentLabel={translate('quality_profiles.change_parent')}
<div className="modal-body">
<MandatoryFieldsExplanation className="modal-field" />
<div className="modal-field">
- <label htmlFor="change-profile-parent">
+ <label htmlFor="change-profile-parent-input">
{translate('quality_profiles.parent')}
<MandatoryFieldMarker />
</label>
- <SelectLegacy
- clearable={false}
- id="change-profile-parent"
+ <Select
+ className="width-100"
+ autoFocus={true}
name="parentKey"
+ isClearable={false}
+ id="change-profile-parent"
+ inputId="change-profile-parent-input"
onChange={this.handleSelectChange}
options={options}
- value={
- this.state.selected != null
- ? this.state.selected
- : this.props.profile.parentKey || ''
- }
+ isSearchable={true}
+ value={options.filter(o => o.value === selectedValue)}
/>
</div>
</div>
<form onSubmit={this.handleFormSubmit}>
<div className="modal-body">
<div className="modal-field">
- <label>{translate('quality_profiles.search_description')}</label>
+ <label htmlFor="change-profile-permission-input">
+ {translate('quality_profiles.search_description')}
+ </label>
<ProfilePermissionsFormSelect
onChange={this.handleValueChange}
onSearch={this.handleSearch}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { debounce, identity } from 'lodash';
+import { debounce, identity, omit } from 'lodash';
import * as React from 'react';
-import SelectLegacy from '../../../components/controls/SelectLegacy';
+import { components, ControlProps, OptionProps, SingleValueProps } from 'react-select';
+import Select from '../../../components/controls/Select';
import GroupIcon from '../../../components/icons/GroupIcon';
import Avatar from '../../../components/ui/Avatar';
import { translate } from '../../../helpers/l10n';
}
};
+ optionRenderer(props: OptionProps<OptionWithValue, false>) {
+ const { data } = props;
+ return (
+ <components.Option {...props} className="Select-option">
+ {customOptions(data)}
+ </components.Option>
+ );
+ }
+
+ singleValueRenderer = (props: SingleValueProps<OptionWithValue>) => (
+ <components.SingleValue {...props} className="Select-value-label">
+ {customOptions(props.data)}
+ </components.SingleValue>
+ );
+
+ controlRenderer = (props: ControlProps<OptionWithValue, false>) => (
+ <components.Control {...omit(props, ['children'])} className="abs-height-100 Select-control">
+ {props.children}
+ </components.Control>
+ );
+
render() {
const noResultsText = translate('no_results');
-
+ const { selected } = this.props;
// create a uniq string both for users and groups
const options = this.state.searchResults.map(r => ({ ...r, value: getStringValue(r) }));
+ // when user input is empty the options shows only top 30 names
+ // the below code add the selected user so that it appears too
+ if (
+ selected !== undefined &&
+ options.find(o => o.value === getStringValue(selected)) === undefined
+ ) {
+ options.unshift({ ...selected, value: getStringValue(selected) });
+ }
+
return (
- <SelectLegacy
+ <Select
+ className="Select-big width-100"
autoFocus={true}
- className="Select-big"
- clearable={false}
- // disable default react-select filtering
- filterOptions={identity}
- isLoading={this.state.loading}
- noResultsText={noResultsText}
+ isClearable={false}
+ id="change-profile-permission"
+ inputId="change-profile-permission-input"
onChange={this.props.onChange}
onInputChange={this.handleInputChange}
- optionRenderer={optionRenderer}
- options={options}
placeholder=""
- searchable={true}
- value={this.props.selected && getStringValue(this.props.selected)}
- valueRenderer={optionRenderer}
+ noOptionsMessage={() => noResultsText}
+ isLoading={this.state.loading}
+ options={options}
+ isSearchable={true}
+ filterOptions={identity}
+ components={{
+ Option: this.optionRenderer,
+ SingleValue: this.singleValueRenderer,
+ Control: this.controlRenderer
+ }}
+ value={options.filter(
+ o => o.value === (this.props.selected && getStringValue(this.props.selected))
+ )}
/>
);
}
return isUser(option) ? `user:${option.login}` : `group:${option.name}`;
}
-function optionRenderer(option: OptionWithValue) {
+function customOptions(option: OptionWithValue) {
return isUser(option) ? (
<>
<Avatar hash={option.avatar} name={option.name} size={16} />
expect(shallowRender()).toMatchSnapshot();
});
-it("should handle form' submit correcty", async () => {
+it('should handle form submit correcty', async () => {
const onChange = jest.fn();
const wrapper = shallowRender({ onChange });
expect(onChange).toHaveBeenCalled();
});
+it('should handle select change correcty', async () => {
+ const wrapper = shallowRender();
+ wrapper.instance().handleSelectChange({ value: 'val' });
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper.instance().state.selected).toEqual('val');
+});
+
function shallowRender(props?: Partial<ChangeParentForm['props']>) {
return shallow<ChangeParentForm>(
<ChangeParentForm
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import {
+ mockReactSelectControlProps,
+ mockReactSelectOptionProps
+} from '../../../../helpers/mocks/react-select';
import ProfilePermissionsFormSelect from '../ProfilePermissionsFormSelect';
jest.mock('lodash', () => {
wrapper.prop<Function>('onInputChange')('foo');
expect(onSearch).not.toBeCalled();
});
+
+it('should render option correctly', () => {
+ const wrapper = shallowRender();
+ const OptionRenderer = wrapper.instance().optionRenderer;
+ expect(
+ shallow(<OptionRenderer {...mockReactSelectOptionProps({ value: 'test', name: 'name' })} />)
+ ).toMatchSnapshot('option renderer');
+});
+
+it('should render value correctly', () => {
+ const wrapper = shallowRender();
+ const ValueRenderer = wrapper.instance().singleValueRenderer;
+ expect(
+ shallow(<ValueRenderer {...mockReactSelectOptionProps({ value: 'test', name: 'name' })} />)
+ ).toMatchSnapshot('value renderer');
+});
+
+it('should render control correctly', () => {
+ const wrapper = shallowRender();
+ const ControlRenderer = wrapper.instance().controlRenderer;
+ expect(shallow(<ControlRenderer {...mockReactSelectControlProps()} />)).toMatchSnapshot(
+ 'control renderer'
+ );
+});
+
+function shallowRender(overrides: Partial<ProfilePermissionsFormSelect['props']> = {}) {
+ return shallow<ProfilePermissionsFormSelect>(
+ <ProfilePermissionsFormSelect
+ onChange={jest.fn()}
+ onSearch={jest.fn(() => Promise.resolve([]))}
+ selected={{ name: 'lambda' }}
+ {...overrides}
+ />
+ );
+}
className="modal-field"
>
<label
- htmlFor="change-profile-parent"
+ htmlFor="change-profile-parent-input"
>
quality_profiles.parent
<MandatoryFieldMarker />
</label>
- <SelectLegacy
- clearable={false}
+ <Select
+ autoFocus={true}
+ className="width-100"
id="change-profile-parent"
+ inputId="change-profile-parent-input"
+ isClearable={false}
+ isSearchable={true}
name="parentKey"
onChange={[Function]}
options={
},
]
}
- value=""
+ value={
+ Array [
+ Object {
+ "label": "none",
+ "value": "",
+ },
+ ]
+ }
/>
</div>
</div>
<div
className="modal-field"
>
- <label>
+ <label
+ htmlFor="change-profile-permission-input"
+ >
quality_profiles.search_description
</label>
<ProfilePermissionsFormSelect
<div
className="modal-field"
>
- <label>
+ <label
+ htmlFor="change-profile-permission-input"
+ >
quality_profiles.search_description
</label>
<ProfilePermissionsFormSelect
<div
className="modal-field"
>
- <label>
+ <label
+ htmlFor="change-profile-permission-input"
+ >
quality_profiles.search_description
</label>
<ProfilePermissionsFormSelect
<div
className="modal-field"
>
- <label>
+ <label
+ htmlFor="change-profile-permission-input"
+ >
quality_profiles.search_description
</label>
<ProfilePermissionsFormSelect
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders 1`] = `
-<SelectLegacy
+<Select
autoFocus={true}
- className="Select-big"
- clearable={false}
+ className="Select-big width-100"
+ components={
+ Object {
+ "Control": [Function],
+ "Option": [Function],
+ "SingleValue": [Function],
+ }
+ }
filterOptions={[Function]}
+ id="change-profile-permission"
+ inputId="change-profile-permission-input"
+ isClearable={false}
isLoading={true}
- noResultsText="no_results"
+ isSearchable={true}
+ noOptionsMessage={[Function]}
onChange={[MockFunction]}
onInputChange={[Function]}
- optionRenderer={[Function]}
- options={Array []}
+ options={
+ Array [
+ Object {
+ "name": "lambda",
+ "value": "group:lambda",
+ },
+ ]
+ }
placeholder=""
- searchable={true}
- value="group:lambda"
- valueRenderer={[Function]}
+ value={
+ Array [
+ Object {
+ "name": "lambda",
+ "value": "group:lambda",
+ },
+ ]
+ }
/>
`;
+
+exports[`should render control correctly: control renderer 1`] = `
+<Control
+ className="abs-height-100 Select-control"
+/>
+`;
+
+exports[`should render option correctly: option renderer 1`] = `
+<Option
+ className="Select-option"
+ data={
+ Object {
+ "name": "name",
+ "value": "test",
+ }
+ }
+>
+ <GroupIcon
+ size={16}
+ />
+ <strong
+ className="spacer-left"
+ >
+ name
+ </strong>
+</Option>
+`;
+
+exports[`should render value correctly: value renderer 1`] = `
+<SingleValue
+ className="Select-value-label"
+ data={
+ Object {
+ "name": "name",
+ "value": "test",
+ }
+ }
+>
+ <GroupIcon
+ size={16}
+ />
+ <strong
+ className="spacer-left"
+ >
+ name
+ </strong>
+</SingleValue>
+`;
*/
import { sortBy } from 'lodash';
import * as React from 'react';
+import Select from '../../../components/controls/Select';
import {
changeProfileParent,
createQualityProfile,
} from '../../../api/quality-profiles';
import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import Modal from '../../../components/controls/Modal';
-import SelectLegacy from '../../../components/controls/SelectLegacy';
import { Location } from '../../../components/hoc/withRouter';
import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
}))
];
}
+ const languagesOptions = languages.map(l => ({
+ label: l.name,
+ value: l.key
+ }));
+
+ const isParentProfileClearable = () => {
+ if (this.state.parent !== undefined && this.state.parent !== '') {
+ return true;
+ }
+ return false;
+ };
return (
<Modal contentLabel={header} onRequestClose={this.props.onClose} size="small">
/>
</div>
<div className="modal-field">
- <label htmlFor="create-profile-language">
+ <label htmlFor="create-profile-language-input">
{translate('language')}
<MandatoryFieldMarker />
</label>
- <SelectLegacy
- clearable={false}
+ <Select
+ className="width-100"
+ autoFocus={true}
id="create-profile-language"
+ inputId="create-profile-language-input"
name="language"
+ isClearable={false}
onChange={this.handleLanguageChange}
- options={languages.map(l => ({
- label: l.name,
- value: l.key
- }))}
- value={selectedLanguage}
+ options={languagesOptions}
+ isSearchable={true}
+ value={languagesOptions.filter(o => o.value === selectedLanguage)}
/>
</div>
{selectedLanguage && profiles.length && (
<div className="modal-field">
- <label htmlFor="create-profile-parent">
+ <label htmlFor="create-profile-parent-input">
{translate('quality_profiles.parent')}
</label>
- <SelectLegacy
- clearable={true}
+ <Select
+ className="width-100"
+ autoFocus={true}
id="create-profile-parent"
+ inputId="create-profile-parent-input"
name="parentKey"
+ isClearable={isParentProfileClearable()}
onChange={this.handleParentChange}
options={profiles}
- value={this.state.parent || ''}
+ isSearchable={true}
+ value={profiles.filter(o => o.value === (this.state.parent || ''))}
/>
</div>
)}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import SelectLegacy from '../../../components/controls/SelectLegacy';
+import { components, OptionProps } from 'react-select';
+import Select from '../../../components/controls/Select';
import { Router, withRouter } from '../../../components/hoc/withRouter';
import { translate } from '../../../helpers/l10n';
import { getProfilesForLanguagePath, PROFILE_PATH } from '../utils';
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) {
value: language.key
}));
- const currentLanguage = currentFilter && options.find(l => l.value === currentFilter);
-
return (
<header className="quality-profiles-list-header clearfix">
- <span className="spacer-right">{translate('quality_profiles.filter_by')}:</span>
- <SelectLegacy
+ <label htmlFor="quality-profiles-filter-input" className="spacer-right">
+ {translate('quality_profiles.filter_by')}:
+ </label>
+ <Select
className="input-medium"
- clearable={true}
+ autoFocus={true}
+ id="quality-profiles-filter"
+ inputId="quality-profiles-filter-input"
+ isClearable={true}
onChange={this.handleChange}
+ components={{
+ Option: this.optionRenderer
+ }}
options={options}
- value={currentLanguage}
+ isSearchable={true}
+ value={options.filter(o => o.value === currentFilter)}
/>
</header>
);
*/
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';
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(
+ return shallow<ProfilesListHeader>(
<ProfilesListHeader
languages={[
{ key: 'js', name: 'JavaScript' },
className="modal-field"
>
<label
- htmlFor="create-profile-language"
+ htmlFor="create-profile-language-input"
>
language
<MandatoryFieldMarker />
</label>
- <SelectLegacy
- clearable={false}
+ <Select
+ autoFocus={true}
+ className="width-100"
id="create-profile-language"
+ inputId="create-profile-language-input"
+ isClearable={false}
+ isSearchable={true}
name="language"
onChange={[Function]}
options={
},
]
}
- value="css"
+ value={
+ Array [
+ Object {
+ "label": "CSS",
+ "value": "css",
+ },
+ ]
+ }
/>
</div>
<div
className="modal-field"
>
<label
- htmlFor="create-profile-parent"
+ htmlFor="create-profile-parent-input"
>
quality_profiles.parent
</label>
- <SelectLegacy
- clearable={true}
+ <Select
+ autoFocus={true}
+ className="width-100"
id="create-profile-parent"
+ inputId="create-profile-parent-input"
+ isClearable={false}
+ isSearchable={true}
name="parentKey"
onChange={[Function]}
options={
},
]
}
- value=""
+ value={
+ Array [
+ Object {
+ "label": "none",
+ "value": "",
+ },
+ ]
+ }
/>
</div>
<input
className="modal-field"
>
<label
- htmlFor="create-profile-language"
+ htmlFor="create-profile-language-input"
>
language
<MandatoryFieldMarker />
</label>
- <SelectLegacy
- clearable={false}
+ <Select
+ autoFocus={true}
+ className="width-100"
id="create-profile-language"
+ inputId="create-profile-language-input"
+ isClearable={false}
+ isSearchable={true}
name="language"
onChange={[Function]}
options={
},
]
}
- value="js"
+ value={
+ Array [
+ Object {
+ "label": "JavaScript",
+ "value": "js",
+ },
+ ]
+ }
/>
</div>
<div
className="modal-field"
>
<label
- htmlFor="create-profile-parent"
+ htmlFor="create-profile-parent-input"
>
quality_profiles.parent
</label>
- <SelectLegacy
- clearable={true}
+ <Select
+ autoFocus={true}
+ className="width-100"
id="create-profile-parent"
+ inputId="create-profile-parent-input"
+ isClearable={false}
+ isSearchable={true}
name="parentKey"
onChange={[Function]}
options={
},
]
}
- value=""
+ value={
+ Array [
+ Object {
+ "label": "none",
+ "value": "",
+ },
+ ]
+ }
/>
</div>
<div
<header
className="quality-profiles-list-header clearfix"
>
- <span
+ <label
className="spacer-right"
+ htmlFor="quality-profiles-filter-input"
>
quality_profiles.filter_by
:
- </span>
- <SelectLegacy
+ </label>
+ <Select
+ autoFocus={true}
className="input-medium"
- clearable={true}
+ components={
+ Object {
+ "Option": [Function],
+ }
+ }
+ id="quality-profiles-filter"
+ inputId="quality-profiles-filter-input"
+ isClearable={true}
+ isSearchable={true}
onChange={[Function]}
options={
Array [
},
]
}
+ value={Array []}
/>
</header>
`;
+
+exports[`should render option correctly: option renderer 1`] = `
+<Option
+ className="Select-option"
+ data={
+ Object {
+ "value": "val",
+ }
+ }
+/>
+`;
import ReactSelect, { GroupTypeBase, IndicatorProps, Props, StylesConfig } from 'react-select';
import { MultiValueRemoveProps } from 'react-select/src/components/MultiValue';
import { colors, others, sizes, zIndexes } from '../../app/theme';
+import { ClearButton } from './buttons';
const ArrowSpan = styled.span`
border-color: #999 transparent transparent;
width: 0;
`;
-export default function Select<
+export default class Select<
Option,
IsMulti extends boolean = false,
Group extends GroupTypeBase<Option> = GroupTypeBase<Option>
->(props: Props<Option, IsMulti, Group>) {
- function DropdownIndicator({ innerProps }: IndicatorProps<Option, IsMulti, Group>) {
+> extends React.PureComponent<Props<Option, IsMulti, Group>> {
+ dropdownIndicator({ innerProps }: IndicatorProps<Option, IsMulti, Group>) {
return <ArrowSpan {...innerProps} />;
}
- function MultiValueRemove(props: MultiValueRemoveProps<Option, Group>) {
+ clearIndicator({ innerProps }: IndicatorProps<Option, IsMulti, Group>) {
+ return (
+ <ClearButton
+ className="button-tiny spacer-left spacer-right text-middle"
+ iconProps={{ size: 12 }}
+ {...innerProps}
+ />
+ );
+ }
+
+ multiValueRemove(props: MultiValueRemoveProps<Option, Group>) {
return <div {...props.innerProps}>×</div>;
}
- return (
- <ReactSelect
- {...props}
- styles={selectStyle<Option, IsMulti, Group>()}
- components={{
- ...props.components,
- DropdownIndicator,
- MultiValueRemove
- }}
- />
- );
+ render() {
+ return (
+ <ReactSelect
+ {...this.props}
+ styles={selectStyle<Option, IsMulti, Group>()}
+ components={{
+ ...this.props.components,
+ DropdownIndicator: this.dropdownIndicator,
+ ClearIndicator: this.clearIndicator,
+ MultiValueRemove: this.multiValueRemove
+ }}
+ />
+ );
+ }
}
export function selectStyle<
}),
control: () => ({
position: 'relative',
- display: 'table',
+ display: 'flex',
width: '100%',
minHeight: `${sizes.controlHeight}`,
lineHeight: `calc(${sizes.controlHeight} - 2px)`,
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}),
- input: () => ({
- paddingLeft: '1px'
- }),
valueContainer: (_provided, state) => {
if (state.hasValue && state.isMulti) {
return {
};
},
indicatorsContainer: () => ({
- cursor: 'pointer',
- display: 'table-cell',
position: 'relative',
- textAlign: 'center',
+ cursor: 'pointer',
+ textAlign: 'end',
verticalAlign: 'middle',
width: '20px',
- paddingRight: '5px'
+ paddingRight: '5px',
+ flex: 1
}),
multiValue: () => ({
display: 'inline-block',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis'
+ }),
+ input: () => ({
+ padding: '0px',
+ margin: '0px',
+ height: '100%',
+ display: 'flex',
+ alignItems: 'center',
+ paddingLeft: '1px'
+ }),
+ loadingIndicator: () => ({
+ position: 'absolute',
+ padding: '8px',
+ fontSize: '4px'
+ }),
+ noOptionsMessage: () => ({
+ color: `${colors.gray60}`,
+ padding: '8px 10px'
})
};
}
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { GroupTypeBase, Props } from 'react-select';
+import { components, GroupTypeBase, InputProps, Props } from 'react-select';
+import { mockReactSelectIndicatorProps } from '../../../helpers/mocks/react-select';
import Select from '../Select';
describe('Select', () => {
expect(shallowRender()).toMatchSnapshot('default');
});
+ it('should render complex select component', () => {
+ const inputRenderer = (props: InputProps) => (
+ <components.Input {...props} className={`little-spacer-top ${props.className}`} />
+ );
+
+ const props = {
+ isClearable: true,
+ isLoading: true,
+ components: {
+ Input: inputRenderer
+ }
+ };
+ expect(shallowRender(props)).toMatchSnapshot('other props');
+ });
+
+ it('should render clearIndicator correctly', () => {
+ const wrapper = shallowRender();
+ const ClearIndicator = wrapper.instance().clearIndicator;
+ const clearIndicator = shallow(<ClearIndicator {...mockReactSelectIndicatorProps()} />);
+ expect(clearIndicator).toBeDefined();
+ });
+
+ it('should render dropdownIndicator correctly', () => {
+ const wrapper = shallowRender();
+ const DropdownIndicator = wrapper.instance().dropdownIndicator;
+ const clearIndicator = shallow(<DropdownIndicator {...mockReactSelectIndicatorProps()} />);
+ expect(clearIndicator).toBeDefined();
+ });
+
function shallowRender<
Option,
IsMulti extends boolean = false,
Group extends GroupTypeBase<Option> = GroupTypeBase<Option>
>(props: Partial<Props<Option, IsMulti, Group>> = {}) {
- return shallow<Props<Option, IsMulti, Group>>(<Select {...props} />);
+ return shallow<Select<Option, IsMulti, Group>>(<Select {...props} />);
}
});
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`Select should render complex select component: other props 1`] = `
+<StateManager
+ components={
+ Object {
+ "ClearIndicator": [Function],
+ "DropdownIndicator": [Function],
+ "Input": [Function],
+ "MultiValueRemove": [Function],
+ }
+ }
+ defaultInputValue=""
+ defaultMenuIsOpen={false}
+ defaultValue={null}
+ isClearable={true}
+ isLoading={true}
+ styles={
+ Object {
+ "container": [Function],
+ "control": [Function],
+ "indicatorsContainer": [Function],
+ "input": [Function],
+ "loadingIndicator": [Function],
+ "menu": [Function],
+ "menuList": [Function],
+ "multiValue": [Function],
+ "multiValueLabel": [Function],
+ "multiValueRemove": [Function],
+ "noOptionsMessage": [Function],
+ "option": [Function],
+ "placeholder": [Function],
+ "singleValue": [Function],
+ "valueContainer": [Function],
+ }
+ }
+/>
+`;
+
exports[`Select should render correctly: default 1`] = `
<StateManager
components={
Object {
+ "ClearIndicator": [Function],
"DropdownIndicator": [Function],
"MultiValueRemove": [Function],
}
"control": [Function],
"indicatorsContainer": [Function],
"input": [Function],
+ "loadingIndicator": [Function],
"menu": [Function],
"menuList": [Function],
"multiValue": [Function],
"multiValueLabel": [Function],
"multiValueRemove": [Function],
+ "noOptionsMessage": [Function],
"option": [Function],
"placeholder": [Function],
"singleValue": [Function],
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { GroupTypeBase, OptionProps } from 'react-select';
+import { ControlProps, GroupTypeBase, IndicatorProps, InputProps, OptionProps } from 'react-select';
export function mockReactSelectOptionProps<
OptionType,
data
} as OptionProps<OptionType, IsMulti, GroupType>;
}
+
+export function mockReactSelectInputProps(): InputProps {
+ return {} as InputProps;
+}
+
+export function mockReactSelectControlProps<
+ OptionType,
+ IsMulti extends boolean,
+ GroupType extends GroupTypeBase<OptionType> = GroupTypeBase<OptionType>
+>(): ControlProps<OptionType, IsMulti, GroupType> {
+ return {} as ControlProps<OptionType, IsMulti, GroupType>;
+}
+
+export function mockReactSelectIndicatorProps<
+ OptionType,
+ IsMulti extends boolean,
+ GroupType extends GroupTypeBase<OptionType> = GroupTypeBase<OptionType>
+>(): IndicatorProps<OptionType, IsMulti, GroupType> {
+ return {} as IndicatorProps<OptionType, IsMulti, GroupType>;
+}