JT Form fixes after rebase

This commit is contained in:
Keith Grant
2019-09-05 13:42:57 -07:00
parent 8b1ca12d8f
commit 93b794eaa7
7 changed files with 104 additions and 96 deletions

View File

@@ -5,9 +5,7 @@ import styled from 'styled-components';
const Container = styled.div` const Container = styled.div`
margin: 15px 0; margin: 15px 0;
transition: all 0.2s ease-out; transition: all 0.2s ease-out;
${props => !props.isExpanded && ` ${props => !props.isExpanded && `overflow: hidden;`}
overflow: hidden;
`}
`; `;
function ExpandingContainer({ isExpanded, children }) { function ExpandingContainer({ isExpanded, children }) {

View File

@@ -30,7 +30,7 @@ function CheckboxField({ id, name, label, tooltip, validate, ...rest }) {
} }
id={id} id={id}
{...rest} {...rest}
checked={field.value} isChecked={field.value}
{...field} {...field}
onChange={(value, event) => { onChange={(value, event) => {
field.onChange(event); field.onChange(event);

View File

@@ -14,52 +14,57 @@ class InstanceGroupsLookup extends React.Component {
render() { render() {
const { value, tooltip, onChange, className, i18n } = this.props; const { value, tooltip, onChange, className, i18n } = this.props;
/*
Wrapping <div> added to workaround PF bug:
https://github.com/patternfly/patternfly-react/issues/2855
*/
return ( return (
<FormGroup <div className={className}>
className={className} <FormGroup
label={ label={
<Fragment> <Fragment>
{i18n._(t`Instance Groups`)}{' '} {i18n._(t`Instance Groups`)}{' '}
{tooltip && ( {tooltip && (
<Tooltip position="right" content={tooltip}> <Tooltip position="right" content={tooltip}>
<QuestionCircleIcon /> <QuestionCircleIcon />
</Tooltip> </Tooltip>
)} )}
</Fragment> </Fragment>
} }
fieldId="org-instance-groups" fieldId="org-instance-groups"
> >
<Lookup <Lookup
id="org-instance-groups" id="org-instance-groups"
lookupHeader={i18n._(t`Instance Groups`)} lookupHeader={i18n._(t`Instance Groups`)}
name="instanceGroups" name="instanceGroups"
value={value} value={value}
onLookupSave={onChange} onLookupSave={onChange}
getItems={getInstanceGroups} getItems={getInstanceGroups}
multiple multiple
columns={[ columns={[
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isSortable: true, isSortable: true,
isSearchable: true, isSearchable: true,
}, },
{ {
name: i18n._(t`Modified`), name: i18n._(t`Modified`),
key: 'modified', key: 'modified',
isSortable: false, isSortable: false,
isNumeric: true, isNumeric: true,
}, },
{ {
name: i18n._(t`Created`), name: i18n._(t`Created`),
key: 'created', key: 'created',
isSortable: false, isSortable: false,
isNumeric: true, isNumeric: true,
}, },
]} ]}
sortedColumnKey="name" sortedColumnKey="name"
/> />
</FormGroup> </FormGroup>
</div>
); );
} }
} }

View File

@@ -7,37 +7,42 @@ function arrayToString(tags) {
} }
function stringToArray(value) { function stringToArray(value) {
return value.split(',').filter(val => !!val).map(val => ({ return value
id: val, .split(',')
name: val, .filter(val => !!val)
})); .map(val => ({
id: val,
name: val,
}));
} }
/* /*
* Adapter providing a simplified API to a MultiSelect. The value * Adapter providing a simplified API to a MultiSelect. The value
* is a comma-separated string. * is a comma-separated string.
*/ */
function TagMultiSelect ({ onChange, value }) { function TagMultiSelect({ onChange, value }) {
const [options, setOptions] = useState(stringToArray(value)); const [options, setOptions] = useState(stringToArray(value));
return ( return (
<MultiSelect <MultiSelect
onChange={val => { onChange(arrayToString(val)) }} onChange={val => {
onAddNewItem={(newItem) => { onChange(arrayToString(val));
}}
onAddNewItem={newItem => {
if (!options.find(o => o.name === newItem.name)) { if (!options.find(o => o.name === newItem.name)) {
setOptions(options.concat(newItem)); setOptions(options.concat(newItem));
} }
}} }}
associatedItems={stringToArray(value)} associatedItems={stringToArray(value)}
options={options} options={options}
createNewItem={(name) => ({ id: name, name })} createNewItem={name => ({ id: name, name })}
/> />
) );
} }
TagMultiSelect.propTypes = { TagMultiSelect.propTypes = {
onChange: func.isRequired, onChange: func.isRequired,
value: string.isRequired, value: string.isRequired,
} };
export default TagMultiSelect; export default TagMultiSelect;

View File

@@ -85,6 +85,7 @@ class JobTemplateForm extends Component {
this.loadLabels = this.loadLabels.bind(this); this.loadLabels = this.loadLabels.bind(this);
this.removeLabel = this.removeLabel.bind(this); this.removeLabel = this.removeLabel.bind(this);
this.handleProjectValidation = this.handleProjectValidation.bind(this); this.handleProjectValidation = this.handleProjectValidation.bind(this);
this.loadRelatedInstanceGroups = this.loadRelatedInstanceGroups.bind(this);
this.loadRelatedProjectPlaybooks = this.loadRelatedProjectPlaybooks.bind( this.loadRelatedProjectPlaybooks = this.loadRelatedProjectPlaybooks.bind(
this this
); );
@@ -95,11 +96,11 @@ class JobTemplateForm extends Component {
componentDidMount() { componentDidMount() {
const { validateField } = this.props; const { validateField } = this.props;
validateField('project');
this.setState({ contentError: null, hasContentLoading: true }); this.setState({ contentError: null, hasContentLoading: true });
Promise.all([this.loadLabels(), this.loadRelatedInstanceGroups()]).then( Promise.all([this.loadLabels(), this.loadRelatedInstanceGroups()]).then(
() => { () => {
this.setState({ hasContentLoading: false }); this.setState({ hasContentLoading: false });
validateField('project');
} }
); );
} }
@@ -242,8 +243,6 @@ class JobTemplateForm extends Component {
inventory, inventory,
project, project,
relatedProjectPlaybooks = [], relatedProjectPlaybooks = [],
newLabels,
removedLabels,
relatedInstanceGroups, relatedInstanceGroups,
allowCallbacks, allowCallbacks,
} = this.state; } = this.state;
@@ -343,8 +342,7 @@ class JobTemplateForm extends Component {
validate={required(null, i18n)} validate={required(null, i18n)}
onBlur={handleBlur} onBlur={handleBlur}
render={({ form, field }) => { render={({ form, field }) => {
const isValid = const isValid = !form.touched.job_type || !form.errors.job_type;
form && (!form.touched[field.name] || !form.errors[field.name]);
return ( return (
<FormGroup <FormGroup
fieldId="template-job-type" fieldId="template-job-type"
@@ -364,7 +362,7 @@ class JobTemplateForm extends Component {
</Tooltip> </Tooltip>
<AnsibleSelect <AnsibleSelect
isValid={isValid} isValid={isValid}
id="job_type" id="template-job-type"
data={jobTypeOptions} data={jobTypeOptions}
{...field} {...field}
/> />
@@ -391,34 +389,29 @@ class JobTemplateForm extends Component {
<Field <Field
name="project" name="project"
validate={this.handleProjectValidation()} validate={this.handleProjectValidation()}
render={({ form }) => { render={({ form }) => (
const isValid = form && !form.errors.project; <ProjectLookup
return ( helperTextInvalid={form.errors.project}
<ProjectLookup isValid={!form.errors.project}
helperTextInvalid={form.errors.project} value={project}
isValid={isValid} onBlur={handleBlur}
value={project} tooltip={i18n._(t`Select the project containing the playbook
onBlur={handleBlur}
tooltip={i18n._(t`Select the project containing the playbook
you want this job to execute.`)} you want this job to execute.`)}
onChange={value => { onChange={value => {
this.loadRelatedProjectPlaybooks(value.id); this.loadRelatedProjectPlaybooks(value.id);
form.setFieldValue('project', value.id); form.setFieldValue('project', value.id);
form.setFieldTouched('project'); this.setState({ project: value });
this.setState({ project: value }); }}
}} required
required />
/> )}
);
}}
/> />
<Field <Field
name="playbook" name="playbook"
validate={required(i18n._(t`Select a value for this field`), i18n)} validate={required(i18n._(t`Select a value for this field`), i18n)}
onBlur={handleBlur} onBlur={handleBlur}
render={({ field, form }) => { render={({ field, form }) => {
const isValid = const isValid = !form.touched.playbook || !form.errors.playbook;
form && (!form.touched[field.name] || !form.errors[field.name]);
return ( return (
<FormGroup <FormGroup
fieldId="template-playbook" fieldId="template-playbook"
@@ -436,7 +429,7 @@ class JobTemplateForm extends Component {
<QuestionCircleIcon /> <QuestionCircleIcon />
</Tooltip> </Tooltip>
<AnsibleSelect <AnsibleSelect
id="playbook" id="template-playbook"
data={playbookOptions} data={playbookOptions}
isValid={isValid} isValid={isValid}
form={form} form={form}
@@ -510,7 +503,11 @@ class JobTemplateForm extends Component {
> >
<QuestionCircleIcon /> <QuestionCircleIcon />
</Tooltip> </Tooltip>
<AnsibleSelect data={verbosityOptions} {...field} /> <AnsibleSelect
id="template-verbosity"
data={verbosityOptions}
{...field}
/>
</FormGroup> </FormGroup>
)} )}
/> />
@@ -528,6 +525,7 @@ class JobTemplateForm extends Component {
id="template-timeout" id="template-timeout"
name="timeout" name="timeout"
type="number" type="number"
min="0"
label={i18n._(t`Timeout`)} label={i18n._(t`Timeout`)}
tooltip={i18n._(t`The amount of time (in seconds) to run tooltip={i18n._(t`The amount of time (in seconds) to run
before the task is canceled. Defaults to 0 for no job before the task is canceled. Defaults to 0 for no job
@@ -653,7 +651,7 @@ class JobTemplateForm extends Component {
</span> </span>
} }
id="option-callbacks" id="option-callbacks"
checked={allowCallbacks} isChecked={allowCallbacks}
onChange={checked => { onChange={checked => {
this.setState({ allowCallbacks: checked }); this.setState({ allowCallbacks: checked });
}} }}
@@ -724,7 +722,7 @@ const FormikApp = withFormik({
forks, forks,
limit, limit,
verbosity, verbosity,
job_slicing, job_slice_count,
timeout, timeout,
diff_mode, diff_mode,
job_tags, job_tags,
@@ -733,6 +731,7 @@ const FormikApp = withFormik({
allow_callbacks, allow_callbacks,
allow_simultaneous, allow_simultaneous,
use_fact_cache, use_fact_cache,
host_config_key,
summary_fields = { labels: { results: [] } }, summary_fields = { labels: { results: [] } },
} = { ...template }; } = { ...template };
@@ -744,11 +743,11 @@ const FormikApp = withFormik({
project: project || '', project: project || '',
playbook: playbook || '', playbook: playbook || '',
labels: summary_fields.labels.results, labels: summary_fields.labels.results,
forks: forks || '', forks: forks || 0,
limit: limit || '', limit: limit || '',
verbosity: verbosity || '0', verbosity: verbosity || '0',
job_slice_count: job_slicing || '', job_slice_count: job_slice_count || 1,
timout: timeout || '', timeout: timeout || 0,
diff_mode: diff_mode || false, diff_mode: diff_mode || false,
job_tags: job_tags || '', job_tags: job_tags || '',
skip_tags: skip_tags || '', skip_tags: skip_tags || '',
@@ -756,6 +755,7 @@ const FormikApp = withFormik({
allow_callbacks: allow_callbacks || false, allow_callbacks: allow_callbacks || false,
allow_simultaneous: allow_simultaneous || false, allow_simultaneous: allow_simultaneous || false,
use_fact_cache: use_fact_cache || false, use_fact_cache: use_fact_cache || false,
host_config_key: host_config_key || '',
}; };
}, },
handleSubmit: (values, bag) => bag.props.handleSubmit(values), handleSubmit: (values, bag) => bag.props.handleSubmit(values),

View File

@@ -10,7 +10,7 @@ export default function omitProps(Component, ...omit) {
const clean = { ...props }; const clean = { ...props };
omit.forEach(key => { omit.forEach(key => {
delete clean[key]; delete clean[key];
}) });
return <Component {...clean} />; return <Component {...clean} />;
} };
} }

View File

@@ -32,4 +32,4 @@ describe('omitProps', () => {
expect(div.prop('foo')).toEqual(undefined); expect(div.prop('foo')).toEqual(undefined);
expect(div.prop('bar')).toEqual('two'); expect(div.prop('bar')).toEqual('two');
}); });
}) });