diff --git a/awx/ui_next/src/screens/Credential/CredentialEdit/CredentialEdit.jsx b/awx/ui_next/src/screens/Credential/CredentialEdit/CredentialEdit.jsx index 507af78334..84d9c7c882 100644 --- a/awx/ui_next/src/screens/Credential/CredentialEdit/CredentialEdit.jsx +++ b/awx/ui_next/src/screens/Credential/CredentialEdit/CredentialEdit.jsx @@ -158,7 +158,7 @@ function CredentialEdit({ credential }) { }, {}); return { credentialTypes: creds, loadedInputSources: inputSources }; }, [credId, me.id]), - { credentialTypes: {}, loadedInputSources: {} } + {} ); useEffect(() => { @@ -178,7 +178,7 @@ function CredentialEdit({ credential }) { return ; } - if (isLoading) { + if (isLoading || !credentialTypes) { return ; } diff --git a/awx/ui_next/src/screens/Credential/shared/CredentialForm.jsx b/awx/ui_next/src/screens/Credential/shared/CredentialForm.jsx index abe76c9644..9d69aa7d13 100644 --- a/awx/ui_next/src/screens/Credential/shared/CredentialForm.jsx +++ b/awx/ui_next/src/screens/Credential/shared/CredentialForm.jsx @@ -1,4 +1,5 @@ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useLocation } from 'react-router-dom'; import { shape } from 'prop-types'; import { Formik, useField, useFormikContext } from 'formik'; import { withI18n } from '@lingui/react'; @@ -11,6 +12,7 @@ import { Select as PFSelect, SelectOption as PFSelectOption, SelectVariant, + Tooltip, } from '@patternfly/react-core'; import styled from 'styled-components'; import FormField, { FormSubmitError } from '../../../components/FormField'; @@ -27,6 +29,7 @@ const Select = styled(PFSelect)` ul { max-width: 495px; } + ${props => (props.isDisabled ? `cursor: not-allowed` : null)} `; const SelectOption = styled(PFSelectOption)` @@ -35,7 +38,8 @@ const SelectOption = styled(PFSelectOption)` overflow: hidden; `; -function CredentialFormFields({ i18n, credentialTypes }) { +function CredentialFormFields({ i18n, initialTypeId, credentialTypes }) { + const { pathname } = useLocation(); const { setFieldValue, initialValues, setFieldTouched } = useFormikContext(); const [isSelectOpen, setIsSelectOpen] = useState(false); const [credTypeField, credTypeMeta, credTypeHelpers] = useField({ @@ -43,9 +47,10 @@ function CredentialFormFields({ i18n, credentialTypes }) { validate: required(i18n._(t`Select a value for this field`), i18n), }); + const [credentialTypeId, setCredentialTypeId] = useState(initialTypeId); + const isGalaxyCredential = - !!credTypeField.value && - credentialTypes[credTypeField.value]?.kind === 'galaxy'; + !!credentialTypeId && credentialTypes[credentialTypeId]?.kind === 'galaxy'; const [orgField, orgMeta, orgHelpers] = useField({ name: 'organization', @@ -67,42 +72,58 @@ function CredentialFormFields({ i18n, credentialTypes }) { }) .sort((a, b) => (a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1)); - const resetSubFormFields = newCredentialType => { - const fields = credentialTypes[newCredentialType].inputs.fields || []; - fields.forEach( - ({ ask_at_runtime, type, id, choices, default: defaultValue }) => { - if (parseInt(newCredentialType, 10) === initialValues.credential_type) { - setFieldValue(`inputs.${id}`, initialValues.inputs[id]); - if (ask_at_runtime) { - setFieldValue( - `passwordPrompts.${id}`, - initialValues.passwordPrompts[id] - ); - } - } else { - switch (type) { - case 'string': - setFieldValue(`inputs.${id}`, defaultValue || ''); - break; - case 'boolean': - setFieldValue(`inputs.${id}`, defaultValue || false); - break; - default: - break; - } + const resetSubFormFields = useCallback( + newCredentialTypeId => { + const fields = credentialTypes[newCredentialTypeId].inputs.fields || []; + fields.forEach( + ({ ask_at_runtime, type, id, choices, default: defaultValue }) => { + if (parseInt(newCredentialTypeId, 10) === initialTypeId) { + setFieldValue(`inputs.${id}`, initialValues.inputs[id]); + if (ask_at_runtime) { + setFieldValue( + `passwordPrompts.${id}`, + initialValues.passwordPrompts[id] + ); + } + } else { + switch (type) { + case 'string': + setFieldValue(`inputs.${id}`, defaultValue || ''); + break; + case 'boolean': + setFieldValue(`inputs.${id}`, defaultValue || false); + break; + default: + break; + } - if (choices) { - setFieldValue(`inputs.${id}`, defaultValue); - } + if (choices) { + setFieldValue(`inputs.${id}`, defaultValue); + } - if (ask_at_runtime) { - setFieldValue(`passwordPrompts.${id}`, false); + if (ask_at_runtime) { + setFieldValue(`passwordPrompts.${id}`, false); + } } + setFieldTouched(`inputs.${id}`, false); } - setFieldTouched(`inputs.${id}`, false); - } - ); - }; + ); + }, + [ + credentialTypes, + initialTypeId, + initialValues.inputs, + initialValues.passwordPrompts, + setFieldTouched, + setFieldValue, + ] + ); + + useEffect(() => { + if (credentialTypeId) { + resetSubFormFields(credentialTypeId); + } + }, [resetSubFormFields, credentialTypeId]); const onOrganizationChange = useCallback( value => { @@ -111,6 +132,38 @@ function CredentialFormFields({ i18n, credentialTypes }) { [setFieldValue] ); + const isCredentialTypeDisabled = pathname.includes('edit'); + const credentialTypeSelect = ( + + ); + return ( <> - + {isCredentialTypeDisabled ? ( + + {credentialTypeSelect} + + ) : ( + credentialTypeSelect + )} - {credTypeField.value !== undefined && - credTypeField.value !== '' && - credentialTypes[credTypeField.value]?.inputs?.fields && ( + {credentialTypeId !== undefined && + credentialTypeId !== '' && + credentialTypes[credentialTypeId]?.inputs?.fields && ( )} @@ -197,12 +235,14 @@ function CredentialForm({ isOrgLookupDisabled, ...rest }) { + const initialTypeId = credential?.credential_type; + const [showExternalTestModal, setShowExternalTestModal] = useState(false); const initialValues = { name: credential.name || '', description: credential.description || '', organization: credential?.summary_fields?.organization || null, - credential_type: credential?.credential_type || '', + credential_type: credentialTypes[initialTypeId]?.name || '', inputs: credential?.inputs || {}, passwordPrompts: {}, isOrgLookupDisabled: isOrgLookupDisabled || false, @@ -253,7 +293,14 @@ function CredentialForm({ { - onSubmit(values); + const { credential_type, ...actualValues } = values; + // credential_type could be the raw id or the displayed name value. + // If it's the name, replace it with the id before making the request. + actualValues.credential_type = + Object.keys(credentialTypes).find( + key => credentialTypes[key].name === credential_type + ) || credential_type; + onSubmit(actualValues); }} > {formik => ( @@ -261,6 +308,7 @@ function CredentialForm({