diff --git a/src/fireedge/src/client/components/Forms/ButtonToTriggerForm.js b/src/fireedge/src/client/components/Forms/ButtonToTriggerForm.js
index 7b2f12dba7..9c49efea8e 100644
--- a/src/fireedge/src/client/components/Forms/ButtonToTriggerForm.js
+++ b/src/fireedge/src/client/components/Forms/ButtonToTriggerForm.js
@@ -69,7 +69,6 @@ const ButtonToTriggerForm = ({
aria-expanded={open ? 'true' : undefined}
aria-haspopup={isGroupButton ? 'true' : false}
disabled={!options.length}
-
endicon={isGroupButton ? : undefined}
onClick={evt => !isGroupButton
? openDialogForm(options[0])
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/configurationSection.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/configurationSection.js
index 76e66c0b2c..2c3b9717c5 100644
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/configurationSection.js
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/configurationSection.js
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
-import { JSXElementConstructor } from 'react'
+import { useMemo, JSXElementConstructor } from 'react'
import { Stack, FormControl, Button } from '@mui/material'
import { useFormContext } from 'react-hook-form'
@@ -23,21 +23,20 @@ import { STEP_ID as EXTRA_ID } from 'client/components/Forms/VmTemplate/CreateFo
import { SSH_PUBLIC_KEY, SCRIPT_FIELDS, OTHER_FIELDS } from './schema'
import { T } from 'client/constants'
-export const SECTION_ID = 'CONTEXT'
-
const SSH_KEY_USER = '$USER[SSH_PUBLIC_KEY]'
/** @returns {JSXElementConstructor} - Configuration section */
const ConfigurationSection = () => {
const { setValue, getValues } = useFormContext()
- const SSH_PUBLIC_KEY_PATH = `${EXTRA_ID}.${SSH_PUBLIC_KEY.name}`
+ const SSH_PUBLIC_KEY_PATH = useMemo(() => `${EXTRA_ID}.${SSH_PUBLIC_KEY.name}`, [])
const handleClearKey = () => setValue(SSH_PUBLIC_KEY_PATH)
const handleAddUserKey = () => {
- const currentSshPublicKey = getValues(SSH_PUBLIC_KEY_PATH) ?? ''
+ let currentKey = getValues(SSH_PUBLIC_KEY_PATH)
+ currentKey &&= currentKey + '\n'
- setValue(SSH_PUBLIC_KEY_PATH, currentSshPublicKey + `\n${SSH_KEY_USER}`)
+ setValue(SSH_PUBLIC_KEY_PATH, `${currentKey ?? ''}${SSH_KEY_USER}`)
}
return (
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/filesSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/filesSchema.js
new file mode 100644
index 0000000000..0d2546f68b
--- /dev/null
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/filesSchema.js
@@ -0,0 +1,54 @@
+/* ------------------------------------------------------------------------- *
+ * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may *
+ * not use this file except in compliance with the License. You may obtain *
+ * a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * ------------------------------------------------------------------------- */
+import { string, ObjectSchema } from 'yup'
+
+import { T, INPUT_TYPES, HYPERVISORS } from 'client/constants'
+import { Field, filterFieldsByHypervisor, getObjectSchemaFromFields } from 'client/utils'
+
+const { vcenter } = HYPERVISORS
+
+/** @type {Field} Files field */
+export const FILES_DS = {
+ name: 'CONTEXT.FILES_DS',
+ label: T.ContextFiles,
+ tooltip: T.ContextFilesConcept,
+ notOnHypervisors: [vcenter],
+ type: INPUT_TYPES.TEXT,
+ validation: string()
+ .trim()
+ .notRequired(),
+ grid: { md: 12 }
+}
+
+/** @type {Field} Init scripts field */
+export const INIT_SCRIPTS = {
+ name: 'CONTEXT.INIT_SCRIPTS',
+ label: T.InitScripts,
+ tooltip: T.InitScriptsConcept,
+ type: INPUT_TYPES.TEXT,
+ validation: string()
+ .trim()
+ .notRequired(),
+ grid: { md: 12 }
+}
+
+/** @type {Field[]} List of Context Files fields */
+export const FILES_FIELDS = hypervisor =>
+ filterFieldsByHypervisor([FILES_DS, INIT_SCRIPTS], hypervisor)
+
+/** @type {ObjectSchema} Context Files schema */
+export const FILES_SCHEMA = hypervisor =>
+ getObjectSchemaFromFields(FILES_FIELDS(hypervisor))
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/filesSection.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/filesSection.js
new file mode 100644
index 0000000000..7093a3b2fc
--- /dev/null
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/filesSection.js
@@ -0,0 +1,48 @@
+/* ------------------------------------------------------------------------- *
+ * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may *
+ * not use this file except in compliance with the License. You may obtain *
+ * a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * ------------------------------------------------------------------------- */
+import { JSXElementConstructor } from 'react'
+import PropTypes from 'prop-types'
+
+import { FormWithSchema } from 'client/components/Forms'
+
+import { STEP_ID as EXTRA_ID } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration'
+import { FILES_FIELDS } from './schema'
+import { T } from 'client/constants'
+
+export const SECTION_ID = 'CONTEXT'
+
+/**
+ * @param {object} props - Props
+ * @param {string} props.hypervisor - VM hypervisor
+ * @returns {JSXElementConstructor} - Files section
+ */
+const FilesSection = ({ hypervisor }) => (
+ FILES_FIELDS(hypervisor)}
+ id={EXTRA_ID}
+ />
+)
+
+FilesSection.propTypes = {
+ data: PropTypes.any,
+ setFormData: PropTypes.func,
+ hypervisor: PropTypes.string,
+ control: PropTypes.object
+}
+
+export default FilesSection
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/index.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/index.js
index a032ebad49..cd164ed162 100644
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/index.js
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/index.js
@@ -17,17 +17,19 @@ import PropTypes from 'prop-types'
import { Folder as ContextIcon } from 'iconoir-react'
import { TabType } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration'
-import ConfigurationSection, { SECTION_ID as CONFIGURATION_ID } from './configurationSection'
import UserInputsSection, { SECTION_ID as USER_INPUTS_ID } from './userInputsSection'
+import ConfigurationSection from './configurationSection'
+import FilesSection from './filesSection'
import { T } from 'client/constants'
-export const TAB_ID = [CONFIGURATION_ID, USER_INPUTS_ID]
+export const TAB_ID = ['CONTEXT', USER_INPUTS_ID]
-const Context = () => {
+const Context = props => {
return (
<>
+
>
)
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/schema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/schema.js
index 129b20ac26..e74d328fd6 100644
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/schema.js
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/schema.js
@@ -13,14 +13,21 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
-import { object } from 'yup'
+import { object, ObjectSchema } from 'yup'
import { USER_INPUTS_SCHEMA } from './userInputsSchema'
import { CONFIGURATION_SCHEMA } from './configurationSchema'
+import { FILES_SCHEMA } from './filesSchema'
-export const SCHEMA = object()
+/**
+ * @param {string} [hypervisor] - VM hypervisor
+ * @returns {ObjectSchema} Context schema
+ */
+export const SCHEMA = hypervisor => object()
.concat(CONFIGURATION_SCHEMA)
.concat(USER_INPUTS_SCHEMA)
+ .concat(FILES_SCHEMA(hypervisor))
export * from './userInputsSchema'
export * from './configurationSchema'
+export * from './filesSchema'
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/userInputsSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/userInputsSchema.js
index 0a816df081..620feaf2f7 100644
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/userInputsSchema.js
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/userInputsSchema.js
@@ -183,5 +183,6 @@ export const USER_INPUT_SCHEMA = getObjectSchemaFromFields(USER_INPUT_FIELDS)
/** @type {ObjectSchema} User Inputs schema */
export const USER_INPUTS_SCHEMA = object({
- USER_INPUTS: array(USER_INPUT_SCHEMA).ensure()
+ USER_INPUTS: array(USER_INPUT_SCHEMA).ensure(),
+ INPUTS_ORDER: string().trim().strip()
})
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/NicItem.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/NicItem.js
new file mode 100644
index 0000000000..5a33bf13e2
--- /dev/null
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/NicItem.js
@@ -0,0 +1,108 @@
+/* ------------------------------------------------------------------------- *
+ * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may *
+ * not use this file except in compliance with the License. You may obtain *
+ * a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * ------------------------------------------------------------------------- */
+import { memo, JSXElementConstructor } from 'react'
+import PropTypes from 'prop-types'
+import { Edit, Trash } from 'iconoir-react'
+
+import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
+import SelectCard, { Action } from 'client/components/Cards/SelectCard'
+import { AttachNicForm } from 'client/components/Forms/Vm'
+import { Translate } from 'client/components/HOC'
+
+import { stringToBoolean } from 'client/models/Helper'
+import { T } from 'client/constants'
+
+/**
+ * @param {object} props - Props
+ * @param {number} props.index - Index in list
+ * @param {object} props.item - NIC
+ * @param {string} props.handleRemove - Remove function
+ * @param {string} props.handleUpdate - Update function
+ * @returns {JSXElementConstructor} - NIC card
+ */
+const NicItem = memo(({
+ item,
+ nics,
+ handleRemove,
+ handleUpdate
+}) => {
+ const { id, NAME, RDP, SSH, NETWORK, PARENT, EXTERNAL } = item
+ const hasAlias = nics?.some(nic => nic.PARENT === NAME)
+
+ return (
+
+ {Object
+ .entries({
+ RDP: stringToBoolean(RDP),
+ SSH: stringToBoolean(SSH),
+ EXTERNAL: stringToBoolean(EXTERNAL),
+ [`PARENT: ${PARENT}`]: PARENT
+ })
+ .map(([k, v]) => v ? `${k}` : '')
+ .filter(Boolean)
+ .join(' | ')
+ }
+ >}
+ action={
+ <>
+ {!hasAlias &&
+ }
+ handleClick={handleRemove}
+ color='error'
+ icon={}
+ />
+ }
+ ,
+ tooltip:
+ }}
+ options={[{
+ dialogProps: {
+ title: (
+
+ )
+ },
+ form: () => AttachNicForm({ nics }, item),
+ onSubmit: handleUpdate
+ }]}
+ />
+ >
+ }
+ />
+ )
+}, (prev, next) => prev.item?.NAME === next.item?.NAME)
+
+NicItem.propTypes = {
+ index: PropTypes.number,
+ item: PropTypes.object,
+ nics: PropTypes.array,
+ handleRemove: PropTypes.func,
+ handleUpdate: PropTypes.func
+}
+
+NicItem.displayName = 'NicItem'
+
+export default NicItem
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/index.js
similarity index 57%
rename from src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking.js
rename to src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/index.js
index ee8ec52413..561e963760 100644
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking.js
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/index.js
@@ -15,19 +15,19 @@
* ------------------------------------------------------------------------- */
import PropTypes from 'prop-types'
import { Stack } from '@mui/material'
-import { ServerConnection as NetworkIcon, Edit, Trash } from 'iconoir-react'
+import { ServerConnection as NetworkIcon } from 'iconoir-react'
import { useFormContext, useFieldArray } from 'react-hook-form'
import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
-import SelectCard, { Action } from 'client/components/Cards/SelectCard'
import { AttachNicForm } from 'client/components/Forms/Vm'
-import { Translate } from 'client/components/HOC'
+import { FormWithSchema } from 'client/components/Forms'
import { STEP_ID as EXTRA_ID, TabType } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration'
import { mapNameByIndex } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/schema'
import { BOOT_ORDER_NAME, reorderBootAfterRemove } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting'
-import { stringToBoolean } from 'client/models/Helper'
+import { FIELDS } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/schema'
import { T } from 'client/constants'
+import NicItem from './NicItem'
export const TAB_ID = 'NIC'
@@ -48,6 +48,10 @@ const Networking = () => {
setValue(BOOT_ORDER_NAME(), updatedBootOrder)
}
+ const handleUpdate = (updatedNic, index) => {
+ update(index, mapNameFunction(updatedNic, index))
+ }
+
return (
<>
{
onSubmit: nic => append(mapNameFunction(nic, nics.length))
}]}
/>
-
- {nics?.map((item, index) => {
- const { id, NAME, RDP, SSH, NETWORK, PARENT, EXTERNAL } = item
- const hasAlias = nics?.some(nic => nic.PARENT === NAME)
-
- return (
-
- {Object
- .entries({
- RDP: stringToBoolean(RDP),
- SSH: stringToBoolean(SSH),
- EXTERNAL: stringToBoolean(EXTERNAL),
- [`PARENT: ${PARENT}`]: PARENT
- })
- .map(([k, v]) => v ? `${k}` : '')
- .filter(Boolean)
- .join(' | ')
- }
- >}
- action={
- <>
- {!hasAlias &&
- removeAndReorder(NAME)}
- icon={}
- />
- }
- ,
- tooltip:
- }}
- options={[{
- dialogProps: {
- title: (
-
- )
- },
- form: () => AttachNicForm({ nics }, item),
- onSubmit: updatedNic =>
- update(index, mapNameFunction(updatedNic, index))
- }]}
- />
- >
- }
- />
- )
- })}
+ {nics?.map(({ id, ...item }, index) => (
+ removeAndReorder(item?.NAME)}
+ handleUpdate={updatedNic => handleUpdate(updatedNic, index)}
+ />
+ ))}
+
>
)
}
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/schema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/schema.js
new file mode 100644
index 0000000000..32a52ce64a
--- /dev/null
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/schema.js
@@ -0,0 +1,54 @@
+/* ------------------------------------------------------------------------- *
+ * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may *
+ * not use this file except in compliance with the License. You may obtain *
+ * a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * ------------------------------------------------------------------------- */
+import { object, string, array, ObjectSchema } from 'yup'
+
+import { T, INPUT_TYPES } from 'client/constants'
+import { Field, getObjectSchemaFromFields } from 'client/utils'
+import { mapNameByIndex } from '../schema'
+
+/** @returns {Field} NIC filter field */
+const FILTER = {
+ name: 'NIC_DEFAULT.FILTER',
+ label: T.DefaultNicFilter,
+ type: INPUT_TYPES.TEXT,
+ validation: string()
+ .trim()
+ .notRequired()
+ .default(() => undefined)
+}
+
+/** @returns {Field} NIC model field */
+const MODEL = {
+ name: 'NIC_DEFAULT.MODEL',
+ label: T.DefaultNicModel,
+ type: INPUT_TYPES.TEXT,
+ validation: string()
+ .trim()
+ .notRequired()
+ .default(() => undefined)
+}
+
+/** @type {Field[]} List of Network defaults fields */
+const FIELDS = [FILTER, MODEL]
+
+/** @type {ObjectSchema} Network schema */
+const SCHEMA = object({
+ NIC: array()
+ .ensure()
+ .transform(nics => nics.map(mapNameByIndex('NIC')))
+}).concat(getObjectSchemaFromFields(FIELDS))
+
+export { FIELDS, SCHEMA }
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/schema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/schema.js
index 3e9852fa2b..c031d9af84 100644
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/schema.js
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/schema.js
@@ -21,6 +21,8 @@ import { FIELDS as OS_FIELDS } from 'client/components/Forms/VmTemplate/CreateFo
import { FIELDS as NUMA_FIELDS } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/numa/schema'
import { SCHEMA as IO_SCHEMA } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/schema'
import { SCHEMA as CONTEXT_SCHEMA } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/context/schema'
+import { SCHEMA as STORAGE_SCHEMA } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/schema'
+import { SCHEMA as NETWORK_SCHEMA } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/networking/schema'
import { getObjectSchemaFromFields } from 'client/utils'
export const mapNameByIndex = (prefixName) => (resource, idx) => ({
@@ -30,28 +32,19 @@ export const mapNameByIndex = (prefixName) => (resource, idx) => ({
: resource?.NAME
})
-export const DISK_SCHEMA = array()
- .ensure()
- .transform(disks => disks.map(mapNameByIndex('DISK')))
-
-export const NIC_SCHEMA = array()
- .ensure()
- .transform(nics => nics.map(mapNameByIndex('NIC')))
-
export const SCHED_ACTION_SCHEMA = array()
.ensure()
.transform(actions => actions.map(mapNameByIndex('SCHED_ACTION')))
export const SCHEMA = hypervisor => object({
- DISK: DISK_SCHEMA,
- NIC: NIC_SCHEMA,
SCHED_ACTION: SCHED_ACTION_SCHEMA
})
- .concat(CONTEXT_SCHEMA)
+ .concat(NETWORK_SCHEMA)
+ .concat(STORAGE_SCHEMA)
+ .concat(CONTEXT_SCHEMA(hypervisor))
.concat(IO_SCHEMA(hypervisor))
.concat(getObjectSchemaFromFields([
...PLACEMENT_FIELDS,
...OS_FIELDS(hypervisor),
...NUMA_FIELDS(hypervisor)
]))
- .noUnknown(false)
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage.js
deleted file mode 100644
index 167f5e31b1..0000000000
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage.js
+++ /dev/null
@@ -1,191 +0,0 @@
-/* ------------------------------------------------------------------------- *
- * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
- * *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may *
- * not use this file except in compliance with the License. You may obtain *
- * a copy of the License at *
- * *
- * http://www.apache.org/licenses/LICENSE-2.0 *
- * *
- * Unless required by applicable law or agreed to in writing, software *
- * distributed under the License is distributed on an "AS IS" BASIS, *
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- * See the License for the specific language governing permissions and *
- * limitations under the License. *
- * ------------------------------------------------------------------------- */
-/* eslint-disable jsdoc/require-jsdoc */
-import PropTypes from 'prop-types'
-import { Stack } from '@mui/material'
-import { Db as DatastoreIcon, Edit, Trash } from 'iconoir-react'
-import { useFormContext, useFieldArray } from 'react-hook-form'
-
-import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
-import SelectCard, { Action } from 'client/components/Cards/SelectCard'
-import { ImageSteps, VolatileSteps } from 'client/components/Forms/Vm'
-import { StatusCircle, StatusChip } from 'client/components/Status'
-import { Translate } from 'client/components/HOC'
-
-import { STEP_ID as EXTRA_ID, TabType } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration'
-import { mapNameByIndex } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/schema'
-import { BOOT_ORDER_NAME, reorderBootAfterRemove } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting'
-import { getState, getDiskType } from 'client/models/Image'
-import { stringToBoolean } from 'client/models/Helper'
-import { prettyBytes } from 'client/utils'
-import { T } from 'client/constants'
-
-export const TAB_ID = 'DISK'
-
-const mapNameFunction = mapNameByIndex('DISK')
-
-const Storage = ({ hypervisor }) => {
- const { getValues, setValue } = useFormContext()
- const { fields: disks, replace, update, append } = useFieldArray({
- name: `${EXTRA_ID}.${TAB_ID}`
- })
-
- const removeAndReorder = diskName => {
- const updatedDisks = disks.filter(({ NAME }) => NAME !== diskName).map(mapNameFunction)
- const currentBootOrder = getValues(BOOT_ORDER_NAME())
- const updatedBootOrder = reorderBootAfterRemove(diskName, disks, currentBootOrder)
-
- replace(updatedDisks)
- setValue(BOOT_ORDER_NAME(), updatedBootOrder)
- }
-
- return (
- <>
- ImageSteps({ hypervisor }),
- onSubmit: image => append(mapNameFunction(image, disks.length))
- },
- {
- cy: 'attach-volatile-disk',
- name: T.Volatile,
- dialogProps: { title: T.AttachVolatile },
- form: () => VolatileSteps({ hypervisor }),
- onSubmit: image => append(mapNameFunction(image, disks.length))
- }
- ]}
- />
-
- {disks?.map((item, index) => {
- const {
- id,
- NAME,
- TYPE,
- IMAGE,
- IMAGE_ID,
- IMAGE_STATE,
- ORIGINAL_SIZE,
- SIZE = ORIGINAL_SIZE,
- READONLY,
- DATASTORE,
- PERSISTENT
- } = item
-
- const isVolatile = !IMAGE && !IMAGE_ID
- const isPersistent = stringToBoolean(PERSISTENT)
- const state = !isVolatile && getState({ STATE: IMAGE_STATE })
- const type = isVolatile ? TYPE : getDiskType(item)
- const originalSize = +ORIGINAL_SIZE ? prettyBytes(+ORIGINAL_SIZE, 'MB') : '-'
- const size = prettyBytes(+SIZE, 'MB')
-
- return (
-
- {`${NAME} - `}
-
- >
- ) : (
-
-
- {`${NAME}: ${IMAGE}`}
- {isPersistent && }
-
- )}
- subheader={<>
- {Object
- .entries({
- [DATASTORE]: DATASTORE,
- READONLY: stringToBoolean(READONLY),
- PERSISTENT: stringToBoolean(PERSISTENT),
- [isVolatile || ORIGINAL_SIZE === SIZE
- ? size : `${originalSize}/${size}`]: true,
- [type]: type
- })
- .map(([k, v]) => v ? `${k}` : '')
- .filter(Boolean)
- .join(' | ')
- }
- >}
- action={
- <>
- }
- handleClick={() => removeAndReorder(NAME, index)}
- icon={}
- />
- ,
- tooltip:
- }}
- options={[{
- dialogProps: {
- title:
- },
- form: () => isVolatile
- ? VolatileSteps({ hypervisor }, item)
- : ImageSteps({ hypervisor }, item),
- onSubmit: updatedDisk =>
- update(index, mapNameFunction(updatedDisk, index))
- }]}
- />
- >
- }
- />
- )
- })}
-
- >
- )
-}
-
-Storage.propTypes = {
- data: PropTypes.any,
- setFormData: PropTypes.func,
- hypervisor: PropTypes.string,
- control: PropTypes.object
-}
-
-/** @type {TabType} */
-const TAB = {
- id: 'storage',
- name: T.Storage,
- icon: DatastoreIcon,
- Content: Storage,
- getError: error => !!error?.[TAB_ID]
-}
-
-export default TAB
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/DiskItem.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/DiskItem.js
new file mode 100644
index 0000000000..4e74cd06a3
--- /dev/null
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/DiskItem.js
@@ -0,0 +1,139 @@
+/* ------------------------------------------------------------------------- *
+ * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may *
+ * not use this file except in compliance with the License. You may obtain *
+ * a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * ------------------------------------------------------------------------- */
+import { memo, JSXElementConstructor } from 'react'
+import PropTypes from 'prop-types'
+import { Stack } from '@mui/material'
+import { Edit, Trash } from 'iconoir-react'
+
+import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
+import SelectCard, { Action } from 'client/components/Cards/SelectCard'
+import { ImageSteps, VolatileSteps } from 'client/components/Forms/Vm'
+import { StatusCircle, StatusChip } from 'client/components/Status'
+import { Translate } from 'client/components/HOC'
+
+import { getState, getDiskType } from 'client/models/Image'
+import { stringToBoolean } from 'client/models/Helper'
+import { prettyBytes } from 'client/utils'
+import { T } from 'client/constants'
+
+/**
+ * The disk item will be included in the VM Template.
+ *
+ * @param {object} props - Props
+ * @param {number} props.index - Index in list
+ * @param {object} props.item - Disk
+ * @param {string} props.hypervisor - VM hypervisor
+ * @param {string} props.handleRemove - Remove function
+ * @param {string} props.handleUpdate - Update function
+ * @returns {JSXElementConstructor} - Disk card
+ */
+const DiskItem = memo(({
+ item,
+ hypervisor,
+ handleRemove,
+ handleUpdate
+}) => {
+ const {
+ NAME,
+ TYPE,
+ IMAGE,
+ IMAGE_ID,
+ IMAGE_STATE,
+ ORIGINAL_SIZE,
+ SIZE = ORIGINAL_SIZE,
+ READONLY,
+ DATASTORE,
+ PERSISTENT
+ } = item
+
+ const isVolatile = !IMAGE && !IMAGE_ID
+ const isPersistent = stringToBoolean(PERSISTENT)
+ const state = !isVolatile && getState({ STATE: IMAGE_STATE })
+ const type = isVolatile ? TYPE : getDiskType(item)
+ const originalSize = +ORIGINAL_SIZE ? prettyBytes(+ORIGINAL_SIZE, 'MB') : '-'
+ const size = prettyBytes(+SIZE, 'MB')
+
+ return (
+
+ {`${NAME} - `}
+
+ >
+ ) : (
+
+
+ {`${NAME}: ${IMAGE}`}
+ {isPersistent && }
+
+ )}
+ subheader={<>
+ {Object
+ .entries({
+ [DATASTORE]: DATASTORE,
+ READONLY: stringToBoolean(READONLY),
+ PERSISTENT: stringToBoolean(PERSISTENT),
+ [isVolatile || ORIGINAL_SIZE === SIZE
+ ? size : `${originalSize}/${size}`]: true,
+ [type]: type
+ })
+ .map(([k, v]) => v ? `${k}` : '')
+ .filter(Boolean)
+ .join(' | ')
+ }
+ >}
+ action={
+ <>
+ }
+ handleClick={handleRemove}
+ color='error'
+ icon={}
+ />
+ ,
+ tooltip:
+ }}
+ options={[{
+ dialogProps: {
+ title:
+ },
+ form: () => isVolatile
+ ? VolatileSteps({ hypervisor }, item)
+ : ImageSteps({ hypervisor }, item),
+ onSubmit: handleUpdate
+ }]}
+ />
+ >
+ }
+ />
+ )
+}, (prev, next) => prev.item?.NAME === next.item?.NAME)
+
+DiskItem.propTypes = {
+ index: PropTypes.number,
+ item: PropTypes.object,
+ hypervisor: PropTypes.string,
+ handleRemove: PropTypes.func,
+ handleUpdate: PropTypes.func
+}
+
+DiskItem.displayName = 'DiskItem'
+
+export default DiskItem
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/index.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/index.js
new file mode 100644
index 0000000000..f8baf6f340
--- /dev/null
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/index.js
@@ -0,0 +1,124 @@
+/* ------------------------------------------------------------------------- *
+ * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may *
+ * not use this file except in compliance with the License. You may obtain *
+ * a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * ------------------------------------------------------------------------- */
+import PropTypes from 'prop-types'
+import { Stack } from '@mui/material'
+import { Db as DatastoreIcon } from 'iconoir-react'
+import { useFieldArray, useFormContext } from 'react-hook-form'
+
+import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
+import { ImageSteps, VolatileSteps } from 'client/components/Forms/Vm'
+import { FormWithSchema } from 'client/components/Forms'
+
+import { STEP_ID as EXTRA_ID, TabType } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration'
+import { mapNameByIndex } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/schema'
+import { BOOT_ORDER_NAME, reorderBootAfterRemove } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting'
+import { FIELDS } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/schema'
+import { T } from 'client/constants'
+import DiskItem from './DiskItem'
+
+export const TAB_ID = 'DISK'
+
+const mapNameFunction = mapNameByIndex('DISK')
+
+const Storage = ({ hypervisor }) => {
+ const { getValues, setValue } = useFormContext()
+ const { fields: disks, append, update, replace } = useFieldArray({
+ name: `${EXTRA_ID}.${TAB_ID}`
+ })
+
+ const removeAndReorder = diskName => {
+ const updatedDisks = disks.filter(({ NAME }) => NAME !== diskName).map(mapNameFunction)
+ const currentBootOrder = getValues(BOOT_ORDER_NAME())
+ const updatedBootOrder = reorderBootAfterRemove(diskName, disks, currentBootOrder)
+
+ replace(updatedDisks)
+ setValue(BOOT_ORDER_NAME(), updatedBootOrder)
+ }
+
+ const handleUpdate = (updatedDisk, index) => {
+ update(index, mapNameFunction(updatedDisk, index))
+ }
+
+ return (
+ <>
+ ImageSteps({ hypervisor }),
+ onSubmit: image => append(mapNameFunction(image, disks.length))
+ },
+ {
+ cy: 'attach-volatile-disk',
+ name: T.Volatile,
+ dialogProps: { title: T.AttachVolatile },
+ form: () => VolatileSteps({ hypervisor }),
+ onSubmit: image => append(mapNameFunction(image, disks.length))
+ }
+ ]}
+ />
+
+ {disks?.map(({ id, ...item }, index) => (
+ removeAndReorder(item?.NAME)}
+ handleUpdate={updatedDisk => handleUpdate(updatedDisk, index)}
+ />
+ ))}
+
+
+ >
+ )
+}
+
+Storage.propTypes = {
+ data: PropTypes.any,
+ setFormData: PropTypes.func,
+ hypervisor: PropTypes.string,
+ control: PropTypes.object
+}
+
+/** @type {TabType} */
+const TAB = {
+ id: 'storage',
+ name: T.Storage,
+ icon: DatastoreIcon,
+ Content: Storage,
+ getError: error => !!error?.[TAB_ID]
+}
+
+export default TAB
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/schema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/schema.js
new file mode 100644
index 0000000000..e6dee55ec6
--- /dev/null
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/schema.js
@@ -0,0 +1,53 @@
+/* ------------------------------------------------------------------------- *
+ * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may *
+ * not use this file except in compliance with the License. You may obtain *
+ * a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * ------------------------------------------------------------------------- */
+import { object, string, array, ObjectSchema } from 'yup'
+
+import { useDatastore } from 'client/features/One'
+import { getDeployMode } from 'client/models/Datastore'
+import { T, INPUT_TYPES } from 'client/constants'
+import { Field, arrayToOptions, getValidationFromFields } from 'client/utils'
+import { mapNameByIndex } from '../schema'
+
+/** @returns {Field} Deploy mode field */
+const TM_MAD_SYSTEM = {
+ name: 'TM_MAD_SYSTEM',
+ label: T.DeployMode,
+ tooltip: T.DeployModeConcept,
+ type: INPUT_TYPES.SELECT,
+ values: () => {
+ const datastores = useDatastore()
+ const modes = datastores?.map(getDeployMode)?.flat()
+
+ return arrayToOptions([...new Set(modes)], { addEmpty: 'Default' })
+ },
+ validation: string()
+ .trim()
+ .notRequired()
+ .default(() => undefined)
+}
+
+/** @type {Field[]} List of Storage fields */
+const FIELDS = [TM_MAD_SYSTEM]
+
+/** @type {ObjectSchema} Storage schema */
+const SCHEMA = object({
+ ...getValidationFromFields(FIELDS),
+ DISK: array()
+ .ensure()
+ .transform(disks => disks.map(mapNameByIndex('DISK')))
+})
+
+export { FIELDS, SCHEMA }
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/capacitySchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/capacitySchema.js
index b9fba8b646..014b479631 100644
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/capacitySchema.js
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/capacitySchema.js
@@ -40,10 +40,16 @@ export const MEMORY = {
/** @type {Field} Hot reloading on memory field */
export const ENABLE_HR_MEMORY = {
- name: 'ENABLE_HR_MEMORY',
+ name: 'HOT_RESIZE.MEMORY_HOT_ADD_ENABLED',
label: T.EnableHotResize,
type: INPUT_TYPES.SWITCH,
- validation: boolean().default(() => false),
+ validation: boolean()
+ .transform(value => {
+ if (typeof value === 'boolean') return value
+
+ return String(value).toUpperCase() === 'YES'
+ })
+ .default(() => false),
grid: { xs: 4, md: 6 }
}
@@ -85,10 +91,16 @@ export const VIRTUAL_CPU = {
/** @type {Field} Hot reloading on virtual CPU field */
export const ENABLE_HR_VCPU = {
- name: 'ENABLE_HR_VCPU',
+ name: 'HOT_RESIZE.CPU_HOT_ADD_ENABLED',
label: T.EnableHotResize,
type: INPUT_TYPES.SWITCH,
- validation: boolean().default(() => false),
+ validation: boolean()
+ .transform(value => {
+ if (typeof value === 'boolean') return value
+
+ return String(value).toUpperCase() === 'YES'
+ })
+ .default(() => false),
grid: { xs: 4, md: 6 }
}
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/index.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/index.js
index 7b07f00e08..e63aea4590 100644
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/index.js
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/index.js
@@ -31,7 +31,7 @@ const Steps = createSteps(
...vmTemplate?.TEMPLATE,
USER_INPUTS: userInputsToArray(vmTemplate?.TEMPLATE?.USER_INPUTS)
}
- }, { context: { [EXTRA_ID]: vmTemplate.TEMPLATE } })
+ }, { stripUnknown: true, context: { [EXTRA_ID]: vmTemplate.TEMPLATE } })
}),
transformBeforeSubmit: formData => {
const {
@@ -42,22 +42,28 @@ const Steps = createSteps(
// const templateXML = jsonToXml({ ...general, ...extraTemplate })
// return { template: templateXML }
+ const userInputs = userInputsToObject(USER_INPUTS)
+ const inputsOrder = USER_INPUTS.map(({ name }) => name).join(',')
const { START_SCRIPT, ENCODE_START_SCRIPT, ...restOfContext } = CONTEXT
const context = {
...restOfContext,
+ // transform start script to base64 if needed
[ENCODE_START_SCRIPT ? 'START_SCRIPT_BASE64' : 'START_SCRIPT']:
ENCODE_START_SCRIPT && !isBase64(START_SCRIPT)
? btoa(unescape(encodeURIComponent(START_SCRIPT)))
: START_SCRIPT
}
- const userInputs = userInputsToObject(USER_INPUTS)
- const inputsOrder = USER_INPUTS.map(({ name }) => name).join(',')
+ // add user inputs to context
+ for (const { name } of USER_INPUTS) {
+ const upperName = String(name).toUpperCase()
+ context[upperName] = `$${upperName}`
+ }
return {
- ...general,
...extraTemplate,
+ ...general,
CONTEXT: context,
USER_INPUTS: userInputs,
INPUTS_ORDER: inputsOrder
diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/index.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/index.js
index 388f06b412..ab7318d680 100644
--- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/index.js
+++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/index.js
@@ -22,7 +22,7 @@ import { yupResolver } from '@hookform/resolvers/yup'
import { useFetch } from 'client/hooks'
// import { useUserApi, useVmGroupApi, useVmTemplateApi } from 'client/features/One'
-import { useVmTemplateApi, useHostApi, useImageApi } from 'client/features/One'
+import { useVmTemplateApi, useHostApi, useImageApi, useDatastoreApi } from 'client/features/One'
import FormStepper, { SkeletonStepsForm } from 'client/components/FormStepper'
import Steps from 'client/components/Forms/VmTemplate/CreateForm/Steps'
@@ -52,6 +52,7 @@ const PreFetchingForm = ({ templateId, onSubmit }) => {
// const { getVmGroups } = useVmGroupApi()
const { getHosts } = useHostApi()
const { getImages } = useImageApi()
+ const { getDatastores } = useDatastoreApi()
const { getVmTemplate } = useVmTemplateApi()
const { fetchRequest, data } = useFetch(
() => getVmTemplate(templateId, { extended: true })
@@ -61,6 +62,7 @@ const PreFetchingForm = ({ templateId, onSubmit }) => {
templateId && fetchRequest()
getHosts()
getImages()
+ getDatastores()
// getUsers()
// getVmGroups()
}, [])
diff --git a/src/fireedge/src/client/components/Image/index.js b/src/fireedge/src/client/components/Image/index.js
index fe5e3a318e..106ec5f9e7 100644
--- a/src/fireedge/src/client/components/Image/index.js
+++ b/src/fireedge/src/client/components/Image/index.js
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
-import { useState, memo, JSXElementConstructor } from 'react'
+import { useState, memo, useEffect, JSXElementConstructor } from 'react'
import PropTypes from 'prop-types'
import { DEFAULT_IMAGE, IMAGE_FORMATS } from 'client/constants'
@@ -46,6 +46,10 @@ const Image = memo(
...imgProps
}
+ useEffect(() => {
+ error && setError(INITIAL_STATE)
+ }, [src])
+
/** Increment retries by one in error state. */
const addRetry = () => {
setError(prev => ({ ...prev, retries: prev.retries + 1 }))
diff --git a/src/fireedge/src/client/components/Tables/Datastores/columns.js b/src/fireedge/src/client/components/Tables/Datastores/columns.js
index 33e2c11944..62ff659f88 100644
--- a/src/fireedge/src/client/components/Tables/Datastores/columns.js
+++ b/src/fireedge/src/client/components/Tables/Datastores/columns.js
@@ -37,7 +37,7 @@ export default [
{
Header: 'Type',
id: 'TYPE',
- accessor: row => DatastoreModel.getType(row)
+ accessor: row => DatastoreModel.getType(row)?.name
},
{
Header: 'Clusters IDs',
diff --git a/src/fireedge/src/client/constants/datastore.js b/src/fireedge/src/client/constants/datastore.js
index 228fd7d221..ed5e0d467b 100644
--- a/src/fireedge/src/client/constants/datastore.js
+++ b/src/fireedge/src/client/constants/datastore.js
@@ -16,10 +16,7 @@
import * as STATES from 'client/constants/states'
import COLOR from 'client/constants/color'
-/**
- * @type {{name: string, shortName: string}}
- * Datastore type information
- */
+/** @type {{name: string, shortName: string}} Datastore type information */
export const DATASTORE_TYPES = [
{
name: 'IMAGE',
diff --git a/src/fireedge/src/client/constants/translates.js b/src/fireedge/src/client/constants/translates.js
index 9fe1e1d763..8fc1b5f34e 100644
--- a/src/fireedge/src/client/constants/translates.js
+++ b/src/fireedge/src/client/constants/translates.js
@@ -354,6 +354,17 @@ module.exports = {
/* VM schema - ownership */
InstantiateAsUser: 'Instantiate as different User',
InstantiateAsGroup: 'Instantiate as different Group',
+ /* VM Template schema - storage */
+ StorageOptions: 'Storage Options',
+ DeployMode: 'Deploy Mode',
+ DeployModeConcept: 'Set an alternative mode to deploy VM disks to the hosts',
+ /* VM Template schema - network */
+ NetworkDefaults: 'Network Defaults',
+ NetworkDefaultsConcept: `
+ Values that will be copied to each new NIC.
+ Final users may not be aware of this`,
+ DefaultNicModel: 'Default hardware model to emulate for all NICs',
+ DefaultNicFilter: 'Default network filtering rule for all NICs',
/* VM Template schema - capacity */
MaxMemory: 'Max memory',
MemoryModification: 'Memory modification',
@@ -485,9 +496,16 @@ module.exports = {
ReportReadyToOneGateConcept: 'Sends READY=YES to OneGate, useful for OneFlow',
StartScript: 'Start script',
StartScriptConcept: `
- Text of the script executed when the machine starts up. It can contain
- shebang in case it is not shell script`,
+ Text of the script executed when the machine starts up. It can contain
+ shebang in case it is not shell script`,
EncodeScriptInBase64: 'Encode script in Base64',
+ ContextFiles: 'Files Datastores',
+ ContextFilesConcept: 'List of File images to include in context device',
+ InitScripts: 'Init scripts',
+ InitScriptsConcept: `
+ The contextualization package executes an init.sh file if it exists.
+ If more than one script file is added, this list contains the scripts
+ to run and their order`,
/* VM Template schema - Input/Output */
InputOrOutput: 'Input / Output',
Inputs: 'Inputs',
diff --git a/src/fireedge/src/client/models/Datastore.js b/src/fireedge/src/client/models/Datastore.js
index 63eb30e31c..e996edcf52 100644
--- a/src/fireedge/src/client/models/Datastore.js
+++ b/src/fireedge/src/client/models/Datastore.js
@@ -34,6 +34,21 @@ export const getType = ({ TYPE } = {}) => DATASTORE_TYPES[TYPE]
*/
export const getState = ({ STATE = 0 } = {}) => DATASTORE_STATES[STATE]
+/**
+ * Return the TM_MAD_SYSTEM attribute.
+ *
+ * @param {object} datastore - Datastore
+ * @returns {string[]} - The list of deploy modes available
+ */
+export const getDeployMode = (datastore = {}) => {
+ const { TEMPLATE = {} } = datastore
+ const isImage = getType(datastore)?.name === DATASTORE_TYPES[0]?.name
+
+ return isImage
+ ? TEMPLATE?.TM_MAD_SYSTEM?.split(',')?.filter(Boolean) ?? []
+ : []
+}
+
/**
* Returns information about datastore capacity.
*
diff --git a/src/fireedge/src/client/utils/schema.js b/src/fireedge/src/client/utils/schema.js
index 59a94aaf39..9d115cd52a 100644
--- a/src/fireedge/src/client/utils/schema.js
+++ b/src/fireedge/src/client/utils/schema.js
@@ -328,7 +328,7 @@ export const mapUserInputs = (userInputs = {}) =>
*
* @param {any[]} array - List of option values
* @param {object} [options] - Options to conversion
- * @param {boolean} [options.addEmpty] - If `true`, add an empty option
+ * @param {boolean|string} [options.addEmpty] - If `true`, add an empty option
* @param {function(any):any} [options.getText] - Function to get the text option
* @param {function(any):any} [options.getValue] - Function to get the value option
* @returns {SelectOption} Options
@@ -338,7 +338,11 @@ export const arrayToOptions = (array = [], options = {}) => {
const values = array.map(item => ({ text: getText(item), value: getValue(item) }))
- addEmpty && values.unshift({ text: '-', value: '' })
+ if (addEmpty) {
+ typeof addEmpty === 'string'
+ ? values.unshift({ text: addEmpty, value: '' })
+ : values.unshift({ text: '-', value: '' })
+ }
return values
}