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:
parent
8da274781b
commit
e147751bed
@ -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])
|
||||
|
||||
|
@ -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])
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
])
|
||||
|
@ -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
|
||||
|
@ -52,6 +52,7 @@ const FilesSection = ({ stepId, hypervisor, oneConfig, adminGroup }) => (
|
||||
),
|
||||
[hypervisor]
|
||||
)}
|
||||
saveState={true}
|
||||
/>
|
||||
)
|
||||
|
||||
|
@ -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 }),
|
||||
|
@ -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)
|
||||
)
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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,15 +50,17 @@ const Placement = ({ oneConfig, adminGroup }) => {
|
||||
// TODO - DS policy options: Packing|Stripping
|
||||
|
||||
<>
|
||||
{SECTIONS(oneConfig, adminGroup).map(({ id, ...section }) => (
|
||||
<FormWithSchema
|
||||
key={id}
|
||||
id={EXTRA_ID}
|
||||
cy={`${EXTRA_ID}-${id}`}
|
||||
saveState={true}
|
||||
{...section}
|
||||
/>
|
||||
))}
|
||||
{SECTIONS(oneConfig, adminGroup, isUpdate, modifiedFields).map(
|
||||
({ id, ...section }) => (
|
||||
<FormWithSchema
|
||||
key={id}
|
||||
id={EXTRA_ID}
|
||||
cy={`${EXTRA_ID}-${id}`}
|
||||
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
|
||||
|
@ -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 }
|
||||
|
@ -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))
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
])
|
||||
)
|
||||
|
@ -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 />}
|
||||
|
@ -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
|
||||
|
@ -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 '<'
|
||||
case '>':
|
||||
return '>'
|
||||
case '&':
|
||||
return '&'
|
||||
default:
|
||||
return c
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user