Do not render setting field if config is empty

This commit is contained in:
Marliana Lara
2020-11-03 14:34:11 -05:00
parent 79930347f9
commit d57fee7b63
7 changed files with 77 additions and 58 deletions

View File

@@ -68,12 +68,24 @@ describe('<ActivityStreamEdit />', () => {
test('should successfully send request to api on form submission', async () => { test('should successfully send request to api on form submission', async () => {
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0); expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
expect(
wrapper.find('Switch#ACTIVITY_STREAM_ENABLED').prop('isChecked')
).toEqual(false);
await act(async () => {
wrapper.find('Switch#ACTIVITY_STREAM_ENABLED').invoke('onChange')(true);
});
wrapper.update();
expect(
wrapper.find('Switch#ACTIVITY_STREAM_ENABLED').prop('isChecked')
).toEqual(true);
await act(async () => { await act(async () => {
wrapper.find('Form').invoke('onSubmit')(); wrapper.find('Form').invoke('onSubmit')();
}); });
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1); expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({ expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
ACTIVITY_STREAM_ENABLED: false, ACTIVITY_STREAM_ENABLED: true,
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: true, ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: true,
}); });
}); });

View File

@@ -14,6 +14,7 @@ import {
InputField, InputField,
ObjectField, ObjectField,
} from '../../shared/SharedFields'; } from '../../shared/SharedFields';
import { formatJson } from '../../shared/settingUtils';
import useModal from '../../../../util/useModal'; import useModal from '../../../../util/useModal';
import useRequest from '../../../../util/useRequest'; import useRequest from '../../../../util/useRequest';
import { SettingsAPI } from '../../../../api'; import { SettingsAPI } from '../../../../api';
@@ -57,10 +58,10 @@ function AzureADEdit() {
const handleSubmit = async form => { const handleSubmit = async form => {
await submitForm({ await submitForm({
...form, ...form,
SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP: JSON.parse( SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP: formatJson(
form.SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP form.SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP
), ),
SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP: JSON.parse( SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP: formatJson(
form.SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP form.SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP
), ),
}); });

View File

@@ -22,6 +22,7 @@ import {
} from '../../shared'; } from '../../shared';
import useModal from '../../../../util/useModal'; import useModal from '../../../../util/useModal';
import useRequest, { useDismissableError } from '../../../../util/useRequest'; import useRequest, { useDismissableError } from '../../../../util/useRequest';
import { formatJson } from '../../shared/settingUtils';
import { SettingsAPI } from '../../../../api'; import { SettingsAPI } from '../../../../api';
function LoggingEdit({ i18n }) { function LoggingEdit({ i18n }) {
@@ -39,6 +40,9 @@ function LoggingEdit({ i18n }) {
const { data } = await SettingsAPI.readCategory('logging'); const { data } = await SettingsAPI.readCategory('logging');
const mergedData = {}; const mergedData = {};
Object.keys(data).forEach(key => { Object.keys(data).forEach(key => {
if (!options[key]) {
return;
}
mergedData[key] = options[key]; mergedData[key] = options[key];
mergedData[key].value = data[key]; mergedData[key].value = data[key];
}); });
@@ -65,7 +69,7 @@ function LoggingEdit({ i18n }) {
const handleSubmit = async form => { const handleSubmit = async form => {
await submitForm({ await submitForm({
...form, ...form,
LOG_AGGREGATOR_LOGGERS: JSON.parse(form.LOG_AGGREGATOR_LOGGERS), LOG_AGGREGATOR_LOGGERS: formatJson(form.LOG_AGGREGATOR_LOGGERS),
LOG_AGGREGATOR_HOST: form.LOG_AGGREGATOR_HOST || null, LOG_AGGREGATOR_HOST: form.LOG_AGGREGATOR_HOST || null,
LOG_AGGREGATOR_TYPE: form.LOG_AGGREGATOR_TYPE || null, LOG_AGGREGATOR_TYPE: form.LOG_AGGREGATOR_TYPE || null,
}); });
@@ -127,10 +131,7 @@ function LoggingEdit({ i18n }) {
{isLoading && <ContentLoading />} {isLoading && <ContentLoading />}
{!isLoading && error && <ContentError error={error} />} {!isLoading && error && <ContentError error={error} />}
{!isLoading && logging && ( {!isLoading && logging && (
<Formik <Formik initialValues={initialValues(logging)} onSubmit={handleSubmit}>
initialValues={{ ...initialValues(logging) }}
onSubmit={handleSubmit}
>
{formik => { {formik => {
return ( return (
<Form autoComplete="off" onSubmit={formik.handleSubmit}> <Form autoComplete="off" onSubmit={formik.handleSubmit}>

View File

@@ -21,7 +21,7 @@ import {
import useModal from '../../../../util/useModal'; import useModal from '../../../../util/useModal';
import useRequest from '../../../../util/useRequest'; import useRequest from '../../../../util/useRequest';
import { SettingsAPI } from '../../../../api'; import { SettingsAPI } from '../../../../api';
import { pluck } from '../../shared/settingUtils'; import { pluck, formatJson } from '../../shared/settingUtils';
function MiscSystemEdit({ i18n }) { function MiscSystemEdit({ i18n }) {
const history = useHistory(); const history = useHistory();
@@ -95,6 +95,9 @@ function MiscSystemEdit({ i18n }) {
const mergedData = {}; const mergedData = {};
Object.keys(systemData).forEach(key => { Object.keys(systemData).forEach(key => {
if (!systemOptions[key]) {
return;
}
mergedData[key] = systemOptions[key]; mergedData[key] = systemOptions[key];
mergedData[key].value = systemData[key]; mergedData[key].value = systemData[key];
}); });
@@ -127,8 +130,8 @@ function MiscSystemEdit({ i18n }) {
} = form; } = form;
await submitForm({ await submitForm({
...formData, ...formData,
CUSTOM_VENV_PATHS: JSON.parse(formData.CUSTOM_VENV_PATHS), CUSTOM_VENV_PATHS: formatJson(formData.CUSTOM_VENV_PATHS),
REMOTE_HOST_HEADERS: JSON.parse(formData.REMOTE_HOST_HEADERS), REMOTE_HOST_HEADERS: formatJson(formData.REMOTE_HOST_HEADERS),
OAUTH2_PROVIDER: { OAUTH2_PROVIDER: {
ACCESS_TOKEN_EXPIRE_SECONDS, ACCESS_TOKEN_EXPIRE_SECONDS,
REFRESH_TOKEN_EXPIRE_SECONDS, REFRESH_TOKEN_EXPIRE_SECONDS,
@@ -181,10 +184,7 @@ function MiscSystemEdit({ i18n }) {
{isLoading && <ContentLoading />} {isLoading && <ContentLoading />}
{!isLoading && error && <ContentError error={error} />} {!isLoading && error && <ContentError error={error} />}
{!isLoading && system && ( {!isLoading && system && (
<Formik <Formik initialValues={initialValues(system)} onSubmit={handleSubmit}>
initialValues={{ ...initialValues(system) }}
onSubmit={handleSubmit}
>
{formik => { {formik => {
return ( return (
<Form autoComplete="off" onSubmit={formik.handleSubmit}> <Form autoComplete="off" onSubmit={formik.handleSubmit}>

View File

@@ -45,6 +45,7 @@ function RevertButton({ i18n, id, defaultValue, isDisabled = false }) {
<ButtonWrapper> <ButtonWrapper>
<Button <Button
aria-label={isRevertable ? i18n._(t`Revert`) : i18n._(t`Undo`)} aria-label={isRevertable ? i18n._(t`Revert`) : i18n._(t`Undo`)}
data-cy={`${id}-revert`}
isInline isInline
isSmall isSmall
onClick={handleConfirm} onClick={handleConfirm}

View File

@@ -44,39 +44,36 @@ const SettingGroup = withI18n()(
label, label,
popoverContent, popoverContent,
validated, validated,
}) => { }) => (
return ( <FormGroup
<FormGroup fieldId={fieldId}
fieldId={fieldId} helperTextInvalid={helperTextInvalid}
helperTextInvalid={helperTextInvalid} isRequired={isRequired}
isRequired={isRequired} label={label}
label={label} validated={validated}
validated={validated} labelIcon={
labelIcon={ <>
<> <Popover
<Popover content={popoverContent}
content={popoverContent} ariaLabel={`${i18n._(t`More information for`)} ${label}`}
ariaLabel={`${i18n._(t`More information for`)} ${label}`} />
/> <RevertButton
<RevertButton id={fieldId}
id={fieldId} defaultValue={defaultValue}
defaultValue={defaultValue} isDisabled={isDisabled}
isDisabled={isDisabled} />
/> </>
</> }
} >
> {children}
{children} </FormGroup>
</FormGroup> )
);
}
); );
const BooleanField = withI18n()( const BooleanField = withI18n()(
({ i18n, ariaLabel = '', name, config, disabled = false }) => { ({ i18n, ariaLabel = '', name, config, disabled = false }) => {
const [field, meta, helpers] = useField(name); const [field, meta, helpers] = useField(name);
return config ? (
return (
<SettingGroup <SettingGroup
defaultValue={config.default ?? false} defaultValue={config.default ?? false}
fieldId={name} fieldId={name}
@@ -95,7 +92,7 @@ const BooleanField = withI18n()(
aria-label={ariaLabel || config.label} aria-label={ariaLabel || config.label}
/> />
</SettingGroup> </SettingGroup>
); ) : null;
} }
); );
BooleanField.propTypes = { BooleanField.propTypes = {
@@ -110,7 +107,7 @@ const ChoiceField = withI18n()(({ i18n, name, config, isRequired = false }) => {
const [field, meta] = useField({ name, validate }); const [field, meta] = useField({ name, validate });
const isValid = !meta.error || !meta.touched; const isValid = !meta.error || !meta.touched;
return ( return config ? (
<SettingGroup <SettingGroup
defaultValue={config.default ?? ''} defaultValue={config.default ?? ''}
fieldId={name} fieldId={name}
@@ -132,7 +129,7 @@ const ChoiceField = withI18n()(({ i18n, name, config, isRequired = false }) => {
]} ]}
/> />
</SettingGroup> </SettingGroup>
); ) : null;
}); });
ChoiceField.propTypes = { ChoiceField.propTypes = {
name: string.isRequired, name: string.isRequired,
@@ -146,7 +143,7 @@ const EncryptedField = withI18n()(
const [, meta] = useField({ name, validate }); const [, meta] = useField({ name, validate });
const isValid = !(meta.touched && meta.error); const isValid = !(meta.touched && meta.error);
return ( return config ? (
<SettingGroup <SettingGroup
defaultValue={config.default ?? ''} defaultValue={config.default ?? ''}
fieldId={name} fieldId={name}
@@ -166,7 +163,7 @@ const EncryptedField = withI18n()(
/> />
</InputGroup> </InputGroup>
</SettingGroup> </SettingGroup>
); ) : null;
} }
); );
EncryptedField.propTypes = { EncryptedField.propTypes = {
@@ -177,10 +174,8 @@ EncryptedField.propTypes = {
const InputField = withI18n()( const InputField = withI18n()(
({ i18n, name, config, type = 'text', isRequired = false }) => { ({ i18n, name, config, type = 'text', isRequired = false }) => {
const { const min_value = config?.min_value ?? Number.MIN_SAFE_INTEGER;
min_value = Number.MIN_SAFE_INTEGER, const max_value = config?.max_value ?? Number.MAX_SAFE_INTEGER;
max_value = Number.MAX_SAFE_INTEGER,
} = config;
const validators = [ const validators = [
...(isRequired ? [required(null, i18n)] : []), ...(isRequired ? [required(null, i18n)] : []),
...(type === 'url' ? [url(i18n)] : []), ...(type === 'url' ? [url(i18n)] : []),
@@ -191,7 +186,7 @@ const InputField = withI18n()(
const [field, meta] = useField({ name, validate: combine(validators) }); const [field, meta] = useField({ name, validate: combine(validators) });
const isValid = !(meta.touched && meta.error); const isValid = !(meta.touched && meta.error);
return ( return config ? (
<SettingGroup <SettingGroup
defaultValue={config.default || ''} defaultValue={config.default || ''}
fieldId={name} fieldId={name}
@@ -213,7 +208,7 @@ const InputField = withI18n()(
}} }}
/> />
</SettingGroup> </SettingGroup>
); ) : null;
} }
); );
InputField.propTypes = { InputField.propTypes = {
@@ -228,12 +223,12 @@ const ObjectField = withI18n()(({ i18n, name, config, isRequired = false }) => {
const [field, meta, helpers] = useField({ name, validate }); const [field, meta, helpers] = useField({ name, validate });
const isValid = !(meta.touched && meta.error); const isValid = !(meta.touched && meta.error);
const emptyDefault = config.type === 'list' ? '[]' : '{}'; const emptyDefault = config?.type === 'list' ? '[]' : '{}';
const defaultRevertValue = config.default const defaultRevertValue = config?.default
? JSON.stringify(config.default, null, 2) ? JSON.stringify(config.default, null, 2)
: emptyDefault; : emptyDefault;
return ( return config ? (
<FormFullWidthLayout> <FormFullWidthLayout>
<SettingGroup <SettingGroup
defaultValue={defaultRevertValue} defaultValue={defaultRevertValue}
@@ -254,7 +249,7 @@ const ObjectField = withI18n()(({ i18n, name, config, isRequired = false }) => {
/> />
</SettingGroup> </SettingGroup>
</FormFullWidthLayout> </FormFullWidthLayout>
); ) : null;
}); });
ObjectField.propTypes = { ObjectField.propTypes = {
name: string.isRequired, name: string.isRequired,

View File

@@ -1,3 +1,5 @@
import { isJsonString } from '../../../util/yaml';
export function sortNestedDetails(obj = {}) { export function sortNestedDetails(obj = {}) {
const nestedTypes = ['nested object', 'list', 'boolean']; const nestedTypes = ['nested object', 'list', 'boolean'];
const notNested = Object.entries(obj).filter( const notNested = Object.entries(obj).filter(
@@ -18,3 +20,10 @@ export function sortNestedDetails(obj = {}) {
export function pluck(sourceObject, ...keys) { export function pluck(sourceObject, ...keys) {
return Object.assign({}, ...keys.map(key => ({ [key]: sourceObject[key] }))); return Object.assign({}, ...keys.map(key => ({ [key]: sourceObject[key] })));
} }
export function formatJson(jsonString) {
if (!jsonString) {
return null;
}
return isJsonString(jsonString) ? JSON.parse(jsonString) : jsonString;
}