import { pickBy, sortBy } from 'lodash';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { components, OptionProps, SingleValueProps } from 'react-select';
import { bulkChangeIssues, searchIssueTags } from '../../../api/issues';
import FormattingTips from '../../../components/common/FormattingTips';
import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import Modal from '../../../components/controls/Modal';
import Radio from '../../../components/controls/Radio';
import SearchSelect from '../../../components/controls/SearchSelect';
-import SelectLegacy from '../../../components/controls/SelectLegacy';
+import Select, { BasicSelectOption } from '../../../components/controls/Select';
import Tooltip from '../../../components/controls/Tooltip';
import IssueTypeIcon from '../../../components/icons/IssueTypeIcon';
import SeverityHelper from '../../../components/shared/SeverityHelper';
this.setState({ comment: event.currentTarget.value });
};
- handleSelectFieldChange = (field: 'severity' | 'type') => (data: { value: string } | null) => {
+ handleSelectFieldChange = (field: 'severity' | 'type') => (data: BasicSelectOption | null) => {
if (data) {
this.setState<keyof FormFields>({ [field]: data.value });
} else {
}
const types: IssueType[] = ['BUG', 'VULNERABILITY', 'CODE_SMELL'];
- const options = types.map(type => ({ label: translate('issue.type', type), value: type }));
+ const options: BasicSelectOption[] = types.map(type => ({
+ label: translate('issue.type', type),
+ value: type
+ }));
- const optionRenderer = (option: { label: string; value: string }) => (
- <>
+ const typeRenderer = (option: BasicSelectOption) => (
+ <div className="display-flex-center">
<IssueTypeIcon query={option.value} />
<span className="little-spacer-left">{option.label}</span>
- </>
+ </div>
);
const input = (
- <SelectLegacy
+ <Select
className="input-super-large"
- clearable={true}
+ isClearable={true}
+ isSearchable={false}
+ components={{
+ Option: (props: OptionProps<BasicSelectOption, false>) => (
+ <components.Option {...props}>{typeRenderer(props.data)}</components.Option>
+ ),
+ SingleValue: (props: SingleValueProps<BasicSelectOption>) => (
+ <components.SingleValue {...props}>{typeRenderer(props.data)}</components.SingleValue>
+ )
+ }}
onChange={this.handleSelectFieldChange('type')}
- optionRenderer={optionRenderer}
options={options}
- searchable={false}
- value={this.state.type}
- valueRenderer={optionRenderer}
/>
);
}
const severities = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'];
- const options = severities.map(severity => ({
+ const options: BasicSelectOption[] = severities.map(severity => ({
label: translate('severity', severity),
value: severity
}));
const input = (
- <SelectLegacy
+ <Select
className="input-super-large"
- clearable={true}
+ isClearable={true}
+ isSearchable={false}
onChange={this.handleSelectFieldChange('severity')}
- optionRenderer={(option: { value: string }) => <SeverityHelper severity={option.value} />}
+ components={{
+ Option: (props: OptionProps<BasicSelectOption, false>) => (
+ <components.Option {...props}>
+ {<SeverityHelper className="display-flex-center" severity={props.data.value} />}
+ </components.Option>
+ ),
+ SingleValue: (props: SingleValueProps<BasicSelectOption>) => (
+ <components.SingleValue {...props}>
+ {<SeverityHelper className="display-flex-center" severity={props.data.value} />}
+ </components.SingleValue>
+ )
+ }}
options={options}
- searchable={false}
- value={this.state.severity}
- valueRenderer={(option: { value: string }) => <SeverityHelper severity={option.value} />}
/>
);
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { SelectComponentsProps } from 'react-select/src/Select';
import { searchIssueTags } from '../../../../api/issues';
import { SubmitButton } from '../../../../components/controls/buttons';
-import SelectLegacy from '../../../../components/controls/SelectLegacy';
+import Select from '../../../../components/controls/Select';
import { mockIssue } from '../../../../helpers/testMocks';
import { change, waitAndUpdate } from '../../../../helpers/testUtils';
import { Issue } from '../../../../types/types';
expect(searchIssueTags).toBeCalled();
});
+it.each([
+ ['type', 'set_type'],
+ ['severity', 'set_severity']
+])('should render select for %s', async (_field, action) => {
+ const wrapper = getWrapper([mockIssue(false, { actions: [action] })]);
+ await waitAndUpdate(wrapper);
+
+ const { Option, SingleValue } = wrapper.find<SelectComponentsProps>(Select).props().components;
+
+ expect(Option({ data: { label: 'label', value: 'value' } })).toMatchSnapshot('Option');
+ expect(SingleValue({ data: { label: 'label', value: 'value' } })).toMatchSnapshot('SingleValue');
+});
+
it('should disable the submit button unless some change is configured', async () => {
const wrapper = getWrapper([mockIssue(false, { actions: ['set_severity', 'comment'] })]);
await waitAndUpdate(wrapper);
expect(wrapper.find(SubmitButton).props().disabled).toBe(true);
const { onChange } = wrapper
- .find(SelectLegacy)
+ .find(Select)
.at(0)
.props();
if (!onChange) {
width: 0;
`;
+export interface BasicSelectOption {
+ label: string;
+ value: string;
+}
+
export default class Select<
Option,
IsMulti extends boolean = false,
textAlign: 'left',
width: '100%'
}),
- control: () => ({
+ control: (_provided, state) => ({
position: 'relative',
display: 'flex',
width: '100%',
minHeight: `${sizes.controlHeight}`,
lineHeight: `calc(${sizes.controlHeight} - 2px)`,
- border: `1px solid ${colors.gray80}`,
+ border: `1px solid ${state.isFocused ? colors.blue : colors.gray80}`,
borderCollapse: 'separate',
borderRadius: '2px',
backgroundColor: '#fff',
overflowY: 'auto'
}),
placeholder: () => ({
+ position: 'absolute',
color: '#666'
}),
option: (_provided, state) => ({