From 265ccea559f9e252948f4487f3b7366903a4ebd0 Mon Sep 17 00:00:00 2001 From: Sergio Betanzos Date: Wed, 25 May 2022 18:48:36 +0200 Subject: [PATCH] F #5422: Reformat info-tabs for VMs (#2080) --- .../src/client/components/Cards/DiskCard.js | 236 ++++++++++-------- .../components/Cards/DiskSnapshotCard.js | 109 ++++---- .../src/client/components/Cards/NicCard.js | 82 +++--- .../components/Cards/VirtualMachineCard.js | 24 +- .../FormControl/SelectController.js | 1 + .../src/client/components/Tabs/Common/List.js | 6 +- .../src/client/constants/translates.js | 1 + 7 files changed, 258 insertions(+), 201 deletions(-) diff --git a/src/fireedge/src/client/components/Cards/DiskCard.js b/src/fireedge/src/client/components/Cards/DiskCard.js index c36f8c3bec..2cdac33ed5 100644 --- a/src/fireedge/src/client/components/Cards/DiskCard.js +++ b/src/fireedge/src/client/components/Cards/DiskCard.js @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo } from 'react' +import { ReactElement, memo, useMemo } from 'react' import PropTypes from 'prop-types' -import { DatabaseSettings, Folder, ModernTv } from 'iconoir-react' +import { DatabaseSettings, Folder, PlugTypeC } from 'iconoir-react' import { Box, Typography, Paper } from '@mui/material' import DiskSnapshotCard from 'client/components/Cards/DiskSnapshotCard' @@ -26,126 +26,140 @@ import { Tr } from 'client/components/HOC' import { getDiskName, getDiskType } from 'client/models/Image' import { stringToBoolean } from 'client/models/Helper' import { prettyBytes, sentenceCase } from 'client/utils' -import { T, Disk } from 'client/constants' +import { T, Disk, DiskSnapshot } from 'client/constants' -const DiskCard = memo(({ disk = {}, actions = [], snapshotActions = [] }) => { - const classes = rowStyles() +const DiskCard = memo( + /** + * @param {object} props - Props + * @param {Disk} props.disk - Disk + * @param {ReactElement} [props.actions] - Actions + * @param {function({ snapshot: DiskSnapshot }):ReactElement} [props.snapshotActions] - Snapshot actions + * @returns {ReactElement} - Card + */ + ({ disk = {}, actions, snapshotActions }) => { + const classes = rowStyles() - /** @type {Disk} */ - const { - DISK_ID, - DATASTORE, - TARGET, - TYPE, - SIZE, - MONITOR_SIZE, - READONLY, - PERSISTENT, - SAVE, - CLONE, - IS_CONTEXT, - SNAPSHOTS, - } = disk + const { + DISK_ID, + DATASTORE, + TARGET, + TYPE, + SIZE, + MONITOR_SIZE, + READONLY, + PERSISTENT, + SAVE, + CLONE, + IS_CONTEXT, + SNAPSHOTS, + } = disk - const size = +SIZE ? prettyBytes(+SIZE, 'MB') : '-' - const monitorSize = +MONITOR_SIZE ? prettyBytes(+MONITOR_SIZE, 'MB') : '-' + const size = useMemo(() => (+SIZE ? prettyBytes(+SIZE, 'MB') : '-'), [SIZE]) - const labels = useMemo( - () => - [ - { label: getDiskType(disk), dataCy: 'type' }, - { - label: stringToBoolean(PERSISTENT) && T.Persistent, - dataCy: 'persistent', - }, - { - label: stringToBoolean(READONLY) && T.ReadOnly, - dataCy: 'readonly', - }, - { - label: stringToBoolean(SAVE) && T.Save, - dataCy: 'save', - }, - { - label: stringToBoolean(CLONE) && T.Clone, - dataCy: 'clone', - }, - ].filter(({ label } = {}) => Boolean(label)), - [TYPE, PERSISTENT, READONLY, SAVE, CLONE] - ) + const monitorSize = useMemo( + () => (+MONITOR_SIZE ? prettyBytes(+MONITOR_SIZE, 'MB') : '-'), + [MONITOR_SIZE] + ) - return ( - -
-
- - {getDiskName(disk)} - - - {labels.map(({ label, dataCy }) => ( - + [ + { label: getDiskType(disk), dataCy: 'type' }, + { + label: stringToBoolean(PERSISTENT) && T.Persistent, + dataCy: 'persistent', + }, + { + label: stringToBoolean(READONLY) && T.ReadOnly, + dataCy: 'readonly', + }, + { + label: stringToBoolean(SAVE) && T.Save, + dataCy: 'save', + }, + { + label: stringToBoolean(CLONE) && T.Clone, + dataCy: 'clone', + }, + ].filter(({ label } = {}) => Boolean(label)), + [TYPE, PERSISTENT, READONLY, SAVE, CLONE] + ) + + return ( + +
+
+ + {getDiskName(disk)} + + + {labels.map(({ label, dataCy }) => ( + + ))} + +
+
+ {`#${DISK_ID}`} + {TARGET && ( + + + {` ${TARGET}`} + + )} + {DATASTORE && ( + + + {` ${DATASTORE}`} + + )} + {+MONITOR_SIZE ? ( + + + {` ${monitorSize}/${size}`} + + ) : ( + + + {` ${size}`} + + )} +
+
+ {!IS_CONTEXT && !!actions && ( +
{actions}
+ )} + {!!SNAPSHOTS?.length && ( + + {SNAPSHOTS?.map((snapshot) => ( + ))} -
-
-
- {`#${DISK_ID}`} - {TARGET && ( - - - {` ${TARGET}`} - - )} - {DATASTORE && ( - - - {` ${DATASTORE}`} - - )} - {+MONITOR_SIZE ? ( - - - {` ${monitorSize}/${size}`} - - ) : ( - - - {` ${size}`} - - )} -
-
- {!IS_CONTEXT && !!actions && ( -
{actions}
- )} - {!!SNAPSHOTS?.length && ( - - {SNAPSHOTS?.map((snapshot) => ( - - ))} - - )} -
- ) -}) + + )} + + ) + } +) DiskCard.propTypes = { disk: PropTypes.object.isRequired, actions: PropTypes.any, - extraActionProps: PropTypes.object, - extraSnapshotActionProps: PropTypes.object, snapshotActions: PropTypes.any, } diff --git a/src/fireedge/src/client/components/Cards/DiskSnapshotCard.js b/src/fireedge/src/client/components/Cards/DiskSnapshotCard.js index 0e5567da06..d4e4ef2211 100644 --- a/src/fireedge/src/client/components/Cards/DiskSnapshotCard.js +++ b/src/fireedge/src/client/components/Cards/DiskSnapshotCard.js @@ -13,72 +13,85 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo } from 'react' +import { ReactElement, memo, useMemo } from 'react' import PropTypes from 'prop-types' import { ModernTv } from 'iconoir-react' import { Typography, Paper } from '@mui/material' import { StatusChip } from 'client/components/Status' import { rowStyles } from 'client/components/Tables/styles' -import { Translate } from 'client/components/HOC' +import { Tr, Translate } from 'client/components/HOC' -import * as Helper from 'client/models/Helper' +import { stringToBoolean, timeFromMilliseconds } from 'client/models/Helper' import { prettyBytes } from 'client/utils' import { T, DiskSnapshot } from 'client/constants' -const DiskSnapshotCard = memo(({ snapshot = {}, actions = [] }) => { - const classes = rowStyles() +const DiskSnapshotCard = memo( + /** + * @param {object} props - Props + * @param {DiskSnapshot} props.snapshot - Disk snapshot + * @param {function({ snapshot: DiskSnapshot }):ReactElement} [props.actions] - Actions + * @returns {ReactElement} - Card + */ + ({ snapshot = {}, actions }) => { + const classes = rowStyles() - /** @type {DiskSnapshot} */ - const { - ID, - NAME, - ACTIVE, - DATE, - SIZE: SNAPSHOT_SIZE, - MONITOR_SIZE: SNAPSHOT_MONITOR_SIZE, - } = snapshot + const { + ID, + NAME, + ACTIVE, + DATE, + SIZE: SNAPSHOT_SIZE, + MONITOR_SIZE: SNAPSHOT_MONITOR_SIZE, + } = snapshot - const isActive = Helper.stringToBoolean(ACTIVE) - const time = Helper.timeFromMilliseconds(+DATE) - const timeAgo = `created ${time.toRelative()}` + const isActive = useMemo(() => stringToBoolean(ACTIVE), [ACTIVE]) + const time = useMemo(() => timeFromMilliseconds(+DATE), [DATE]) + const timeFormat = useMemo(() => time.toFormat('ff'), [DATE]) + const timeAgo = useMemo(() => `created ${time.toRelative()}`, [DATE]) - const size = +SNAPSHOT_SIZE ? prettyBytes(+SNAPSHOT_SIZE, 'MB') : '-' - const monitorSize = +SNAPSHOT_MONITOR_SIZE - ? prettyBytes(+SNAPSHOT_MONITOR_SIZE, 'MB') - : '-' + const sizeInfo = useMemo(() => { + const size = +SNAPSHOT_SIZE ? prettyBytes(+SNAPSHOT_SIZE, 'MB') : '-' + const monitorSize = +SNAPSHOT_MONITOR_SIZE + ? prettyBytes(+SNAPSHOT_MONITOR_SIZE, 'MB') + : '-' - return ( - -
-
- - {NAME} - - - {isActive && } />} - } /> - + return `${monitorSize}/${size}` + }, [SNAPSHOT_SIZE, SNAPSHOT_MONITOR_SIZE]) + + return ( + +
+
+ + {NAME} + + + {isActive && } />} + } /> + +
+
+ {`#${ID} ${timeAgo}`} + + + {` ${sizeInfo}`} + +
-
- {`#${ID} ${timeAgo}`} - - - {` ${monitorSize}/${size}`} - -
-
- {typeof actions === 'function' && ( -
{actions({ snapshot })}
- )} - - ) -}) + {typeof actions === 'function' && ( +
{actions({ snapshot })}
+ )} + + ) + } +) DiskSnapshotCard.propTypes = { snapshot: PropTypes.object.isRequired, - extraActionProps: PropTypes.object, - actions: PropTypes.arrayOf(PropTypes.string), + actions: PropTypes.func, } DiskSnapshotCard.displayName = 'DiskSnapshotCard' diff --git a/src/fireedge/src/client/components/Cards/NicCard.js b/src/fireedge/src/client/components/Cards/NicCard.js index ae8118a38c..fdc92e040c 100644 --- a/src/fireedge/src/client/components/Cards/NicCard.js +++ b/src/fireedge/src/client/components/Cards/NicCard.js @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo } from 'react' +import { ReactElement, memo, useMemo } from 'react' import PropTypes from 'prop-types' +import { Network } from 'iconoir-react' import { useMediaQuery, Typography, @@ -37,6 +38,16 @@ import { groupBy } from 'client/utils' import { T, Nic, NicAlias, PrettySecurityGroupRule } from 'client/constants' const NicCard = memo( + /** + * @param {object} props - Props + * @param {Nic|NicAlias} props.nic - NIC + * @param {ReactElement} [props.actions] - Actions + * @param {function({ alias: NicAlias }):ReactElement} [props.aliasActions] - Alias actions + * @param {function({ securityGroupId: string }):ReactElement} [props.securityGroupActions] - Security group actions + * @param {boolean} [props.showParents] - + * @param {boolean} [props.clipboardOnTags] - + * @returns {ReactElement} - Card + */ ({ nic = {}, actions, @@ -48,7 +59,6 @@ const NicCard = memo( const classes = rowStyles() const isMobile = useMediaQuery((theme) => theme.breakpoints.down('md')) - /** @type {Nic|NicAlias} */ const { NIC_ID, NETWORK = '-', @@ -65,24 +75,32 @@ const NicCard = memo( const isAlias = !!PARENT?.length const isPciDevice = PCI_ID !== undefined - const isAdditionalIp = NIC_ID !== undefined || NETWORK === 'Additional IP' + const isAdditionalIp = NIC_ID === undefined || NETWORK === 'Additional IP' const dataCy = isAlias ? 'alias' : 'nic' - const noClipboardTags = [ - { text: stringToBoolean(RDP) && 'RDP', dataCy: `${dataCy}-rdp` }, - { text: stringToBoolean(SSH) && 'SSH', dataCy: `${dataCy}-ssh` }, - showParents && { - text: isAlias ? `PARENT: ${PARENT}` : false, - dataCy: `${dataCy}-parent`, - }, - ].filter(({ text } = {}) => Boolean(text)) + const noClipboardTags = useMemo( + () => + [ + { text: stringToBoolean(RDP) && 'RDP', dataCy: `${dataCy}-rdp` }, + { text: stringToBoolean(SSH) && 'SSH', dataCy: `${dataCy}-ssh` }, + showParents && { + text: isAlias ? `PARENT: ${PARENT}` : false, + dataCy: `${dataCy}-parent`, + }, + ].filter(({ text } = {}) => Boolean(text)), + [RDP, SSH, showParents, PARENT] + ) - const tags = [ - { text: IP, dataCy: `${dataCy}-ip` }, - { text: MAC, dataCy: `${dataCy}-mac` }, - { text: ADDRESS, dataCy: `${dataCy}-address` }, - ].filter(({ text } = {}) => Boolean(text)) + const tags = useMemo( + () => + [ + { text: IP, dataCy: `${dataCy}-ip` }, + { text: MAC, dataCy: `${dataCy}-mac` }, + { text: ADDRESS, dataCy: `${dataCy}-address` }, + ].filter(({ text } = {}) => Boolean(text)), + [IP, MAC, ADDRESS] + ) return (
- - {`${NIC_ID} | ${NETWORK}`} + + {NETWORK} {isAlias && } @@ -113,11 +126,24 @@ const NicCard = memo( dataCy={tag.dataCy} /> ))} - + +
+
+ {`#${NIC_ID}`} + + + + +
diff --git a/src/fireedge/src/client/components/Cards/VirtualMachineCard.js b/src/fireedge/src/client/components/Cards/VirtualMachineCard.js index 4c784a70c4..220fca86ee 100644 --- a/src/fireedge/src/client/components/Cards/VirtualMachineCard.js +++ b/src/fireedge/src/client/components/Cards/VirtualMachineCard.js @@ -66,7 +66,7 @@ const VirtualMachineCard = memo( ETIME, LOCK, USER_TEMPLATE: { LABELS } = {}, - TEMPLATE: { CPU, MEMORY } = {}, + TEMPLATE: { VCPU = '-', MEMORY } = {}, } = vm const { HOSTNAME = '--', VM_MAD: hypervisor } = useMemo( @@ -74,10 +74,11 @@ const VirtualMachineCard = memo( [vm.HISTORY_RECORDS] ) - const time = useMemo( - () => timeFromMilliseconds(+ETIME || +STIME), - [ETIME, STIME] - ) + const [time, timeFormat] = useMemo(() => { + const fromMill = timeFromMilliseconds(+ETIME || +STIME) + + return [fromMill, fromMill.toFormat('ff')] + }, [ETIME, STIME]) const { color: stateColor, name: stateName } = getState(vm) const error = useMemo(() => getErrorMessage(vm), [vm]) @@ -121,27 +122,24 @@ const VirtualMachineCard = memo(
{`#${ID}`} - time.toFormat('ff'), [ETIME, STIME])}> + {`${+ETIME ? T.Done : T.Started} `} - + - {CPU} + {VCPU} {memValue} - + {HOSTNAME} {!!ips?.length && ( - + diff --git a/src/fireedge/src/client/components/FormControl/SelectController.js b/src/fireedge/src/client/components/FormControl/SelectController.js index ee748ad032..71cf579773 100644 --- a/src/fireedge/src/client/components/FormControl/SelectController.js +++ b/src/fireedge/src/client/components/FormControl/SelectController.js @@ -90,6 +90,7 @@ const SelectController = memo( label={labelCanBeTranslated(label) ? Tr(label) : label} InputLabelProps={{ shrink: needShrink }} InputProps={{ + ...(multiple && { sx: { paddingTop: '0.5em' } }), readOnly, startAdornment: (optionSelected && renderValue?.(optionSelected)) || diff --git a/src/fireedge/src/client/components/Tabs/Common/List.js b/src/fireedge/src/client/components/Tabs/Common/List.js index 2314369a5e..71c8ebbcf5 100644 --- a/src/fireedge/src/client/components/Tabs/Common/List.js +++ b/src/fireedge/src/client/components/Tabs/Common/List.js @@ -120,7 +120,11 @@ const AttributeList = ({ {/* TITLE */} {title && ( - {Tr(title)} + {typeof title === 'string' ? ( + {Tr(title)} + ) : ( + title + )} )} diff --git a/src/fireedge/src/client/constants/translates.js b/src/fireedge/src/client/constants/translates.js index 3285ec22f9..e3d4fbe555 100644 --- a/src/fireedge/src/client/constants/translates.js +++ b/src/fireedge/src/client/constants/translates.js @@ -462,6 +462,7 @@ module.exports = { Snapshot: 'Snapshot', SnapshotName: 'Snapshot name', DiskSnapshot: 'Disk snapshot', + DiskSize: 'Disk size', NewImageName: 'New Image name', NewImageNameConcept: 'Name for the new Image where the disk will be saved', /* VM schema - network */