mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-16 22:50:10 +03:00
parent
5ff147b27c
commit
6625e09592
@ -42,9 +42,12 @@ const useStyles = makeStyles((theme) => ({
|
||||
}))
|
||||
|
||||
const ButtonComponent = forwardRef(
|
||||
({ icon, endicon, children, size, variant = 'contained', ...props }, ref) =>
|
||||
(
|
||||
{ icon, endicon, children, size, variant = 'contained', value, ...props },
|
||||
ref
|
||||
) =>
|
||||
icon && !endicon ? (
|
||||
<IconButton ref={ref} {...props}>
|
||||
<IconButton ref={ref} {...props} value={value}>
|
||||
{children}
|
||||
</IconButton>
|
||||
) : (
|
||||
@ -122,6 +125,7 @@ export const SubmitButtonPropTypes = {
|
||||
color: PropTypes.string,
|
||||
size: PropTypes.string,
|
||||
variant: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
}
|
||||
|
||||
TooltipComponent.propTypes = SubmitButtonPropTypes
|
||||
|
@ -50,7 +50,7 @@ const Content = () => {
|
||||
<FormWithSchema
|
||||
key={id}
|
||||
className={classes[id]}
|
||||
cy={`instantiate-vm-template-configuration.${id}`}
|
||||
cy={id}
|
||||
fields={fields}
|
||||
legend={legend}
|
||||
id={STEP_ID}
|
||||
|
@ -38,7 +38,10 @@ const InternalLayout = ({ title, children }) => {
|
||||
}, [title])
|
||||
|
||||
return (
|
||||
<Box className={clsx(classes.root, { [classes.isDrawerFixed]: isFixMenu })}>
|
||||
<Box
|
||||
data-cy="main-layout"
|
||||
className={clsx(classes.root, { [classes.isDrawerFixed]: isFixMenu })}
|
||||
>
|
||||
<Header scrollContainer={container.current} />
|
||||
<Box component="main" className={classes.main}>
|
||||
<CSSTransition
|
||||
|
@ -27,11 +27,18 @@ const MultipleTags = ({ tags, limitTags = 1, clipboard }) => {
|
||||
|
||||
const more = tags.length - limitTags
|
||||
|
||||
const Tags = tags
|
||||
.splice(0, limitTags)
|
||||
.map((tag, idx) => (
|
||||
<StatusChip key={`${idx}-${tag}`} text={tag} clipboard={clipboard} />
|
||||
))
|
||||
const Tags = tags.splice(0, limitTags).map((tag, idx) => {
|
||||
const text = tag.text ?? tag
|
||||
|
||||
return (
|
||||
<StatusChip
|
||||
key={`${idx}-${text}`}
|
||||
text={text}
|
||||
clipboard={clipboard}
|
||||
dataCy={tag.dataCy ?? ''}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -39,15 +46,20 @@ const MultipleTags = ({ tags, limitTags = 1, clipboard }) => {
|
||||
{more > 0 && (
|
||||
<Tooltip
|
||||
arrow
|
||||
title={tags.map((tag, idx) => (
|
||||
<Typography
|
||||
key={`${idx}-${tag}`}
|
||||
variant="subtitle2"
|
||||
sx={{ height: 'max-content' }}
|
||||
>
|
||||
{tag}
|
||||
</Typography>
|
||||
))}
|
||||
title={tags.map((tag, idx) => {
|
||||
const text = tag.text ?? tag
|
||||
|
||||
return (
|
||||
<Typography
|
||||
key={`${idx}-${text}`}
|
||||
variant="subtitle2"
|
||||
sx={{ height: 'max-content' }}
|
||||
{...(tag.dataCy && { dataCy: tag.dataCy })}
|
||||
>
|
||||
{text}
|
||||
</Typography>
|
||||
)
|
||||
})}
|
||||
>
|
||||
<Typography component="span" variant="subtitle2" sx={{ ml: 1 }}>
|
||||
{`+${more} more`}
|
||||
|
@ -68,7 +68,14 @@ const callAll =
|
||||
fns.forEach((fn) => fn && fn?.(...args))
|
||||
|
||||
const StatusChip = memo(
|
||||
({ stateColor, text = '', clipboard = false, onClick, ...props }) => {
|
||||
({
|
||||
stateColor,
|
||||
text = '',
|
||||
dataCy = '',
|
||||
clipboard = false,
|
||||
onClick,
|
||||
...props
|
||||
}) => {
|
||||
const { copy, isCopied } = useClipboard()
|
||||
const textToCopy = typeof clipboard === 'string' ? clipboard : text
|
||||
const classes = useStyles({ stateColor, clipboard })
|
||||
@ -93,6 +100,7 @@ const StatusChip = memo(
|
||||
component="span"
|
||||
className={classes.text}
|
||||
onClick={callAll(onClick, clipboard && handleCopy)}
|
||||
data-cy={dataCy}
|
||||
{...props}
|
||||
>
|
||||
{text}
|
||||
@ -113,6 +121,7 @@ StatusChip.propTypes = {
|
||||
stateColor: PropTypes.string,
|
||||
text: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||
clipboard: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
|
||||
dataCy: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,7 @@ const ActionItem = memo(
|
||||
({ item, selectedRows }) => {
|
||||
const {
|
||||
accessor,
|
||||
dataCy,
|
||||
tooltip,
|
||||
label,
|
||||
color,
|
||||
@ -75,7 +76,8 @@ const ActionItem = memo(
|
||||
const buttonProps = {
|
||||
color,
|
||||
variant,
|
||||
'data-cy': accessor && `action.${accessor}`,
|
||||
'data-cy':
|
||||
(dataCy && `action-${dataCy}`) ?? (accessor && `action-${accessor}`),
|
||||
disabled:
|
||||
typeof disabled === 'function' ? disabled(selectedRows) : disabled,
|
||||
icon: Icon && <Icon />,
|
||||
@ -141,6 +143,7 @@ const ActionItem = memo(
|
||||
|
||||
export const ActionPropTypes = PropTypes.shape({
|
||||
accessor: PropTypes.string,
|
||||
dataCy: PropTypes.string,
|
||||
variant: PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
size: PropTypes.string,
|
||||
|
@ -58,6 +58,7 @@ const EnhancedTable = ({
|
||||
showPageCount,
|
||||
singleSelect = false,
|
||||
classes = {},
|
||||
rootProps = {},
|
||||
}) => {
|
||||
const styles = EnhancedTableStyles()
|
||||
|
||||
@ -140,7 +141,11 @@ const EnhancedTable = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Box {...getTableProps()} className={clsx(styles.root, classes.root)}>
|
||||
<Box
|
||||
{...getTableProps()}
|
||||
className={clsx(styles.root, classes.root)}
|
||||
{...rootProps}
|
||||
>
|
||||
<div className={styles.toolbar}>
|
||||
{/* TOOLBAR */}
|
||||
{!isFetching && (
|
||||
@ -236,6 +241,9 @@ export const EnhancedTableProps = {
|
||||
root: PropTypes.string,
|
||||
body: PropTypes.string,
|
||||
}),
|
||||
rootProps: PropTypes.shape({
|
||||
'data-cy': PropTypes.string,
|
||||
}),
|
||||
isLoading: PropTypes.bool,
|
||||
onlyGlobalSearch: PropTypes.bool,
|
||||
onlyGlobalSelectedRows: PropTypes.bool,
|
||||
|
@ -44,7 +44,7 @@ const Row = ({ original, value, ...props }) => {
|
||||
const timeAgo = `registered ${time.toRelative()}`
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<div {...props} data-cy={`template-${ID}`}>
|
||||
<div className={classes.figure}>
|
||||
<Image src={logoSource} imgProps={{ className: classes.image }} />
|
||||
</div>
|
||||
|
@ -135,6 +135,7 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_ACTIONS.CREATE_DIALOG,
|
||||
dataCy: `vm_${VM_ACTIONS.CREATE_DIALOG}`,
|
||||
tooltip: T.Create,
|
||||
icon: AddSquare,
|
||||
action: () => {
|
||||
|
@ -47,7 +47,7 @@ const Row = ({ original, value, ...props }) => {
|
||||
VirtualMachineModel.getState(original)
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<div {...props} data-cy={`vm-${ID}`}>
|
||||
<div>
|
||||
<StatusCircle color={stateColor} tooltip={stateName} />
|
||||
</div>
|
||||
|
@ -53,6 +53,7 @@ const Attribute = memo(
|
||||
showActionsOnHover = false,
|
||||
value,
|
||||
valueInOptionList,
|
||||
dataCy,
|
||||
}) => {
|
||||
const numberOfParents = useMemo(() => path.split('.').length - 1, [path])
|
||||
|
||||
@ -131,6 +132,7 @@ const Attribute = memo(
|
||||
variant="body2"
|
||||
flexGrow={1}
|
||||
title={typeof value === 'string' ? value : undefined}
|
||||
data-cy={dataCy}
|
||||
>
|
||||
{link ? (
|
||||
<Link color="secondary" component={RouterLink} to={link}>
|
||||
@ -183,6 +185,7 @@ export const AttributePropTypes = {
|
||||
showActionsOnHover: PropTypes.bool,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
valueInOptionList: PropTypes.string,
|
||||
dataCy: PropTypes.string,
|
||||
}
|
||||
|
||||
Attribute.propTypes = AttributePropTypes
|
||||
|
@ -53,6 +53,7 @@ const Ownership = memo(
|
||||
canEdit: actions?.includes?.(ACTIONS.CHANGE_OWNER),
|
||||
handleGetOptionList: getUserOptions,
|
||||
handleEdit: (_, user) => handleEdit?.({ user }),
|
||||
dataCy: 'owner',
|
||||
},
|
||||
{
|
||||
name: T.Group,
|
||||
@ -62,6 +63,7 @@ const Ownership = memo(
|
||||
canEdit: actions?.includes?.(ACTIONS.CHANGE_GROUP),
|
||||
handleGetOptionList: getGroupOptions,
|
||||
handleEdit: (_, group) => handleEdit?.({ group }),
|
||||
dataCy: 'group',
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -83,6 +83,7 @@ const Permissions = memo(({ handleEdit, actions, ...permissions }) => {
|
||||
cy={`permission-${key}`}
|
||||
disabled={permission === undefined}
|
||||
icon={getIcon(permission)}
|
||||
value={permission}
|
||||
handleClick={() => handleChange(key, permission)}
|
||||
/>
|
||||
) : (
|
||||
|
@ -36,10 +36,12 @@ const InformationPanel = ({ actions, vm = {}, handleResizeCapacity }) => {
|
||||
{
|
||||
name: T.PhysicalCpu,
|
||||
value: TEMPLATE?.CPU,
|
||||
dataCy: 'cpu',
|
||||
},
|
||||
{
|
||||
name: T.VirtualCpu,
|
||||
value: TEMPLATE?.VCPU ?? '-',
|
||||
dataCy: 'virtualcpu',
|
||||
},
|
||||
isVCenter && {
|
||||
name: T.VirtualCores,
|
||||
@ -49,18 +51,22 @@ const InformationPanel = ({ actions, vm = {}, handleResizeCapacity }) => {
|
||||
${Tr(T.Sockets)} ${TEMPLATE?.TOPOLOGY?.SOCKETS || '-'}`}
|
||||
</>
|
||||
),
|
||||
dataCy: 'virtualcores',
|
||||
},
|
||||
{
|
||||
name: T.Memory,
|
||||
value: prettyBytes(+TEMPLATE?.MEMORY, 'MB'),
|
||||
dataCy: 'memory',
|
||||
},
|
||||
{
|
||||
name: T.CostCpu,
|
||||
value: TEMPLATE?.CPU_COST || 0,
|
||||
dataCy: 'cpucost',
|
||||
},
|
||||
{
|
||||
name: T.CostMByte,
|
||||
value: TEMPLATE?.MEMORY_COST || 0,
|
||||
dataCy: 'memorycost',
|
||||
},
|
||||
].filter(Boolean)
|
||||
|
||||
@ -85,12 +91,12 @@ const InformationPanel = ({ actions, vm = {}, handleResizeCapacity }) => {
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{capacity.map(({ name, value }) => (
|
||||
{capacity.map(({ name, value, dataCy }) => (
|
||||
<div key={name} className={classes.item}>
|
||||
<Typography className={classes.title} noWrap title={name}>
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography variant="body2" noWrap title={value}>
|
||||
<Typography variant="body2" noWrap title={value} data-cy={dataCy}>
|
||||
{value}
|
||||
</Typography>
|
||||
</div>
|
||||
|
@ -57,36 +57,48 @@ const InformationPanel = ({ vm = {}, handleRename, actions }) => {
|
||||
}, [])
|
||||
|
||||
const info = [
|
||||
{ name: T.ID, value: ID },
|
||||
{
|
||||
name: T.ID,
|
||||
value: ID,
|
||||
dataCy: 'id',
|
||||
},
|
||||
{
|
||||
name: T.Name,
|
||||
value: NAME,
|
||||
canEdit: actions?.includes?.(VM_ACTIONS.RENAME),
|
||||
handleEdit: handleRename,
|
||||
dataCy: 'name',
|
||||
},
|
||||
{
|
||||
name: T.State,
|
||||
value: <StatusChip text={stateName} stateColor={stateColor} />,
|
||||
value: (
|
||||
<StatusChip dataCy={'state'} text={stateName} stateColor={stateColor} />
|
||||
),
|
||||
},
|
||||
{
|
||||
name: T.Reschedule,
|
||||
value: Helper.booleanToString(+RESCHED),
|
||||
dataCy: 'reschedule',
|
||||
},
|
||||
{
|
||||
name: T.Locked,
|
||||
value: Helper.levelLockToString(LOCK?.LOCKED),
|
||||
dataCy: 'locked',
|
||||
},
|
||||
{
|
||||
name: T.IP,
|
||||
value: ips?.length ? <MultipleTags tags={ips} /> : '--',
|
||||
dataCy: 'ips',
|
||||
},
|
||||
{
|
||||
name: T.StartTime,
|
||||
value: Helper.timeToString(STIME),
|
||||
dataCy: 'starttime',
|
||||
},
|
||||
{
|
||||
name: T.EndTime,
|
||||
value: Helper.timeToString(ETIME),
|
||||
dataCy: 'endtime',
|
||||
},
|
||||
hostId && {
|
||||
name: T.Host,
|
||||
@ -94,6 +106,7 @@ const InformationPanel = ({ vm = {}, handleRename, actions }) => {
|
||||
link:
|
||||
!Number.isNaN(+hostId) &&
|
||||
generatePath(PATH.INFRASTRUCTURE.HOSTS.DETAIL, { id: hostId }),
|
||||
dataCy: 'hostid',
|
||||
},
|
||||
clusterId && {
|
||||
name: T.Cluster,
|
||||
@ -101,10 +114,12 @@ const InformationPanel = ({ vm = {}, handleRename, actions }) => {
|
||||
link:
|
||||
!Number.isNaN(+clusterId) &&
|
||||
generatePath(PATH.INFRASTRUCTURE.CLUSTERS.DETAIL, { id: clusterId }),
|
||||
dataCy: 'clusterid',
|
||||
},
|
||||
{
|
||||
name: T.DeployID,
|
||||
value: DEPLOY_ID,
|
||||
dataCy: 'deployid',
|
||||
},
|
||||
].filter(Boolean)
|
||||
|
||||
|
@ -37,6 +37,10 @@ import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
import { T, VM_ACTIONS } from 'client/constants'
|
||||
|
||||
const DATACYSECURITY = 'securitygroup-'
|
||||
const DATACYNETWORK = 'network-'
|
||||
const DATACYALIAS = 'alias-'
|
||||
|
||||
const Accordion = styled((props) => (
|
||||
<MAccordion disableGutters elevation={0} square {...props} />
|
||||
))(({ theme }) => ({
|
||||
@ -126,17 +130,34 @@ const NetworkItem = ({ nic = {}, actions }) => {
|
||||
/>
|
||||
)
|
||||
|
||||
const tags = [
|
||||
{
|
||||
text: IP,
|
||||
dataCy: `${DATACYNETWORK}ip`,
|
||||
},
|
||||
{
|
||||
text: MAC,
|
||||
dataCy: `${DATACYNETWORK}mac`,
|
||||
},
|
||||
{
|
||||
text: ADDRESS,
|
||||
dataCy: `${DATACYNETWORK}address`,
|
||||
},
|
||||
].filter(({ text } = {}) => Boolean(text))
|
||||
|
||||
return (
|
||||
<>
|
||||
<Accordion>
|
||||
<Accordion data-cy={`${DATACYNETWORK}${NIC_ID}`}>
|
||||
<Summary {...(hasDetails && { expandIcon: <ExpandIcon /> })}>
|
||||
<Row>
|
||||
<Typography noWrap>{`${NIC_ID} | ${NETWORK}`}</Typography>
|
||||
<Typography noWrap data-cy={`${DATACYNETWORK}name`}>
|
||||
{`${NIC_ID} | ${NETWORK}`}
|
||||
</Typography>
|
||||
<Labels>
|
||||
<MultipleTags
|
||||
clipboard
|
||||
limitTags={isMobile ? 1 : 3}
|
||||
tags={[IP, MAC, ADDRESS].filter(Boolean)}
|
||||
tags={tags}
|
||||
/>
|
||||
</Labels>
|
||||
{!isMobile && !isPciDevice && detachAction(NIC_ID)}
|
||||
@ -144,24 +165,43 @@ const NetworkItem = ({ nic = {}, actions }) => {
|
||||
</Summary>
|
||||
{hasDetails && (
|
||||
<Details>
|
||||
{ALIAS?.map(({ NIC_ID, NETWORK = '-', BRIDGE, IP, MAC }) => (
|
||||
<Row key={NIC_ID}>
|
||||
<Typography noWrap variant="body2">
|
||||
<Translate word={T.Alias} />
|
||||
{`${NIC_ID} | ${NETWORK}`}
|
||||
</Typography>
|
||||
<Labels>
|
||||
<MultipleTags
|
||||
clipboard
|
||||
limitTags={isMobile ? 1 : 3}
|
||||
tags={[IP, MAC, BRIDGE && `BRIDGE - ${BRIDGE}`].filter(
|
||||
Boolean
|
||||
)}
|
||||
/>
|
||||
</Labels>
|
||||
{!isMobile && !isPciDevice && detachAction(NIC_ID, true)}
|
||||
</Row>
|
||||
))}
|
||||
{ALIAS?.map(({ NIC_ID, NETWORK = '-', BRIDGE, IP, MAC }) => {
|
||||
const tags = [
|
||||
{
|
||||
text: IP,
|
||||
dataCy: `${DATACYALIAS}ip`,
|
||||
},
|
||||
{
|
||||
text: MAC,
|
||||
dataCy: `${DATACYALIAS}mac`,
|
||||
},
|
||||
{
|
||||
text: BRIDGE && `BRIDGE - ${BRIDGE}`,
|
||||
dataCy: `${DATACYALIAS}bridge`,
|
||||
},
|
||||
].filter(({ text } = {}) => Boolean(text))
|
||||
|
||||
return (
|
||||
<Row key={NIC_ID} data-cy={`${DATACYALIAS}${NIC_ID}`}>
|
||||
<Typography
|
||||
noWrap
|
||||
variant="body2"
|
||||
data-cy={`${DATACYALIAS}name`}
|
||||
>
|
||||
<Translate word={T.Alias} />
|
||||
{`${NIC_ID} | ${NETWORK}`}
|
||||
</Typography>
|
||||
<Labels>
|
||||
<MultipleTags
|
||||
clipboard
|
||||
limitTags={isMobile ? 1 : 3}
|
||||
tags={tags}
|
||||
/>
|
||||
</Labels>
|
||||
{!isMobile && !isPciDevice && detachAction(NIC_ID, true)}
|
||||
</Row>
|
||||
)
|
||||
})}
|
||||
{!!SECURITY_GROUPS?.length && (
|
||||
<SecGroups variant="outlined">
|
||||
<Typography variant="body1">
|
||||
@ -172,6 +212,7 @@ const NetworkItem = ({ nic = {}, actions }) => {
|
||||
(
|
||||
{
|
||||
ID,
|
||||
SECURITY_GROUP_ID,
|
||||
NAME,
|
||||
PROTOCOL,
|
||||
RULE_TYPE,
|
||||
@ -180,25 +221,51 @@ const NetworkItem = ({ nic = {}, actions }) => {
|
||||
NETWORK_ID,
|
||||
},
|
||||
idx
|
||||
) => (
|
||||
<Row key={`${idx}-${NAME}`}>
|
||||
<Typography noWrap variant="body2">
|
||||
{`${ID} | ${NAME}`}
|
||||
</Typography>
|
||||
<Labels>
|
||||
<MultipleTags
|
||||
limitTags={isMobile ? 2 : 5}
|
||||
tags={[
|
||||
PROTOCOL,
|
||||
RULE_TYPE,
|
||||
RANGE,
|
||||
NETWORK_ID,
|
||||
ICMP_TYPE,
|
||||
].filter(Boolean)}
|
||||
/>
|
||||
</Labels>
|
||||
</Row>
|
||||
)
|
||||
) => {
|
||||
const tags = [
|
||||
{
|
||||
text: PROTOCOL,
|
||||
dataCy: `${DATACYSECURITY}protocol`,
|
||||
},
|
||||
{
|
||||
text: RULE_TYPE,
|
||||
dataCy: `${DATACYSECURITY}ruletype`,
|
||||
},
|
||||
{
|
||||
text: RANGE,
|
||||
dataCy: `${DATACYSECURITY}range`,
|
||||
},
|
||||
{
|
||||
text: NETWORK_ID,
|
||||
dataCy: `${DATACYSECURITY}networkid`,
|
||||
},
|
||||
{
|
||||
text: ICMP_TYPE,
|
||||
dataCy: `${DATACYSECURITY}icmp_type`,
|
||||
},
|
||||
].filter(({ text } = {}) => Boolean(text))
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={`${idx}-${NAME}`}
|
||||
data-cy={`${DATACYSECURITY}${idx}`}
|
||||
>
|
||||
<Typography
|
||||
noWrap
|
||||
variant="body2"
|
||||
data-cy={`${DATACYSECURITY}name`}
|
||||
>
|
||||
{`${ID} | ${NAME}`}
|
||||
</Typography>
|
||||
<Labels>
|
||||
<MultipleTags
|
||||
limitTags={isMobile ? 2 : 5}
|
||||
tags={tags}
|
||||
/>
|
||||
</Labels>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</SecGroups>
|
||||
)}
|
||||
|
@ -63,23 +63,42 @@ const StorageItem = ({ disk, actions = [] }) => {
|
||||
}[type]
|
||||
|
||||
const labels = [
|
||||
...new Set([
|
||||
TYPE,
|
||||
Helper.stringToBoolean(PERSISTENT) && 'PERSISTENT',
|
||||
Helper.stringToBoolean(READONLY) && 'READONLY',
|
||||
Helper.stringToBoolean(SAVE) && 'SAVE',
|
||||
Helper.stringToBoolean(CLONE) && 'CLONE',
|
||||
]),
|
||||
].filter(Boolean)
|
||||
{
|
||||
label: TYPE,
|
||||
dataCy: 'type',
|
||||
},
|
||||
{
|
||||
label: Helper.stringToBoolean(PERSISTENT) && 'PERSISTENT',
|
||||
dataCy: 'persistent',
|
||||
},
|
||||
{
|
||||
label: Helper.stringToBoolean(READONLY) && 'READONLY',
|
||||
dataCy: 'readonly',
|
||||
},
|
||||
{
|
||||
label: Helper.stringToBoolean(SAVE) && 'SAVE',
|
||||
dataCy: 'save',
|
||||
},
|
||||
{
|
||||
label: Helper.stringToBoolean(CLONE) && 'CLONE',
|
||||
dataCy: 'clone',
|
||||
},
|
||||
].filter(({ label } = {}) => Boolean(label))
|
||||
|
||||
return (
|
||||
<Paper variant="outlined" className={classes.root}>
|
||||
<Paper
|
||||
variant="outlined"
|
||||
className={classes.root}
|
||||
data-cy={`disk-${DISK_ID}`}
|
||||
>
|
||||
<div className={classes.main}>
|
||||
<div className={classes.title}>
|
||||
<Typography component="span">{image}</Typography>
|
||||
<Typography component="span" data-cy={'name'}>
|
||||
{image}
|
||||
</Typography>
|
||||
<span className={classes.labels}>
|
||||
{labels.map((label) => (
|
||||
<StatusChip key={label} text={label} />
|
||||
{labels.map(({ label, dataCy }) => (
|
||||
<StatusChip key={label} text={label} dataCy={dataCy} />
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
@ -88,18 +107,18 @@ const StorageItem = ({ disk, actions = [] }) => {
|
||||
{TARGET && (
|
||||
<span title={`Target: ${TARGET}`}>
|
||||
<DatabaseSettings />
|
||||
<span>{` ${TARGET}`}</span>
|
||||
<span data-cy={'target'}>{` ${TARGET}`}</span>
|
||||
</span>
|
||||
)}
|
||||
{DATASTORE && (
|
||||
<span title={`Datastore Name: ${DATASTORE}`}>
|
||||
<Folder />
|
||||
<span>{` ${DATASTORE}`}</span>
|
||||
<span data-cy={'datastore'}>{` ${DATASTORE}`}</span>
|
||||
</span>
|
||||
)}
|
||||
<span title={`Monitor Size / Disk Size: ${monitorSize}/${size}`}>
|
||||
<ModernTv />
|
||||
<span>{` ${monitorSize}/${size}`}</span>
|
||||
<span data-cy={'monitorsize'}>{` ${monitorSize}/${size}`}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -81,6 +81,7 @@ const Tabs = ({
|
||||
icon={error ? <WarningIcon /> : Icon && <Icon />}
|
||||
value={value ?? idx}
|
||||
label={label ?? name}
|
||||
data-cy={`tab-${name}`}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
|
@ -33,10 +33,11 @@ function VirtualMachines() {
|
||||
<VmsTable
|
||||
onSelectedRowsChange={onSelectedRowsChange}
|
||||
globalActions={actions}
|
||||
rootProps={{ 'data-cy': 'vms' }}
|
||||
/>
|
||||
|
||||
{selectedRows?.length > 0 && (
|
||||
<Stack overflow="auto">
|
||||
<Stack overflow="auto" data-cy={'detail'}>
|
||||
{selectedRows?.length === 1 ? (
|
||||
<VmTabs id={selectedRows[0]?.values.ID} />
|
||||
) : (
|
||||
|
Loading…
x
Reference in New Issue
Block a user