mirror of
https://github.com/ansible/awx.git
synced 2026-02-26 07:26:03 -03:30
add generic onChange prop to MultiSelect
This commit is contained in:
@@ -5,7 +5,9 @@ import styled from 'styled-components';
|
||||
const Container = styled.div`
|
||||
margin: 15px 0;
|
||||
transition: all 0.2s ease-out;
|
||||
overflow: hidden;
|
||||
${props => !props.isExpanded && `
|
||||
overflow: hidden;
|
||||
`}
|
||||
`;
|
||||
|
||||
function ExpandingContainer({ isExpanded, children }) {
|
||||
@@ -21,6 +23,7 @@ function ExpandingContainer({ isExpanded, children }) {
|
||||
css={`
|
||||
height: ${height}px;
|
||||
`}
|
||||
isExpanded={isExpanded}
|
||||
>
|
||||
{children}
|
||||
</Container>
|
||||
|
||||
@@ -45,10 +45,17 @@ class MultiSelect extends Component {
|
||||
name: PropTypes.string.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
onAddNewItem: PropTypes.func.isRequired,
|
||||
onRemoveItem: PropTypes.func.isRequired,
|
||||
onAddNewItem: PropTypes.func,
|
||||
onRemoveItem: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onAddNewItem: () => {},
|
||||
onRemoveItem: () => {},
|
||||
onChange: () => {},
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -92,19 +99,21 @@ class MultiSelect extends Component {
|
||||
|
||||
handleSelection(e, item) {
|
||||
const { chipItems } = this.state;
|
||||
const { onAddNewItem } = this.props;
|
||||
const { onAddNewItem, onChange } = this.props;
|
||||
e.preventDefault();
|
||||
|
||||
const items = chipItems.concat({ name: item.name, id: item.id });
|
||||
this.setState({
|
||||
chipItems: chipItems.concat({ name: item.name, id: item.id }),
|
||||
chipItems: items,
|
||||
isExpanded: false,
|
||||
});
|
||||
onAddNewItem(item);
|
||||
onChange(items);
|
||||
}
|
||||
|
||||
handleAddItem(event) {
|
||||
const { input, chipItems } = this.state;
|
||||
const { onAddNewItem } = this.props;
|
||||
const { onAddNewItem, onChange } = this.props;
|
||||
const isIncluded = chipItems.some(chipItem => chipItem.name === input);
|
||||
|
||||
if (!input) {
|
||||
@@ -120,12 +129,14 @@ class MultiSelect extends Component {
|
||||
}
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
const items = chipItems.concat({ name: input, id: input });
|
||||
this.setState({
|
||||
chipItems: chipItems.concat({ name: input, id: input }),
|
||||
chipItems: items,
|
||||
isExpanded: false,
|
||||
input: '',
|
||||
});
|
||||
onAddNewItem(input);
|
||||
onChange(items);
|
||||
} else if (event.key === 'Tab') {
|
||||
this.setState({ input: '' });
|
||||
}
|
||||
@@ -136,12 +147,13 @@ class MultiSelect extends Component {
|
||||
}
|
||||
|
||||
removeChip(e, item) {
|
||||
const { onRemoveItem } = this.props;
|
||||
const { onRemoveItem, onChange } = this.props;
|
||||
const { chipItems } = this.state;
|
||||
const chips = chipItems.filter(chip => chip.id !== item.id);
|
||||
|
||||
this.setState({ chipItems: chips });
|
||||
onRemoveItem(item);
|
||||
onChange(chips);
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ describe('<MultiSelect />', () => {
|
||||
expect(getInitialChipItems).toBeCalled();
|
||||
expect(component.state().chipItems.length).toBe(2);
|
||||
});
|
||||
|
||||
test('handleSelection add item to chipItems', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<MultiSelect
|
||||
@@ -45,12 +46,15 @@ describe('<MultiSelect />', () => {
|
||||
await sleep(1);
|
||||
expect(component.state().chipItems.length).toBe(2);
|
||||
});
|
||||
|
||||
test('handleAddItem adds a chip only when Tab is pressed', () => {
|
||||
const onAddNewItem = jest.fn();
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<MultiSelect
|
||||
onAddNewItem={onAddNewItem}
|
||||
onRemoveItem={jest.fn()}
|
||||
onChange={onChange}
|
||||
associatedItems={associatedItems}
|
||||
options={options}
|
||||
/>
|
||||
@@ -68,14 +72,18 @@ describe('<MultiSelect />', () => {
|
||||
expect(component.state().input.length).toBe(0);
|
||||
expect(component.state().isExpanded).toBe(false);
|
||||
expect(onAddNewItem).toBeCalled();
|
||||
expect(onChange).toBeCalled();
|
||||
});
|
||||
|
||||
test('removeChip removes chip properly', () => {
|
||||
const onRemoveItem = jest.fn();
|
||||
const onChange = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<MultiSelect
|
||||
onAddNewItem={jest.fn()}
|
||||
onRemoveItem={onRemoveItem}
|
||||
onChange={onChange}
|
||||
associatedItems={associatedItems}
|
||||
options={options}
|
||||
/>
|
||||
@@ -89,5 +97,6 @@ describe('<MultiSelect />', () => {
|
||||
.removeChip(event, { name: 'Foo', id: 1, organization: 1 });
|
||||
expect(component.state().chipItems.length).toBe(1);
|
||||
expect(onRemoveItem).toBeCalled();
|
||||
expect(onChange).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -501,6 +501,7 @@ class JobTemplateForm extends Component {
|
||||
id="template-job-slicing"
|
||||
name="job_slice_count"
|
||||
type="number"
|
||||
min="1"
|
||||
label={i18n._(t`Job Slicing`)}
|
||||
tooltip={i18n._(t`Divide the work done by this job template
|
||||
into the specified number of job slices, each running the
|
||||
@@ -551,6 +552,42 @@ class JobTemplateForm extends Component {
|
||||
t`Select the Instance Groups for this Organization to run on.`
|
||||
)}
|
||||
/>
|
||||
<FormGroup label={i18n._(t`Job Tags`)} fieldId="template-job-tags">
|
||||
<Tooltip
|
||||
position="right"
|
||||
content={i18n._(t`Tags are useful when you have a large
|
||||
playbook, and you want to run a specific part of a play
|
||||
or task. Use commas to separate multiple tags. Refer to
|
||||
Ansible Tower documentation for details on the usage of
|
||||
tags.`)}
|
||||
>
|
||||
<QuestionCircleIcon />
|
||||
</Tooltip>
|
||||
<MultiSelect
|
||||
onAddNewItem={this.handleNewLabel}
|
||||
onRemoveItem={this.removeLabel}
|
||||
associatedItems={template.job_tags.split(',')}
|
||||
options={loadedLabels}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup label={i18n._(t`Skip Tags`)} fieldId="template-skip-tags">
|
||||
<Tooltip
|
||||
position="right"
|
||||
content={i18n._(t`Skip tags are useful when you have a
|
||||
large playbook, and you want to skip specific parts of a
|
||||
play or task. Use commas to separate multiple tags. Refer
|
||||
to Ansible Tower documentation for details on the usage
|
||||
of tags.`)}
|
||||
>
|
||||
<QuestionCircleIcon />
|
||||
</Tooltip>
|
||||
<MultiSelect
|
||||
onAddNewItem={this.handleNewLabel}
|
||||
onRemoveItem={this.removeLabel}
|
||||
associatedItems={template.skip_tags.split(',')}
|
||||
options={loadedLabels}
|
||||
/>
|
||||
</FormGroup>
|
||||
</CollapsibleSection>
|
||||
<FormActionGroup onCancel={handleCancel} onSubmit={handleSubmit} />
|
||||
</Form>
|
||||
|
||||
Reference in New Issue
Block a user