Compare commits
	
		
			2 Commits
		
	
	
		
			AUT-1371
			...
			AUT-157-AU
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 8f3ecb6d4d | ||
|   | 47caa5aa37 | 
| @@ -68,7 +68,10 @@ function AccountDropdownMenu(props) { | |||||||
| AccountDropdownMenu.propTypes = { | AccountDropdownMenu.propTypes = { | ||||||
|   open: PropTypes.bool.isRequired, |   open: PropTypes.bool.isRequired, | ||||||
|   onClose: PropTypes.func.isRequired, |   onClose: PropTypes.func.isRequired, | ||||||
|   anchorEl: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), |   anchorEl: PropTypes.oneOfType([ | ||||||
|  |     PropTypes.func, | ||||||
|  |     PropTypes.shape({ current: PropTypes.instanceOf(Element) }), | ||||||
|  |   ]), | ||||||
|   id: PropTypes.string.isRequired, |   id: PropTypes.string.isRequired, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,7 +21,9 @@ const CustomOptions = (props) => { | |||||||
|     label, |     label, | ||||||
|     initialTabIndex, |     initialTabIndex, | ||||||
|   } = props; |   } = props; | ||||||
|  |  | ||||||
|   const [activeTabIndex, setActiveTabIndex] = React.useState(undefined); |   const [activeTabIndex, setActiveTabIndex] = React.useState(undefined); | ||||||
|  |  | ||||||
|   React.useEffect( |   React.useEffect( | ||||||
|     function applyInitialActiveTabIndex() { |     function applyInitialActiveTabIndex() { | ||||||
|       setActiveTabIndex((currentActiveTabIndex) => { |       setActiveTabIndex((currentActiveTabIndex) => { | ||||||
| @@ -33,6 +35,7 @@ const CustomOptions = (props) => { | |||||||
|     }, |     }, | ||||||
|     [initialTabIndex], |     [initialTabIndex], | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <Popper |     <Popper | ||||||
|       open={open} |       open={open} | ||||||
| @@ -76,7 +79,10 @@ const CustomOptions = (props) => { | |||||||
|  |  | ||||||
| CustomOptions.propTypes = { | CustomOptions.propTypes = { | ||||||
|   open: PropTypes.bool.isRequired, |   open: PropTypes.bool.isRequired, | ||||||
|   anchorEl: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired, |   anchorEl: PropTypes.oneOfType([ | ||||||
|  |     PropTypes.func, | ||||||
|  |     PropTypes.shape({ current: PropTypes.instanceOf(Element) }), | ||||||
|  |   ]), | ||||||
|   data: PropTypes.arrayOf( |   data: PropTypes.arrayOf( | ||||||
|     PropTypes.shape({ |     PropTypes.shape({ | ||||||
|       id: PropTypes.string.isRequired, |       id: PropTypes.string.isRequired, | ||||||
|   | |||||||
| @@ -11,9 +11,6 @@ import IconButton from '@mui/material/IconButton'; | |||||||
| import ErrorIcon from '@mui/icons-material/Error'; | import ErrorIcon from '@mui/icons-material/Error'; | ||||||
| import CircularProgress from '@mui/material/CircularProgress'; | import CircularProgress from '@mui/material/CircularProgress'; | ||||||
| import CheckCircleIcon from '@mui/icons-material/CheckCircle'; | import CheckCircleIcon from '@mui/icons-material/CheckCircle'; | ||||||
| import { yupResolver } from '@hookform/resolvers/yup'; |  | ||||||
| import * as yup from 'yup'; |  | ||||||
|  |  | ||||||
| import { EditorContext } from 'contexts/Editor'; | import { EditorContext } from 'contexts/Editor'; | ||||||
| import { StepExecutionsProvider } from 'contexts/StepExecutions'; | import { StepExecutionsProvider } from 'contexts/StepExecutions'; | ||||||
| import TestSubstep from 'components/TestSubstep'; | import TestSubstep from 'components/TestSubstep'; | ||||||
| @@ -33,77 +30,18 @@ import { | |||||||
|   Header, |   Header, | ||||||
|   Wrapper, |   Wrapper, | ||||||
| } from './style'; | } from './style'; | ||||||
| import isEmpty from 'helpers/isEmpty'; |  | ||||||
| import { StepPropType } from 'propTypes/propTypes'; | import { StepPropType } from 'propTypes/propTypes'; | ||||||
| import useTriggers from 'hooks/useTriggers'; | import useTriggers from 'hooks/useTriggers'; | ||||||
| import useActions from 'hooks/useActions'; | import useActions from 'hooks/useActions'; | ||||||
| import useTriggerSubsteps from 'hooks/useTriggerSubsteps'; | import useTriggerSubsteps from 'hooks/useTriggerSubsteps'; | ||||||
| import useActionSubsteps from 'hooks/useActionSubsteps'; | import useActionSubsteps from 'hooks/useActionSubsteps'; | ||||||
| import useStepWithTestExecutions from 'hooks/useStepWithTestExecutions'; | import useStepWithTestExecutions from 'hooks/useStepWithTestExecutions'; | ||||||
|  | import { validationSchemaResolver } from './validation'; | ||||||
|  | import { isEqual } from 'lodash'; | ||||||
|  |  | ||||||
| const validIcon = <CheckCircleIcon color="success" />; | const validIcon = <CheckCircleIcon color="success" />; | ||||||
| const errorIcon = <ErrorIcon color="error" />; | const errorIcon = <ErrorIcon color="error" />; | ||||||
|  |  | ||||||
| function generateValidationSchema(substeps) { |  | ||||||
|   const fieldValidations = substeps?.reduce( |  | ||||||
|     (allValidations, { arguments: args }) => { |  | ||||||
|       if (!args || !Array.isArray(args)) return allValidations; |  | ||||||
|       const substepArgumentValidations = {}; |  | ||||||
|       for (const arg of args) { |  | ||||||
|         const { key, required } = arg; |  | ||||||
|         // base validation for the field if not exists |  | ||||||
|         if (!substepArgumentValidations[key]) { |  | ||||||
|           substepArgumentValidations[key] = yup.mixed(); |  | ||||||
|         } |  | ||||||
|         if ( |  | ||||||
|           typeof substepArgumentValidations[key] === 'object' && |  | ||||||
|           (arg.type === 'string' || arg.type === 'dropdown') |  | ||||||
|         ) { |  | ||||||
|           // if the field is required, add the required validation |  | ||||||
|           if (required) { |  | ||||||
|             substepArgumentValidations[key] = substepArgumentValidations[key] |  | ||||||
|               .required(`${key} is required.`) |  | ||||||
|               .test( |  | ||||||
|                 'empty-check', |  | ||||||
|                 `${key} must be not empty`, |  | ||||||
|                 (value) => !isEmpty(value), |  | ||||||
|               ); |  | ||||||
|           } |  | ||||||
|           // if the field depends on another field, add the dependsOn required validation |  | ||||||
|           if (Array.isArray(arg.dependsOn) && arg.dependsOn.length > 0) { |  | ||||||
|             for (const dependsOnKey of arg.dependsOn) { |  | ||||||
|               const missingDependencyValueMessage = `We're having trouble loading '${key}' data as required field '${dependsOnKey}' is missing.`; |  | ||||||
|               // TODO: make `dependsOnKey` agnostic to the field. However, nested validation schema is not supported. |  | ||||||
|               // So the fields under the `parameters` key are subject to their siblings only and thus, `parameters.` is removed. |  | ||||||
|               substepArgumentValidations[key] = substepArgumentValidations[ |  | ||||||
|                 key |  | ||||||
|               ].when(`${dependsOnKey.replace('parameters.', '')}`, { |  | ||||||
|                 is: (value) => Boolean(value) === false, |  | ||||||
|                 then: (schema) => |  | ||||||
|                   schema |  | ||||||
|                     .notOneOf([''], missingDependencyValueMessage) |  | ||||||
|                     .required(missingDependencyValueMessage), |  | ||||||
|               }); |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       return { |  | ||||||
|         ...allValidations, |  | ||||||
|         ...substepArgumentValidations, |  | ||||||
|       }; |  | ||||||
|     }, |  | ||||||
|     {}, |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   const validationSchema = yup.object({ |  | ||||||
|     parameters: yup.object(fieldValidations), |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   return yupResolver(validationSchema); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function FlowStep(props) { | function FlowStep(props) { | ||||||
|   const { collapsed, onChange, onContinue, flowId } = props; |   const { collapsed, onChange, onContinue, flowId } = props; | ||||||
|   const editorContext = React.useContext(EditorContext); |   const editorContext = React.useContext(EditorContext); | ||||||
| @@ -114,6 +52,10 @@ function FlowStep(props) { | |||||||
|   const isAction = step.type === 'action'; |   const isAction = step.type === 'action'; | ||||||
|   const formatMessage = useFormatMessage(); |   const formatMessage = useFormatMessage(); | ||||||
|   const [currentSubstep, setCurrentSubstep] = React.useState(0); |   const [currentSubstep, setCurrentSubstep] = React.useState(0); | ||||||
|  |   const [formResolverContext, setFormResolverContext] = React.useState({ | ||||||
|  |     substeps: [], | ||||||
|  |     additionalFields: {}, | ||||||
|  |   }); | ||||||
|   const useAppsOptions = {}; |   const useAppsOptions = {}; | ||||||
|  |  | ||||||
|   if (isTrigger) { |   if (isTrigger) { | ||||||
| @@ -168,6 +110,12 @@ function FlowStep(props) { | |||||||
|       ? triggerSubstepsData |       ? triggerSubstepsData | ||||||
|       : actionSubstepsData || []; |       : actionSubstepsData || []; | ||||||
|  |  | ||||||
|  |   React.useEffect(() => { | ||||||
|  |     if (!isEqual(substeps, formResolverContext.substeps)) { | ||||||
|  |       setFormResolverContext({ substeps, additionalFields: {} }); | ||||||
|  |     } | ||||||
|  |   }, [substeps]); | ||||||
|  |  | ||||||
|   const handleChange = React.useCallback(({ step }) => { |   const handleChange = React.useCallback(({ step }) => { | ||||||
|     onChange(step); |     onChange(step); | ||||||
|   }, []); |   }, []); | ||||||
| @@ -180,11 +128,6 @@ function FlowStep(props) { | |||||||
|     handleChange({ step: val }); |     handleChange({ step: val }); | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   const stepValidationSchema = React.useMemo( |  | ||||||
|     () => generateValidationSchema(substeps), |  | ||||||
|     [substeps], |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   if (!apps?.data) { |   if (!apps?.data) { | ||||||
|     return ( |     return ( | ||||||
|       <CircularProgress |       <CircularProgress | ||||||
| @@ -213,6 +156,15 @@ function FlowStep(props) { | |||||||
|       value !== substepIndex ? substepIndex : null, |       value !== substepIndex ? substepIndex : null, | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|  |   const addAdditionalFieldsValidation = (additionalFields) => { | ||||||
|  |     if (additionalFields) { | ||||||
|  |       setFormResolverContext((prev) => ({ | ||||||
|  |         ...prev, | ||||||
|  |         additionalFields: { ...prev.additionalFields, ...additionalFields }, | ||||||
|  |       })); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|   const validationStatusIcon = |   const validationStatusIcon = | ||||||
|     step.status === 'completed' ? validIcon : errorIcon; |     step.status === 'completed' ? validIcon : errorIcon; | ||||||
|  |  | ||||||
| @@ -266,7 +218,8 @@ function FlowStep(props) { | |||||||
|               <Form |               <Form | ||||||
|                 defaultValues={step} |                 defaultValues={step} | ||||||
|                 onSubmit={handleSubmit} |                 onSubmit={handleSubmit} | ||||||
|                 resolver={stepValidationSchema} |                 resolver={validationSchemaResolver} | ||||||
|  |                 context={formResolverContext} | ||||||
|               > |               > | ||||||
|                 <ChooseAppAndEventSubstep |                 <ChooseAppAndEventSubstep | ||||||
|                   expanded={currentSubstep === 0} |                   expanded={currentSubstep === 0} | ||||||
| @@ -330,6 +283,9 @@ function FlowStep(props) { | |||||||
|                             onSubmit={expandNextStep} |                             onSubmit={expandNextStep} | ||||||
|                             onChange={handleChange} |                             onChange={handleChange} | ||||||
|                             step={step} |                             step={step} | ||||||
|  |                             addAdditionalFieldsValidation={ | ||||||
|  |                               addAdditionalFieldsValidation | ||||||
|  |                             } | ||||||
|                           /> |                           /> | ||||||
|                         )} |                         )} | ||||||
|                     </React.Fragment> |                     </React.Fragment> | ||||||
|   | |||||||
							
								
								
									
										120
									
								
								packages/web/src/components/FlowStep/validation.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								packages/web/src/components/FlowStep/validation.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | |||||||
|  | import * as yup from 'yup'; | ||||||
|  | import { yupResolver } from '@hookform/resolvers/yup'; | ||||||
|  | import isEmpty from 'helpers/isEmpty'; | ||||||
|  |  | ||||||
|  | function addRequiredValidation({ required, schema, key }) { | ||||||
|  |   // if the field is required, add the required validation | ||||||
|  |   if (required) { | ||||||
|  |     return schema | ||||||
|  |       .required(`${key} is required.`) | ||||||
|  |       .test( | ||||||
|  |         'empty-check', | ||||||
|  |         `${key} must be not empty`, | ||||||
|  |         (value) => !isEmpty(value), | ||||||
|  |       ); | ||||||
|  |   } | ||||||
|  |   return schema; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function addDependsOnValidation({ schema, dependsOn, key, args }) { | ||||||
|  |   // if the field depends on another field, add the dependsOn required validation | ||||||
|  |   if (Array.isArray(dependsOn) && dependsOn.length > 0) { | ||||||
|  |     for (const dependsOnKey of dependsOn) { | ||||||
|  |       const dependsOnKeyShort = dependsOnKey.replace('parameters.', ''); | ||||||
|  |       const dependsOnField = args.find(({ key }) => key === dependsOnKeyShort); | ||||||
|  |  | ||||||
|  |       if (dependsOnField?.required) { | ||||||
|  |         const missingDependencyValueMessage = `We're having trouble loading '${key}' data as required field '${dependsOnKey}' is missing.`; | ||||||
|  |  | ||||||
|  |         // TODO: make `dependsOnKey` agnostic to the field. However, nested validation schema is not supported. | ||||||
|  |         // So the fields under the `parameters` key are subject to their siblings only and thus, `parameters.` is removed. | ||||||
|  |         return schema.when(dependsOnKeyShort, { | ||||||
|  |           is: (dependsOnValue) => Boolean(dependsOnValue) === false, | ||||||
|  |           then: (schema) => | ||||||
|  |             schema | ||||||
|  |               .notOneOf([''], missingDependencyValueMessage) | ||||||
|  |               .required(missingDependencyValueMessage), | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return schema; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function validationSchemaResolver(data, context, options) { | ||||||
|  |   const { substeps = [], additionalFields = {} } = context; | ||||||
|  |  | ||||||
|  |   const fieldValidations = [ | ||||||
|  |     ...substeps, | ||||||
|  |     { | ||||||
|  |       arguments: Object.values(additionalFields) | ||||||
|  |         .filter((field) => !!field) | ||||||
|  |         .flat(), | ||||||
|  |     }, | ||||||
|  |   ].reduce((allValidations, { arguments: args }) => { | ||||||
|  |     if (!args || !Array.isArray(args)) return allValidations; | ||||||
|  |  | ||||||
|  |     const substepArgumentValidations = {}; | ||||||
|  |  | ||||||
|  |     for (const arg of args) { | ||||||
|  |       const { key, required } = arg; | ||||||
|  |  | ||||||
|  |       // base validation for the field if not exists | ||||||
|  |       if (!substepArgumentValidations[key]) { | ||||||
|  |         substepArgumentValidations[key] = yup.mixed(); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (arg.type === 'dynamic') { | ||||||
|  |         const fieldsSchema = {}; | ||||||
|  |  | ||||||
|  |         for (const field of arg.fields) { | ||||||
|  |           fieldsSchema[field.key] = yup.mixed(); | ||||||
|  |  | ||||||
|  |           fieldsSchema[field.key] = addRequiredValidation({ | ||||||
|  |             required: field.required, | ||||||
|  |             schema: fieldsSchema[field.key], | ||||||
|  |             key: field.key, | ||||||
|  |           }); | ||||||
|  |  | ||||||
|  |           fieldsSchema[field.key] = addDependsOnValidation({ | ||||||
|  |             schema: fieldsSchema[field.key], | ||||||
|  |             dependsOn: field.dependsOn, | ||||||
|  |             key: field.key, | ||||||
|  |             args, | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         substepArgumentValidations[key] = yup | ||||||
|  |           .array() | ||||||
|  |           .of(yup.object(fieldsSchema)); | ||||||
|  |       } else if ( | ||||||
|  |         typeof substepArgumentValidations[key] === 'object' && | ||||||
|  |         (arg.type === 'string' || arg.type === 'dropdown') | ||||||
|  |       ) { | ||||||
|  |         substepArgumentValidations[key] = addRequiredValidation({ | ||||||
|  |           required, | ||||||
|  |           schema: substepArgumentValidations[key], | ||||||
|  |           key, | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         substepArgumentValidations[key] = addDependsOnValidation({ | ||||||
|  |           schema: substepArgumentValidations[key], | ||||||
|  |           dependsOn: arg.dependsOn, | ||||||
|  |           key, | ||||||
|  |           args, | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |       ...allValidations, | ||||||
|  |       ...substepArgumentValidations, | ||||||
|  |     }; | ||||||
|  |   }, {}); | ||||||
|  |  | ||||||
|  |   const validationSchema = yup.object({ | ||||||
|  |     parameters: yup.object(fieldValidations), | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   return yupResolver(validationSchema)(data, context, options); | ||||||
|  | } | ||||||
| @@ -43,7 +43,10 @@ function FlowStepContextMenu(props) { | |||||||
| FlowStepContextMenu.propTypes = { | FlowStepContextMenu.propTypes = { | ||||||
|   stepId: PropTypes.string.isRequired, |   stepId: PropTypes.string.isRequired, | ||||||
|   onClose: PropTypes.func.isRequired, |   onClose: PropTypes.func.isRequired, | ||||||
|   anchorEl: PropTypes.element.isRequired, |   anchorEl: PropTypes.oneOfType([ | ||||||
|  |     PropTypes.func, | ||||||
|  |     PropTypes.shape({ current: PropTypes.instanceOf(Element) }), | ||||||
|  |   ]).isRequired, | ||||||
|   deletable: PropTypes.bool.isRequired, |   deletable: PropTypes.bool.isRequired, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,7 +19,9 @@ function FlowSubstep(props) { | |||||||
|     onCollapse, |     onCollapse, | ||||||
|     onSubmit, |     onSubmit, | ||||||
|     step, |     step, | ||||||
|  |     addAdditionalFieldsValidation, | ||||||
|   } = props; |   } = props; | ||||||
|  |  | ||||||
|   const { name, arguments: args } = substep; |   const { name, arguments: args } = substep; | ||||||
|   const editorContext = React.useContext(EditorContext); |   const editorContext = React.useContext(EditorContext); | ||||||
|   const formContext = useFormContext(); |   const formContext = useFormContext(); | ||||||
| @@ -54,6 +56,7 @@ function FlowSubstep(props) { | |||||||
|                   stepId={step.id} |                   stepId={step.id} | ||||||
|                   disabled={editorContext.readOnly} |                   disabled={editorContext.readOnly} | ||||||
|                   showOptionValue={true} |                   showOptionValue={true} | ||||||
|  |                   addAdditionalFieldsValidation={addAdditionalFieldsValidation} | ||||||
|                 /> |                 /> | ||||||
|               ))} |               ))} | ||||||
|             </Stack> |             </Stack> | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| import * as React from 'react'; | import * as React from 'react'; | ||||||
| import { FormProvider, useForm, useWatch } from 'react-hook-form'; | import { FormProvider, useForm, useWatch } from 'react-hook-form'; | ||||||
|  |  | ||||||
| const noop = () => null; | const noop = () => null; | ||||||
|  |  | ||||||
| export default function Form(props) { | export default function Form(props) { | ||||||
|   const { |   const { | ||||||
|     children, |     children, | ||||||
| @@ -9,24 +11,31 @@ export default function Form(props) { | |||||||
|     resolver, |     resolver, | ||||||
|     render, |     render, | ||||||
|     mode = 'all', |     mode = 'all', | ||||||
|  |     context, | ||||||
|     ...formProps |     ...formProps | ||||||
|   } = props; |   } = props; | ||||||
|  |  | ||||||
|   const methods = useForm({ |   const methods = useForm({ | ||||||
|     defaultValues, |     defaultValues, | ||||||
|     reValidateMode: 'onBlur', |     reValidateMode: 'onBlur', | ||||||
|     resolver, |     resolver, | ||||||
|     mode, |     mode, | ||||||
|  |     context, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   const form = useWatch({ control: methods.control }); |   const form = useWatch({ control: methods.control }); | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * For fields having `dependsOn` fields, we need to re-validate the form. |    * For fields having `dependsOn` fields, we need to re-validate the form. | ||||||
|    */ |    */ | ||||||
|   React.useEffect(() => { |   React.useEffect(() => { | ||||||
|     methods.trigger(); |     methods.trigger(); | ||||||
|   }, [methods.trigger, form]); |   }, [methods.trigger, form]); | ||||||
|  |  | ||||||
|   React.useEffect(() => { |   React.useEffect(() => { | ||||||
|     methods.reset(defaultValues); |     methods.reset(defaultValues); | ||||||
|   }, [defaultValues]); |   }, [defaultValues]); | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <FormProvider {...methods}> |     <FormProvider {...methods}> | ||||||
|       <form onSubmit={methods.handleSubmit(onSubmit)} {...formProps}> |       <form onSubmit={methods.handleSubmit(onSubmit)} {...formProps}> | ||||||
|   | |||||||
| @@ -23,7 +23,9 @@ export default function InputCreator(props) { | |||||||
|     disabled, |     disabled, | ||||||
|     showOptionValue, |     showOptionValue, | ||||||
|     shouldUnregister, |     shouldUnregister, | ||||||
|  |     addAdditionalFieldsValidation, | ||||||
|   } = props; |   } = props; | ||||||
|  |  | ||||||
|   const { |   const { | ||||||
|     key: name, |     key: name, | ||||||
|     label, |     label, | ||||||
| @@ -33,6 +35,7 @@ export default function InputCreator(props) { | |||||||
|     description, |     description, | ||||||
|     type, |     type, | ||||||
|   } = schema; |   } = schema; | ||||||
|  |  | ||||||
|   const { data, loading } = useDynamicData(stepId, schema); |   const { data, loading } = useDynamicData(stepId, schema); | ||||||
|   const { data: additionalFieldsData, isLoading: isDynamicFieldsLoading } = |   const { data: additionalFieldsData, isLoading: isDynamicFieldsLoading } = | ||||||
|     useDynamicFields(stepId, schema); |     useDynamicFields(stepId, schema); | ||||||
| @@ -40,6 +43,10 @@ export default function InputCreator(props) { | |||||||
|  |  | ||||||
|   const computedName = namePrefix ? `${namePrefix}.${name}` : name; |   const computedName = namePrefix ? `${namePrefix}.${name}` : name; | ||||||
|  |  | ||||||
|  |   React.useEffect(() => { | ||||||
|  |     addAdditionalFieldsValidation?.({ [name]: additionalFields }); | ||||||
|  |   }, [additionalFields]); | ||||||
|  |  | ||||||
|   if (type === 'dynamic') { |   if (type === 'dynamic') { | ||||||
|     return ( |     return ( | ||||||
|       <DynamicField |       <DynamicField | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import { useQuery } from '@tanstack/react-query'; | |||||||
| import api from 'helpers/api'; | import api from 'helpers/api'; | ||||||
|  |  | ||||||
| const variableRegExp = /({.*?})/; | const variableRegExp = /({.*?})/; | ||||||
|  |  | ||||||
| // TODO: extract this function to a separate file | // TODO: extract this function to a separate file | ||||||
| function computeArguments(args, getValues) { | function computeArguments(args, getValues) { | ||||||
|   const initialValue = {}; |   const initialValue = {}; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user