mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-21 14:50:08 +03:00
parent
f90b25aa68
commit
b12b55945a
@ -87,6 +87,10 @@ info-tabs:
|
||||
actions:
|
||||
chown: true
|
||||
chgrp: true
|
||||
capacity_panel:
|
||||
enabled: true
|
||||
actions:
|
||||
resize_capacity: true
|
||||
vcenter_panel:
|
||||
enabled: true
|
||||
actions:
|
||||
@ -113,11 +117,6 @@ info-tabs:
|
||||
edit: true
|
||||
delete: true
|
||||
|
||||
capacity:
|
||||
enabled: true
|
||||
actions:
|
||||
resize_capacity: true
|
||||
|
||||
storage:
|
||||
enabled: true
|
||||
actions:
|
||||
|
@ -88,6 +88,10 @@ info-tabs:
|
||||
actions:
|
||||
chown: false
|
||||
chgrp: false
|
||||
capacity_panel:
|
||||
enabled: true
|
||||
actions:
|
||||
resize_capacity: true
|
||||
vcenter_panel:
|
||||
enabled: true
|
||||
actions:
|
||||
@ -114,11 +118,6 @@ info-tabs:
|
||||
edit: false
|
||||
delete: false
|
||||
|
||||
capacity:
|
||||
enabled: true
|
||||
actions:
|
||||
resize_capacity: true
|
||||
|
||||
storage:
|
||||
enabled: true
|
||||
actions:
|
||||
|
@ -1,71 +0,0 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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, useMemo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { useGetVmQuery, useResizeMutation } from 'client/features/OneApi/vm'
|
||||
import InformationPanel from 'client/components/Tabs/Vm/Capacity/information'
|
||||
|
||||
import { getHypervisor, isAvailableAction } from 'client/models/VirtualMachine'
|
||||
import { getActionsAvailable, jsonToXml } from 'client/models/Helper'
|
||||
|
||||
/**
|
||||
* Renders capacity tab.
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {object} props.tabProps - Tab information
|
||||
* @param {string[]} props.tabProps.actions - Actions tab
|
||||
* @param {string} props.id - Virtual Machine id
|
||||
* @returns {ReactElement} Capacity tab
|
||||
*/
|
||||
const VmCapacityTab = ({ tabProps: { actions } = {}, id }) => {
|
||||
const [resizeCapacity] = useResizeMutation()
|
||||
const { data: vm = {} } = useGetVmQuery({ id })
|
||||
|
||||
const actionsAvailable = useMemo(() => {
|
||||
const hypervisor = getHypervisor(vm)
|
||||
const actionsByHypervisor = getActionsAvailable(actions, hypervisor)
|
||||
const actionsByState = actionsByHypervisor.filter((action) =>
|
||||
isAvailableAction(action, vm)
|
||||
)
|
||||
|
||||
return actionsByState
|
||||
}, [vm])
|
||||
|
||||
const handleResizeCapacity = async (formData) => {
|
||||
const { enforce, ...restOfData } = formData
|
||||
const template = jsonToXml(restOfData)
|
||||
|
||||
await resizeCapacity({ id: vm.ID, enforce, template })
|
||||
}
|
||||
|
||||
return (
|
||||
<InformationPanel
|
||||
actions={actionsAvailable}
|
||||
handleResizeCapacity={handleResizeCapacity}
|
||||
vm={vm}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
VmCapacityTab.propTypes = {
|
||||
tabProps: PropTypes.object,
|
||||
id: PropTypes.string,
|
||||
}
|
||||
|
||||
VmCapacityTab.displayName = 'VmCapacityTab'
|
||||
|
||||
export default VmCapacityTab
|
@ -1,140 +0,0 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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 PropTypes from 'prop-types'
|
||||
import { Typography } from '@mui/material'
|
||||
|
||||
import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
|
||||
import { ResizeCapacityForm } from 'client/components/Forms/Vm'
|
||||
import { Tr, Translate } from 'client/components/HOC'
|
||||
import useCapacityTabStyles from 'client/components/Tabs/Vm/Capacity/styles'
|
||||
|
||||
import { isVCenter } from 'client/models/VirtualMachine'
|
||||
import { formatNumberByCurrency } from 'client/models/Helper'
|
||||
import { prettyBytes } from 'client/utils'
|
||||
import { T, VM_ACTIONS, VM } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Renders capacity information.
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {string[]} props.actions - Actions tab
|
||||
* @param {VM} props.vm - Virtual Machine id
|
||||
* @param {string} props.handleResizeCapacity - Resize capacity
|
||||
* @returns {ReactElement} Capacity information
|
||||
*/
|
||||
const InformationPanel = ({ actions, vm = {}, handleResizeCapacity }) => {
|
||||
const classes = useCapacityTabStyles()
|
||||
const { TEMPLATE } = vm
|
||||
|
||||
const memory = TEMPLATE?.MEMORY
|
||||
const memoryCost = useMemo(() => {
|
||||
const cost = TEMPLATE?.MEMORY_COST || 0
|
||||
const monthCost = formatNumberByCurrency(memory * cost * 24 * 30)
|
||||
|
||||
return <Translate word={T.CostEachMonth} values={[monthCost]} />
|
||||
}, [memory, TEMPLATE?.MEMORY_COST])
|
||||
|
||||
const cpu = TEMPLATE?.CPU
|
||||
const cpuCost = useMemo(() => {
|
||||
const cost = TEMPLATE?.CPU_COST || 0
|
||||
const monthCost = formatNumberByCurrency(cpu * cost * 24 * 30)
|
||||
|
||||
return <Translate word={T.CostEachMonth} values={[monthCost]} />
|
||||
}, [cpu, TEMPLATE?.CPU_COST])
|
||||
|
||||
const capacity = [
|
||||
{
|
||||
name: T.PhysicalCpu,
|
||||
value: cpu,
|
||||
dataCy: 'cpu',
|
||||
},
|
||||
{
|
||||
name: T.VirtualCpu,
|
||||
value: TEMPLATE?.VCPU ?? '-',
|
||||
dataCy: 'virtualcpu',
|
||||
},
|
||||
isVCenter(vm) && {
|
||||
name: T.VirtualCores,
|
||||
value: (
|
||||
<>
|
||||
{`${Tr(T.Cores)} x ${TEMPLATE?.TOPOLOGY?.CORES || '-'} |
|
||||
${Tr(T.Sockets)} ${TEMPLATE?.TOPOLOGY?.SOCKETS || '-'}`}
|
||||
</>
|
||||
),
|
||||
dataCy: 'virtualcores',
|
||||
},
|
||||
{
|
||||
name: T.Memory,
|
||||
value: prettyBytes(+memory, 'MB'),
|
||||
dataCy: 'memory',
|
||||
},
|
||||
{
|
||||
name: T.CostCpu,
|
||||
value: cpuCost,
|
||||
dataCy: 'cpucost',
|
||||
},
|
||||
{
|
||||
name: T.CostMemory,
|
||||
value: memoryCost,
|
||||
dataCy: 'memorycost',
|
||||
},
|
||||
].filter(Boolean)
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<div className={classes.actions}>
|
||||
{actions?.includes?.(VM_ACTIONS.RESIZE_CAPACITY) && (
|
||||
<ButtonToTriggerForm
|
||||
buttonProps={{
|
||||
color: 'secondary',
|
||||
'data-cy': 'resize-capacity',
|
||||
label: T.Resize,
|
||||
variant: 'outlined',
|
||||
}}
|
||||
options={[
|
||||
{
|
||||
dialogProps: { title: T.ResizeCapacity },
|
||||
form: () => ResizeCapacityForm({ initialValues: vm.TEMPLATE }),
|
||||
onSubmit: handleResizeCapacity,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{capacity.map(({ name, value, dataCy }) => (
|
||||
<div key={name} className={classes.item}>
|
||||
<Typography fontWeight="medium" noWrap title={name}>
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography variant="body2" noWrap title={value} data-cy={dataCy}>
|
||||
{value}
|
||||
</Typography>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
InformationPanel.propTypes = {
|
||||
handleResizeCapacity: PropTypes.func,
|
||||
actions: PropTypes.array,
|
||||
vm: PropTypes.object,
|
||||
}
|
||||
|
||||
InformationPanel.displayName = 'InformationPanel'
|
||||
|
||||
export default InformationPanel
|
@ -1,47 +0,0 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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 default makeStyles((theme) => ({
|
||||
root: {
|
||||
padding: '0.5em',
|
||||
display: 'grid',
|
||||
gap: '1em',
|
||||
gridAutoFlow: 'column',
|
||||
[theme.breakpoints.down('md')]: {
|
||||
gridAutoFlow: 'initial',
|
||||
},
|
||||
},
|
||||
item: {
|
||||
[theme.breakpoints.down('md')]: {
|
||||
display: 'flex',
|
||||
gap: '1em',
|
||||
'& > *': {
|
||||
width: '50%',
|
||||
},
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
[theme.breakpoints.down('md')]: {
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
padding: '0 1em 1em 1em',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
order: 1,
|
||||
textAlign: 'end',
|
||||
},
|
||||
},
|
||||
}))
|
169
src/fireedge/src/client/components/Tabs/Vm/Info/capacity.js
Normal file
169
src/fireedge/src/client/components/Tabs/Vm/Info/capacity.js
Normal file
@ -0,0 +1,169 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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, useMemo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Edit as EditIcon } from 'iconoir-react'
|
||||
import { Stack, Typography } from '@mui/material'
|
||||
|
||||
import { useResizeMutation } from 'client/features/OneApi/vm'
|
||||
import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
|
||||
import { ResizeCapacityForm } from 'client/components/Forms/Vm'
|
||||
import { List } from 'client/components/Tabs/Common'
|
||||
import { Tr, Translate } from 'client/components/HOC'
|
||||
|
||||
import { isVCenter, isAvailableAction } from 'client/models/VirtualMachine'
|
||||
import { formatNumberByCurrency, jsonToXml } from 'client/models/Helper'
|
||||
import { prettyBytes } from 'client/utils'
|
||||
import { T, VM, VM_ACTIONS } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Renders mainly capacity tab.
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {VM} props.vm - Virtual machine
|
||||
* @param {string[]} props.actions - Available actions to capacity tab
|
||||
* @returns {ReactElement} Capacity tab
|
||||
*/
|
||||
const CapacityPanel = ({ vm = {}, actions }) => {
|
||||
const {
|
||||
CPU,
|
||||
VCPU = '-',
|
||||
MEMORY,
|
||||
CPU_COST,
|
||||
MEMORY_COST,
|
||||
TOPOLOGY: { CORES = '-', SOCKETS = '-' } = {},
|
||||
} = vm?.TEMPLATE || {}
|
||||
|
||||
const memoryCost = useMemo(() => {
|
||||
const cost = MEMORY_COST || 0
|
||||
const monthCost = formatNumberByCurrency(MEMORY * cost * 24 * 30)
|
||||
|
||||
return <Translate word={T.CostEachMonth} values={[monthCost]} />
|
||||
}, [MEMORY, MEMORY_COST])
|
||||
|
||||
const cpuCost = useMemo(() => {
|
||||
const cost = CPU_COST || 0
|
||||
const monthCost = formatNumberByCurrency(CPU * cost * 24 * 30)
|
||||
|
||||
return <Translate word={T.CostEachMonth} values={[monthCost]} />
|
||||
}, [CPU, CPU_COST])
|
||||
|
||||
const info = [
|
||||
{
|
||||
name: T.PhysicalCpu,
|
||||
value: CPU,
|
||||
dataCy: 'cpu',
|
||||
},
|
||||
{
|
||||
name: T.VirtualCpu,
|
||||
value: VCPU,
|
||||
dataCy: 'vcpu',
|
||||
},
|
||||
isVCenter(vm) && {
|
||||
name: T.VirtualCores,
|
||||
value: [
|
||||
`${Tr(T.Cores)} x ${CORES}`,
|
||||
`${Tr(T.Sockets)} x ${SOCKETS}`,
|
||||
].join(' | '),
|
||||
dataCy: 'virtualcores',
|
||||
},
|
||||
{
|
||||
name: T.Memory,
|
||||
value: prettyBytes(+MEMORY, 'MB'),
|
||||
dataCy: 'memory',
|
||||
},
|
||||
{
|
||||
name: T.CostCpu,
|
||||
value: cpuCost,
|
||||
dataCy: 'cpucost',
|
||||
},
|
||||
{
|
||||
name: T.CostMemory,
|
||||
value: memoryCost,
|
||||
dataCy: 'memorycost',
|
||||
},
|
||||
].filter(Boolean)
|
||||
|
||||
return <List title={<PanelHeader vm={vm} actions={actions} />} list={info} />
|
||||
}
|
||||
|
||||
CapacityPanel.propTypes = {
|
||||
actions: PropTypes.arrayOf(PropTypes.string),
|
||||
vm: PropTypes.object,
|
||||
}
|
||||
|
||||
CapacityPanel.displayName = 'CapacityPanel'
|
||||
|
||||
/**
|
||||
* Renders header of capacity panel.
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {VM} props.vm - Virtual machine
|
||||
* @param {string[]} props.actions - Available actions to capacity tab
|
||||
* @returns {ReactElement} Capacity panel header
|
||||
*/
|
||||
const PanelHeader = ({ vm = {}, actions = [] }) => {
|
||||
const [resizeCapacity] = useResizeMutation()
|
||||
|
||||
const handleResizeCapacity = async (formData) => {
|
||||
const { enforce, ...restOfData } = formData
|
||||
const template = jsonToXml(restOfData)
|
||||
|
||||
await resizeCapacity({ id: vm.ID, enforce, template })
|
||||
}
|
||||
|
||||
const resizeIsAvailable = useMemo(
|
||||
() =>
|
||||
actions
|
||||
.filter((action) => isAvailableAction(action, vm))
|
||||
.includes?.(VM_ACTIONS.RESIZE_CAPACITY),
|
||||
[vm]
|
||||
)
|
||||
|
||||
return (
|
||||
<Stack
|
||||
width={1}
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Typography noWrap>
|
||||
<Translate word={T.Capacity} />
|
||||
</Typography>
|
||||
{resizeIsAvailable && (
|
||||
<ButtonToTriggerForm
|
||||
buttonProps={{
|
||||
'data-cy': 'resize-capacity',
|
||||
icon: <EditIcon />,
|
||||
tooltip: <Translate word={T.Resize} />,
|
||||
}}
|
||||
options={[
|
||||
{
|
||||
dialogProps: { title: T.ResizeCapacity },
|
||||
form: () => ResizeCapacityForm({ initialValues: vm.TEMPLATE }),
|
||||
onSubmit: handleResizeCapacity,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
PanelHeader.propTypes = { ...CapacityPanel.propTypes }
|
||||
PanelHeader.displayName = 'PanelHeader'
|
||||
|
||||
export default CapacityPanel
|
@ -30,6 +30,7 @@ import {
|
||||
AttributePanel,
|
||||
} from 'client/components/Tabs/Common'
|
||||
import Information from 'client/components/Tabs/Vm/Info/information'
|
||||
import Capacity from 'client/components/Tabs/Vm/Info/capacity'
|
||||
import { SubmitButton } from 'client/components/FormControl'
|
||||
|
||||
import { Tr, Translate } from 'client/components/HOC'
|
||||
@ -60,6 +61,7 @@ const HIDDEN_MONITORING_REG =
|
||||
const VmInfoTab = ({ tabProps = {}, id }) => {
|
||||
const {
|
||||
information_panel: informationPanel,
|
||||
capacity_panel: capacityPanel,
|
||||
permissions_panel: permissionsPanel,
|
||||
ownership_panel: ownershipPanel,
|
||||
vcenter_panel: vcenterPanel,
|
||||
@ -180,6 +182,9 @@ const VmInfoTab = ({ tabProps = {}, id }) => {
|
||||
groupName={GNAME}
|
||||
/>
|
||||
)}
|
||||
{capacityPanel?.enabled && (
|
||||
<Capacity actions={getActions(capacityPanel?.actions)} vm={vm} />
|
||||
)}
|
||||
{attributesPanel?.enabled && attributes && (
|
||||
<AttributePanel
|
||||
{...ATTRIBUTE_FUNCTION}
|
||||
|
@ -23,7 +23,6 @@ import { getAvailableInfoTabs } from 'client/models/Helper'
|
||||
import { RESOURCE_NAMES } from 'client/constants'
|
||||
|
||||
import Tabs from 'client/components/Tabs'
|
||||
import Capacity from 'client/components/Tabs/Vm/Capacity'
|
||||
import Configuration from 'client/components/Tabs/Vm/Configuration'
|
||||
import Info from 'client/components/Tabs/Vm/Info'
|
||||
import Network from 'client/components/Tabs/Vm/Network'
|
||||
@ -34,7 +33,6 @@ import Storage from 'client/components/Tabs/Vm/Storage'
|
||||
|
||||
const getTabComponent = (tabName) =>
|
||||
({
|
||||
capacity: Capacity,
|
||||
configuration: Configuration,
|
||||
info: Info,
|
||||
network: Network,
|
||||
|
Loading…
x
Reference in New Issue
Block a user