diff --git a/awx/ui_next/src/components/FormField/FormSubmitError.jsx b/awx/ui_next/src/components/FormField/FormSubmitError.jsx
new file mode 100644
index 0000000000..186f17bf7c
--- /dev/null
+++ b/awx/ui_next/src/components/FormField/FormSubmitError.jsx
@@ -0,0 +1,42 @@
+import React, { useState, useEffect } from 'react';
+import { useFormikContext } from 'formik';
+import { t } from '@lingui/macro';
+import { withI18n } from '@lingui/react';
+import ErrorDetail from '@components/ErrorDetail';
+import AlertModal from '@components/AlertModal';
+
+function FormSubmitError({ error, i18n }) {
+ const [formError, setFormError] = useState(null);
+ const { setErrors } = useFormikContext();
+
+ useEffect(() => {
+ if (!error) {
+ return;
+ }
+ // check for field-specific errors from API
+ if (error.response?.data && typeof error.response.data === 'object') {
+ setErrors(error.response.data);
+ setFormError(null);
+ } else {
+ setFormError(error);
+ }
+ }, [error, setErrors]);
+
+ if (!formError) {
+ return null;
+ }
+
+ return (
+ setFormError(null)}
+ >
+ {i18n._(t`An error occurred when saving`)}
+
+
+ );
+}
+
+export default withI18n()(FormSubmitError);
diff --git a/awx/ui_next/src/components/FormField/index.js b/awx/ui_next/src/components/FormField/index.js
index 2b23e65900..563f8519eb 100644
--- a/awx/ui_next/src/components/FormField/index.js
+++ b/awx/ui_next/src/components/FormField/index.js
@@ -2,3 +2,4 @@ export { default } from './FormField';
export { default as CheckboxField } from './CheckboxField';
export { default as FieldTooltip } from './FieldTooltip';
export { default as PasswordField } from './PasswordField';
+export { default as FormSubmitError } from './FormSubmitError';
diff --git a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx
index a4511f4e10..69a55550f1 100644
--- a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx
+++ b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx
@@ -1,15 +1,11 @@
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
-import { t } from '@lingui/macro';
-import { withI18n } from '@lingui/react';
import { Card } from '@patternfly/react-core';
import { CardBody } from '@components/Card';
-import ErrorDetail from '@components/ErrorDetail';
-import AlertModal from '@components/AlertModal';
import JobTemplateForm from '../shared/JobTemplateForm';
import { JobTemplatesAPI } from '@api';
-function JobTemplateAdd({ i18n }) {
+function JobTemplateAdd() {
const [formSubmitError, setFormSubmitError] = useState(null);
const history = useHistory();
@@ -35,10 +31,6 @@ function JobTemplateAdd({ i18n }) {
]);
history.push(`/templates/${type}/${id}/details`);
} catch (error) {
- // check for field-specific errors from API
- if (error.response?.data && typeof error.response.data === 'object') {
- throw error.response.data;
- }
setFormSubmitError(error);
}
}
@@ -74,21 +66,11 @@ function JobTemplateAdd({ i18n }) {
- {formSubmitError && (
- setFormSubmitError(null)}
- >
- {i18n._(t`An error occurred when saving`)}
-
-
- )}
);
}
-export default withI18n()(JobTemplateAdd);
+export default JobTemplateAdd;
diff --git a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.jsx b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.jsx
index 07e1085936..1e8efd94d0 100644
--- a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.jsx
+++ b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.jsx
@@ -1,13 +1,9 @@
/* eslint react/no-unused-state: 0 */
import React, { Component } from 'react';
import { withRouter, Redirect } from 'react-router-dom';
-import { t } from '@lingui/macro';
-import { withI18n } from '@lingui/react';
import { CardBody } from '@components/Card';
import ContentError from '@components/ContentError';
import ContentLoading from '@components/ContentLoading';
-import ErrorDetail from '@components/ErrorDetail';
-import AlertModal from '@components/AlertModal';
import { JobTemplatesAPI, ProjectsAPI } from '@api';
import { JobTemplate } from '@types';
import { getAddedAndRemoved } from '@util/lists';
@@ -118,10 +114,6 @@ class JobTemplateEdit extends Component {
]);
history.push(this.detailsUrl);
} catch (error) {
- // check for field-specific errors from API
- if (error.response?.data && typeof error.response.data === 'object') {
- throw error.response.data;
- }
this.setState({ formSubmitError: error });
}
}
@@ -181,7 +173,7 @@ class JobTemplateEdit extends Component {
}
render() {
- const { template, i18n } = this.props;
+ const { template } = this.props;
const {
contentError,
formSubmitError,
@@ -217,21 +209,11 @@ class JobTemplateEdit extends Component {
handleCancel={this.handleCancel}
handleSubmit={this.handleSubmit}
relatedProjectPlaybooks={relatedProjectPlaybooks}
+ submitError={formSubmitError}
/>
- {formSubmitError && (
- this.setState({ formSubmitError: null })}
- >
- {i18n._(t`An error occurred when saving`)}
-
-
- )}
);
}
}
-export default withI18n()(withRouter(JobTemplateEdit));
+export default withRouter(JobTemplateEdit);
diff --git a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx
index 19973cfdd5..932e610849 100644
--- a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx
+++ b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx
@@ -16,7 +16,11 @@ import ContentLoading from '@components/ContentLoading';
import AnsibleSelect from '@components/AnsibleSelect';
import { TagMultiSelect } from '@components/MultiSelect';
import FormActionGroup from '@components/FormActionGroup';
-import FormField, { CheckboxField, FieldTooltip } from '@components/FormField';
+import FormField, {
+ CheckboxField,
+ FieldTooltip,
+ FormSubmitError,
+} from '@components/FormField';
import FormRow from '@components/FormRow';
import CollapsibleSection from '@components/CollapsibleSection';
import { required } from '@util/validators';
@@ -48,6 +52,7 @@ class JobTemplateForm extends Component {
template: JobTemplate,
handleCancel: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
+ submitError: PropTypes.shape({}),
};
static defaultProps = {
@@ -66,6 +71,7 @@ class JobTemplateForm extends Component {
},
isNew: true,
},
+ submitError: null,
};
constructor(props) {
@@ -161,9 +167,9 @@ class JobTemplateForm extends Component {
handleSubmit,
handleBlur,
setFieldValue,
- i18n,
template,
- formik,
+ submitError,
+ i18n,
} = this.props;
const jobTypeOptions = [
@@ -202,6 +208,7 @@ class JobTemplateForm extends Component {
if (contentError) {
return ;
}
+
const AdvancedFieldsWrapper = template.isNew ? CollapsibleSection : 'div';
return (
);
}