From 8b69b089915f136f53da57af10e9357efda66293 Mon Sep 17 00:00:00 2001 From: Alex Corey Date: Thu, 2 Apr 2020 15:37:40 -0400 Subject: [PATCH] Adds formik hook functionality to wfjt form --- .../WorkflowJobTemplateAdd.jsx | 14 +- .../WorkflowJobTemplateEdit.jsx | 19 +- .../shared/WorkflowJobTemplateForm.jsx | 678 ++++++++---------- 3 files changed, 330 insertions(+), 381 deletions(-) diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.jsx index c1efe45572..f69349bb70 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.jsx +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.jsx @@ -12,7 +12,19 @@ function WorkflowJobTemplateAdd() { const [formSubmitError, setFormSubmitError] = useState(null); const handleSubmit = async values => { - const { labels, organizationId, ...remainingValues } = values; + const { + labels, + inventory, + organization, + webhook_credential, + webhookKey, + ...remainingValues + } = values; + remainingValues.inventory = inventory?.id; + remainingValues.organization = organization?.id; + remainingValues.webhook_credential = webhook_credential?.id; + const organizationId = + organization?.id || inventory?.summary_fields?.organization.id || null; try { const { data: { id }, diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.jsx index b958ff9ff4..0d0d94b7de 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.jsx +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.jsx @@ -11,10 +11,23 @@ function WorkflowJobTemplateEdit({ template, webhook_key }) { const [formSubmitError, setFormSubmitError] = useState(null); const handleSubmit = async values => { - const { labels, ...remainingValues } = values; + const { + labels, + inventory, + organization, + webhook_credential, + webhookKey, + ...remainingValues + } = values; + remainingValues.inventory = inventory?.id; + remainingValues.organization = organization?.id; + remainingValues.webhook_credential = webhook_credential?.id || null; + + const formOrgId = + organization?.id || inventory?.summary_fields?.organization.id || null; try { await Promise.all( - await submitLabels(labels, values.organization, template.organization) + await submitLabels(labels, formOrgId, template.organization) ); await WorkflowJobTemplatesAPI.update(template.id, remainingValues); history.push(`/templates/workflow_job_template/${template.id}/details`); @@ -60,7 +73,7 @@ function WorkflowJobTemplateEdit({ template, webhook_key }) { handleSubmit={handleSubmit} handleCancel={handleCancel} template={template} - webhook_key={webhook_key} + webhookKey={webhook_key} submitError={formSubmitError} /> diff --git a/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.jsx b/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.jsx index 1079f9a5dd..673bce96cb 100644 --- a/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.jsx +++ b/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.jsx @@ -1,11 +1,11 @@ import React, { useState, useEffect, useCallback } from 'react'; import { t } from '@lingui/macro'; -import { useRouteMatch, useParams } from 'react-router-dom'; +import { useRouteMatch, useParams, withRouter } from 'react-router-dom'; -import { func, shape } from 'prop-types'; +import PropTypes, { shape } from 'prop-types'; import { withI18n } from '@lingui/react'; -import { Formik, Field } from 'formik'; +import { useField, withFormik } from 'formik'; import { Form, FormGroup, @@ -40,38 +40,49 @@ import ContentError from '@components/ContentError'; import CheckboxField from '@components/FormField/CheckboxField'; import LabelSelect from './LabelSelect'; +const urlOrigin = window.location.origin; function WorkflowJobTemplateForm({ handleSubmit, handleCancel, i18n, - template = {}, - webhook_key, submitError, }) { - const urlOrigin = window.location.origin; const { id } = useParams(); const wfjtAddMatch = useRouteMatch('/templates/workflow_job_template/add'); const [hasContentError, setContentError] = useState(null); - const [webhook_url, setWebhookUrl] = useState( - template?.related?.webhook_receiver - ? `${urlOrigin}${template.related.webhook_receiver}` - : '' + + const [organizationField, organizationMeta, organizationHelpers] = useField( + 'organization' ); - const [inventory, setInventory] = useState( - template?.summary_fields?.inventory || null + const [inventoryField, inventoryMeta, inventoryHelpers] = useField( + 'inventory' ); - const [organization, setOrganization] = useState( - template?.summary_fields?.organization || null + const [labelsField, , labelsHelpers] = useField('labels'); + + const [ + webhookServiceField, + webhookServiceMeta, + webhookServiceHelpers, + ] = useField('webhook_service'); + + const [webhookKeyField, webhookKeyMeta, webhookKeyHelpers] = useField( + 'webhookKey' ); - const [webhookCredential, setWebhookCredential] = useState( - template?.summary_fields?.webhook_credential || null + + const [hasWebhooks, setHasWebhooks] = useState( + Boolean(webhookServiceField.value) ); - const [webhookKey, setWebHookKey] = useState(webhook_key); - const [webhookService, setWebHookService] = useState( - template.webhook_service || '' + + const [ + webhookCredentialField, + webhookCredentialMeta, + webhookCredentialHelpers, + ] = useField('webhook_credential'); + + const [webhookUrlField, webhookUrlMeta, webhookUrlHelpers] = useField( + 'webhook_url' ); - const [hasWebhooks, setHasWebhooks] = useState(Boolean(webhookService)); const webhookServiceOptions = [ { @@ -93,6 +104,38 @@ function WorkflowJobTemplateForm({ isDisabled: false, }, ]; + + const storeWebhookValues = webhookServiceValue => { + if ( + webhookServiceValue === webhookServiceMeta.initialValue || + webhookServiceValue === '' + ) { + webhookCredentialHelpers.setValue(webhookCredentialMeta.initialValue); + webhookUrlHelpers.setValue(webhookUrlMeta.initialValue); + webhookServiceHelpers.setValue(webhookServiceMeta.initialValue); + webhookKeyHelpers.setValue(webhookKeyMeta.initialValue); + } else { + webhookCredentialHelpers.setValue(null); + webhookUrlHelpers.setValue( + `${urlOrigin}/api/v2/workflow_job_templates/${id}/${webhookServiceValue}/` + ); + webhookKeyHelpers.setValue( + i18n._(t`a new webhook key will be generated on save.`).toUpperCase() + ); + } + }; + + const handleWebhookEnablement = (enabledWebhooks, webhookServiceValue) => { + if (!enabledWebhooks) { + webhookCredentialHelpers.setValue(null); + webhookServiceHelpers.setValue(''); + webhookUrlHelpers.setValue(''); + webhookKeyHelpers.setValue(''); + } else { + storeWebhookValues(webhookServiceValue); + } + }; + const { request: loadCredentialType, error: contentError, @@ -101,15 +144,15 @@ function WorkflowJobTemplateForm({ } = useRequest( useCallback(async () => { let results; - if (webhookService) { + if (webhookServiceField.value) { results = await CredentialTypesAPI.read({ - namespace: `${webhookService}_token`, + namespace: `${webhookServiceField.value}_token`, }); // TODO: Consider how to handle the situation where the results returns // and empty array, or any of the other values is undefined or null (data, results, id) } return results?.data?.results[0]?.id; - }, [webhookService]) + }, [webhookServiceField.value]) ); useEffect(() => { @@ -124,66 +167,12 @@ function WorkflowJobTemplateForm({ const { data: { webhook_key: key }, } = await WorkflowJobTemplatesAPI.updateWebhookKey(id); - setWebHookKey(key); + webhookKeyHelpers.setValue(key); } catch (err) { setContentError(err); } }; - let initialWebhookKey = webhook_key; - const initialWebhookCredential = template?.summary_fields?.webhook_credential; - - const storeWebhookValues = (form, webhookServiceValue) => { - if ( - webhookServiceValue === form.initialValues.webhook_service || - webhookServiceValue === '' - ) { - form.setFieldValue( - 'webhook_credential', - form.initialValues.webhook_credential - ); - setWebhookCredential(initialWebhookCredential); - - setWebhookUrl( - template?.related?.webhook_receiver - ? `${urlOrigin}${template.related.webhook_receiver}` - : '' - ); - form.setFieldValue('webhook_service', form.initialValues.webhook_service); - setWebHookService(form.initialValues.webhook_service); - - setWebHookKey(initialWebhookKey); - } else { - form.setFieldValue('webhook_credential', null); - setWebhookCredential(null); - - setWebhookUrl( - `${urlOrigin}/api/v2/workflow_job_templates/${template.id}/${webhookServiceValue}/` - ); - - setWebHookKey( - i18n._(t`a new webhook key will be generated on save.`).toUpperCase() - ); - } - }; - - const handleWebhookEnablement = ( - form, - enabledWebhooks, - webhookServiceValue - ) => { - if (!enabledWebhooks) { - initialWebhookKey = webhookKey; - form.setFieldValue('webhook_credential', null); - form.setFieldValue('webhook_service', ''); - setWebhookUrl(''); - setWebHookService(''); - setWebHookKey(''); - } else { - storeWebhookValues(form, webhookServiceValue); - } - }; - if (hasContentError || contentError) { return ; } @@ -193,312 +182,213 @@ function WorkflowJobTemplateForm({ } return ( - { - if (values.webhook_service === '') { - values.webhook_credential = ''; - } - return handleSubmit(values); - }} - initialValues={{ - name: template.name || '', - description: template.description || '', - inventory: template?.summary_fields?.inventory?.id || null, - organization: template?.summary_fields?.organization?.id || null, - labels: template.summary_fields?.labels?.results || [], - extra_vars: template.extra_vars || '---', - limit: template.limit || '', - scm_branch: template.scm_branch || '', - allow_simultaneous: template.allow_simultaneous || false, - webhook_credential: - template?.summary_fields?.webhook_credential?.id || null, - webhook_service: template.webhook_service || '', - ask_limit_on_launch: template.ask_limit_on_launch || false, - ask_inventory_on_launch: template.ask_inventory_on_launch || false, - ask_variables_on_launch: template.ask_variables_on_launch || false, - ask_scm_branch_on_launch: template.ask_scm_branch_on_launch || false, - }} - > - {formik => ( -
- - - - - {({ form }) => ( - { - form.setFieldValue('organization', value?.id || null); - setOrganization(value); - }} - value={organization} - isValid={!form.errors.organization} - /> - )} - - - {({ form }) => ( - - - { - form.setFieldValue('inventory', value?.id || null); - setInventory(value); - form.setFieldValue('organizationId', value?.organization); - }} - /> - - )} - - - - - - - {({ form, field }) => ( - - + + + + { + organizationHelpers.setValue(value || null); + }} + value={organizationField.value} + isValid={!organizationMeta.error} + /> + + + { + inventoryHelpers.setValue(value || null); + }} + /> + + + + + + + - form.setFieldValue('labels', labels)} - onError={err => setContentError(err)} - /> - - )} - - - - - - - - {({ form }) => ( - - {i18n._(t`Enable Webhooks`)} -   - - - } - id="wfjt-enabled-webhooks" - isChecked={ - Boolean(form.values.webhook_service) || hasWebhooks - } - onChange={checked => { - setHasWebhooks(checked); - handleWebhookEnablement(form, checked, webhookService); - }} - /> - )} - - - - - {hasWebhooks && ( - - - {({ form, field }) => ( - - - { - setWebHookService(val); - storeWebhookValues(form, val); - - form.setFieldValue('webhook_service', val); - }} - /> - - )} - - {!wfjtAddMatch && ( - <> - - - - - - {({ form }) => ( - - - - - - - - )} - - - )} - {credTypeId && ( - // TODO: Consider how to handle the situation where the results returns - // an empty array, or any of the other values is undefined or null - // (data, results, id) - - {({ form }) => ( - { - form.setFieldValue( - 'webhook_credential', - value?.id || null - ); - setWebhookCredential(value); - }} - isValid={!form.errors.webhook_credential} - helperTextInvalid={form.errors.webhook_credential} - value={webhookCredential} - /> - )} - - )} - - )} - {submitError && } - - + labelsHelpers.setValue(labels)} + onError={setContentError} + /> + + + + + + + + {i18n._(t`Enable Webhook`)} +   + + + } + id="wfjt-enabled-webhooks" + isChecked={Boolean(webhookServiceField.value) || hasWebhooks} + onChange={checked => { + setHasWebhooks(checked); + handleWebhookEnablement(checked, webhookServiceField.value); + }} + /> + + + {hasWebhooks && ( + + + + { + storeWebhookValues(val); + + webhookServiceHelpers.setValue(val); + }} + /> + + {!wfjtAddMatch && ( + <> + + + + + + + + + + + + + )} + {credTypeId && ( + // TODO: Consider how to handle the situation where the results returns + // an empty array, or any of the other values is undefined or null + // (data, results, id) + { + webhookCredentialHelpers.setValue(value || null); + }} + isValid={!webhookCredentialMeta.error} + helperTextInvalid={webhookCredentialMeta.error} + value={webhookCredentialField.value} + /> + )} + )} -
+ {submitError && } + + ); } WorkflowJobTemplateForm.propTypes = { - handleSubmit: func.isRequired, - handleCancel: func.isRequired, + handleSubmit: PropTypes.func.isRequired, + handleCancel: PropTypes.func.isRequired, submitError: shape({}), }; @@ -506,4 +396,38 @@ WorkflowJobTemplateForm.defaultProps = { submitError: null, }; -export default withI18n()(WorkflowJobTemplateForm); +const FormikApp = withFormik({ + mapPropsToValues({ template = {}, webhookKey }) { + return { + name: template.name || '', + description: template.description || '', + inventory: template?.summary_fields?.inventory || null, + organization: template?.summary_fields?.organization || null, + labels: template.summary_fields?.labels?.results || [], + extra_vars: template.extra_vars || '---', + limit: template.limit || '', + scm_branch: template.scm_branch || '', + allow_simultaneous: template.allow_simultaneous || false, + webhook_credential: template?.summary_fields?.webhook_credential || null, + webhook_service: template.webhook_service || '', + ask_limit_on_launch: template.ask_limit_on_launch || false, + ask_inventory_on_launch: template.ask_inventory_on_launch || false, + ask_variables_on_launch: template.ask_variables_on_launch || false, + ask_scm_branch_on_launch: template.ask_scm_branch_on_launch || false, + webhook_url: template?.related?.webhook_receiver + ? `${urlOrigin}${template.related.webhook_receiver}` + : '', + webhookKey: webhookKey || null, + }; + }, + handleSubmit: async (values, { props, setErrors }) => { + try { + await props.handleSubmit(values); + } catch (errors) { + setErrors(errors); + } + }, +})(WorkflowJobTemplateForm); + +export { WorkflowJobTemplateForm as _WorkflowJobTemplateForm }; +export default withI18n()(withRouter(FormikApp));