mirror of
https://github.com/ansible/awx.git
synced 2026-05-21 07:47:44 -02:30
Merge pull request #6318 from AlexSCorey/6100-ConvertWFJTandJTtoHooks
Moves JT Form to using react hooks and custom hooks Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { withI18n } from '@lingui/react';
|
||||
@@ -15,6 +15,8 @@ import ContentError from '@components/ContentError';
|
||||
import ContentLoading from '@components/ContentLoading';
|
||||
import AnsibleSelect from '@components/AnsibleSelect';
|
||||
import { TagMultiSelect } from '@components/MultiSelect';
|
||||
import useRequest from '@util/useRequest';
|
||||
|
||||
import FormActionGroup from '@components/FormActionGroup';
|
||||
import FormField, {
|
||||
CheckboxField,
|
||||
@@ -40,91 +42,64 @@ import { JobTemplatesAPI, ProjectsAPI } from '@api';
|
||||
import LabelSelect from './LabelSelect';
|
||||
import PlaybookSelect from './PlaybookSelect';
|
||||
|
||||
class JobTemplateForm extends Component {
|
||||
static propTypes = {
|
||||
template: JobTemplate,
|
||||
handleCancel: PropTypes.func.isRequired,
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
submitError: PropTypes.shape({}),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
template: {
|
||||
name: '',
|
||||
description: '',
|
||||
job_type: 'run',
|
||||
inventory: undefined,
|
||||
project: undefined,
|
||||
playbook: '',
|
||||
summary_fields: {
|
||||
inventory: null,
|
||||
labels: { results: [] },
|
||||
project: null,
|
||||
credentials: [],
|
||||
},
|
||||
isNew: true,
|
||||
},
|
||||
submitError: null,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
hasContentLoading: true,
|
||||
contentError: false,
|
||||
project: props.template.summary_fields.project,
|
||||
inventory: props.template.summary_fields.inventory,
|
||||
allowCallbacks: !!props.template.host_config_key,
|
||||
};
|
||||
this.handleProjectValidation = this.handleProjectValidation.bind(this);
|
||||
this.loadRelatedInstanceGroups = this.loadRelatedInstanceGroups.bind(this);
|
||||
this.handleProjectUpdate = this.handleProjectUpdate.bind(this);
|
||||
this.setContentError = this.setContentError.bind(this);
|
||||
this.fetchProject = this.fetchProject.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { validateField } = this.props;
|
||||
this.setState({ contentError: null, hasContentLoading: true });
|
||||
// TODO: determine when LabelSelect has finished loading labels
|
||||
Promise.all([this.loadRelatedInstanceGroups(), this.fetchProject()]).then(
|
||||
() => {
|
||||
this.setState({ hasContentLoading: false });
|
||||
validateField('project');
|
||||
}
|
||||
function JobTemplateForm({
|
||||
template,
|
||||
validateField,
|
||||
handleCancel,
|
||||
handleSubmit,
|
||||
handleBlur,
|
||||
setFieldValue,
|
||||
submitError,
|
||||
i18n,
|
||||
touched,
|
||||
}) {
|
||||
const [contentError, setContentError] = useState(false);
|
||||
const [project, setProject] = useState(null);
|
||||
const [inventory, setInventory] = useState(
|
||||
template?.summary_fields?.inventory
|
||||
);
|
||||
const [allowCallbacks, setAllowCallbacks] = useState(
|
||||
Boolean(template?.host_config_key)
|
||||
);
|
||||
}
|
||||
|
||||
async fetchProject() {
|
||||
const { project } = this.state;
|
||||
if (project && project.id) {
|
||||
try {
|
||||
const { data: projectData } = await ProjectsAPI.readDetail(project.id);
|
||||
this.setState({ project: projectData });
|
||||
} catch (err) {
|
||||
this.setState({ contentError: err });
|
||||
const {
|
||||
request: fetchProject,
|
||||
error: projectContentError,
|
||||
contentLoading: hasProjectLoading,
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
let projectData;
|
||||
if (template?.project) {
|
||||
projectData = await ProjectsAPI.readDetail(template?.project);
|
||||
validateField('project');
|
||||
setProject(projectData.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async loadRelatedInstanceGroups() {
|
||||
const { setFieldValue, template } = this.props;
|
||||
if (!template.id) {
|
||||
}, [template, validateField])
|
||||
);
|
||||
const {
|
||||
request: loadRelatedInstanceGroups,
|
||||
error: instanceGroupError,
|
||||
contentLoading: instanceGroupLoading,
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
if (!template?.id) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const { data } = await JobTemplatesAPI.readInstanceGroups(template.id);
|
||||
setFieldValue('initialInstanceGroups', data.results);
|
||||
setFieldValue('instanceGroups', [...data.results]);
|
||||
} catch (err) {
|
||||
this.setState({ contentError: err });
|
||||
}
|
||||
}
|
||||
}, [setFieldValue, template])
|
||||
);
|
||||
|
||||
handleProjectValidation() {
|
||||
const { i18n, touched } = this.props;
|
||||
const { project } = this.state;
|
||||
return () => {
|
||||
useEffect(() => {
|
||||
fetchProject();
|
||||
}, [fetchProject]);
|
||||
|
||||
useEffect(() => {
|
||||
loadRelatedInstanceGroups();
|
||||
}, [loadRelatedInstanceGroups]);
|
||||
|
||||
const handleProjectValidation = () => {
|
||||
if (!project && touched.project) {
|
||||
return i18n._(t`Select a value for this field`);
|
||||
}
|
||||
@@ -133,37 +108,13 @@ class JobTemplateForm extends Component {
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
|
||||
handleProjectUpdate(project) {
|
||||
const { setFieldValue } = this.props;
|
||||
setFieldValue('project', project.id);
|
||||
const handleProjectUpdate = newProject => {
|
||||
setProject(newProject);
|
||||
setFieldValue('project', newProject.id);
|
||||
setFieldValue('playbook', 0);
|
||||
setFieldValue('scm_branch', '');
|
||||
this.setState({ project });
|
||||
}
|
||||
|
||||
setContentError(contentError) {
|
||||
this.setState({ contentError });
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
contentError,
|
||||
hasContentLoading,
|
||||
inventory,
|
||||
project,
|
||||
allowCallbacks,
|
||||
} = this.state;
|
||||
const {
|
||||
handleCancel,
|
||||
handleSubmit,
|
||||
handleBlur,
|
||||
setFieldValue,
|
||||
template,
|
||||
submitError,
|
||||
i18n,
|
||||
} = this.props;
|
||||
};
|
||||
|
||||
const jobTypeOptions = [
|
||||
{
|
||||
@@ -188,17 +139,17 @@ class JobTemplateForm extends Component {
|
||||
{ value: '4', key: '4', label: i18n._(t`4 (Connection Debug)`) },
|
||||
];
|
||||
let callbackUrl;
|
||||
if (template && template.related) {
|
||||
if (template?.related) {
|
||||
const { origin } = document.location;
|
||||
const path = template.related.callback || `${template.url}callback`;
|
||||
callbackUrl = `${origin}${path}`;
|
||||
}
|
||||
|
||||
if (hasContentLoading) {
|
||||
if (instanceGroupLoading || hasProjectLoading) {
|
||||
return <ContentLoading />;
|
||||
}
|
||||
|
||||
if (contentError) {
|
||||
if (instanceGroupError || projectContentError) {
|
||||
return <ContentError error={contentError} />;
|
||||
}
|
||||
|
||||
@@ -274,7 +225,7 @@ class JobTemplateForm extends Component {
|
||||
inventory: value.id,
|
||||
organizationId: value.organization,
|
||||
});
|
||||
this.setState({ inventory: value });
|
||||
setInventory(value);
|
||||
}}
|
||||
required
|
||||
touched={form.touched.inventory}
|
||||
@@ -294,7 +245,7 @@ class JobTemplateForm extends Component {
|
||||
)}
|
||||
</Field>
|
||||
</FieldWithPrompt>
|
||||
<Field name="project" validate={this.handleProjectValidation()}>
|
||||
<Field name="project" validate={() => handleProjectValidation()}>
|
||||
{({ form }) => (
|
||||
<ProjectLookup
|
||||
value={project}
|
||||
@@ -303,7 +254,7 @@ class JobTemplateForm extends Component {
|
||||
you want this job to execute.`)}
|
||||
isValid={!form.touched.project || !form.errors.project}
|
||||
helperTextInvalid={form.errors.project}
|
||||
onChange={this.handleProjectUpdate}
|
||||
onChange={handleProjectUpdate}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
@@ -356,7 +307,7 @@ class JobTemplateForm extends Component {
|
||||
form={form}
|
||||
field={field}
|
||||
onBlur={() => form.setFieldTouched('playbook')}
|
||||
onError={this.setContentError}
|
||||
onError={setContentError}
|
||||
/>
|
||||
</FormGroup>
|
||||
);
|
||||
@@ -382,7 +333,7 @@ class JobTemplateForm extends Component {
|
||||
onChange={newCredentials =>
|
||||
setFieldValue('credentials', newCredentials)
|
||||
}
|
||||
onError={this.setContentError}
|
||||
onError={setContentError}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
@@ -399,7 +350,7 @@ class JobTemplateForm extends Component {
|
||||
<LabelSelect
|
||||
value={field.value}
|
||||
onChange={labels => setFieldValue('labels', labels)}
|
||||
onError={this.setContentError}
|
||||
onError={setContentError}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
@@ -446,9 +397,7 @@ class JobTemplateForm extends Component {
|
||||
<TextInput
|
||||
id="template-limit"
|
||||
{...field}
|
||||
isValid={
|
||||
!form.touched.job_type || !form.errors.job_type
|
||||
}
|
||||
isValid={!form.touched.job_type || !form.errors.job_type}
|
||||
onChange={(value, event) => {
|
||||
field.onChange(event);
|
||||
}}
|
||||
@@ -545,9 +494,7 @@ class JobTemplateForm extends Component {
|
||||
{({ field, form }) => (
|
||||
<TagMultiSelect
|
||||
value={field.value}
|
||||
onChange={value =>
|
||||
form.setFieldValue(field.name, value)
|
||||
}
|
||||
onChange={value => form.setFieldValue(field.name, value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
@@ -567,9 +514,7 @@ class JobTemplateForm extends Component {
|
||||
{({ field, form }) => (
|
||||
<TagMultiSelect
|
||||
value={field.value}
|
||||
onChange={value =>
|
||||
form.setFieldValue(field.name, value)
|
||||
}
|
||||
onChange={value => form.setFieldValue(field.name, value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
@@ -603,7 +548,7 @@ class JobTemplateForm extends Component {
|
||||
id="option-callbacks"
|
||||
isChecked={allowCallbacks}
|
||||
onChange={checked => {
|
||||
this.setState({ allowCallbacks: checked });
|
||||
setAllowCallbacks(checked);
|
||||
}}
|
||||
/>
|
||||
<CheckboxField
|
||||
@@ -653,11 +598,33 @@ class JobTemplateForm extends Component {
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
JobTemplateForm.propTypes = {
|
||||
template: JobTemplate,
|
||||
handleCancel: PropTypes.func.isRequired,
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
submitError: PropTypes.shape({}),
|
||||
};
|
||||
JobTemplateForm.defaultProps = {
|
||||
template: {
|
||||
name: '',
|
||||
description: '',
|
||||
job_type: 'run',
|
||||
inventory: undefined,
|
||||
project: undefined,
|
||||
playbook: '',
|
||||
summary_fields: {
|
||||
inventory: null,
|
||||
labels: { results: [] },
|
||||
project: null,
|
||||
credentials: [],
|
||||
},
|
||||
isNew: true,
|
||||
},
|
||||
submitError: null,
|
||||
};
|
||||
|
||||
const FormikApp = withFormik({
|
||||
mapPropsToValues(props) {
|
||||
const { template = {} } = props;
|
||||
mapPropsToValues({ template = {} }) {
|
||||
const {
|
||||
summary_fields = {
|
||||
labels: { results: [] },
|
||||
|
||||
@@ -157,6 +157,7 @@ describe('<JobTemplateForm />', () => {
|
||||
name: 'inventory',
|
||||
});
|
||||
});
|
||||
|
||||
wrapper.update();
|
||||
await act(async () => {
|
||||
wrapper.find('input#template-scm-branch').simulate('change', {
|
||||
|
||||
Reference in New Issue
Block a user