Merge pull request #9662 from jakemcdermott/fix-9636

Fix cred type display on form initialization

SUMMARY
For #9636 and #8828

Reviewed-by: Kersom <None>
This commit is contained in:
softwarefactory-project-zuul[bot]
2021-04-06 16:30:01 +00:00
committed by GitHub
2 changed files with 119 additions and 71 deletions

View File

@@ -158,7 +158,7 @@ function CredentialEdit({ credential }) {
}, {}); }, {});
return { credentialTypes: creds, loadedInputSources: inputSources }; return { credentialTypes: creds, loadedInputSources: inputSources };
}, [credId, me.id]), }, [credId, me.id]),
{ credentialTypes: {}, loadedInputSources: {} } {}
); );
useEffect(() => { useEffect(() => {
@@ -178,7 +178,7 @@ function CredentialEdit({ credential }) {
return <ContentError error={error} />; return <ContentError error={error} />;
} }
if (isLoading) { if (isLoading || !credentialTypes) {
return <ContentLoading />; return <ContentLoading />;
} }

View File

@@ -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 { shape } from 'prop-types';
import { Formik, useField, useFormikContext } from 'formik'; import { Formik, useField, useFormikContext } from 'formik';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
@@ -11,6 +12,7 @@ import {
Select as PFSelect, Select as PFSelect,
SelectOption as PFSelectOption, SelectOption as PFSelectOption,
SelectVariant, SelectVariant,
Tooltip,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import styled from 'styled-components'; import styled from 'styled-components';
import FormField, { FormSubmitError } from '../../../components/FormField'; import FormField, { FormSubmitError } from '../../../components/FormField';
@@ -27,6 +29,7 @@ const Select = styled(PFSelect)`
ul { ul {
max-width: 495px; max-width: 495px;
} }
${props => (props.isDisabled ? `cursor: not-allowed` : null)}
`; `;
const SelectOption = styled(PFSelectOption)` const SelectOption = styled(PFSelectOption)`
@@ -35,7 +38,8 @@ const SelectOption = styled(PFSelectOption)`
overflow: hidden; overflow: hidden;
`; `;
function CredentialFormFields({ i18n, credentialTypes }) { function CredentialFormFields({ i18n, initialTypeId, credentialTypes }) {
const { pathname } = useLocation();
const { setFieldValue, initialValues, setFieldTouched } = useFormikContext(); const { setFieldValue, initialValues, setFieldTouched } = useFormikContext();
const [isSelectOpen, setIsSelectOpen] = useState(false); const [isSelectOpen, setIsSelectOpen] = useState(false);
const [credTypeField, credTypeMeta, credTypeHelpers] = useField({ const [credTypeField, credTypeMeta, credTypeHelpers] = useField({
@@ -43,9 +47,10 @@ function CredentialFormFields({ i18n, credentialTypes }) {
validate: required(i18n._(t`Select a value for this field`), i18n), validate: required(i18n._(t`Select a value for this field`), i18n),
}); });
const [credentialTypeId, setCredentialTypeId] = useState(initialTypeId);
const isGalaxyCredential = const isGalaxyCredential =
!!credTypeField.value && !!credentialTypeId && credentialTypes[credentialTypeId]?.kind === 'galaxy';
credentialTypes[credTypeField.value]?.kind === 'galaxy';
const [orgField, orgMeta, orgHelpers] = useField({ const [orgField, orgMeta, orgHelpers] = useField({
name: 'organization', name: 'organization',
@@ -67,42 +72,58 @@ function CredentialFormFields({ i18n, credentialTypes }) {
}) })
.sort((a, b) => (a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1)); .sort((a, b) => (a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1));
const resetSubFormFields = newCredentialType => { const resetSubFormFields = useCallback(
const fields = credentialTypes[newCredentialType].inputs.fields || []; newCredentialTypeId => {
fields.forEach( const fields = credentialTypes[newCredentialTypeId].inputs.fields || [];
({ ask_at_runtime, type, id, choices, default: defaultValue }) => { fields.forEach(
if (parseInt(newCredentialType, 10) === initialValues.credential_type) { ({ ask_at_runtime, type, id, choices, default: defaultValue }) => {
setFieldValue(`inputs.${id}`, initialValues.inputs[id]); if (parseInt(newCredentialTypeId, 10) === initialTypeId) {
if (ask_at_runtime) { setFieldValue(`inputs.${id}`, initialValues.inputs[id]);
setFieldValue( if (ask_at_runtime) {
`passwordPrompts.${id}`, setFieldValue(
initialValues.passwordPrompts[id] `passwordPrompts.${id}`,
); initialValues.passwordPrompts[id]
} );
} else { }
switch (type) { } else {
case 'string': switch (type) {
setFieldValue(`inputs.${id}`, defaultValue || ''); case 'string':
break; setFieldValue(`inputs.${id}`, defaultValue || '');
case 'boolean': break;
setFieldValue(`inputs.${id}`, defaultValue || false); case 'boolean':
break; setFieldValue(`inputs.${id}`, defaultValue || false);
default: break;
break; default:
} break;
}
if (choices) { if (choices) {
setFieldValue(`inputs.${id}`, defaultValue); setFieldValue(`inputs.${id}`, defaultValue);
} }
if (ask_at_runtime) { if (ask_at_runtime) {
setFieldValue(`passwordPrompts.${id}`, false); 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( const onOrganizationChange = useCallback(
value => { value => {
@@ -111,6 +132,38 @@ function CredentialFormFields({ i18n, credentialTypes }) {
[setFieldValue] [setFieldValue]
); );
const isCredentialTypeDisabled = pathname.includes('edit');
const credentialTypeSelect = (
<Select
isDisabled={isCredentialTypeDisabled}
ouiaId="CredentialForm-credential_type"
aria-label={i18n._(t`Credential Type`)}
isOpen={isSelectOpen}
variant={SelectVariant.typeahead}
onToggle={setIsSelectOpen}
onSelect={(event, value) => {
setCredentialTypeId(value);
credTypeHelpers.setValue(value);
setIsSelectOpen(false);
}}
selections={credTypeField.value}
placeholder={i18n._(t`Select a credential Type`)}
isCreatable={false}
maxHeight="300px"
width="100%"
>
{credentialTypeOptions.map(credType => (
<SelectOption
key={credType.value}
value={credType.value}
dataCy={`${credType.id}-credential-type-select-option`}
>
{credType.label}
</SelectOption>
))}
</Select>
);
return ( return (
<> <>
<FormField <FormField
@@ -147,39 +200,24 @@ function CredentialFormFields({ i18n, credentialTypes }) {
} }
label={i18n._(t`Credential Type`)} label={i18n._(t`Credential Type`)}
> >
<Select {isCredentialTypeDisabled ? (
ouiaId="CredentialForm-credential_type" <Tooltip
aria-label={i18n._(t`Credential Type`)} content={i18n._(
isOpen={isSelectOpen} `You cannot change the credential type of a credential,
variant={SelectVariant.typeahead} as it may break the functionality of the resources using it.`
onToggle={setIsSelectOpen} )}
onSelect={(event, value) => { >
credTypeHelpers.setValue(value); {credentialTypeSelect}
resetSubFormFields(value); </Tooltip>
setIsSelectOpen(false); ) : (
}} credentialTypeSelect
selections={credTypeField.value} )}
placeholder={i18n._(t`Select a credential Type`)}
isCreatable={false}
maxHeight="300px"
width="100%"
>
{credentialTypeOptions.map(credType => (
<SelectOption
key={credType.value}
value={credType.value}
dataCy={`${credType.id}-credential-type-select-option`}
>
{credType.label}
</SelectOption>
))}
</Select>
</FormGroup> </FormGroup>
{credTypeField.value !== undefined && {credentialTypeId !== undefined &&
credTypeField.value !== '' && credentialTypeId !== '' &&
credentialTypes[credTypeField.value]?.inputs?.fields && ( credentialTypes[credentialTypeId]?.inputs?.fields && (
<TypeInputsSubForm <TypeInputsSubForm
credentialType={credentialTypes[credTypeField.value]} credentialType={credentialTypes[credentialTypeId]}
/> />
)} )}
</> </>
@@ -197,12 +235,14 @@ function CredentialForm({
isOrgLookupDisabled, isOrgLookupDisabled,
...rest ...rest
}) { }) {
const initialTypeId = credential?.credential_type;
const [showExternalTestModal, setShowExternalTestModal] = useState(false); const [showExternalTestModal, setShowExternalTestModal] = useState(false);
const initialValues = { const initialValues = {
name: credential.name || '', name: credential.name || '',
description: credential.description || '', description: credential.description || '',
organization: credential?.summary_fields?.organization || null, organization: credential?.summary_fields?.organization || null,
credential_type: credential?.credential_type || '', credential_type: credentialTypes[initialTypeId]?.name || '',
inputs: credential?.inputs || {}, inputs: credential?.inputs || {},
passwordPrompts: {}, passwordPrompts: {},
isOrgLookupDisabled: isOrgLookupDisabled || false, isOrgLookupDisabled: isOrgLookupDisabled || false,
@@ -253,7 +293,14 @@ function CredentialForm({
<Formik <Formik
initialValues={initialValues} initialValues={initialValues}
onSubmit={values => { onSubmit={values => {
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 => ( {formik => (
@@ -261,6 +308,7 @@ function CredentialForm({
<Form autoComplete="off" onSubmit={formik.handleSubmit}> <Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout> <FormColumnLayout>
<CredentialFormFields <CredentialFormFields
initialTypeId={initialTypeId}
credentialTypes={credentialTypes} credentialTypes={credentialTypes}
i18n={i18n} i18n={i18n}
{...rest} {...rest}