mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-30 22:50:10 +03:00
Co-authored-by: ie-saiko <i.saiko@spd-ukraine.com> Co-authored-by: Tino Vázquez <cvazquez@opennebula.io>
This commit is contained in:
parent
07c752c353
commit
7aaec867e7
@ -106,6 +106,9 @@ const Hosts = loadable(() => import('client/containers/Hosts'), { ssr: false })
|
||||
const HostDetail = loadable(() => import('client/containers/Hosts/Detail'), {
|
||||
ssr: false,
|
||||
})
|
||||
const CreateHost = loadable(() => import('client/containers/Hosts/Create'), {
|
||||
ssr: false,
|
||||
})
|
||||
const Zones = loadable(() => import('client/containers/Zones'), { ssr: false })
|
||||
|
||||
const Users = loadable(() => import('client/containers/Users'), { ssr: false })
|
||||
@ -180,6 +183,7 @@ export const PATH = {
|
||||
HOSTS: {
|
||||
LIST: `/${RESOURCE_NAMES.HOST}`,
|
||||
DETAIL: `/${RESOURCE_NAMES.HOST}/:id`,
|
||||
CREATE: `/${RESOURCE_NAMES.HOST}/create`,
|
||||
},
|
||||
ZONES: {
|
||||
LIST: `/${RESOURCE_NAMES.ZONE}`,
|
||||
@ -329,6 +333,11 @@ const ENDPOINTS = [
|
||||
icon: HostIcon,
|
||||
Component: Hosts,
|
||||
},
|
||||
{
|
||||
label: 'Create Host',
|
||||
path: PATH.INFRASTRUCTURE.HOSTS.CREATE,
|
||||
Component: CreateHost,
|
||||
},
|
||||
{
|
||||
label: (params) => `Hosts #${params.id}`,
|
||||
path: PATH.INFRASTRUCTURE.HOSTS.DETAIL,
|
||||
|
@ -50,10 +50,8 @@ const ToggleController = memo(
|
||||
fieldProps = {},
|
||||
readOnly = false,
|
||||
}) => {
|
||||
const defaultValue = multiple ? [values?.[0]?.value] : values?.[0]?.value
|
||||
|
||||
const {
|
||||
field: { ref, value: optionSelected = defaultValue, onChange },
|
||||
field: { ref, value: optionSelected, onChange },
|
||||
fieldState: { error: { message } = {} },
|
||||
} = useController({ name, control })
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { createForm } from 'client/utils'
|
||||
import {
|
||||
SCHEMA,
|
||||
FIELDS,
|
||||
} from 'client/components/Forms/Host/ChangeClusterForm/schema'
|
||||
|
||||
const ChangeClusterForm = createForm(SCHEMA, FIELDS)
|
||||
|
||||
export default ChangeClusterForm
|
@ -0,0 +1,39 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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, object, ObjectSchema } from 'yup'
|
||||
|
||||
import { ClustersTable } from 'client/components/Tables'
|
||||
import { T, INPUT_TYPES } from 'client/constants'
|
||||
import { Field, getValidationFromFields } from 'client/utils'
|
||||
|
||||
/** @type {Field} Cluster field */
|
||||
const CLUSTER = {
|
||||
name: 'cluster',
|
||||
label: T.SelectNewCluster,
|
||||
type: INPUT_TYPES.TABLE,
|
||||
Table: () => ClustersTable,
|
||||
validation: string()
|
||||
.trim()
|
||||
.required()
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
/** @type {Field[]} List of fields */
|
||||
export const FIELDS = [CLUSTER]
|
||||
|
||||
/** @type {ObjectSchema} Schema */
|
||||
export const SCHEMA = object(getValidationFromFields(FIELDS))
|
@ -0,0 +1,69 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { useListForm } from 'client/hooks'
|
||||
import { ClustersTable } from 'client/components/Tables'
|
||||
import { Step } from 'client/utils'
|
||||
|
||||
import { SCHEMA } from 'client/components/Forms/Host/CreateForm/Steps/ClustersTable/schema'
|
||||
import { T } from 'client/constants'
|
||||
|
||||
export const STEP_ID = 'cluster'
|
||||
|
||||
const Content = ({ data, setFormData }) => {
|
||||
const { ID } = data?.[0] ?? {}
|
||||
|
||||
const { handleSelect, handleClear } = useListForm({
|
||||
key: STEP_ID,
|
||||
setList: setFormData,
|
||||
})
|
||||
|
||||
const handleSelectedRows = (rows) => {
|
||||
const { original = {} } = rows?.[0] ?? {}
|
||||
|
||||
original.ID !== undefined ? handleSelect(original) : handleClear()
|
||||
}
|
||||
|
||||
return (
|
||||
<ClustersTable
|
||||
singleSelect
|
||||
onlyGlobalSearch
|
||||
onlyGlobalSelectedRows
|
||||
initialState={{ selectedRowIds: { [ID]: true } }}
|
||||
onSelectedRowsChange={handleSelectedRows}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Step to select the Cluster.
|
||||
*
|
||||
* @returns {Step} Cluster Selection step
|
||||
*/
|
||||
const ClustersTableStep = () => ({
|
||||
id: STEP_ID,
|
||||
label: T.SelectCluster,
|
||||
resolver: SCHEMA,
|
||||
content: Content,
|
||||
})
|
||||
|
||||
Content.propTypes = {
|
||||
data: PropTypes.any,
|
||||
setFormData: PropTypes.func,
|
||||
}
|
||||
|
||||
export default ClustersTableStep
|
@ -0,0 +1,23 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { array, object } from 'yup'
|
||||
|
||||
export const SCHEMA = array(object())
|
||||
.min(1)
|
||||
.max(1)
|
||||
.required()
|
||||
.ensure()
|
||||
.default(() => [])
|
@ -0,0 +1,84 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { useMemo } from 'react'
|
||||
import { useWatch } from 'react-hook-form'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
import { Step } from 'client/utils'
|
||||
import { T, CUSTOM_HOST_HYPERVISOR } from 'client/constants'
|
||||
|
||||
import {
|
||||
SCHEMA,
|
||||
INFORMATION_FIELD,
|
||||
DRIVERS_FIELDS,
|
||||
HYPERVISOR_FIELD,
|
||||
} from 'client/components/Forms/Host/CreateForm/Steps/General/schema'
|
||||
|
||||
export const STEP_ID = 'general'
|
||||
|
||||
const Content = () => {
|
||||
const hypervisor = useWatch({ name: `${STEP_ID}.vmmMad` })
|
||||
const driversFields = useMemo(
|
||||
() => hypervisor === CUSTOM_HOST_HYPERVISOR.NAME && DRIVERS_FIELDS,
|
||||
[hypervisor]
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormWithSchema
|
||||
id={STEP_ID}
|
||||
cy={`${STEP_ID}-hypervisor`}
|
||||
legend={T.Hypervisor}
|
||||
fields={[HYPERVISOR_FIELD]}
|
||||
/>
|
||||
<FormWithSchema
|
||||
id={STEP_ID}
|
||||
cy={`${STEP_ID}-information`}
|
||||
legend={T.Information}
|
||||
fields={[INFORMATION_FIELD]}
|
||||
/>
|
||||
{driversFields && (
|
||||
<FormWithSchema
|
||||
id={STEP_ID}
|
||||
cy={`${STEP_ID}-drivers`}
|
||||
legend={T.Drivers}
|
||||
fields={driversFields}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Step to input the Host General information.
|
||||
*
|
||||
* @returns {Step} General information step
|
||||
*/
|
||||
const General = () => ({
|
||||
id: STEP_ID,
|
||||
label: T.General,
|
||||
resolver: SCHEMA,
|
||||
optionsValidate: { abortEarly: false },
|
||||
content: Content,
|
||||
})
|
||||
|
||||
General.propTypes = {
|
||||
data: PropTypes.object,
|
||||
setFormData: PropTypes.func,
|
||||
}
|
||||
|
||||
export default General
|
@ -0,0 +1,162 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { BaseSchema, string } from 'yup'
|
||||
|
||||
import { T, INPUT_TYPES, CUSTOM_HOST_HYPERVISOR } from 'client/constants'
|
||||
|
||||
import {
|
||||
Field,
|
||||
getObjectSchemaFromFields,
|
||||
OPTION_SORTERS,
|
||||
arrayToOptions,
|
||||
} from 'client/utils'
|
||||
|
||||
import { getHostHypervisors } from 'client/models/Host'
|
||||
|
||||
/** @type {Field} Hypervisor field */
|
||||
const HYPERVISOR_FIELD = {
|
||||
name: 'vmmMad',
|
||||
type: INPUT_TYPES.TOGGLE,
|
||||
values: () =>
|
||||
arrayToOptions(getHostHypervisors({ includeCustom: true }), {
|
||||
addEmpty: false,
|
||||
getText: (hypervisor) => hypervisor.displayName,
|
||||
getValue: (hypervisor) => hypervisor.driverName,
|
||||
sorter: OPTION_SORTERS.unsort,
|
||||
}),
|
||||
validation: string()
|
||||
.trim()
|
||||
.required()
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
/** @type {Field} Name field */
|
||||
const INFORMATION_FIELD = {
|
||||
name: 'hostname',
|
||||
label: T.Name,
|
||||
type: INPUT_TYPES.TEXT,
|
||||
validation: string()
|
||||
.trim()
|
||||
.required()
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
/** @type {Field} Custom virtualization selector field */
|
||||
const CUSTOM_VM_MAD = {
|
||||
name: 'customVmmMad',
|
||||
label: T.Virtualization,
|
||||
type: INPUT_TYPES.AUTOCOMPLETE,
|
||||
dependOf: HYPERVISOR_FIELD.name,
|
||||
htmlType: (vmmMad) =>
|
||||
vmmMad !== CUSTOM_HOST_HYPERVISOR.NAME && INPUT_TYPES.HIDDEN,
|
||||
values: () =>
|
||||
arrayToOptions(getHostHypervisors({ includeCustom: true }), {
|
||||
addEmpty: false,
|
||||
getText: (item) => item.displayName,
|
||||
getValue: (item) => item.driverName,
|
||||
sorter: OPTION_SORTERS.unsort,
|
||||
}),
|
||||
validation: string()
|
||||
.trim()
|
||||
.default(() => undefined)
|
||||
.when(HYPERVISOR_FIELD.name, (vmmMad, schema) =>
|
||||
vmmMad === CUSTOM_HOST_HYPERVISOR.NAME
|
||||
? schema.required()
|
||||
: schema.strip().notRequired()
|
||||
),
|
||||
grid: { md: 7 },
|
||||
}
|
||||
|
||||
/** @type {Field} Custom information selector field */
|
||||
const CUSTOM_IM_MAD = {
|
||||
name: 'customImMad',
|
||||
label: T.Information,
|
||||
type: INPUT_TYPES.AUTOCOMPLETE,
|
||||
dependOf: HYPERVISOR_FIELD.name,
|
||||
htmlType: (vmmMad) =>
|
||||
vmmMad !== CUSTOM_HOST_HYPERVISOR.NAME && INPUT_TYPES.HIDDEN,
|
||||
values: () =>
|
||||
arrayToOptions(getHostHypervisors({ includeCustom: true }), {
|
||||
addEmpty: false,
|
||||
getText: (item) => item.displayName,
|
||||
getValue: (item) => item.driverName,
|
||||
sorter: OPTION_SORTERS.unsort,
|
||||
}),
|
||||
validation: string()
|
||||
.trim()
|
||||
.default(() => undefined)
|
||||
.when(HYPERVISOR_FIELD.name, (vmmMad, schema) =>
|
||||
vmmMad === CUSTOM_HOST_HYPERVISOR.NAME
|
||||
? schema.required()
|
||||
: schema.strip().notRequired()
|
||||
),
|
||||
grid: { md: 7 },
|
||||
}
|
||||
|
||||
/** @type {Field} Custom Virtualization field */
|
||||
const CUSTOM_VIRTUALIZATION = {
|
||||
name: 'customVmm',
|
||||
label: T.CustomVirtualization,
|
||||
type: INPUT_TYPES.TEXT,
|
||||
dependOf: CUSTOM_VM_MAD.name,
|
||||
htmlType: (vmm) => vmm !== CUSTOM_HOST_HYPERVISOR.NAME && INPUT_TYPES.HIDDEN,
|
||||
validation: string()
|
||||
.trim()
|
||||
.default(() => undefined)
|
||||
.when(CUSTOM_VM_MAD.name, (vmm, schema) =>
|
||||
vmm === CUSTOM_HOST_HYPERVISOR.NAME
|
||||
? schema.required()
|
||||
: schema.strip().notRequired()
|
||||
),
|
||||
grid: { md: 5 },
|
||||
}
|
||||
|
||||
/** @type {Field} Custom Information field */
|
||||
const CUSTOM_INFORMATION = {
|
||||
name: 'customIm',
|
||||
label: T.CustomInformation,
|
||||
type: INPUT_TYPES.TEXT,
|
||||
dependOf: CUSTOM_IM_MAD.name,
|
||||
htmlType: (im) => im !== CUSTOM_HOST_HYPERVISOR.NAME && INPUT_TYPES.HIDDEN,
|
||||
validation: string()
|
||||
.trim()
|
||||
.default(() => undefined)
|
||||
.when(CUSTOM_IM_MAD.name, (im, schema) =>
|
||||
im === CUSTOM_HOST_HYPERVISOR.NAME
|
||||
? schema.required()
|
||||
: schema.notRequired()
|
||||
),
|
||||
grid: { md: 5 },
|
||||
}
|
||||
|
||||
/** @type {Field[]} List of drivers fields */
|
||||
const DRIVERS_FIELDS = [
|
||||
CUSTOM_VM_MAD,
|
||||
CUSTOM_VIRTUALIZATION,
|
||||
CUSTOM_IM_MAD,
|
||||
CUSTOM_INFORMATION,
|
||||
]
|
||||
|
||||
/** @type {BaseSchema} General step schema */
|
||||
const SCHEMA = getObjectSchemaFromFields([
|
||||
HYPERVISOR_FIELD,
|
||||
INFORMATION_FIELD,
|
||||
...DRIVERS_FIELDS,
|
||||
])
|
||||
|
||||
export { SCHEMA, HYPERVISOR_FIELD, INFORMATION_FIELD, DRIVERS_FIELDS }
|
@ -0,0 +1,37 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 ClustersTable, {
|
||||
STEP_ID as CLUSTER_ID,
|
||||
} from 'client/components/Forms/Host/CreateForm/Steps/ClustersTable'
|
||||
import General, {
|
||||
STEP_ID as GENERAL_ID,
|
||||
} from 'client/components/Forms/Host/CreateForm/Steps/General'
|
||||
import { createSteps } from 'client/utils'
|
||||
|
||||
const Steps = createSteps([General, ClustersTable], {
|
||||
transformBeforeSubmit: (formData) => {
|
||||
const { [GENERAL_ID]: general, [CLUSTER_ID]: [cluster] = [] } = formData
|
||||
|
||||
return {
|
||||
hostname: general.hostname,
|
||||
vmmMad: general.customVmm || general.customVmmMad || general.vmmMad,
|
||||
imMad: general.customIm || general.customImMad || general.vmmMad,
|
||||
cluster: cluster.ID,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export default Steps
|
@ -0,0 +1,16 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
export { default } from 'client/components/Forms/Host/CreateForm/Steps'
|
34
src/fireedge/src/client/components/Forms/Host/index.js
Normal file
34
src/fireedge/src/client/components/Forms/Host/index.js
Normal file
@ -0,0 +1,34 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import { AsyncLoadForm, ConfigurationProps } from 'client/components/HOC'
|
||||
import { CreateFormCallback, CreateStepsCallback } from 'client/utils/schema'
|
||||
|
||||
/**
|
||||
* @param {ConfigurationProps} configProps - Configuration
|
||||
* @returns {ReactElement|CreateFormCallback} Asynchronous loaded form
|
||||
*/
|
||||
const ChangeClusterForm = (configProps) =>
|
||||
AsyncLoadForm({ formPath: 'Host/ChangeClusterForm' }, configProps)
|
||||
|
||||
/**
|
||||
* @param {ConfigurationProps} configProps - Configuration
|
||||
* @returns {ReactElement|CreateStepsCallback} Asynchronous loaded form
|
||||
*/
|
||||
const CreateForm = (configProps) =>
|
||||
AsyncLoadForm({ formPath: 'Host/CreateForm' }, configProps)
|
||||
|
||||
export { ChangeClusterForm, CreateForm }
|
172
src/fireedge/src/client/components/Tables/Hosts/actions.js
Normal file
172
src/fireedge/src/client/components/Tables/Hosts/actions.js
Normal file
@ -0,0 +1,172 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { useMemo } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { AddSquare, Trash } from 'iconoir-react'
|
||||
|
||||
import { useViews } from 'client/features/Auth'
|
||||
import { useAddHostToClusterMutation } from 'client/features/OneApi/cluster'
|
||||
import {
|
||||
useDisableHostMutation,
|
||||
useEnableHostMutation,
|
||||
useOfflineHostMutation,
|
||||
useRemoveHostMutation,
|
||||
} from 'client/features/OneApi/host'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
|
||||
import { ChangeClusterForm } from 'client/components/Forms/Host'
|
||||
import {
|
||||
createActions,
|
||||
GlobalAction,
|
||||
} from 'client/components/Tables/Enhanced/Utils'
|
||||
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
import { T, HOST_ACTIONS, RESOURCE_NAMES } from 'client/constants'
|
||||
|
||||
const MessageToConfirmAction = (rows) => {
|
||||
const names = rows?.map?.(({ original }) => original?.NAME)
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Translate word={T.Hosts} />
|
||||
{`: ${names.join(', ')}`}
|
||||
</p>
|
||||
<p>
|
||||
<Translate word={T.DoYouWantProceed} />
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
MessageToConfirmAction.displayName = 'MessageToConfirmAction'
|
||||
|
||||
/**
|
||||
* Generates the actions to operate resources on Host table.
|
||||
*
|
||||
* @returns {GlobalAction} - Actions
|
||||
*/
|
||||
const Actions = () => {
|
||||
const history = useHistory()
|
||||
const { view, getResourceView } = useViews()
|
||||
const [enable] = useEnableHostMutation()
|
||||
const [remove] = useRemoveHostMutation()
|
||||
const [disable] = useDisableHostMutation()
|
||||
const [offline] = useOfflineHostMutation()
|
||||
const [changeCluster] = useAddHostToClusterMutation()
|
||||
|
||||
const hostActions = useMemo(
|
||||
() =>
|
||||
createActions({
|
||||
filters: getResourceView(RESOURCE_NAMES.HOST)?.actions,
|
||||
actions: [
|
||||
{
|
||||
accessor: HOST_ACTIONS.CREATE_DIALOG,
|
||||
dataCy: `host_${HOST_ACTIONS.CREATE_DIALOG}`,
|
||||
tooltip: T.Create,
|
||||
icon: AddSquare,
|
||||
action: () => history.push(PATH.INFRASTRUCTURE.HOSTS.CREATE),
|
||||
},
|
||||
{
|
||||
accessor: HOST_ACTIONS.CHANGE_CLUSTER,
|
||||
color: 'secondary',
|
||||
dataCy: `host-${HOST_ACTIONS.CHANGE_CLUSTER}`,
|
||||
label: T.SelectCluster,
|
||||
tooltip: T.SelectCluster,
|
||||
selected: true,
|
||||
options: [
|
||||
{
|
||||
dialogProps: {
|
||||
title: T.SelectCluster,
|
||||
},
|
||||
form: (rows) => ChangeClusterForm(),
|
||||
onSubmit: (rows) => async (formData) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(
|
||||
ids.map((id) =>
|
||||
changeCluster({ id: formData.cluster, host: id })
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
accessor: HOST_ACTIONS.ENABLE,
|
||||
color: 'secondary',
|
||||
dataCy: `host_${HOST_ACTIONS.ENABLE}`,
|
||||
label: T.Enable,
|
||||
tooltip: T.Enable,
|
||||
selected: true,
|
||||
action: async (rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map((id) => enable(id)))
|
||||
},
|
||||
},
|
||||
{
|
||||
accessor: HOST_ACTIONS.DISABLE,
|
||||
color: 'secondary',
|
||||
dataCy: `host_${HOST_ACTIONS.DISABLE}`,
|
||||
label: T.Disable,
|
||||
tooltip: T.Disable,
|
||||
selected: true,
|
||||
action: async (rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map((id) => disable(id)))
|
||||
},
|
||||
},
|
||||
{
|
||||
accessor: HOST_ACTIONS.OFFLINE,
|
||||
color: 'secondary',
|
||||
dataCy: `host_${HOST_ACTIONS.OFFLINE}`,
|
||||
label: T.Offline,
|
||||
tooltip: T.Offline,
|
||||
selected: true,
|
||||
action: async (rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map((id) => offline(id)))
|
||||
},
|
||||
},
|
||||
{
|
||||
accessor: HOST_ACTIONS.DELETE,
|
||||
color: 'error',
|
||||
dataCy: 'host-delete',
|
||||
icon: Trash,
|
||||
tooltip: T.Delete,
|
||||
selected: true,
|
||||
options: [
|
||||
{
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Delete,
|
||||
children: MessageToConfirmAction,
|
||||
},
|
||||
onSubmit: (rows) => async () => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map((id) => remove({ id })))
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
[view]
|
||||
)
|
||||
|
||||
return hostActions
|
||||
}
|
||||
|
||||
export default Actions
|
@ -20,8 +20,9 @@ import { HostCard } from 'client/components/Cards'
|
||||
|
||||
const Row = memo(
|
||||
({ original, ...props }) => {
|
||||
const detail = hostApi.endpoints.getHost.useQueryState(original.ID, {
|
||||
selectFromResult: ({ data }) => data,
|
||||
const detail = hostApi.endpoints.getHosts.useQueryState(undefined, {
|
||||
selectFromResult: ({ data }) =>
|
||||
[data ?? []].flat().find((host) => +host?.ID === +original.ID),
|
||||
})
|
||||
|
||||
return <HostCard host={detail ?? original} rootProps={props} />
|
||||
|
@ -34,6 +34,7 @@ const VmsTable = (props) => {
|
||||
rootProps = {},
|
||||
searchProps = {},
|
||||
initialState = {},
|
||||
host,
|
||||
...rest
|
||||
} = props ?? {}
|
||||
|
||||
@ -45,10 +46,16 @@ const VmsTable = (props) => {
|
||||
)
|
||||
|
||||
const { view, getResourceView } = useViews()
|
||||
|
||||
const { data, refetch, isFetching } = useGetVmsQuery(undefined, {
|
||||
selectFromResult: (result) => ({
|
||||
...result,
|
||||
data: result?.data?.filter(({ STATE }) => STATE !== '6') ?? [],
|
||||
data:
|
||||
result?.data
|
||||
?.filter((vm) =>
|
||||
host?.ID ? [host?.VMS?.ID ?? []].flat().includes(vm.ID) : true
|
||||
)
|
||||
?.filter(({ STATE }) => STATE !== '6') ?? [],
|
||||
}),
|
||||
})
|
||||
|
||||
|
19
src/fireedge/src/client/components/Tables/Wilds/columns.js
Normal file
19
src/fireedge/src/client/components/Tables/Wilds/columns.js
Normal file
@ -0,0 +1,19 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
export default [
|
||||
{ Header: 'VM name', accessor: 'VM_NAME', sortType: 'string' },
|
||||
{ Header: 'Remote ID', accessor: 'DEPLOY_ID' },
|
||||
]
|
51
src/fireedge/src/client/components/Tables/Wilds/index.js
Normal file
51
src/fireedge/src/client/components/Tables/Wilds/index.js
Normal file
@ -0,0 +1,51 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { useMemo, ReactElement } from 'react'
|
||||
|
||||
import EnhancedTable from 'client/components/Tables/Enhanced'
|
||||
import WildColumns from 'client/components/Tables/Wilds/columns'
|
||||
import WildRow from 'client/components/Tables/Wilds/row'
|
||||
|
||||
const DEFAULT_DATA_CY = 'wilds'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @returns {ReactElement} - Wilds table
|
||||
*/
|
||||
const WildsTable = (props) => {
|
||||
const { rootProps = {}, searchProps = {}, wilds, ...rest } = props ?? {}
|
||||
rootProps['data-cy'] ??= DEFAULT_DATA_CY
|
||||
searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}`
|
||||
|
||||
const columns = useMemo(() => WildColumns, [])
|
||||
|
||||
return (
|
||||
<EnhancedTable
|
||||
columns={columns}
|
||||
data={useMemo(() => wilds, [wilds])}
|
||||
rootProps={rootProps}
|
||||
searchProps={searchProps}
|
||||
getRowId={(row) => String(row.DEPLOY_ID)}
|
||||
RowComponent={WildRow}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
WildsTable.propTypes = { ...EnhancedTable.propTypes }
|
||||
WildsTable.displayName = 'WildsTable'
|
||||
|
||||
export default WildsTable
|
57
src/fireedge/src/client/components/Tables/Wilds/row.js
Normal file
57
src/fireedge/src/client/components/Tables/Wilds/row.js
Normal file
@ -0,0 +1,57 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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, ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Typography } from '@mui/material'
|
||||
|
||||
import { rowStyles } from 'client/components/Tables/styles'
|
||||
import { Row as RowType } from 'react-table'
|
||||
|
||||
/**
|
||||
* @param {RowType} props - Props
|
||||
* @param {object} props.original - Wild
|
||||
* @param {boolean} props.isSelected - Wild selection
|
||||
* @param {Function} props.handleClick - Action by click
|
||||
* @returns {ReactElement} - Table row
|
||||
*/
|
||||
const Row = memo(({ original, ...props }) => {
|
||||
const classes = rowStyles()
|
||||
const { DEPLOY_ID, VM_NAME } = original
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<div className={classes.main}>
|
||||
<div className={classes.title}>
|
||||
<Typography component="span">{VM_NAME}</Typography>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span>{`#${DEPLOY_ID}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
Row.propTypes = {
|
||||
original: PropTypes.object,
|
||||
isSelected: PropTypes.bool,
|
||||
handleClick: PropTypes.func,
|
||||
}
|
||||
|
||||
Row.displayName = 'WildsRow'
|
||||
|
||||
export default Row
|
18
src/fireedge/src/client/components/Tables/Zombies/columns.js
Normal file
18
src/fireedge/src/client/components/Tables/Zombies/columns.js
Normal file
@ -0,0 +1,18 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
export default [
|
||||
{ Header: 'VM name', accessor: 'ZOMBIE_VM', sortType: 'string' },
|
||||
]
|
51
src/fireedge/src/client/components/Tables/Zombies/index.js
Normal file
51
src/fireedge/src/client/components/Tables/Zombies/index.js
Normal file
@ -0,0 +1,51 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { useMemo, ReactElement } from 'react'
|
||||
|
||||
import EnhancedTable from 'client/components/Tables/Enhanced'
|
||||
import ZombieColumns from 'client/components/Tables/Zombies/columns'
|
||||
import ZombieRow from 'client/components/Tables/Zombies/row'
|
||||
|
||||
const DEFAULT_DATA_CY = 'zombie'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @returns {ReactElement} - Zombies table
|
||||
*/
|
||||
const ZombiesTable = (props) => {
|
||||
const { rootProps = {}, searchProps = {}, zombies, ...rest } = props ?? {}
|
||||
rootProps['data-cy'] ??= DEFAULT_DATA_CY
|
||||
searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}`
|
||||
|
||||
const columns = useMemo(() => ZombieColumns, [])
|
||||
|
||||
return (
|
||||
<EnhancedTable
|
||||
columns={columns}
|
||||
data={useMemo(() => zombies, [zombies])}
|
||||
rootProps={rootProps}
|
||||
searchProps={searchProps}
|
||||
getRowId={(row) => String(row.ZOMBIE_VM)}
|
||||
RowComponent={ZombieRow}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
ZombiesTable.propTypes = { ...EnhancedTable.propTypes }
|
||||
ZombiesTable.displayName = 'ZombiesTable'
|
||||
|
||||
export default ZombiesTable
|
54
src/fireedge/src/client/components/Tables/Zombies/row.js
Normal file
54
src/fireedge/src/client/components/Tables/Zombies/row.js
Normal file
@ -0,0 +1,54 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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, ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Typography } from '@mui/material'
|
||||
|
||||
import { rowStyles } from 'client/components/Tables/styles'
|
||||
import { Row as RowType } from 'react-table'
|
||||
|
||||
/**
|
||||
* @param {RowType} props - Props
|
||||
* @param {object} props.original - Zombie
|
||||
* @param {boolean} props.isSelected - Zombie selection
|
||||
* @param {Function} props.handleClick - Action by click
|
||||
* @returns {ReactElement} - Table row
|
||||
*/
|
||||
const Row = memo(({ original, ...props }) => {
|
||||
const classes = rowStyles()
|
||||
const { ZOMBIE_VM } = original
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<div className={classes.main}>
|
||||
<div className={classes.title}>
|
||||
<Typography component="span">{ZOMBIE_VM}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
Row.propTypes = {
|
||||
original: PropTypes.object,
|
||||
isSelected: PropTypes.bool,
|
||||
handleClick: PropTypes.func,
|
||||
}
|
||||
|
||||
Row.displayName = 'ZombiesRow'
|
||||
|
||||
export default Row
|
42
src/fireedge/src/client/components/Tabs/EmptyTab/index.js
Normal file
42
src/fireedge/src/client/components/Tabs/EmptyTab/index.js
Normal file
@ -0,0 +1,42 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import { InfoEmpty } from 'iconoir-react'
|
||||
|
||||
import { Translate } from 'client/components/HOC/Translate'
|
||||
import { useStyles } from 'client/components/Tabs/EmptyTab/styles'
|
||||
|
||||
import { T } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Renders default empty tab.
|
||||
*
|
||||
* @returns {ReactElement} Empty tab
|
||||
*/
|
||||
const EmptyTab = () => {
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<span className={classes.noDataMessage}>
|
||||
<InfoEmpty />
|
||||
<Translate word={T.NoDataAvailable} />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
EmptyTab.displayName = 'EmptyTab'
|
||||
|
||||
export default EmptyTab
|
27
src/fireedge/src/client/components/Tabs/EmptyTab/styles.js
Normal file
27
src/fireedge/src/client/components/Tabs/EmptyTab/styles.js
Normal file
@ -0,0 +1,27 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 makeStyles from '@mui/styles/makeStyles'
|
||||
|
||||
export const useStyles = makeStyles(({ typography, palette }) => ({
|
||||
noDataMessage: {
|
||||
...typography.h6,
|
||||
color: palette.text.hint,
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '0.8em',
|
||||
padding: '1em',
|
||||
},
|
||||
}))
|
@ -0,0 +1,52 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Box, Grid, Paper, Typography } from '@mui/material'
|
||||
|
||||
import { Translate } from 'client/components/HOC'
|
||||
import { T, CPU_STATUS } from 'client/constants'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @param {string} props.core - Numa core
|
||||
* @param {object} props.cpus - List of numa cores
|
||||
* @returns {ReactElement} Information tab
|
||||
*/
|
||||
const NumaCoreCPU = ({ core, cpus }) => (
|
||||
<Grid item xs={6}>
|
||||
<Paper sx={{ pt: '0.3rem', pb: '0.1rem' }}>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Typography gutterBottom variant="body2" component="div" align="center">
|
||||
<Translate word={T.NumaNodeCPUItem} values={core} />
|
||||
</Typography>
|
||||
<Typography gutterBottom variant="body2" component="div" align="center">
|
||||
{CPU_STATUS[String(cpus[core])]}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Grid>
|
||||
)
|
||||
|
||||
NumaCoreCPU.propTypes = {
|
||||
core: PropTypes.string.isRequired,
|
||||
cpus: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
NumaCoreCPU.displayName = 'NumaCoreCPU'
|
||||
|
||||
export default NumaCoreCPU
|
@ -0,0 +1,57 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import { Box, Grid, Typography } from '@mui/material'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Translate } from 'client/components/HOC'
|
||||
import { T } from 'client/constants'
|
||||
|
||||
import NumaCoreCPU from 'client/components/Tabs/Host/Numa/CPU'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @param {object} props.core - Numa core
|
||||
* @returns {ReactElement} Information tab
|
||||
*/
|
||||
const NumaCore = ({ core }) => {
|
||||
const cpus = Object.fromEntries(
|
||||
core.CPUS.split(',').map((item) => item.split(':'))
|
||||
)
|
||||
|
||||
return (
|
||||
<Grid item xs={12} sm={6} md={3} display="flex" justifyContent="center">
|
||||
<Box width="200px">
|
||||
<Typography gutterBottom variant="body1" component="div" align="center">
|
||||
<Translate word={T.NumaCore} values={core.ID} />
|
||||
</Typography>
|
||||
<Grid container spacing={1}>
|
||||
{Object.keys(cpus).map((cpu, index) => (
|
||||
<NumaCoreCPU key={index} core={cpu} cpus={cpus} />
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
NumaCore.propTypes = {
|
||||
core: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
NumaCore.displayName = 'Core'
|
||||
|
||||
export default NumaCore
|
@ -0,0 +1,76 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Box, List, ListItem, Paper, Typography } from '@mui/material'
|
||||
|
||||
import { Translate } from 'client/components/HOC'
|
||||
import { useStyles } from 'client/components/Tabs/Host/Numa/Hugepage/styles'
|
||||
|
||||
import { T } from 'client/constants'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @param {string[]} props.hugepage - Numa hugepage tab info
|
||||
* @returns {ReactElement} Information view
|
||||
*/
|
||||
const NumaHugepage = ({ hugepage }) => {
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography gutterBottom variant="subtitle1" component="h3">
|
||||
<Translate word={T.HugepageNode} />
|
||||
</Typography>
|
||||
<Paper variant="outlined">
|
||||
<List className={classes.list}>
|
||||
<ListItem className={classes.title}>
|
||||
<Typography noWrap>
|
||||
<Translate word={T.HugepageNodeSize} />
|
||||
</Typography>
|
||||
<Typography noWrap>
|
||||
<Translate word={T.HugepageNodeFree} />
|
||||
</Typography>
|
||||
<Typography noWrap>
|
||||
<Translate word={T.HugepageNodePages} />
|
||||
</Typography>
|
||||
<Typography noWrap>
|
||||
<Translate word={T.HugepageNodeUsage} />
|
||||
</Typography>
|
||||
</ListItem>
|
||||
{hugepage.length > 0 &&
|
||||
hugepage.map(({ FREE, PAGES, SIZE, USAGE }, index) => (
|
||||
<ListItem key={index} className={classes.item} dense>
|
||||
<Typography noWrap>{SIZE}</Typography>
|
||||
<Typography noWrap>{FREE}</Typography>
|
||||
<Typography noWrap>{PAGES}</Typography>
|
||||
<Typography noWrap>{USAGE}</Typography>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
NumaHugepage.propTypes = {
|
||||
hugepage: PropTypes.array,
|
||||
}
|
||||
|
||||
NumaHugepage.displayName = 'NumaHugepage'
|
||||
|
||||
export default NumaHugepage
|
@ -0,0 +1,29 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 makeStyles from '@mui/styles/makeStyles'
|
||||
|
||||
export const useStyles = makeStyles((theme) => ({
|
||||
list: {
|
||||
'& > * > *': {
|
||||
width: '25%',
|
||||
},
|
||||
},
|
||||
title: {
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
textTransform: 'uppercase',
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
}))
|
@ -0,0 +1,57 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Box, Paper, Typography } from '@mui/material'
|
||||
|
||||
import LinearProgressWithLabel from 'client/components/Status/LinearProgressWithLabel'
|
||||
|
||||
import { T } from 'client/constants'
|
||||
import { Tr, Translate } from 'client/components/HOC'
|
||||
|
||||
import { getNumaMemory } from 'client/models/Host'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @param {string} props.node - Numa node
|
||||
* @returns {ReactElement} Information tab
|
||||
*/
|
||||
const NumaMemory = ({ node }) => {
|
||||
const { percentMemUsed, percentMemLabel } = getNumaMemory(node)
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography gutterBottom variant="subtitle1" component="h3">
|
||||
<Translate word={T.NumaNodeMemory} />
|
||||
</Typography>
|
||||
<Paper variant="outlined" sx={{ p: '1.25rem' }}>
|
||||
<LinearProgressWithLabel
|
||||
value={percentMemUsed}
|
||||
label={percentMemLabel}
|
||||
title={`${Tr(T.AllocatedCpu)}`}
|
||||
/>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
NumaMemory.propTypes = {
|
||||
node: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
NumaMemory.displayName = 'NumaMemory'
|
||||
|
||||
export default NumaMemory
|
@ -0,0 +1,114 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import { FormProvider, useForm } from 'react-hook-form'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Box } from '@mui/material'
|
||||
import { yupResolver } from '@hookform/resolvers/yup'
|
||||
|
||||
import {
|
||||
FORM_FIELDS_ISOLATION,
|
||||
FORM_SCHEMA_ISOLATION,
|
||||
} from 'client/components/Tabs/Host/Numa/UpdateIsolatedCPUS/schema'
|
||||
|
||||
import SubmitButton from 'client/components/FormControl/SubmitButton'
|
||||
import FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
|
||||
import { useUpdateHostMutation } from 'client/features/OneApi/host'
|
||||
import { useGeneralApi } from 'client/features/General/hooks'
|
||||
|
||||
import { jsonToXml } from 'client/models/Helper'
|
||||
import { cloneObject } from 'client/utils'
|
||||
|
||||
import { T, Host } from 'client/constants'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @param {Host} props.host - Host resource
|
||||
* @returns {ReactElement} Form for updating isolated CPU
|
||||
*/
|
||||
const UpdateIsolatedCPUSForm = ({ host }) => {
|
||||
const { TEMPLATE } = host
|
||||
|
||||
const { enqueueError } = useGeneralApi()
|
||||
const [updateUserTemplate] = useUpdateHostMutation()
|
||||
|
||||
const { handleSubmit, reset, formState, ...methods } = useForm({
|
||||
reValidateMode: 'onSubmit',
|
||||
defaultValues: {
|
||||
ISOLATION: TEMPLATE.ISOLCPUS,
|
||||
},
|
||||
resolver: yupResolver(FORM_SCHEMA_ISOLATION),
|
||||
})
|
||||
|
||||
const onSubmit = async (formData) => {
|
||||
try {
|
||||
const newTemplate = cloneObject(TEMPLATE)
|
||||
newTemplate.ISOLCPUS = formData.ISOLATION
|
||||
const xml = jsonToXml(newTemplate)
|
||||
await updateUserTemplate({ id: host.ID, template: xml, replace: 0 })
|
||||
|
||||
// Reset either the entire form state or part of the form state
|
||||
reset(formData)
|
||||
} catch {
|
||||
enqueueError(T.SomethingWrong)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Box component="form" onSubmit={handleSubmit(onSubmit)}>
|
||||
<FormProvider {...methods}>
|
||||
<Box display="flex">
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<FormWithSchema
|
||||
cy="numa-isolate-cpus"
|
||||
fields={FORM_FIELDS_ISOLATION}
|
||||
legend={T.ISOLCPUS}
|
||||
legendTooltip={T.TemplateToIsolateCpus}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="end"
|
||||
justifyContent="center"
|
||||
minWidth="7rem"
|
||||
paddingBottom="1.25rem"
|
||||
>
|
||||
<SubmitButton
|
||||
color="secondary"
|
||||
data-cy="isolate-cpus-submit-button"
|
||||
label={Tr(T.Update)}
|
||||
onClick={handleSubmit}
|
||||
disabled={!formState.isDirty}
|
||||
isSubmitting={formState.isSubmitting}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</FormProvider>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
UpdateIsolatedCPUSForm.propTypes = {
|
||||
host: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
UpdateIsolatedCPUSForm.displayName = 'UpdateIsolatedCPUSForm'
|
||||
|
||||
export default UpdateIsolatedCPUSForm
|
@ -0,0 +1,35 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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, ObjectSchema } from 'yup'
|
||||
import { Field, getValidationFromFields } from 'client/utils'
|
||||
|
||||
import { INPUT_TYPES } from 'client/constants'
|
||||
|
||||
/** @type {Field} Isolation field */
|
||||
const ISOLATION = {
|
||||
name: 'ISOLATION',
|
||||
type: INPUT_TYPES.TEXT,
|
||||
validation: string().default(() => ''),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
/** @type {Field[]} List of fields */
|
||||
export const FORM_FIELDS_ISOLATION = [ISOLATION]
|
||||
|
||||
/** @type {ObjectSchema} Schema */
|
||||
export const FORM_SCHEMA_ISOLATION = object(
|
||||
getValidationFromFields(FORM_FIELDS_ISOLATION)
|
||||
)
|
@ -0,0 +1,85 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement, useEffect } from 'react'
|
||||
import { FormProvider, useForm } from 'react-hook-form'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { yupResolver } from '@hookform/resolvers/yup'
|
||||
|
||||
import {
|
||||
FORM_FIELDS_PIN_POLICY,
|
||||
FORM_SCHEMA_PIN_POLICY,
|
||||
} from 'client/components/Tabs/Host/Numa/UpdatePinPolicy/schema'
|
||||
|
||||
import FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
|
||||
import { useGeneralApi } from 'client/features/General'
|
||||
|
||||
import { useUpdateHostMutation } from 'client/features/OneApi/host'
|
||||
|
||||
import { T, Host } from 'client/constants'
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @param {Host} props.host - Host resource
|
||||
* @returns {ReactElement} Form for updating pin policy
|
||||
*/
|
||||
const UpdatePinPolicyForm = ({ host }) => {
|
||||
const { TEMPLATE } = host
|
||||
|
||||
const { enqueueError } = useGeneralApi()
|
||||
const [updateUserTemplate] = useUpdateHostMutation()
|
||||
|
||||
const { watch, ...methods } = useForm({
|
||||
reValidateMode: 'onSubmit',
|
||||
defaultValues: {
|
||||
PIN_POLICY: TEMPLATE.PIN_POLICY,
|
||||
},
|
||||
resolver: yupResolver(FORM_SCHEMA_PIN_POLICY),
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
watch((data) => {
|
||||
try {
|
||||
updateUserTemplate({
|
||||
id: host.ID,
|
||||
template: `PIN_POLICY = ${data.PIN_POLICY}`,
|
||||
replace: 1,
|
||||
})
|
||||
} catch {
|
||||
enqueueError(T.SomethingWrong)
|
||||
}
|
||||
})
|
||||
}, [watch])
|
||||
|
||||
return (
|
||||
<FormProvider {...methods}>
|
||||
<FormWithSchema
|
||||
cy="numa-pinned-policy"
|
||||
fields={FORM_FIELDS_PIN_POLICY}
|
||||
legend={T.PinPolicy}
|
||||
/>
|
||||
</FormProvider>
|
||||
)
|
||||
}
|
||||
|
||||
UpdatePinPolicyForm.propTypes = {
|
||||
host: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
UpdatePinPolicyForm.displayName = 'UpdateIsolatedCPUSForm'
|
||||
|
||||
export default UpdatePinPolicyForm
|
@ -0,0 +1,43 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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, ObjectSchema } from 'yup'
|
||||
|
||||
import { Field, getValidationFromFields } from 'client/utils'
|
||||
|
||||
import { PIN_POLICY, INPUT_TYPES } from 'client/constants'
|
||||
|
||||
/** @type {Field} Pin Policy field */
|
||||
const PIN_POLICY_FIELD = {
|
||||
name: 'PIN_POLICY',
|
||||
type: INPUT_TYPES.SELECT,
|
||||
values: [
|
||||
{ text: 'None', value: PIN_POLICY.NONE },
|
||||
{ text: 'Pinned', value: PIN_POLICY.PINNED },
|
||||
],
|
||||
validation: string()
|
||||
.trim()
|
||||
.required()
|
||||
.default(() => PIN_POLICY.NONE),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
/** @type {Field[]} List of fields */
|
||||
export const FORM_FIELDS_PIN_POLICY = [PIN_POLICY_FIELD]
|
||||
|
||||
/** @type {ObjectSchema} Schema */
|
||||
export const FORM_SCHEMA_PIN_POLICY = object(
|
||||
getValidationFromFields(FORM_FIELDS_PIN_POLICY)
|
||||
)
|
61
src/fireedge/src/client/components/Tabs/Host/Numa/index.js
Normal file
61
src/fireedge/src/client/components/Tabs/Host/Numa/index.js
Normal file
@ -0,0 +1,61 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import EmptyTab from 'client/components/Tabs/EmptyTab'
|
||||
import Information from 'client/components/Tabs/Host/Numa/information'
|
||||
|
||||
import { getHostNuma } from 'client/models/Host'
|
||||
import { useGetHostQuery } from 'client/features/OneApi/host'
|
||||
|
||||
import UpdatePinPolicyForm from 'client/components/Tabs/Host/Numa/UpdatePinPolicy'
|
||||
import UpdateIsolatedCPUSForm from 'client/components/Tabs/Host/Numa/UpdateIsolatedCPUS'
|
||||
|
||||
/**
|
||||
* Renders mainly information tab.
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {string} props.id - Host id
|
||||
* @returns {ReactElement} Information tab
|
||||
*/
|
||||
const NumaInfoTab = ({ id }) => {
|
||||
const { data: host = {} } = useGetHostQuery(id)
|
||||
const numa = getHostNuma(host)
|
||||
|
||||
return (
|
||||
<>
|
||||
<UpdatePinPolicyForm host={host} />
|
||||
<UpdateIsolatedCPUSForm host={host} />
|
||||
{numa?.length > 0 ? (
|
||||
numa.map((node) => (
|
||||
<Information key={node.NODE_ID} node={node} host={host} />
|
||||
))
|
||||
) : (
|
||||
<EmptyTab />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
NumaInfoTab.propTypes = {
|
||||
tabProps: PropTypes.object,
|
||||
id: PropTypes.string,
|
||||
}
|
||||
|
||||
NumaInfoTab.displayName = 'NumaInfoTab'
|
||||
|
||||
export default NumaInfoTab
|
@ -0,0 +1,75 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Divider, Grid, Stack, Typography } from '@mui/material'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
|
||||
import NumaCore from 'client/components/Tabs/Host/Numa/Core'
|
||||
import NumaMemory from 'client/components/Tabs/Host/Numa/Memory'
|
||||
import NumaHugepage from 'client/components/Tabs/Host/Numa/Hugepage'
|
||||
|
||||
import { T } from 'client/constants'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @param {object} props.node - Numa Node
|
||||
* @returns {ReactElement} Information tab
|
||||
*/
|
||||
const InformationPanel = ({ node = {} }) => {
|
||||
const { CORE, HUGEPAGE } = node
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack
|
||||
gap="1em"
|
||||
gridTemplateColumns="repeat(auto-fit, minmax(480px, 1fr))"
|
||||
padding="0.8em"
|
||||
>
|
||||
<Typography gutterBottom variant="h2" component="h2">
|
||||
<Translate word={T.NumaNodeItem} values={node.NODE_ID} />
|
||||
</Typography>
|
||||
<Typography gutterBottom variant="subtitle1" component="h3">
|
||||
<Translate word={T.NumaNodeTitle} />
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Divider variant="middle" />
|
||||
<Grid container spacing={2} sx={{ padding: '10px 0 20px' }}>
|
||||
{CORE.length &&
|
||||
CORE.map((core) => <NumaCore key={core.ID} core={core} />)}
|
||||
</Grid>
|
||||
<Divider variant="middle" />
|
||||
<Stack
|
||||
display="grid"
|
||||
gap="1em"
|
||||
gridTemplateColumns="repeat(auto-fit, minmax(480px, 1fr))"
|
||||
padding="0.8em"
|
||||
>
|
||||
<NumaHugepage hugepage={[HUGEPAGE].flat()} />
|
||||
<NumaMemory node={node} />
|
||||
</Stack>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
InformationPanel.propTypes = {
|
||||
node: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
InformationPanel.displayName = 'InformationPanel'
|
||||
|
||||
export default InformationPanel
|
62
src/fireedge/src/client/components/Tabs/Host/Vms.js
Normal file
62
src/fireedge/src/client/components/Tabs/Host/Vms.js
Normal file
@ -0,0 +1,62 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Container, Stack } from '@mui/material'
|
||||
import { useHistory, generatePath } from 'react-router-dom'
|
||||
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
|
||||
import { useGetHostQuery } from 'client/features/OneApi/host'
|
||||
|
||||
import { VmsTable } from 'client/components/Tables'
|
||||
|
||||
/**
|
||||
* Renders mainly information tab.
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {string} props.id - Host id
|
||||
* @returns {ReactElement} Information tab
|
||||
*/
|
||||
const VmsInfoTab = ({ id }) => {
|
||||
const { data: host = {} } = useGetHostQuery(id)
|
||||
const path = PATH.INSTANCE.VMS.DETAIL
|
||||
const history = useHistory()
|
||||
|
||||
const handleRowClick = (rowId) => {
|
||||
history.push(generatePath(path, { id: String(rowId) }))
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack height={1} py={2} overflow="auto" component={Container}>
|
||||
<VmsTable
|
||||
disableRowSelect
|
||||
disableGlobalSort
|
||||
host={host}
|
||||
onRowClick={(row) => handleRowClick(row.ID)}
|
||||
/>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
VmsInfoTab.propTypes = {
|
||||
tabProps: PropTypes.object,
|
||||
id: PropTypes.string,
|
||||
}
|
||||
|
||||
VmsInfoTab.displayName = 'WildsInfoTab'
|
||||
|
||||
export default VmsInfoTab
|
55
src/fireedge/src/client/components/Tabs/Host/Wilds.js
Normal file
55
src/fireedge/src/client/components/Tabs/Host/Wilds.js
Normal file
@ -0,0 +1,55 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Stack } from '@mui/material'
|
||||
|
||||
import { getHostWilds } from 'client/models/Host'
|
||||
import { useGetHostQuery } from 'client/features/OneApi/host'
|
||||
|
||||
import WildsTable from 'client/components/Tables/Wilds'
|
||||
|
||||
/**
|
||||
* Renders mainly information tab.
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {string} props.id - Host id
|
||||
* @returns {ReactElement} - Wild information tab
|
||||
*/
|
||||
const WildsInfoTab = ({ id }) => {
|
||||
const { data: host = {} } = useGetHostQuery(id)
|
||||
const wilds = getHostWilds(host)
|
||||
|
||||
return (
|
||||
<Stack
|
||||
display="grid"
|
||||
gap="1em"
|
||||
gridTemplateColumns="repeat(auto-fit, minmax(480px, 1fr))"
|
||||
padding="0.8em"
|
||||
>
|
||||
<WildsTable wilds={wilds} />
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
WildsInfoTab.propTypes = {
|
||||
tabProps: PropTypes.object,
|
||||
id: PropTypes.string,
|
||||
}
|
||||
|
||||
WildsInfoTab.displayName = 'WildsInfoTab'
|
||||
|
||||
export default WildsInfoTab
|
55
src/fireedge/src/client/components/Tabs/Host/Zombies.js
Normal file
55
src/fireedge/src/client/components/Tabs/Host/Zombies.js
Normal file
@ -0,0 +1,55 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Stack } from '@mui/material'
|
||||
|
||||
import { useGetHostQuery } from 'client/features/OneApi/host'
|
||||
import { getHostZombies } from 'client/models/Host'
|
||||
|
||||
import ZombiesTable from 'client/components/Tables/Zombies'
|
||||
|
||||
/**
|
||||
* Renders mainly information tab.
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {string} props.id - Host id
|
||||
* @returns {ReactElement} - Zombies information tab
|
||||
*/
|
||||
const ZombiesInfoTab = ({ id }) => {
|
||||
const { data: host = {} } = useGetHostQuery(id)
|
||||
const zombies = getHostZombies(host)
|
||||
|
||||
return (
|
||||
<Stack
|
||||
display="grid"
|
||||
gap="1em"
|
||||
gridTemplateColumns="repeat(auto-fit, minmax(480px, 1fr))"
|
||||
padding="0.8em"
|
||||
>
|
||||
<ZombiesTable disableRowSelect disableGlobalSort zombies={zombies} />
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
ZombiesInfoTab.propTypes = {
|
||||
tabProps: PropTypes.object,
|
||||
id: PropTypes.string,
|
||||
}
|
||||
|
||||
ZombiesInfoTab.displayName = 'ZombiesInfoTab'
|
||||
|
||||
export default ZombiesInfoTab
|
@ -17,21 +17,29 @@ import { memo, useMemo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Alert, LinearProgress } from '@mui/material'
|
||||
|
||||
import { useAuth } from 'client/features/Auth'
|
||||
import { useViews } from 'client/features/Auth/hooks'
|
||||
import { useGetHostQuery } from 'client/features/OneApi/host'
|
||||
import { getAvailableInfoTabs } from 'client/models/Helper'
|
||||
import { RESOURCE_NAMES } from 'client/constants'
|
||||
|
||||
import Tabs from 'client/components/Tabs'
|
||||
import Info from 'client/components/Tabs/Host/Info'
|
||||
import Wilds from 'client/components/Tabs/Host/Wilds'
|
||||
import Numa from 'client/components/Tabs/Host/Numa'
|
||||
import Zombies from 'client/components/Tabs/Host/Zombies'
|
||||
import Vms from 'client/components/Tabs/Host/Vms'
|
||||
|
||||
const getTabComponent = (tabName) =>
|
||||
({
|
||||
info: Info,
|
||||
vms: Vms,
|
||||
wild: Wilds,
|
||||
numa: Numa,
|
||||
zombies: Zombies,
|
||||
}[tabName])
|
||||
|
||||
const HostTabs = memo(({ id }) => {
|
||||
const { view, getResourceView } = useAuth()
|
||||
const { view, getResourceView } = useViews()
|
||||
const { isLoading, isError, error } = useGetHostQuery(id)
|
||||
|
||||
const tabsAvailable = useMemo(() => {
|
||||
|
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import * as STATES from 'client/constants/states'
|
||||
import * as ACTIONS from 'client/constants/actions'
|
||||
import COLOR from 'client/constants/color'
|
||||
|
||||
import * as STATES from 'client/constants/states'
|
||||
import * as T from 'client/constants/translates'
|
||||
/**
|
||||
* @typedef {object} PciDevice - PCI device
|
||||
* @property {string} ADDRESS - Address, bus, slot and function
|
||||
@ -183,3 +183,21 @@ export const HOST_ACTIONS = {
|
||||
OFFLINE: 'offline',
|
||||
DELETE: 'delete',
|
||||
}
|
||||
|
||||
/** @enum {string} Numa Node CPU Status */
|
||||
export const CPU_STATUS = {
|
||||
'-1': 'FREE',
|
||||
'-2': 'ISOLATED',
|
||||
}
|
||||
|
||||
/** @enum {string} Pin Policy */
|
||||
export const PIN_POLICY = {
|
||||
NONE: 'NONE',
|
||||
PINNED: 'PINNED',
|
||||
}
|
||||
|
||||
/** @type {object} Custom Hypervisor */
|
||||
export const CUSTOM_HOST_HYPERVISOR = {
|
||||
NAME: 'Custom',
|
||||
SUNSTONE_NAME: T.CustomHypervisor,
|
||||
}
|
||||
|
@ -64,10 +64,12 @@ module.exports = {
|
||||
Deploy: 'Deploy',
|
||||
Detach: 'Detach',
|
||||
DetachSomething: 'Detach: %s',
|
||||
Disable: 'Disable',
|
||||
Dismiss: 'Dismiss',
|
||||
Done: 'Done',
|
||||
Edit: 'Edit',
|
||||
EditSomething: 'Edit: %s',
|
||||
Enable: 'Enable',
|
||||
Failure: 'Failure',
|
||||
Finish: 'Finish',
|
||||
Hold: 'Hold',
|
||||
@ -77,6 +79,7 @@ module.exports = {
|
||||
Lock: 'Lock',
|
||||
Migrate: 'Migrate',
|
||||
MigrateLive: 'Migrate live',
|
||||
Offline: 'Offline',
|
||||
Pin: 'Pin',
|
||||
Poweroff: 'Poweroff',
|
||||
PoweroffHard: 'Poweroff hard',
|
||||
@ -105,12 +108,14 @@ module.exports = {
|
||||
SaveAsTemplate: 'Save as Template',
|
||||
Search: 'Search',
|
||||
Select: 'Select',
|
||||
SelectCluster: 'Select Cluster',
|
||||
SelectDatastore: 'Select a Datastore to store the resource',
|
||||
SelectDockerHubTag: 'Select DockerHub image tag (default latest)',
|
||||
SelectGroup: 'Select a group',
|
||||
SelectHost: 'Select a host',
|
||||
SelectMarketplace: 'Select Marketplace',
|
||||
SelectNetwork: 'Select a network',
|
||||
SelectNewCluster: 'Select a new Cluster',
|
||||
SelectRequest: 'Select request',
|
||||
SelectTheNewDatastore: 'Select the new datastore',
|
||||
SelectTheNewGroup: 'Select the new group',
|
||||
@ -324,6 +329,7 @@ module.exports = {
|
||||
Provisions: 'Provisions',
|
||||
|
||||
/* tabs */
|
||||
Drivers: 'Drivers',
|
||||
General: 'General',
|
||||
Information: 'Information',
|
||||
Placement: 'Placement',
|
||||
@ -455,11 +461,15 @@ module.exports = {
|
||||
|
||||
/* VM Template schema */
|
||||
/* VM Template schema - general */
|
||||
Logo: 'Logo',
|
||||
Hypervisor: 'Hypervisor',
|
||||
TemplateName: 'Template name',
|
||||
MakeNewImagePersistent: 'Make the new images persistent',
|
||||
CustomHypervisor: 'Custom',
|
||||
CustomVariables: 'Custom Variables',
|
||||
Hypervisor: 'Hypervisor',
|
||||
Logo: 'Logo',
|
||||
MakeNewImagePersistent: 'Make the new images persistent',
|
||||
TemplateName: 'Template name',
|
||||
Virtualization: 'Virtualization',
|
||||
CustomInformation: 'Custom information',
|
||||
CustomVirtualization: 'Custom virtualization',
|
||||
VmTemplateNameHelper: `
|
||||
Defaults to 'template name-<vmid>' when empty.
|
||||
When creating several VMs, the wildcard %%idx will be
|
||||
@ -656,11 +666,21 @@ module.exports = {
|
||||
NumaTopologyConcept:
|
||||
'These settings will help you to fine tune the performance of VMs',
|
||||
PinPolicy: 'Pin Policy',
|
||||
NumaNodeItem: 'Node #%s',
|
||||
NumaNodeTitle: 'Cores & CPUS',
|
||||
PinPolicyConcept: 'Virtual CPU pinning preference: %s',
|
||||
NumaSocketsConcept: 'Number of sockets or NUMA nodes',
|
||||
NumaCoresConcept: 'Number of cores per node',
|
||||
NumaNodeMemory: 'Memory',
|
||||
NumaCore: 'Core %s',
|
||||
NumaNodeCPUItem: 'CPU #%s',
|
||||
Threads: 'Threads',
|
||||
ThreadsConcept: 'Number of threads per core',
|
||||
HugepageNode: 'Hugepage',
|
||||
HugepageNodeFree: 'Free',
|
||||
HugepageNodePages: 'Pages',
|
||||
HugepageNodeSize: 'Size',
|
||||
HugepageNodeUsage: 'Usage',
|
||||
HugepagesSize: 'Hugepages size',
|
||||
HugepagesSizeConcept:
|
||||
'Size of hugepages (MB). If not defined no hugepages will be used',
|
||||
@ -740,6 +760,10 @@ module.exports = {
|
||||
RealMemory: 'Real Memory',
|
||||
RealCpu: 'Real CPU',
|
||||
Overcommitment: 'Overcommitment',
|
||||
/* Host schema - template */
|
||||
ISOLCPUS: 'Isolated CPUS',
|
||||
TemplateToIsolateCpus:
|
||||
'Comma separated list of CPU IDs that will be isolated from the NUMA scheduler',
|
||||
|
||||
/* Cluster schema */
|
||||
/* Cluster schema - capacity */
|
||||
|
69
src/fireedge/src/client/containers/Hosts/Create.js
Normal file
69
src/fireedge/src/client/containers/Hosts/Create.js
Normal file
@ -0,0 +1,69 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import { useHistory, useLocation } from 'react-router'
|
||||
import { Container } from '@mui/material'
|
||||
|
||||
import { useGeneralApi } from 'client/features/General'
|
||||
import {
|
||||
useUpdateHostMutation,
|
||||
useAllocateHostMutation,
|
||||
} from 'client/features/OneApi/host'
|
||||
|
||||
import {
|
||||
DefaultFormStepper,
|
||||
SkeletonStepsForm,
|
||||
} from 'client/components/FormStepper'
|
||||
import { CreateForm } from 'client/components/Forms/Host'
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
|
||||
/**
|
||||
* Displays the creation or modification form to a Host.
|
||||
*
|
||||
* @returns {ReactElement} Host form
|
||||
*/
|
||||
function CreateHost() {
|
||||
const history = useHistory()
|
||||
const { state: { ID: id, NAME } = {} } = useLocation()
|
||||
|
||||
const { enqueueSuccess } = useGeneralApi()
|
||||
const [update] = useUpdateHostMutation()
|
||||
const [allocate] = useAllocateHostMutation()
|
||||
|
||||
const onSubmit = async (props) => {
|
||||
try {
|
||||
if (!id) {
|
||||
const newHostId = await allocate(props).unwrap()
|
||||
history.push(PATH.INFRASTRUCTURE.HOSTS.LIST)
|
||||
enqueueSuccess(`Host created - #${newHostId}`)
|
||||
} else {
|
||||
await update({ id, ...props })
|
||||
history.push(PATH.INFRASTRUCTURE.HOSTS.LIST)
|
||||
enqueueSuccess(`Host updated - #${id} ${NAME}`)
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return (
|
||||
<Container sx={{ display: 'flex', flexFlow: 'column' }} disableGutters>
|
||||
<CreateForm onSubmit={onSubmit} fallback={<SkeletonStepsForm />}>
|
||||
{(config) => <DefaultFormStepper {...config} />}
|
||||
</CreateForm>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default CreateHost
|
@ -19,16 +19,21 @@ import { Container, Stack, Chip } from '@mui/material'
|
||||
|
||||
import { HostsTable } from 'client/components/Tables'
|
||||
import HostTabs from 'client/components/Tabs/Host'
|
||||
import HostActions from 'client/components/Tables/Hosts/actions'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
|
||||
function Hosts() {
|
||||
const [selectedRows, onSelectedRowsChange] = useState(() => [])
|
||||
const actions = HostActions()
|
||||
|
||||
return (
|
||||
<Stack height={1} py={2} overflow="auto" component={Container}>
|
||||
<SplitPane>
|
||||
<HostsTable onSelectedRowsChange={onSelectedRowsChange} />
|
||||
<HostsTable
|
||||
onSelectedRowsChange={onSelectedRowsChange}
|
||||
globalActions={actions}
|
||||
/>
|
||||
|
||||
{selectedRows?.length > 0 && (
|
||||
<Stack overflow="auto">
|
||||
|
@ -21,8 +21,8 @@ import {
|
||||
} from 'client/features/OneApi'
|
||||
import { Cluster } from 'client/constants'
|
||||
|
||||
const { CLUSTER } = ONE_RESOURCES
|
||||
const { CLUSTER_POOL } = ONE_RESOURCES_POOL
|
||||
const { CLUSTER, HOST } = ONE_RESOURCES
|
||||
const { CLUSTER_POOL, HOST_POOL } = ONE_RESOURCES_POOL
|
||||
|
||||
const clusterApi = oneApi.injectEndpoints({
|
||||
endpoints: (builder) => ({
|
||||
@ -157,7 +157,12 @@ const clusterApi = oneApi.injectEndpoints({
|
||||
|
||||
return { params, command }
|
||||
},
|
||||
invalidatesTags: (_, __, { id }) => [{ type: CLUSTER, id }, CLUSTER_POOL],
|
||||
invalidatesTags: (_, __, { id, host }) => [
|
||||
{ type: CLUSTER, id },
|
||||
{ type: HOST, id: host },
|
||||
CLUSTER_POOL,
|
||||
HOST_POOL,
|
||||
],
|
||||
}),
|
||||
removeHostFromCluster: builder.mutation({
|
||||
/**
|
||||
|
@ -16,22 +16,26 @@
|
||||
import { prettyBytes } from 'client/utils'
|
||||
import {
|
||||
DEFAULT_CPU_MODELS,
|
||||
CUSTOM_HOST_HYPERVISOR,
|
||||
Host,
|
||||
HOST_STATES,
|
||||
HYPERVISORS,
|
||||
NumaNode,
|
||||
PciDevice,
|
||||
StateInfo,
|
||||
} from 'client/constants'
|
||||
import { useGetOneConfigQuery } from 'client/features/OneApi/system'
|
||||
|
||||
/**
|
||||
* Returns information about the host state.
|
||||
*
|
||||
* @param {object} host - Host
|
||||
* @param {Host} host - Host
|
||||
* @returns {StateInfo} Host state object
|
||||
*/
|
||||
export const getState = (host) => HOST_STATES[+host?.STATE ?? 0]
|
||||
|
||||
/**
|
||||
* @param {object} host - Host
|
||||
* @param {Host} host - Host
|
||||
* @returns {Array} List of datastores from resource
|
||||
*/
|
||||
export const getDatastores = (host) =>
|
||||
@ -40,7 +44,7 @@ export const getDatastores = (host) =>
|
||||
/**
|
||||
* Returns the allocate information.
|
||||
*
|
||||
* @param {object} host - Host
|
||||
* @param {Host} host - Host
|
||||
* @returns {{
|
||||
* percentCpuUsed: number,
|
||||
* percentCpuLabel: string,
|
||||
@ -75,7 +79,7 @@ export const getAllocatedInfo = (host) => {
|
||||
/**
|
||||
* Returns list of hugepage sizes from the host numa nodes.
|
||||
*
|
||||
* @param {object} host - Host
|
||||
* @param {Host} host - Host
|
||||
* @returns {Array} List of hugepages sizes from resource
|
||||
*/
|
||||
export const getHugepageSizes = (host) => {
|
||||
@ -90,7 +94,7 @@ export const getHugepageSizes = (host) => {
|
||||
/**
|
||||
* Returns list of PCI devices from the host.
|
||||
*
|
||||
* @param {object} host - Host
|
||||
* @param {Host} host - Host
|
||||
* @returns {PciDevice[]} List of PCI devices from resource
|
||||
*/
|
||||
export const getPciDevices = (host) =>
|
||||
@ -99,7 +103,7 @@ export const getPciDevices = (host) =>
|
||||
/**
|
||||
* Returns list of KVM CPU Models available from the host pool.
|
||||
*
|
||||
* @param {object[]} hosts - Hosts
|
||||
* @param {Host[]} hosts - Hosts
|
||||
* @returns {Array} List of KVM CPU Models from the pool
|
||||
*/
|
||||
export const getKvmCpuModels = (hosts = []) =>
|
||||
@ -111,7 +115,7 @@ export const getKvmCpuModels = (hosts = []) =>
|
||||
/**
|
||||
* Returns list of KVM Machines available from the host pool.
|
||||
*
|
||||
* @param {object[]} hosts - Hosts
|
||||
* @param {Host[]} hosts - Hosts
|
||||
* @returns {Array} List of KVM Machines from the pool
|
||||
*/
|
||||
export const getKvmMachines = (hosts = []) => {
|
||||
@ -122,3 +126,81 @@ export const getKvmMachines = (hosts = []) => {
|
||||
|
||||
return [DEFAULT_CPU_MODELS, ...machineTypes]
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of Zombies available from the host.
|
||||
*
|
||||
* @param {Host} host - Host
|
||||
* @returns {object[]} - List of zombies from host
|
||||
*/
|
||||
export const getHostZombies = (host = {}) =>
|
||||
[
|
||||
host?.TEMPLATE?.ZOMBIES?.split(', ')?.map((zombie) => ({
|
||||
ZOMBIE_VM: zombie,
|
||||
})) ?? [],
|
||||
].flat()
|
||||
|
||||
/**
|
||||
* Returns list of Wilds available from the host.
|
||||
*
|
||||
* @param {Host} host - Host
|
||||
* @returns {object[]} - List of wilds from host
|
||||
*/
|
||||
export const getHostWilds = (host = {}) =>
|
||||
[host?.TEMPLATE?.VM ?? []]
|
||||
.flat()
|
||||
.filter((vm) => vm.VCENTER_TEMPLATE === 'YES')
|
||||
/**
|
||||
* Returns list of Numa available from the host.
|
||||
*
|
||||
* @param {Host} host - Host
|
||||
* @returns {NumaNode[]} - List of Numa nodes from host
|
||||
*/
|
||||
export const getHostNuma = (host = {}) =>
|
||||
[host?.HOST_SHARE?.NUMA_NODES?.NODE ?? []].flat()
|
||||
|
||||
/**
|
||||
* Returns the Numa Node memory information.
|
||||
*
|
||||
* @param {NumaNode} numa - Host Numa
|
||||
* @returns {{
|
||||
* percentMemUsed: number,
|
||||
* percentMemLabel: string
|
||||
* }} Numa Node memory information
|
||||
*/
|
||||
export const getNumaMemory = (numa) => {
|
||||
const { TOTAL, USED } = numa?.MEMORY ?? {}
|
||||
|
||||
const percentMemUsed = (+USED * 100) / +TOTAL || 0
|
||||
|
||||
const usedMemBytes = prettyBytes(Math.abs(+USED))
|
||||
const totalMemBytes = prettyBytes(+TOTAL)
|
||||
const percentMemLabel = `${usedMemBytes} / ${totalMemBytes}
|
||||
(${Math.round(isFinite(percentMemUsed) ? percentMemUsed : '--')}%)`
|
||||
|
||||
return {
|
||||
percentMemUsed,
|
||||
percentMemLabel,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of Hypervisors available to the host.
|
||||
*
|
||||
* @param {object} [options] - Options to conversion
|
||||
* @param {boolean} [options.includeCustom] - If `true`, add an Custom hypervisor
|
||||
* @returns {object[]} - List of hypervisors
|
||||
*/
|
||||
export const getHostHypervisors = (options = {}) => {
|
||||
const { includeCustom = false } = options
|
||||
const { data } = useGetOneConfigQuery()
|
||||
const { VM_MAD } = data
|
||||
|
||||
return [VM_MAD ?? [], includeCustom ? CUSTOM_HOST_HYPERVISOR : []]
|
||||
.flat()
|
||||
.filter((hypervisor) => hypervisor.NAME !== HYPERVISORS.vcenter)
|
||||
.map((hypervisor) => ({
|
||||
displayName: hypervisor.SUNSTONE_NAME,
|
||||
driverName: hypervisor.NAME,
|
||||
}))
|
||||
}
|
||||
|
@ -208,6 +208,7 @@ export const OPTION_SORTERS = {
|
||||
numeric: true,
|
||||
ignorePunctuation: true,
|
||||
}),
|
||||
unsort: () => null,
|
||||
}
|
||||
|
||||
const SEMICOLON_CHAR = ';'
|
||||
|
Loading…
x
Reference in New Issue
Block a user