1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-22 13:33:52 +03:00

M #-: VM template default values (#2982)

Signed-off-by: David Carracedo <dcarracedo@opennebula.io>
Co-authored-by: Tino Vázquez <cvazquez@opennebula.io>
This commit is contained in:
David 2024-03-14 16:27:11 +01:00 committed by GitHub
parent 8da274781b
commit e147751bed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 263 additions and 75 deletions

View File

@ -76,7 +76,7 @@ const SwitchController = memo(
useEffect(() => {
if (!watcher || !dependencies || !watch) return
const watcherValue = watcher(watch, name)
const watcherValue = watcher(watch, { name })
watcherValue !== undefined && onChange(watcherValue)
}, [watch, watcher, dependencies])

View File

@ -17,7 +17,7 @@ import { memo, useCallback, useEffect } from 'react'
import PropTypes from 'prop-types'
import { TextField } from '@mui/material'
import { useController, useWatch } from 'react-hook-form'
import { useController, useWatch, useFormContext } from 'react-hook-form'
import { ErrorHelper, Tooltip } from 'client/components/FormControl'
import { Tr, labelCanBeTranslated } from 'client/components/HOC'
@ -49,10 +49,13 @@ const TextController = memo(
fieldState: { error },
} = useController({ name, control })
const formContext = useFormContext()
useEffect(() => {
if (!watcher || !dependencies || !watch) return
const watcherValue = watcher(watch)
const watcherValue = watcher(watch, { name, formContext })
watcherValue !== undefined && onChange(watcherValue)
}, [watch, watcher, dependencies])

View File

@ -202,8 +202,21 @@ const FormWithSchema = ({
set(fieldsHiddenMerge, id ? `${id}.${element}` : `${element}`, true)
})
const fieldsToMergeinSchema = {}
// Add only the fields of the FormWithSchema component that is being checking
fields.forEach(
(field) =>
get(fieldsToMerge, `${id}.${field.name}`) &&
set(
fieldsToMergeinSchema,
`${id}.${field.name}`,
get(fieldsToMerge, `${id}.${field.name}`)
)
)
// Set modified fields
const mix = merge({}, fieldsToMerge, fieldsHiddenMerge)
const mix = merge({}, fieldsToMergeinSchema, fieldsHiddenMerge)
setModifiedFields(mix)
// If fieldPath exists, set in the store

View File

@ -31,7 +31,7 @@ const VIEW = (name, admin) => ({
label: name,
type: INPUT_TYPES.SWITCH,
dependOf: admin ? `GROUP_ADMIN_DEFAULT_VIEW` : `DEFAULT_VIEW`,
watcher: (value, nameField) => {
watcher: (value, { name: nameField }) => {
// Check the switch if it is the default view
const view =
nameField.split('.').length === 3 ? nameField.split('.')[2] : undefined

View File

@ -40,16 +40,16 @@ export const SSH_PUBLIC_KEY = (isUpdate) => ({
})
/** @type {Field} Network context field */
const NETWORK = {
const NETWORK = (isUpdate) => ({
name: 'CONTEXT.NETWORK',
label: T.AddNetworkContextualization,
tooltip: T.AddNetworkContextualizationConcept,
type: INPUT_TYPES.SWITCH,
validation: boolean()
.yesOrNo()
.default(() => true),
.default(() => (isUpdate ? undefined : true)),
grid: { md: 12 },
}
})
/** @type {Field} Token OneGate token field */
const TOKEN = {
@ -112,7 +112,11 @@ export const START_SCRIPT_BASE64 = {
export const SCRIPT_FIELDS = [START_SCRIPT, ENCODE_START_SCRIPT]
/** @type {Field[]} List of other fields */
export const OTHER_FIELDS = [NETWORK, TOKEN, REPORT_READY]
export const OTHER_FIELDS = (isUpdate) => [
NETWORK(isUpdate),
TOKEN,
REPORT_READY,
]
/** @type {ObjectSchema} User context configuration schema */
export const CONFIGURATION_SCHEMA = (isUpdate) =>
@ -120,5 +124,5 @@ export const CONFIGURATION_SCHEMA = (isUpdate) =>
SSH_PUBLIC_KEY(isUpdate),
START_SCRIPT_BASE64,
...SCRIPT_FIELDS,
...OTHER_FIELDS,
...OTHER_FIELDS(isUpdate),
])

View File

@ -93,7 +93,12 @@ const ConfigurationSection = ({ stepId, oneConfig, adminGroup, isUpdate }) => {
id={stepId}
saveState={true}
cy={getCyPath('context-configuration-others')}
fields={disableFields(OTHER_FIELDS, 'CONTEXT', oneConfig, adminGroup)}
fields={disableFields(
OTHER_FIELDS(isUpdate),
'CONTEXT',
oneConfig,
adminGroup
)}
/>
<section>
<FormWithSchema

View File

@ -52,6 +52,7 @@ const FilesSection = ({ stepId, hypervisor, oneConfig, adminGroup }) => (
),
[hypervisor]
)}
saveState={true}
/>
)

View File

@ -120,9 +120,10 @@ const ExtraConfiguration = ({
apiTemplateDataExtended: vmTemplate,
oneConfig,
adminGroup,
store,
}) => {
const initialHypervisor = vmTemplate?.TEMPLATE?.HYPERVISOR
const isUpdate = vmTemplate?.NAME
const isUpdate = !!vmTemplate?.NAME
return {
id: STEP_ID,
@ -130,7 +131,10 @@ const ExtraConfiguration = ({
resolver: (formData) => {
const hypervisor = formData?.[GENERAL_ID]?.HYPERVISOR ?? initialHypervisor
return SCHEMA(hypervisor, isUpdate)
const currentState = store.getState()
const modifiedFields = currentState.general?.modifiedFields
return SCHEMA(hypervisor, oneConfig, adminGroup, isUpdate, modifiedFields)
},
optionsValidate: { abortEarly: false },
content: (props) => Content({ ...props, oneConfig, adminGroup, isUpdate }),

View File

@ -66,7 +66,7 @@ const KEYMAP_VALUES = {
}
/** @type {Field} Type field */
export const TYPE = {
export const TYPE = (isUpdate) => ({
name: 'GRAPHICS.TYPE',
type: INPUT_TYPES.TOGGLE,
dependOf: ['HYPERVISOR', '$general.HYPERVISOR'],
@ -82,24 +82,24 @@ export const TYPE = {
.trim()
.notRequired()
.uppercase()
.default(() => undefined),
.default(() => (isUpdate ? undefined : T.Vnc)),
grid: { md: 12 },
}
})
/** @type {Field} Listen field */
export const LISTEN = {
export const LISTEN = (isUpdate) => ({
name: 'GRAPHICS.LISTEN',
label: T.ListenOnIp,
type: INPUT_TYPES.TEXT,
dependOf: TYPE.name,
dependOf: TYPE().name,
htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN,
validation: string()
.trim()
.notRequired()
.default(() => undefined),
.default(() => (isUpdate ? undefined : '0.0.0.0')),
fieldProps: { placeholder: '0.0.0.0' },
grid: { md: 12 },
}
})
/** @type {Field} Port field */
export const PORT = {
@ -107,7 +107,7 @@ export const PORT = {
label: T.ServerPort,
tooltip: T.ServerPortConcept,
type: INPUT_TYPES.TEXT,
dependOf: TYPE.name,
dependOf: TYPE().name,
htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN,
validation: string()
.trim()
@ -120,7 +120,7 @@ export const KEYMAP = {
name: 'GRAPHICS.KEYMAP',
label: T.Keymap,
type: INPUT_TYPES.AUTOCOMPLETE,
dependOf: TYPE.name,
dependOf: TYPE().name,
values: arrayToOptions(Object.entries(KEYMAP_VALUES), {
addEmpty: false,
getText: ([_, label]) => label,
@ -177,7 +177,7 @@ export const RANDOM_PASSWD = {
name: 'GRAPHICS.RANDOM_PASSWD',
label: T.GenerateRandomPassword,
type: INPUT_TYPES.CHECKBOX,
dependOf: TYPE.name,
dependOf: TYPE().name,
htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN,
validation: boolean().yesOrNo(),
grid: { md: 12 },
@ -188,7 +188,7 @@ export const PASSWD = {
name: 'GRAPHICS.PASSWD',
label: T.Password,
type: INPUT_TYPES.PASSWORD,
dependOf: [TYPE.name, RANDOM_PASSWD.name],
dependOf: [TYPE().name, RANDOM_PASSWD.name],
htmlType: ([noneType, random] = []) =>
(!noneType || random) && INPUT_TYPES.HIDDEN,
validation: string()
@ -204,7 +204,7 @@ export const COMMAND = {
label: T.Command,
notOnHypervisors: [lxc],
type: INPUT_TYPES.TEXT,
dependOf: TYPE.name,
dependOf: TYPE().name,
htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN,
validation: string()
.trim()
@ -217,14 +217,15 @@ export const COMMAND = {
* @param {string} [hypervisor] - VM hypervisor
* @param {object} oneConfig - Config of oned.conf
* @param {boolean} adminGroup - User is admin or not
* @param {boolean} isUpdate - The form is being updated
* @returns {Field[]} List of Graphics fields
*/
export const GRAPHICS_FIELDS = (hypervisor, oneConfig, adminGroup) =>
export const GRAPHICS_FIELDS = (hypervisor, oneConfig, adminGroup, isUpdate) =>
disableFields(
filterFieldsByHypervisor(
[
TYPE,
LISTEN,
TYPE(isUpdate),
LISTEN(isUpdate),
PORT,
KEYMAP,
CUSTOM_KEYMAP,
@ -240,5 +241,7 @@ export const GRAPHICS_FIELDS = (hypervisor, oneConfig, adminGroup) =>
)
/** @type {ObjectSchema} Graphics schema */
export const GRAPHICS_SCHEMA = (hypervisor) =>
getObjectSchemaFromFields(GRAPHICS_FIELDS(hypervisor))
export const GRAPHICS_SCHEMA = (hypervisor, oneConfig, adminGroup, isUpdate) =>
getObjectSchemaFromFields(
GRAPHICS_FIELDS(hypervisor, oneConfig, adminGroup, isUpdate)
)

View File

@ -33,7 +33,7 @@ import { useGeneralApi } from 'client/features/General'
export const TAB_ID = ['GRAPHICS', INPUT_ID, PCI_ID, VIDEO_ID]
const InputOutput = ({ hypervisor, oneConfig, adminGroup }) => {
const InputOutput = ({ hypervisor, oneConfig, adminGroup, isUpdate }) => {
const { setFieldPath } = useGeneralApi()
useEffect(() => {
setFieldPath(`extra.InputOutput`)
@ -47,7 +47,7 @@ const InputOutput = ({ hypervisor, oneConfig, adminGroup }) => {
>
<FormWithSchema
cy={`${EXTRA_ID}-io-graphics`}
fields={GRAPHICS_FIELDS(hypervisor, oneConfig, adminGroup)}
fields={GRAPHICS_FIELDS(hypervisor, oneConfig, adminGroup, isUpdate)}
legend={T.Graphics}
id={EXTRA_ID}
saveState={true}
@ -81,6 +81,7 @@ InputOutput.propTypes = {
control: PropTypes.object,
oneConfig: PropTypes.object,
adminGroup: PropTypes.bool,
isUpdate: PropTypes.bool,
}
InputOutput.displayName = 'InputOutput'

View File

@ -22,13 +22,16 @@ import { VIDEO_SCHEMA } from './videoSchema'
/**
* @param {string} [hypervisor] - VM hypervisor
* @param {object} oneConfig - Config of oned.conf
* @param {boolean} adminGroup - User is admin or not
* @param {boolean} isUpdate - The form is being updated
* @returns {ObjectSchema} I/O schema
*/
export const SCHEMA = (hypervisor) =>
export const SCHEMA = (hypervisor, oneConfig, adminGroup, isUpdate) =>
object()
.concat(INPUTS_SCHEMA)
.concat(PCI_DEVICES_SCHEMA)
.concat(GRAPHICS_SCHEMA(hypervisor))
.concat(GRAPHICS_SCHEMA(hypervisor, oneConfig, adminGroup, isUpdate))
.concat(VIDEO_SCHEMA(hypervisor))
export * from './graphicsSchema'

View File

@ -30,8 +30,14 @@ import {
import { T } from 'client/constants'
import { useGeneralApi } from 'client/features/General'
const Placement = ({ oneConfig, adminGroup }) => {
import { useSelector } from 'react-redux'
const Placement = ({ oneConfig, adminGroup, isUpdate }) => {
const { setFieldPath } = useGeneralApi()
// Get modified fields by the user
const modifiedFields = useSelector((state) => state.general.modifiedFields)
useEffect(() => {
setFieldPath(`extra.Placement`)
}, [])
@ -44,7 +50,8 @@ const Placement = ({ oneConfig, adminGroup }) => {
// TODO - DS policy options: Packing|Stripping
<>
{SECTIONS(oneConfig, adminGroup).map(({ id, ...section }) => (
{SECTIONS(oneConfig, adminGroup, isUpdate, modifiedFields).map(
({ id, ...section }) => (
<FormWithSchema
key={id}
id={EXTRA_ID}
@ -52,7 +59,8 @@ const Placement = ({ oneConfig, adminGroup }) => {
saveState={true}
{...section}
/>
))}
)
)}
</>
)
}
@ -62,6 +70,7 @@ Placement.propTypes = {
setFormData: PropTypes.func,
oneConfig: PropTypes.object,
adminGroup: PropTypes.bool,
isUpdate: PropTypes.bool,
}
Placement.displayName = 'Placement'
@ -72,7 +81,7 @@ const TAB = {
name: T.Placement,
icon: PlacementIcon,
Content: Placement,
getError: (error) => FIELDS.some(({ name }) => error?.[name]),
getError: (error) => FIELDS({}).some(({ name }) => error?.[name]),
}
export default TAB

View File

@ -17,15 +17,89 @@ import { string } from 'yup'
import { Field, Section, disableFields } from 'client/utils'
import { T, INPUT_TYPES } from 'client/constants'
import { transformXmlString } from 'client/models/Helper'
/**
* Add or replace the hypervisor type in SCHED_REQUIREMENTS attribute.
*
* @param {string} schedRequirements - Actual value
* @param {string} hypervisor - Value of the hypervisor
* @returns {string} - The result after replace or add the new hypervsior
*/
const addHypervisorRequirement = (schedRequirements, hypervisor) => {
// Regular expression pattern to match (HYPERVISOR=VALUE)
const regexPattern = /\(HYPERVISOR=(kvm|dummy|lxc|vcenter|firecracker|qemu)\)/
// If exists a condition with hypervisor, replace the type. If not, add the hypervisor type.
if (regexPattern.test(schedRequirements)) {
// Replace the matched pattern with the new hypervisor
return schedRequirements.replace(
regexPattern,
'(HYPERVISOR=' + hypervisor + ')'
)
} else {
// Add the condition only
return schedRequirements
? `(${schedRequirements}) & (HYPERVISOR=${hypervisor})`
: `(HYPERVISOR=${hypervisor})`
}
}
/** @type {Field} Host requirement field */
const HOST_REQ_FIELD = {
const HOST_REQ_FIELD = (isUpdate, modifiedFields, instantiate) => ({
name: 'SCHED_REQUIREMENTS',
label: T.HostReqExpression,
tooltip: T.HostReqExpressionConcept,
type: INPUT_TYPES.TEXT,
validation: string().trim().notRequired(),
}
dependOf: '$general.HYPERVISOR',
watcher: (hypervisor, { formContext }) => {
// Value of SCHED_REQUIREMENTS
const actualValue = formContext.getValues('extra.SCHED_REQUIREMENTS')
// Check if the hypervisor was changed by the user
const hypervisorHasChanged = modifiedFields?.general?.HYPERVISOR
// Add condition only if the hypervisor was changed by the user or if we are in the create form
if (hypervisorHasChanged || !isUpdate) {
// Return SCHED_REQUIREMENTS with the condition of hypervisor
return addHypervisorRequirement(actualValue, hypervisor)
} else {
// Return SCHED_REQUIREMENTS without the condition of hypervisor
return actualValue
}
},
validation: string()
.trim()
.notRequired()
.afterSubmit((value, { context }) => {
// After submit case exists because if the user don't enter on Placement section, the watcher function will not be executed
// Instantiate not use default values
if (instantiate) return transformXmlString(value)
// Check if SCHED_REQUIREMENTS was changed by the user
const schedRequirementsHasChanged =
modifiedFields?.extra?.Placement?.SCHED_REQUIREMENTS
// Check if the hypervisor was change by the user
const hypervisorHasChanged = modifiedFields?.general?.HYPERVISOR
// Replace or add hyperviosr condition
if (
(!isUpdate && !schedRequirementsHasChanged) ||
(isUpdate && hypervisorHasChanged && !schedRequirementsHasChanged)
) {
const result = addHypervisorRequirement(
value,
context.general.HYPERVISOR
)
return transformXmlString(result)
} else {
return transformXmlString(value)
}
}),
})
/** @type {Field} Host rank requirement field */
const HOST_RANK_FIELD = {
@ -55,12 +129,12 @@ const DS_RANK_FIELD = {
}
/** @type {Section[]} Sections */
const SECTIONS = (oneConfig, adminGroup) => [
const SECTIONS = (oneConfig, adminGroup, isUpdate, modifiedFields) => [
{
id: 'placement-host',
legend: T.Host,
fields: disableFields(
[HOST_REQ_FIELD, HOST_RANK_FIELD],
[HOST_REQ_FIELD(isUpdate, modifiedFields), HOST_RANK_FIELD],
'',
oneConfig,
adminGroup
@ -79,6 +153,11 @@ const SECTIONS = (oneConfig, adminGroup) => [
]
/** @type {Field[]} List of Placement fields */
const FIELDS = [HOST_REQ_FIELD, HOST_RANK_FIELD, DS_REQ_FIELD, DS_RANK_FIELD]
const FIELDS = ({ isUpdate, modifiedFields, instantiate }) => [
HOST_REQ_FIELD(isUpdate, modifiedFields, instantiate),
HOST_RANK_FIELD,
DS_REQ_FIELD,
DS_RANK_FIELD,
]
export { SECTIONS, FIELDS }

View File

@ -48,18 +48,30 @@ const SCHED_ACTION_SCHEMA = object({
/**
* @param {HYPERVISORS} hypervisor - VM hypervisor
* @param {boolean} isUpdate - If it's an update of the form
* @param {object} oneConfig - Config of oned.conf
* @param {boolean} adminGroup - User is admin or not
* @param {boolean} isUpdate - The form is being updated
* @param {object} modifiedFields - Map with the fields modified by the user
* @returns {ObjectSchema} Extra configuration schema
*/
export const SCHEMA = (hypervisor, isUpdate) =>
export const SCHEMA = (
hypervisor,
oneConfig,
adminGroup,
isUpdate,
modifiedFields
) =>
object()
.concat(SCHED_ACTION_SCHEMA)
.concat(NETWORK_SCHEMA)
.concat(STORAGE_SCHEMA)
.concat(CONTEXT_SCHEMA(hypervisor, isUpdate))
.concat(IO_SCHEMA(hypervisor))
.concat(IO_SCHEMA(hypervisor, oneConfig, adminGroup, isUpdate))
.concat(
getObjectSchemaFromFields([...PLACEMENT_FIELDS, ...OS_FIELDS(hypervisor)])
getObjectSchemaFromFields([
...PLACEMENT_FIELDS({ isUpdate, modifiedFields }),
...OS_FIELDS(hypervisor),
])
)
.concat(getObjectSchemaFromFields([...BACKUP_FIELDS]))
.concat(NUMA_SCHEMA(hypervisor))

View File

@ -56,7 +56,7 @@ export const DESCRIPTION = {
}
/** @type {Field} Hypervisor field */
export const HYPERVISOR_FIELD = {
export const HYPERVISOR_FIELD = (isUpdate) => ({
name: 'HYPERVISOR',
type: INPUT_TYPES.TOGGLE,
values: arrayToOptions(Object.values(HYPERVISORS), {
@ -66,9 +66,10 @@ export const HYPERVISOR_FIELD = {
validation: string()
.trim()
.required()
.default(() => HYPERVISORS.kvm),
.default(() => (isUpdate ? undefined : HYPERVISORS.kvm)),
grid: { md: 12 },
}
})
/** @type {Field} Logo field */
export const LOGO = {

View File

@ -65,7 +65,7 @@ const SECTIONS = (hypervisor, isUpdate, features, oneConfig, adminGroup) =>
legend: T.Hypervisor,
required: true,
fields: disableFields(
[HYPERVISOR_FIELD, VROUTER_FIELD],
[HYPERVISOR_FIELD(isUpdate), VROUTER_FIELD],
'',
oneConfig,
adminGroup

View File

@ -109,7 +109,13 @@ const ExtraConfiguration = ({ data: vmTemplate, oneConfig, adminGroup }) => {
resolver: SCHEMA,
optionsValidate: { abortEarly: false },
content: (props) =>
Content({ ...props, hypervisor, oneConfig, adminGroup }),
Content({
...props,
hypervisor,
oneConfig,
adminGroup,
instantiate: true,
}),
}
}

View File

@ -34,4 +34,9 @@ export const SCHEMA = object()
.concat(SCHED_ACTION_SCHEMA)
.concat(NETWORK_SCHEMA)
.concat(STORAGE_SCHEMA)
.concat(getObjectSchemaFromFields([...PLACEMENT_FIELDS, BOOT_ORDER_FIELD]))
.concat(
getObjectSchemaFromFields([
...PLACEMENT_FIELDS({ instantiate: true }),
BOOT_ORDER_FIELD,
])
)

View File

@ -96,7 +96,11 @@ function CreateVmTemplate() {
rawTemplate,
modifiedFields,
existingTemplate,
TAB_FORM_MAP
TAB_FORM_MAP,
{
instantiate: false,
update: !!templateId,
}
)
// Every action that is not an human action
@ -131,6 +135,7 @@ function CreateVmTemplate() {
apiTemplateDataExtended,
oneConfig,
adminGroup,
store,
}}
onSubmit={onSubmit}
fallback={<SkeletonStepsForm />}

View File

@ -86,7 +86,10 @@ function InstantiateVmTemplate() {
rawTemplate,
modifiedFields,
existingTemplate,
TAB_FORM_MAP
TAB_FORM_MAP,
{
instantiate: true,
}
)
// Every action that is not an human action

View File

@ -625,13 +625,15 @@ export const getErrorMessage = (resource) => {
* @param {string} xmlString - The string with xml value
* @returns {string} - A string with the same value but with the replace characters
*/
export const transformXmlString = (xmlString) =>
xmlString.replace(/[<>"']/g, function (c) {
export const transformXmlString = (xmlString = '') =>
xmlString.replace(/[<>&"']/g, function (c) {
switch (c) {
case '<':
return '&lt;'
case '>':
return '&gt;'
case '&':
return '&amp;'
default:
return c
}

View File

@ -20,9 +20,6 @@ import { transformXmlString } from 'client/models/Helper'
// Attributes that will be always modify with the value of the form (except Storage, Network and PCI sections)
const alwaysIncludeAttributes = {
general: {
HYPERVISOR: true,
},
extra: {
OsCpu: {
OS: {
@ -36,10 +33,9 @@ const alwaysIncludeAttributes = {
Context: {
INPUTS_ORDER: true,
USER_INPUTS: true,
CONTEXT: {
SSH_PUBLIC_KEY: true,
NETWORK: true,
},
Placement: {
SCHED_REQUIREMENTS: true,
},
},
}
@ -54,6 +50,31 @@ const alwaysIncludeNic = {
NAME: true,
}
const defaultValuesCreate = {
general: {
HYPERVISOR: true,
},
extra: {
Context: {
CONTEXT: {
NETWORK: true,
SSH_PUBLIC_KEY: true,
},
},
InputOutput: {
GRAPHICS: {
LISTEN: true,
TYPE: true,
},
},
Placement: {
SCHED_REQUIREMENTS: true,
},
},
}
const defaultValuesUpdate = {}
// Attributes that will be always modify with the value of the form in the Nic alias section
const alwaysIncludeNicAlias = {
PARENT: true,
@ -67,23 +88,31 @@ const alwaysIncludeNicAlias = {
* @param {object} modifiedFields - Touched/Dirty fields object
* @param {object} existingTemplate - Existing data
* @param {object} tabFormMap - Maps formData fields to tabs
* @param {boolean} update - If the form is being updated
* @returns {object} - Filtered template data
*/
const filterTemplateData = (
formData,
modifiedFields,
existingTemplate,
tabFormMap
tabFormMap,
{ update = true, instantiate = false }
) => {
// Generate a form from the original data
const normalizedTemplate = normalizeTemplate(existingTemplate, tabFormMap)
const includeAtributes = !instantiate
? update
? merge({}, alwaysIncludeAttributes, defaultValuesUpdate)
: merge({}, alwaysIncludeAttributes, defaultValuesCreate)
: alwaysIncludeAttributes
// Filter data of formData.general
const newGeneral = reduceGeneral(
formData?.general,
modifiedFields?.general,
normalizedTemplate?.general,
alwaysIncludeAttributes
includeAtributes
)
// Filter data of formData.extra
@ -92,7 +121,7 @@ const filterTemplateData = (
modifiedFields,
normalizedTemplate,
tabFormMap,
alwaysIncludeAttributes
includeAtributes
)
// Add custom variables