From a934e146ee22e2da554ee96136ffa6a9b2d475bd Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 4 Feb 2020 09:58:22 -0800 Subject: [PATCH] add FormSubmitError component --- .../components/FormField/FormSubmitError.jsx | 42 +++++++++++++++++++ awx/ui_next/src/components/FormField/index.js | 1 + .../JobTemplateAdd/JobTemplateAdd.jsx | 24 ++--------- .../JobTemplateEdit/JobTemplateEdit.jsx | 24 ++--------- .../Template/shared/JobTemplateForm.jsx | 14 +++++-- 5 files changed, 60 insertions(+), 45 deletions(-) create mode 100644 awx/ui_next/src/components/FormField/FormSubmitError.jsx 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 (
@@ -587,6 +594,7 @@ class JobTemplateForm extends Component { + ); }