From cb181ea4135f7b9e73d00de9664bc7134ad7693c Mon Sep 17 00:00:00 2001 From: Sergio Betanzos Date: Wed, 7 Jul 2021 18:16:05 +0200 Subject: [PATCH] F OpenNebula/one#5422: Add styles to some vm tabs --- .../components/Cards/SelectCard/Action.js | 2 +- .../src/client/components/Tables/Vms/row.js | 15 +- .../src/client/components/Tables/styles.js | 20 ++- .../src/client/components/Tabs/Common/List.js | 33 +++-- .../components/Tabs/Common/Permissions.js | 11 +- .../src/client/components/Tabs/Vm/Capacity.js | 96 +++++++++++++ .../Vm/{configuration.js => Configuration.js} | 0 .../client/components/Tabs/Vm/Info/index.js | 36 +++++ .../Tabs/Vm/{info.js => Info/information.js} | 43 +++--- .../components/Tabs/Vm/{log.js => Log.js} | 0 .../client/components/Tabs/Vm/Network/Item.js | 72 ++++++++++ .../client/components/Tabs/Vm/Network/List.js | 26 ++++ .../components/Tabs/Vm/Network/Network.js | 34 +++++ .../components/Tabs/Vm/Network/index.js | 30 ++++ .../Tabs/Vm/{placement.js => Placement.js} | 0 .../Vm/{schedActions.js => SchedActions.js} | 0 .../Tabs/Vm/{snapshot.js => Snapshot.js} | 0 .../client/components/Tabs/Vm/Storage/Item.js | 134 ++++++++++++++++++ .../client/components/Tabs/Vm/Storage/List.js | 30 ++++ .../components/Tabs/Vm/Storage/index.js | 30 ++++ .../src/client/components/Tabs/Vm/capacity.js | 30 ---- .../src/client/components/Tabs/Vm/index.js | 42 +++--- .../src/client/components/Tabs/Vm/network.js | 33 ----- .../src/client/components/Tabs/Vm/storage.js | 55 ------- src/fireedge/src/client/constants/vm.js | 75 ++++++++++ src/fireedge/src/client/models/Helper.js | 16 +++ .../src/client/models/VirtualMachine.js | 46 ++++-- 27 files changed, 704 insertions(+), 205 deletions(-) create mode 100644 src/fireedge/src/client/components/Tabs/Vm/Capacity.js rename src/fireedge/src/client/components/Tabs/Vm/{configuration.js => Configuration.js} (100%) create mode 100644 src/fireedge/src/client/components/Tabs/Vm/Info/index.js rename src/fireedge/src/client/components/Tabs/Vm/{info.js => Info/information.js} (57%) rename src/fireedge/src/client/components/Tabs/Vm/{log.js => Log.js} (100%) create mode 100644 src/fireedge/src/client/components/Tabs/Vm/Network/Item.js create mode 100644 src/fireedge/src/client/components/Tabs/Vm/Network/List.js create mode 100644 src/fireedge/src/client/components/Tabs/Vm/Network/Network.js create mode 100644 src/fireedge/src/client/components/Tabs/Vm/Network/index.js rename src/fireedge/src/client/components/Tabs/Vm/{placement.js => Placement.js} (100%) rename src/fireedge/src/client/components/Tabs/Vm/{schedActions.js => SchedActions.js} (100%) rename src/fireedge/src/client/components/Tabs/Vm/{snapshot.js => Snapshot.js} (100%) create mode 100644 src/fireedge/src/client/components/Tabs/Vm/Storage/Item.js create mode 100644 src/fireedge/src/client/components/Tabs/Vm/Storage/List.js create mode 100644 src/fireedge/src/client/components/Tabs/Vm/Storage/index.js delete mode 100644 src/fireedge/src/client/components/Tabs/Vm/capacity.js delete mode 100644 src/fireedge/src/client/components/Tabs/Vm/network.js delete mode 100644 src/fireedge/src/client/components/Tabs/Vm/storage.js diff --git a/src/fireedge/src/client/components/Cards/SelectCard/Action.js b/src/fireedge/src/client/components/Cards/SelectCard/Action.js index a20af313ab..8ecc0a10ff 100644 --- a/src/fireedge/src/client/components/Cards/SelectCard/Action.js +++ b/src/fireedge/src/client/components/Cards/SelectCard/Action.js @@ -12,7 +12,7 @@ const Action = memo(({ handleClick, icon, cy, ...props }) => { return ( { -
- {!!IPS?.length && ( -
+ {!!IPS?.length && ( +
+
- )} -
+
+ )}
) } diff --git a/src/fireedge/src/client/components/Tables/styles.js b/src/fireedge/src/client/components/Tables/styles.js index 2f9658ab38..e0da525128 100644 --- a/src/fireedge/src/client/components/Tables/styles.js +++ b/src/fireedge/src/client/components/Tables/styles.js @@ -1,7 +1,21 @@ import { makeStyles } from '@material-ui/core' export const rowStyles = makeStyles( - ({ palette, typography, breakpoints }) => ({ + ({ palette, typography, breakpoints, shadows }) => ({ + root: { + padding: '0.8em', + color: palette.text.primary, + backgroundColor: palette.background.paper, + fontWeight: typography.fontWeightMedium, + fontSize: '1em', + borderRadius: 6, + display: 'flex', + gap: 8, + boxShadow: shadows[1], + [breakpoints.down('md')]: { + flexWrap: 'wrap' + } + }, main: { flex: 'auto', overflow: 'hidden' @@ -38,6 +52,10 @@ export const rowStyles = makeStyles( flexShrink: 0, whiteSpace: 'nowrap' } + }, + actions: { + flexShrink: 0 } }) + ) diff --git a/src/fireedge/src/client/components/Tabs/Common/List.js b/src/fireedge/src/client/components/Tabs/Common/List.js index b4faa88d3d..8c4de433ef 100644 --- a/src/fireedge/src/client/components/Tabs/Common/List.js +++ b/src/fireedge/src/client/components/Tabs/Common/List.js @@ -6,15 +6,17 @@ import { makeStyles, List as MList, ListItem, Typography, Paper } from '@materia import { Tr } from 'client/components/HOC' const useStyles = makeStyles(theme => ({ - list: { - ...theme.typography.body2, - '& > * > *': { - width: '50%' - } - }, title: { fontWeight: theme.typography.fontWeightBold, borderBottom: `1px solid ${theme.palette.divider}` + }, + item: { + '& > $typo': { + width: '50%' + } + }, + typo: { + ...theme.typography.body2 } })) @@ -32,9 +34,17 @@ const List = ({ title, list = [], ...props }) => { )} {/* LIST */} {list.map(({ key, value }, idx) => ( - - {Tr(key)} - {value} + + + {Tr(key)} + + + {value} + ))} @@ -46,10 +56,7 @@ List.propTypes = { title: PropTypes.string, list: PropTypes.arrayOf(PropTypes.shape({ key: PropTypes.string, - value: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.node - ]) + value: PropTypes.any })) } diff --git a/src/fireedge/src/client/components/Tabs/Common/Permissions.js b/src/fireedge/src/client/components/Tabs/Common/Permissions.js index 5d7fdf66da..b7b708770b 100644 --- a/src/fireedge/src/client/components/Tabs/Common/Permissions.js +++ b/src/fireedge/src/client/components/Tabs/Common/Permissions.js @@ -19,7 +19,6 @@ const CATEGORIES = [ const useStyles = makeStyles(theme => ({ list: { - ...theme.typography.body2, '& > * > *': { width: '25%' } @@ -69,9 +68,11 @@ const Permissions = React.memo(({ {Tr(T.Admin)} {CATEGORIES.map(({ title, category }) => ( - + {/* TITLE */} - {Tr(title)} + + {Tr(title)} + {/* PERMISSIONS */} {Object.entries(permissions) @@ -81,7 +82,9 @@ const Permissions = React.memo(({ : } + icon={ + +permission ? : + } handleClick={() => handleChange(key, permission)} /> diff --git a/src/fireedge/src/client/components/Tabs/Vm/Capacity.js b/src/fireedge/src/client/components/Tabs/Vm/Capacity.js new file mode 100644 index 0000000000..226dfd08be --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Capacity.js @@ -0,0 +1,96 @@ +import * as React from 'react' +import { makeStyles, Paper, Typography } from '@material-ui/core' + +import { Action } from 'client/components/Cards/SelectCard' +import * as VirtualMachine from 'client/models/VirtualMachine' +import { prettyBytes } from 'client/utils' + +const useStyles = makeStyles(theme => ({ + root: { + padding: '1em' + }, + grid: { + padding: '1em', + display: 'grid', + gap: '1em', + gridAutoFlow: 'column', + [theme.breakpoints.down('sm')]: { + gridAutoFlow: 'initial' + } + }, + item: { + [theme.breakpoints.down('sm')]: { + display: 'flex', + gap: '1em', + '& > *': { + width: '50%' + } + } + }, + actions: { + [theme.breakpoints.down('sm')]: { + borderBottom: `1px solid ${theme.palette.divider}`, + padding: '1em' + }, + [theme.breakpoints.up('md')]: { + order: 1, + textAlign: 'end' + } + }, + title: { + fontWeight: theme.typography.fontWeightBold + } +})) + +const VmCapacityTab = data => { + const classes = useStyles() + + const { TEMPLATE } = data + + const isVCenter = VirtualMachine.isVCenter(data) + + const capacity = [ + { key: 'Physical CPU', value: TEMPLATE?.CPU }, + { key: 'Virtual CPU', value: TEMPLATE?.VCPU ?? '-' }, + (isVCenter && { + key: 'Virtual Cores', + value: ` + Cores x ${TEMPLATE?.TOPOLOGY?.CORES || '-'} | + Sockets ${TEMPLATE?.TOPOLOGY?.SOCKETS || '-'}` + }), + { key: 'Memory', value: prettyBytes(+TEMPLATE?.MEMORY, 'MB') }, + { key: 'Cost / CPU', value: TEMPLATE?.CPU_COST || 0 }, + { key: 'Cost / MByte', value: TEMPLATE?.MEMORY_COST || 0 } + ].filter(Boolean) + + return ( +
+ +
+ undefined} + /> +
+ {capacity.map(({ key, value }) => ( +
+ + {key} + + + {value} + +
+ ))} +
+
+ ) +} + +VmCapacityTab.displayName = 'VmCapacityTab' + +export default VmCapacityTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/configuration.js b/src/fireedge/src/client/components/Tabs/Vm/Configuration.js similarity index 100% rename from src/fireedge/src/client/components/Tabs/Vm/configuration.js rename to src/fireedge/src/client/components/Tabs/Vm/Configuration.js diff --git a/src/fireedge/src/client/components/Tabs/Vm/Info/index.js b/src/fireedge/src/client/components/Tabs/Vm/Info/index.js new file mode 100644 index 0000000000..65ccadc67c --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Info/index.js @@ -0,0 +1,36 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import { Permissions, Ownership } from 'client/components/Tabs/Common' +import Information from 'client/components/Tabs/Vm/Info/information' + +const VmInfoTab = ({ tabProps, ...data }) => { + const { ID, UNAME, GNAME, PERMISSIONS } = data + + return ( +
+ {tabProps?.information_panel?.enabled && + + } + {tabProps?.permissions_panel?.enabled && + + } + {tabProps?.ownership_panel?.enabled && + + } +
+ ) +} + +VmInfoTab.propTypes = { + tabProps: PropTypes.object +} + +VmInfoTab.displayName = 'VmInfoTab' + +export default VmInfoTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/info.js b/src/fireedge/src/client/components/Tabs/Vm/Info/information.js similarity index 57% rename from src/fireedge/src/client/components/Tabs/Vm/info.js rename to src/fireedge/src/client/components/Tabs/Vm/Info/information.js index 7583340100..de1e53ce7e 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/info.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Info/information.js @@ -1,15 +1,15 @@ import * as React from 'react' import { StatusChip } from 'client/components/Status' -import { List, Permissions, Ownership } from 'client/components/Tabs/Common' +import { List } from 'client/components/Tabs/Common' import Multiple from 'client/components/Tables/Vms/multiple' import * as VirtualMachine from 'client/models/VirtualMachine' import * as Helper from 'client/models/Helper' import { T } from 'client/constants' -const VmInfoTab = data => { - const { ID, NAME, UNAME, GNAME, RESCHED, STIME, ETIME, LOCK, DEPLOY_ID, PERMISSIONS } = data +const InformationPanel = data => { + const { ID, NAME, RESCHED, STIME, ETIME, LOCK, DEPLOY_ID } = data const { name: stateName, color: stateColor } = VirtualMachine.getState(data) @@ -19,60 +19,51 @@ const VmInfoTab = data => { const ips = VirtualMachine.getIps(data) const info = [ - { key: [T.ID], value: ID }, - { key: [T.Name], value: NAME }, + { key: T.ID, value: ID }, + { key: T.Name, value: NAME }, { - key: [T.State], + key: T.State, value: }, { - key: [T.Reschedule], + key: T.Reschedule, value: Helper.booleanToString(+RESCHED) }, { - key: [T.Locked], + key: T.Locked, value: Helper.levelLockToString(LOCK?.LOCKED) }, { - key: [T.IP], + key: T.IP, value: ips?.length ? : '--' }, { - key: [T.StartTime], + key: T.StartTime, value: Helper.timeToString(STIME) }, { - key: [T.EndTime], + key: T.EndTime, value: Helper.timeToString(ETIME) }, { - key: [T.Host], + key: T.Host, value: hostId ? `#${hostId} ${hostname}` : '' }, { - key: [T.Cluster], + key: T.Cluster, value: clusterId ? `#${clusterId} ${clusterName}` : '' }, { - key: [T.DeployID], + key: T.DeployID, value: DEPLOY_ID } ] return ( -
- - - -
+ ) } -VmInfoTab.displayName = 'VmInfoTab' +InformationPanel.displayName = 'InformationPanel' -export default VmInfoTab +export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/Vm/log.js b/src/fireedge/src/client/components/Tabs/Vm/Log.js similarity index 100% rename from src/fireedge/src/client/components/Tabs/Vm/log.js rename to src/fireedge/src/client/components/Tabs/Vm/Log.js diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/Item.js b/src/fireedge/src/client/components/Tabs/Vm/Network/Item.js new file mode 100644 index 0000000000..1b73f96c11 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Network/Item.js @@ -0,0 +1,72 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import { Trash } from 'iconoir-react' +import { Typography } from '@material-ui/core' + +// import { useVmApi } from 'client/features/One' +import { Action } from 'client/components/Cards/SelectCard' +import { StatusChip } from 'client/components/Status' +import { rowStyles } from 'client/components/Tables/styles' + +import { VM_ACTIONS } from 'client/constants' + +const NetworkItem = ({ nic = {}, actions }) => { + const classes = rowStyles() + + const { + NIC_ID, + NETWORK = '-', + BRIDGE, + IP, + MAC, + PCI_ID, + ALIAS + } = nic + + const detachAction = () => actions.includes(VM_ACTIONS.DETACH_NIC) && ( + } + handleClick={() => undefined} + /> + ) + + const renderLabels = labels => labels + ?.filter(Boolean) + ?.map(label => ( + + )) + + return ( +
+
+
+ + {`${NIC_ID} | ${NETWORK}`} + {renderLabels([IP, MAC, BRIDGE && `BRIDGE - ${BRIDGE}`, PCI_ID])} + {detachAction()} + +
+
+ {ALIAS?.map(({ NIC_ID, NETWORK = '-', BRIDGE, IP, MAC }) => ( + + {`${NIC_ID} | ${NETWORK}`} + {renderLabels([IP, MAC, BRIDGE && `BRIDGE - ${BRIDGE}`])} + {detachAction()} + + ))} +
+
+
+ ) +} + +NetworkItem.propTypes = { + nic: PropTypes.object, + actions: PropTypes.arrayOf(PropTypes.string) +} + +NetworkItem.displayName = 'NetworkItem' + +export default NetworkItem diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/List.js b/src/fireedge/src/client/components/Tabs/Vm/Network/List.js new file mode 100644 index 0000000000..67a99cf70a --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Network/List.js @@ -0,0 +1,26 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import NetworkItem from 'client/components/Tabs/Vm/Network/Item' + +const NetworkList = ({ nics, actions }) => ( +
+ {nics.map((nic, idx) => ( + + ))} +
+) + +NetworkList.propTypes = { + nics: PropTypes.array, + actions: PropTypes.object +} + +NetworkList.displayName = 'NetworkList' + +export default NetworkList diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/Network.js b/src/fireedge/src/client/components/Tabs/Vm/Network/Network.js new file mode 100644 index 0000000000..32137d6e0a --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Network/Network.js @@ -0,0 +1,34 @@ +import * as React from 'react' + +import * as VirtualMachine from 'client/models/VirtualMachine' + +const VmNetworkTab = data => { + const nics = VirtualMachine.getNics(data, true) + // const { nics, alias } = VirtualMachine.splitNicAlias(data) + + console.log(nics) + + return ( +
+
+

VM NICS

+ {nics.map(({ NIC_ID, NETWORK = '-', BRIDGE = '-', IP = '-', MAC = '-', PCI_ID = '', ALIAS }) => ( +
+

+ {`${NIC_ID} | ${NETWORK} | ${BRIDGE} | ${IP} | ${MAC} | ${PCI_ID}`} +

+ {ALIAS?.map(({ NIC_ID, NETWORK = '-', BRIDGE = '-', IP = '-', MAC = '-' }) => ( +

+ {`${NIC_ID} | ${NETWORK} | ${BRIDGE} | ${IP} | ${MAC}`} +

+ ))} +
+ ))} +
+
+ ) +} + +VmNetworkTab.displayName = 'VmNetworkTab' + +export default VmNetworkTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/index.js b/src/fireedge/src/client/components/Tabs/Vm/Network/index.js new file mode 100644 index 0000000000..08f7cc770d --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Network/index.js @@ -0,0 +1,30 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import NetworkList from 'client/components/Tabs/Vm/Network/List' + +import * as VirtualMachine from 'client/models/VirtualMachine' +import * as Helper from 'client/models/Helper' + +const VmNetworkTab = ({ tabProps, ...data }) => { + const { actions = [] } = tabProps + + const nics = VirtualMachine.getNics(data, { groupAlias: true }) + const hypervisor = VirtualMachine.getHypervisor(data) + const actionsAvailable = Helper.getActionsAvailable(actions, hypervisor) + + return ( + + ) +} + +VmNetworkTab.propTypes = { + tabProps: PropTypes.shape({ + actions: PropTypes.object + }), + actions: PropTypes.array +} + +VmNetworkTab.displayName = 'VmNetworkTab' + +export default VmNetworkTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/placement.js b/src/fireedge/src/client/components/Tabs/Vm/Placement.js similarity index 100% rename from src/fireedge/src/client/components/Tabs/Vm/placement.js rename to src/fireedge/src/client/components/Tabs/Vm/Placement.js diff --git a/src/fireedge/src/client/components/Tabs/Vm/schedActions.js b/src/fireedge/src/client/components/Tabs/Vm/SchedActions.js similarity index 100% rename from src/fireedge/src/client/components/Tabs/Vm/schedActions.js rename to src/fireedge/src/client/components/Tabs/Vm/SchedActions.js diff --git a/src/fireedge/src/client/components/Tabs/Vm/snapshot.js b/src/fireedge/src/client/components/Tabs/Vm/Snapshot.js similarity index 100% rename from src/fireedge/src/client/components/Tabs/Vm/snapshot.js rename to src/fireedge/src/client/components/Tabs/Vm/Snapshot.js diff --git a/src/fireedge/src/client/components/Tabs/Vm/Storage/Item.js b/src/fireedge/src/client/components/Tabs/Vm/Storage/Item.js new file mode 100644 index 0000000000..eb1fa1b335 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Storage/Item.js @@ -0,0 +1,134 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import { + DatabaseSettings, Folder, ModernTv, + Trash, SaveActionFloppy, Camera, Expand +} from 'iconoir-react' +import { Typography } from '@material-ui/core' + +// import { useVmApi } from 'client/features/One' +import { Action } from 'client/components/Cards/SelectCard' +import { StatusChip } from 'client/components/Status' +import { rowStyles } from 'client/components/Tables/styles' + +import * as Helper from 'client/models/Helper' +import { prettyBytes } from 'client/utils' +import { VM_ACTIONS } from 'client/constants' + +const StorageItem = ({ disk, actions = [] }) => { + const classes = rowStyles() + + const { + DISK_ID, + DATASTORE, + TARGET, + IMAGE, + TYPE, + FORMAT, + SIZE, + MONITOR_SIZE, + READONLY, + PERSISTENT, + SAVE, + CLONE, + IS_CONTEXT + } = disk + + const size = +SIZE ? prettyBytes(+SIZE, 'MB') : '-' + const monitorSize = +MONITOR_SIZE ? prettyBytes(+MONITOR_SIZE, 'MB') : '-' + + const type = String(TYPE).toLowerCase() + + const image = IMAGE ?? ({ + fs: `${FORMAT} - ${size}`, + swap: size + }[type]) + + const labels = [...new Set([ + TYPE, + Helper.stringToBoolean(PERSISTENT) && 'PERSISTENT', + Helper.stringToBoolean(READONLY) && 'READONLY', + Helper.stringToBoolean(SAVE) && 'SAVE', + Helper.stringToBoolean(CLONE) && 'CLONE' + ])].filter(Boolean) + + return ( +
+
+
+ + {image} + + + {labels.map(label => ( + + ))} + +
+
+ + {`#${DISK_ID}`} + + {TARGET && ( + + + {` ${TARGET}`} + + )} + {DATASTORE && ( + + + {` ${DATASTORE}`} + + )} + + + {` ${monitorSize}/${size}`} + +
+
+ {!IS_CONTEXT && !!actions.length && ( +
+ {actions.includes(VM_ACTIONS.DISK_SAVEAS) && ( + } + handleClick={() => undefined} + /> + )} + {actions.includes(VM_ACTIONS.SNAPSHOT_DISK_CREATE) && ( + } + handleClick={() => undefined} + /> + )} + {actions.includes(VM_ACTIONS.RESIZE_DISK) && ( + } + handleClick={() => undefined} + /> + )} + {actions.includes(VM_ACTIONS.DETACH_DISK) && ( + } + handleClick={() => undefined} + /> + )} +
+ )} +
+ ) +} + +StorageItem.propTypes = { + disk: PropTypes.object.isRequired, + actions: PropTypes.arrayOf(PropTypes.string) +} + +StorageItem.displayName = 'StorageItem' + +export default StorageItem diff --git a/src/fireedge/src/client/components/Tabs/Vm/Storage/List.js b/src/fireedge/src/client/components/Tabs/Vm/Storage/List.js new file mode 100644 index 0000000000..dada2af73c --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Storage/List.js @@ -0,0 +1,30 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import StorageItem from 'client/components/Tabs/Vm/Storage/Item' + +const StorageList = ({ disks, actions }) => ( +
+ {disks.map((disk, idx) => ( + + ))} +
+) + +StorageList.propTypes = { + disks: PropTypes.array, + actions: PropTypes.object +} + +StorageList.displayName = 'StorageList' + +export default StorageList diff --git a/src/fireedge/src/client/components/Tabs/Vm/Storage/index.js b/src/fireedge/src/client/components/Tabs/Vm/Storage/index.js new file mode 100644 index 0000000000..af4de694ac --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Storage/index.js @@ -0,0 +1,30 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import StorageList from 'client/components/Tabs/Vm/Storage/List' + +import * as VirtualMachine from 'client/models/VirtualMachine' +import * as Helper from 'client/models/Helper' + +const VmStorageTab = ({ tabProps, ...data }) => { + const { actions = [] } = tabProps + + const disks = VirtualMachine.getDisks(data) + const hypervisor = VirtualMachine.getHypervisor(data) + const actionsAvailable = Helper.getActionsAvailable(actions, hypervisor) + + return ( + + ) +} + +VmStorageTab.propTypes = { + tabProps: PropTypes.shape({ + actions: PropTypes.object + }), + actions: PropTypes.array +} + +VmStorageTab.displayName = 'VmStorageTab' + +export default VmStorageTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/capacity.js b/src/fireedge/src/client/components/Tabs/Vm/capacity.js deleted file mode 100644 index 218d31c0a7..0000000000 --- a/src/fireedge/src/client/components/Tabs/Vm/capacity.js +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from 'react' - -import * as VirtualMachine from 'client/models/VirtualMachine' -import { prettyBytes } from 'client/utils' - -const VmCapacityTab = data => { - const { TEMPLATE } = data - - const isVCenter = VirtualMachine.isVCenter(data) - - return ( -
-

Physical CPU: {TEMPLATE?.CPU}

-

Virtual CPU: {TEMPLATE?.VCPU ?? '-'}

- {isVCenter && ( -

Virtual Cores: {` - Cores x ${TEMPLATE?.TOPOLOGY?.CORES || '-'} | - Sockets ${TEMPLATE?.TOPOLOGY?.SOCKETS || '-'} - `}

- )} -

Memory: {prettyBytes(+TEMPLATE?.MEMORY, 'MB')}

-

Cost / CPU: {TEMPLATE?.CPU_COST}

-

Cost / MByte: {TEMPLATE?.MEMORY_COST}

-
- ) -} - -VmCapacityTab.displayName = 'VmCapacityTab' - -export default VmCapacityTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/index.js b/src/fireedge/src/client/components/Tabs/Vm/index.js index 7d0cff94fe..c4a4ca1381 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/index.js +++ b/src/fireedge/src/client/components/Tabs/Vm/index.js @@ -1,21 +1,20 @@ import * as React from 'react' import PropTypes from 'prop-types' -import loadable from '@loadable/component' import { useAuth } from 'client/features/Auth' import Tabs from 'client/components/Tabs' import { stringToCamelCase, stringToCamelSpace } from 'client/utils' -const Capacity = loadable(() => import('client/components/Tabs/Vm/capacity')) -const Configuration = loadable(() => import('client/components/Tabs/Vm/configuration')) -const Info = loadable(() => import('client/components/Tabs/Vm/info')) -const Log = loadable(() => import('client/components/Tabs/Vm/log')) -const Network = loadable(() => import('client/components/Tabs/Vm/network')) -const Placement = loadable(() => import('client/components/Tabs/Vm/placement')) -const SchedActions = loadable(() => import('client/components/Tabs/Vm/schedActions')) -const Snapshot = loadable(() => import('client/components/Tabs/Vm/snapshot')) -const Storage = loadable(() => import('client/components/Tabs/Vm/storage')) +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 Log from 'client/components/Tabs/Vm/Log' +import Network from 'client/components/Tabs/Vm/Network' +import Placement from 'client/components/Tabs/Vm/Placement' +import SchedActions from 'client/components/Tabs/Vm/SchedActions' +import Snapshot from 'client/components/Tabs/Vm/Snapshot' +import Storage from 'client/components/Tabs/Vm/Storage' const loadTab = tabName => ({ capacity: Capacity, @@ -36,19 +35,18 @@ const VmTabs = ({ data }) => { React.useEffect(() => { const infoTabs = getResourceView('VM')?.['info-tabs'] ?? {} - const tabs = Object.entries(infoTabs) - ?.map(([tabName, { enabled } = {}]) => !!enabled && tabName) - ?.filter(Boolean) + setTabs(() => Object.entries(infoTabs) + ?.filter(([_, { enabled } = {}]) => !!enabled) + ?.map(([tabName, tabProps]) => { + const nameSanitize = stringToCamelCase(tabName) + const TabContent = loadTab(nameSanitize) - setTabs(() => tabs.map(tabName => { - const nameSanitize = stringToCamelCase(tabName) - const TabContent = loadTab(nameSanitize) - - return TabContent && { - name: stringToCamelSpace(nameSanitize), - renderContent: props => TabContent.render({ ...props }) - } - }).filter(Boolean)) + return TabContent && { + name: stringToCamelSpace(nameSanitize), + renderContent: props => TabContent({ ...props, tabProps }) + } + }) + ?.filter(Boolean)) }, [view]) return diff --git a/src/fireedge/src/client/components/Tabs/Vm/network.js b/src/fireedge/src/client/components/Tabs/Vm/network.js deleted file mode 100644 index 1b77cb1fa5..0000000000 --- a/src/fireedge/src/client/components/Tabs/Vm/network.js +++ /dev/null @@ -1,33 +0,0 @@ -import * as React from 'react' - -import * as VirtualMachine from 'client/models/VirtualMachine' - -const VmNetworkTab = data => { - const { nics, alias } = VirtualMachine.splitNicAlias(data) - - return ( -
-
-

VM NICS

- {nics.map(({ NIC_ID, NETWORK = '-', BRIDGE = '-', IP = '-', MAC = '-', PCI_ID = '' }) => ( -

- {`${NIC_ID} | ${NETWORK} | ${BRIDGE} | ${IP} | ${MAC} | ${PCI_ID}`} -

- ))} -
-
-
-

VM ALIAS

- {alias.map(({ NIC_ID, NETWORK = '-', BRIDGE = '-', IP = '-', MAC = '-' }) => ( -

- {`${NIC_ID} | ${NETWORK} | ${BRIDGE} | ${IP} | ${MAC}`} -

- ))} -
-
- ) -} - -VmNetworkTab.displayName = 'VmNetworkTab' - -export default VmNetworkTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/storage.js b/src/fireedge/src/client/components/Tabs/Vm/storage.js deleted file mode 100644 index 61eb84a91a..0000000000 --- a/src/fireedge/src/client/components/Tabs/Vm/storage.js +++ /dev/null @@ -1,55 +0,0 @@ -import * as React from 'react' - -import * as VirtualMachine from 'client/models/VirtualMachine' -import { prettyBytes } from 'client/utils' - -const VmStorageTab = data => { - const disks = VirtualMachine.getDisks(data) - - return ( -
-

VM DISKS

- {disks.map(({ - DISK_ID, - DATASTORE = '-', - TARGET = '-', - IMAGE, - TYPE, - FORMAT, - SIZE, - MONITOR_SIZE, - READONLY, - SAVE = 'No', - CLONE - }) => { - const size = +SIZE ? prettyBytes(+SIZE, 'MB') : '-' - const monitorSize = +MONITOR_SIZE ? prettyBytes(+MONITOR_SIZE, 'MB') : '-' - - const type = String(TYPE).toLowerCase() - - const image = IMAGE ?? ({ - fs: `${FORMAT} - ${size}`, - swap: size - }[type]) - - return ( -

- {`${DISK_ID} | - ${DATASTORE} | - ${TARGET} | - ${image} | - ${monitorSize}/${size} | - ${type} | - ${READONLY} | - ${SAVE} | - ${CLONE}`} -

- ) - })} -
- ) -} - -VmStorageTab.displayName = 'VmStorageTab' - -export default VmStorageTab diff --git a/src/fireedge/src/client/constants/vm.js b/src/fireedge/src/client/constants/vm.js index 4f5df4c8bf..6b73fdab8f 100644 --- a/src/fireedge/src/client/constants/vm.js +++ b/src/fireedge/src/client/constants/vm.js @@ -411,3 +411,78 @@ export const VM_LCM_STATES = [ meaning: '' } ] + +export const VM_ACTIONS = { + CREATE_DIALOG: 'create_dialog', + DEPLOY: 'deploy', + MIGRATE: 'migrate', + MIGRATE_LIVE: 'migrate_live', + MIGRATE_POFF: 'migrate_poff', + MIGRATE_POFF_HARD: 'migrate_poff_hard', + HOLD: 'hold', + RELEASE: 'release', + SUSPEND: 'suspend', + RESUME: 'resume', + STOP: 'stop', + RECOVER: 'recover', + REBOOT: 'reboot', + REBOOT_HARD: 'reboot_hard', + POWEROFF: 'poweroff', + POWEROFF_HARD: 'poweroff_hard', + UNDEPLOY: 'undeploy', + UNDEPLOY_HARD: 'undeploy_hard', + TERMINATE: 'terminate', + TERMINATE_HARD: 'terminate_hard', + RESCHED: 'resched', + UNRESCHED: 'unresched', + SAVE_AS_TEMPLATE: 'save_as_template', + LOCK: 'lockU', + UNLOCK: 'unlock', + STAR_TVNC: 'startvnc', + STAR_TVMRC: 'startvmrc', + STAR_TSPICE: 'startspice', + VNC: 'vnc', + SSH: 'ssh', + RDP: 'rdp', + SAVE_RDP: 'save_rdp', + SAVE_VIRT_VIEWER: 'save_virt_viewer', + + // INFORMATION + RENAME: 'rename', + + // PERMISSION + CHMOD: 'chmod', + + // OWNERSHIP + CHOWN: 'chown', + CHANGE_GROUP: 'chgrp', + + // CAPACITY + RESIZE_CAPACITY: 'resize_capacity', + + // STORAGE + ATTACH_DISK: 'attach_disk', + DETACH_DISK: 'detach_disk', + SNAPSHOT_DISK_CREATE: 'snapshot_disk_create', + SNAPSHOT_DISK_REVERT: 'snapshot_disk_revert', + SNAPSHOT_DISK_DELETE: 'snapshot_disk_delete', + RESIZE_DISK: 'resize_disk', + DISK_SAVEAS: 'disk_saveas', + + // NETWORK + ATTACH_NIC: 'attach_nic', + DETACH_NIC: 'detach_nic', + + // SNAPSHOT + SNAPSHOT_CREATE: 'snapshot_create', + SNAPSHOT_REVERT: 'snapshot_revert', + SNAPSHOT_DELETE: 'snapshot_delete', + + // SCHEDULING ACTION + SCHED_ACTION_CREATE: 'sched_action_create', + SCHED_ACTION_DELETE: 'sched_action_delete', + CHARTER_CREATE: 'charter_create', + + // CONFIGURATION + UPDATE_CONF: 'update_configuration' +} diff --git a/src/fireedge/src/client/models/Helper.js b/src/fireedge/src/client/models/Helper.js index 42a2aec9c0..07a61d24ea 100644 --- a/src/fireedge/src/client/models/Helper.js +++ b/src/fireedge/src/client/models/Helper.js @@ -38,3 +38,19 @@ export const permissionsToOctal = permissions => { [OTHER_U, OTHER_M, OTHER_A] ].map(getCategoryValue).join('') } + +/** + * @param {Object} actions Actions from view yaml + * @param {String} [hypervisor] Resource hypervisor + * @returns {String[]} List of actions available for the resource + */ +export const getActionsAvailable = (actions = {}, hypervisor = '') => + Object.entries(actions) + .filter(([_, action]) => { + if (typeof action === 'boolean') return !!action + + const { enabled = false, not_on: notOn = [] } = action || {} + + return !!enabled && !notOn?.includes?.(hypervisor) + }) + .map(([actionName, _]) => actionName) diff --git a/src/fireedge/src/client/models/VirtualMachine.js b/src/fireedge/src/client/models/VirtualMachine.js index 61a113bcb0..5bef55c4d2 100644 --- a/src/fireedge/src/client/models/VirtualMachine.js +++ b/src/fireedge/src/client/models/VirtualMachine.js @@ -72,12 +72,17 @@ export const getState = ({ STATE, LCM_STATE } = {}) => { * @param {Object} vm Virtual machine * @returns {Array} List of disks from resource */ -export const getDisks = ({ TEMPLATE = {}, MONITORING = {}, ...vm } = {}) => { - const contextDisk = TEMPLATE.CONTEXT && !isVCenter(vm) && { - ...TEMPLATE.CONTEXT, +export const getDisks = vm => { + const { TEMPLATE = {}, MONITORING = {} } = vm ?? {} + + const { DISK, CONTEXT } = TEMPLATE + const { DISK_SIZE = [] } = MONITORING + + const contextDisk = CONTEXT && !isVCenter(vm) && { + ...CONTEXT, IMAGE: 'CONTEXT', + IS_CONTEXT: true, DATASTORE: '-', - TYPE: '-', READONLY: '-', SAVE: '-', CLONE: '-', @@ -87,11 +92,12 @@ export const getDisks = ({ TEMPLATE = {}, MONITORING = {}, ...vm } = {}) => { const addMonitoringData = disk => ({ ...disk, // get monitoring data - MONITOR_SIZE: MONITORING.DISK_SIZE + MONITOR_SIZE: [DISK_SIZE ?? []] + ?.flat() ?.find(({ ID }) => ID === disk.DISK_ID)?.SIZE || '-' }) - return [TEMPLATE.DISK, contextDisk] + return [DISK, contextDisk] .flat() .filter(Boolean) .map(addMonitoringData) @@ -99,9 +105,13 @@ export const getDisks = ({ TEMPLATE = {}, MONITORING = {}, ...vm } = {}) => { /** * @param {Object} vm Virtual machine + * @param {Boolean} [options.groupAlias] Map ALIAS_IDS attribute with NIC_ALIAS * @returns {Array} List of nics from resource */ -export const getNics = ({ TEMPLATE = {}, MONITORING = {} } = {}) => { +export const getNics = (vm, options = {}) => { + const { groupAlias = false } = options + const { TEMPLATE = {}, MONITORING = {} } = vm ?? {} + const { NIC = [], NIC_ALIAS = [], PCI = [] } = TEMPLATE const { GUEST_IP, GUEST_IP_ADDRESSES = '' } = MONITORING @@ -109,7 +119,14 @@ export const getNics = ({ TEMPLATE = {}, MONITORING = {} } = {}) => { .filter(Boolean) .map(ip => ({ NIC_ID: '-', IP: ip, NETWORK: 'Additional IP', BRIDGE: '-' })) - return [NIC, NIC_ALIAS, PCI, extraIps].flat().filter(Boolean) + const nics = [NIC, PCI, extraIps].flat().filter(Boolean) + + return groupAlias + ? nics.map(({ ALIAS_IDS, ...nic }) => ({ + ...nic, + ALIAS: NIC_ALIAS?.filter(({ NIC_ID }) => ALIAS_IDS?.includes(NIC_ID)) + })) + : nics.concat(NIC_ALIAS) } /** @@ -123,13 +140,12 @@ export const getIps = vm => { } /** - * @type {{nics: Array, alias: Array}} Nics&Alias - * * @param {Object} vm Virtual machine - * @returns {Nics&Alias} Lists of nics and alias from resource + * @returns {{ nics: Array, alias: Array }} Lists of nics and alias from resource */ -export const splitNicAlias = vm => getNics(vm).reduce((result, nic) => { - result[nic?.PARENT !== undefined ? 'alias' : 'nics'].push(nic) +export const splitNicAlias = vm => + getNics(vm).reduce((result, nic) => { + result[nic?.PARENT !== undefined ? 'alias' : 'nics'].push(nic) - return result -}, { nics: [], alias: [] }) + return result + }, { nics: [], alias: [] })