Skip to content

Commit

Permalink
feat: improves conditional logic performance and edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
jmikrut committed Jul 27, 2021
1 parent ea358a6 commit d43390f
Show file tree
Hide file tree
Showing 23 changed files with 67 additions and 76 deletions.
13 changes: 3 additions & 10 deletions src/admin/components/forms/Form/buildStateFromSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@ import ObjectID from 'bson-objectid';
import { Field as FieldSchema } from '../../../../fields/config/types';
import { Fields, Field, Data } from './types';

const buildValidationPromise = async (fieldState: Field, field: FieldSchema, fullData: Data = {}, data: Data = {}) => {
const buildValidationPromise = async (fieldState: Field, field: FieldSchema) => {
const validatedFieldState = fieldState;

let passesConditionalLogic = true;

if (field?.admin?.condition) {
passesConditionalLogic = await field.admin.condition(fullData, data);
}

let validationResult: boolean | string = true;

if (passesConditionalLogic && typeof field.validate === 'function') {
if (typeof field.validate === 'function') {
validationResult = await field.validate(fieldState.value, field);
}

Expand All @@ -37,10 +31,9 @@ const buildStateFromSchema = async (fieldSchema: FieldSchema[], fullData: Data =
initialValue: value,
valid: true,
validate: field.validate,
condition: field?.admin?.condition,
};

validationPromises.push(buildValidationPromise(fieldState, field, fullData, data));
validationPromises.push(buildValidationPromise(fieldState, field));

return fieldState;
};
Expand Down
25 changes: 24 additions & 1 deletion src/admin/components/forms/Form/fieldReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,29 @@ function fieldReducer(state: Fields, action): Fields {
return newState;
}

case 'MODIFY_CONDITION': {
const { path, result } = action;

return Object.entries(state).reduce((newState, [key, val]) => {
if (key === path || key.indexOf(`${path}.`) === 0) {
return {
...newState,
[key]: {
...val,
passesCondition: result,
},
};
}

return {
...newState,
[key]: {
...val,
},
};
}, {});
}

default: {
const newField = {
value: action.value,
Expand All @@ -113,7 +136,7 @@ function fieldReducer(state: Fields, action): Fields {
initialValue: action.initialValue,
stringify: action.stringify,
validate: action.validate,
condition: action.condition,
passesCondition: action.passesCondition,
};

return {
Expand Down
28 changes: 10 additions & 18 deletions src/admin/components/forms/Form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,32 +67,24 @@ const Form: React.FC<Props> = (props) => {
const validatedFieldState = {};
let isValid = true;

const data = contextRef.current.getData();

const validationPromises = Object.entries(contextRef.current.fields).map(async ([path, field]) => {
const validatedField = {
...field,
valid: true,
};

const siblingData = contextRef.current.getSiblingData(path);

let passesConditionalLogic = true;

if (typeof field?.condition === 'function') {
passesConditionalLogic = await field.condition(data, siblingData);
}

let validationResult: boolean | string = true;
if (field.passesCondition !== false) {
let validationResult: boolean | string = true;

if (passesConditionalLogic && typeof field.validate === 'function') {
validationResult = await field.validate(field.value);
}
if (typeof field.validate === 'function') {
validationResult = await field.validate(field.value);
}

if (typeof validationResult === 'string') {
validatedField.errorMessage = validationResult;
validatedField.valid = false;
isValid = false;
if (typeof validationResult === 'string') {
validatedField.errorMessage = validationResult;
validatedField.valid = false;
isValid = false;
}
}

validatedFieldState[path] = validatedField;
Expand Down
4 changes: 1 addition & 3 deletions src/admin/components/forms/Form/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Condition } from '../../../../fields/config/types';

export type Field = {
value: unknown
initialValue: unknown
Expand All @@ -9,7 +7,7 @@ export type Field = {
disableFormData?: boolean
ignoreWhileFlattening?: boolean
stringify?: boolean
condition?: Condition
passesCondition?: boolean
}

export type Fields = {
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Array/Array.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const ArrayFieldType: React.FC<Props> = (props) => {
permissions,
admin: {
readOnly,
condition,
},
} = props;

Expand Down Expand Up @@ -69,7 +68,6 @@ const ArrayFieldType: React.FC<Props> = (props) => {
validate: memoizedValidate,
disableFormData,
ignoreWhileFlattening: true,
condition,
});

const addRow = useCallback(async (rowIndex) => {
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Blocks/Blocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const Blocks: React.FC<Props> = (props) => {
permissions,
admin: {
readOnly,
condition,
},
} = props;

Expand Down Expand Up @@ -79,7 +78,6 @@ const Blocks: React.FC<Props> = (props) => {
validate: memoizedValidate,
disableFormData,
ignoreWhileFlattening: true,
condition,
});

const addRow = useCallback(async (rowIndex, blockType) => {
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Checkbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const Checkbox: React.FC<Props> = (props) => {
readOnly,
style,
width,
condition,
} = {},
} = props;

Expand All @@ -43,7 +42,6 @@ const Checkbox: React.FC<Props> = (props) => {
path,
validate: memoizedValidate,
disableFormData,
condition,
});

return (
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Code/Code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const Code: React.FC<Props> = (props) => {
style,
width,
language,
condition,
} = {},
label,
minLength,
Expand Down Expand Up @@ -54,7 +53,6 @@ const Code: React.FC<Props> = (props) => {
path,
validate: memoizedValidate,
enableDebouncedValue: true,
condition,
});

const classes = [
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/DateTime/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const DateTime: React.FC<Props> = (props) => {
style,
width,
date,
condition,
} = {},
} = props;

Expand All @@ -44,7 +43,6 @@ const DateTime: React.FC<Props> = (props) => {
} = useFieldType({
path,
validate: memoizedValidate,
condition,
});

const classes = [
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Email/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const Email: React.FC<Props> = (props) => {
width,
placeholder,
autoComplete,
condition,
} = {},
label,
} = props;
Expand All @@ -36,7 +35,6 @@ const Email: React.FC<Props> = (props) => {
path,
validate: memoizedValidate,
enableDebouncedValue: true,
condition,
});

const {
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Number/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const NumberField: React.FC<Props> = (props) => {
width,
step,
placeholder,
condition,
} = {},
} = props;

Expand All @@ -43,7 +42,6 @@ const NumberField: React.FC<Props> = (props) => {
path,
validate: memoizedValidate,
enableDebouncedValue: true,
condition,
});

const handleChange = useCallback((e) => {
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/RadioGroup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const RadioGroup: React.FC<Props> = (props) => {
layout = 'horizontal',
style,
width,
condition,
} = {},
options,
} = props;
Expand All @@ -45,7 +44,6 @@ const RadioGroup: React.FC<Props> = (props) => {
} = useFieldType({
path,
validate: memoizedValidate,
condition,
});

const classes = [
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Relationship/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ const Relationship: React.FC<Props> = (props) => {
readOnly,
style,
width,
condition,
} = {},
} = props;

Expand Down Expand Up @@ -72,7 +71,6 @@ const Relationship: React.FC<Props> = (props) => {
} = useFieldType({
path: path || name,
validate: memoizedValidate,
condition,
});

const addOptions = useCallback((data, relation) => {
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/RichText/RichText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ const RichText: React.FC<Props> = (props) => {
style,
width,
placeholder,
condition,
hideGutter,
} = {},
} = props;
Expand Down Expand Up @@ -105,7 +104,6 @@ const RichText: React.FC<Props> = (props) => {
path,
validate: memoizedValidate,
stringify: true,
condition,
});

const {
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ const Select: React.FC<Props> = (props) => {
readOnly,
style,
width,
condition,
} = {},
} = props;

Expand All @@ -57,7 +56,6 @@ const Select: React.FC<Props> = (props) => {
} = useFieldType({
path,
validate: memoizedValidate,
condition,
});

const classes = [
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Text/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const Text: React.FC<Props> = (props) => {
readOnly,
style,
width,
condition,
} = {},
} = props;

Expand All @@ -29,7 +28,6 @@ const Text: React.FC<Props> = (props) => {
const fieldType = useFieldType<string>({
path,
validate,
condition,
enableDebouncedValue: true,
});

Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Textarea/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const Textarea: React.FC<Props> = (props) => {
width,
placeholder,
rows,
condition,
} = {},
label,
minLength,
Expand All @@ -43,7 +42,6 @@ const Textarea: React.FC<Props> = (props) => {
path,
validate: memoizedValidate,
enableDebouncedValue: true,
condition,
});

const classes = [
Expand Down
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Upload/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const Upload: React.FC<Props> = (props) => {
readOnly,
style,
width,
condition,
} = {},
label,
validate = upload,
Expand All @@ -52,7 +51,6 @@ const Upload: React.FC<Props> = (props) => {
const fieldType = useFieldType({
path,
validate: memoizedValidate,
condition,
});

const {
Expand Down
4 changes: 1 addition & 3 deletions src/admin/components/forms/useFieldType/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const useFieldType = <T extends unknown>(options: Options): FieldType<T> => {
disableFormData,
ignoreWhileFlattening,
stringify,
condition,
} = options;

const formContext = useForm();
Expand Down Expand Up @@ -49,7 +48,6 @@ const useFieldType = <T extends unknown>(options: Options): FieldType<T> => {
ignoreWhileFlattening,
initialValue,
validate,
condition,
value: valueToSend,
valid: false,
errorMessage: undefined,
Expand All @@ -65,7 +63,7 @@ const useFieldType = <T extends unknown>(options: Options): FieldType<T> => {
}

dispatchFields(fieldToDispatch);
}, [path, dispatchFields, validate, disableFormData, ignoreWhileFlattening, initialValue, stringify, condition]);
}, [path, dispatchFields, validate, disableFormData, ignoreWhileFlattening, initialValue, stringify]);

// Method to return from `useFieldType`, used to
// update internal field values from field component(s)
Expand Down
3 changes: 1 addition & 2 deletions src/admin/components/forms/useFieldType/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Validate, Condition } from '../../../../fields/config/types';
import { Validate } from '../../../../fields/config/types';

export type Options = {
path: string
Expand All @@ -7,7 +7,6 @@ export type Options = {
disableFormData?: boolean
ignoreWhileFlattening?: boolean
stringify?: boolean
condition?: Condition
}

export type FieldType<T> = {
Expand Down
Loading

0 comments on commit d43390f

Please sign in to comment.