mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-29 18:50:08 +03:00
OpenNebula/one#6124: ACL tab (#2879)
This commit is contained in:
parent
547d1c4fdd
commit
34e3698d5c
@ -42,6 +42,7 @@ import {
|
||||
Shuffle as VRoutersIcons,
|
||||
ModernTv as VmsIcons,
|
||||
MinusPinAlt as ZoneIcon,
|
||||
KeyAlt as ACLIcon,
|
||||
} from 'iconoir-react'
|
||||
|
||||
import loadable from '@loadable/component'
|
||||
@ -261,7 +262,10 @@ const BackupJobsCreate = loadable(
|
||||
}
|
||||
)
|
||||
|
||||
// const ACLs = loadable(() => import('client/containers/ACLs'), { ssr: false })
|
||||
const ACLs = loadable(() => import('client/containers/ACLs'), { ssr: false })
|
||||
const CreateACLs = loadable(() => import('client/containers/ACLs/Create'), {
|
||||
ssr: false,
|
||||
})
|
||||
|
||||
export const PATH = {
|
||||
INSTANCE: {
|
||||
@ -381,6 +385,10 @@ export const PATH = {
|
||||
DETAIL: `/${RESOURCE_NAMES.VDC}/:id`,
|
||||
CREATE: `/${RESOURCE_NAMES.VDC}/create`,
|
||||
},
|
||||
ACLS: {
|
||||
LIST: `/${RESOURCE_NAMES.ACL}`,
|
||||
CREATE: `/${RESOURCE_NAMES.ACL}/create`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -771,6 +779,18 @@ const ENDPOINTS = [
|
||||
path: PATH.SYSTEM.VDCS.DETAIL,
|
||||
Component: VDCDetail,
|
||||
},
|
||||
{
|
||||
title: T.ACLs,
|
||||
path: PATH.SYSTEM.ACLS.CREATE,
|
||||
Component: CreateACLs,
|
||||
},
|
||||
{
|
||||
title: T.ACLs,
|
||||
path: PATH.SYSTEM.ACLS.LIST,
|
||||
sidebar: true,
|
||||
icon: ACLIcon,
|
||||
Component: ACLs,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
130
src/fireedge/src/client/components/Cards/ACLCards/ACLCardCLI.js
Normal file
130
src/fireedge/src/client/components/Cards/ACLCards/ACLCardCLI.js
Normal file
@ -0,0 +1,130 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { Component } from 'react'
|
||||
|
||||
import { ACL_USERS } from 'client/constants'
|
||||
|
||||
import { rowStyles } from 'client/components/Tables/styles'
|
||||
|
||||
/**
|
||||
* ACLCardIcon component to display ACL details.
|
||||
*
|
||||
* @param {object} props - Component props
|
||||
* @param {object} props.acl - ACL details
|
||||
* @param {object} props.rootProps - Additional props for the root element
|
||||
* @returns {Component} UserCard component
|
||||
*/
|
||||
const ACLCardIcon = ({ acl, rootProps }) => {
|
||||
const {
|
||||
ID,
|
||||
idUserId,
|
||||
idUserType,
|
||||
resources,
|
||||
idResourceId,
|
||||
idResourceType,
|
||||
rights,
|
||||
zoneId,
|
||||
zoneType,
|
||||
} = acl
|
||||
|
||||
// Row styles
|
||||
const classes = rowStyles()
|
||||
|
||||
return (
|
||||
<div {...rootProps} data-cy={`acl-${ID}`}>
|
||||
<div className={classes.main}>
|
||||
<div
|
||||
className={classes.title}
|
||||
style={{ display: 'flex', width: '100%' }}
|
||||
>
|
||||
<div style={{ flex: '10%' }} data-cy="acl-card-user">
|
||||
<span>
|
||||
{ACL_USERS[idUserType].id}
|
||||
{idUserId}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ flex: '25%' }} data-cy="acl-card-resources">
|
||||
{resources.includes('VM') ? 'V' : '-'}
|
||||
{resources.includes('HOST') ? 'H' : '-'}
|
||||
{resources.includes('NET') ? 'N' : '-'}
|
||||
{resources.includes('IMAGE') ? 'I' : '-'}
|
||||
{resources.includes('USER') ? 'U' : '-'}
|
||||
{resources.includes('TEMPLATE') ? 'T' : '-'}
|
||||
{resources.includes('GROUP') ? 'G' : '-'}
|
||||
{resources.includes('DATASTORE') ? 'D' : '-'}
|
||||
{resources.includes('CLUSTER') ? 'C' : '-'}
|
||||
{resources.includes('DOCUMENT') ? 'O' : '-'}
|
||||
{resources.includes('ZONE') ? 'Z' : '-'}
|
||||
{resources.includes('SECGROUP') ? 'S' : '-'}
|
||||
{resources.includes('VDC') ? 'v' : '-'}
|
||||
{resources.includes('VROUTER') ? 'R' : '-'}
|
||||
{resources.includes('MARKETPLACE') ? 'M' : '-'}
|
||||
{resources.includes('MARKETPLACEAPP') ? 'A' : '-'}
|
||||
{resources.includes('VMGROUP') ? 'P' : '-'}
|
||||
{resources.includes('VNTEMPLATE') ? 't' : '-'}
|
||||
{resources.includes('BACKUPJOB') ? 'B' : '-'}
|
||||
</div>
|
||||
<div style={{ flex: '10%' }} data-cy="acl-card-resourcesIdentifier">
|
||||
<span>
|
||||
{ACL_USERS[idResourceType].id}
|
||||
{idResourceId}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ flex: '10%' }} data-cy="acl-card-rights">
|
||||
{rights.includes('USE') ? 'u' : '-'}
|
||||
{rights.includes('MANAGE') ? 'm' : '-'}
|
||||
{rights.includes('ADMIN') ? 'a' : '-'}
|
||||
{rights.includes('CREATE') ? 'c' : '-'}
|
||||
</div>
|
||||
<div style={{ flex: '10%' }} data-cy="acl-card-zone">
|
||||
<span>
|
||||
{ACL_USERS[zoneType].id}
|
||||
{zoneId}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span data-cy="acl-card-id">{`#${ID}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ACLCardIcon.propTypes = {
|
||||
acl: PropTypes.shape({
|
||||
ID: PropTypes.string.isRequired,
|
||||
idUserId: PropTypes.string.isRequired,
|
||||
idUserName: PropTypes.string,
|
||||
idUserType: PropTypes.string.isRequired,
|
||||
resources: PropTypes.array.isRequired,
|
||||
idResourceId: PropTypes.string,
|
||||
idResourceName: PropTypes.string,
|
||||
idResourceType: PropTypes.string.isRequired,
|
||||
rights: PropTypes.array.isRequired,
|
||||
zoneId: PropTypes.string,
|
||||
zoneName: PropTypes.string,
|
||||
zoneType: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
rootProps: PropTypes.shape({
|
||||
className: PropTypes.string,
|
||||
}),
|
||||
}
|
||||
|
||||
ACLCardIcon.displayName = 'ACLCardIcon'
|
||||
|
||||
export default ACLCardIcon
|
@ -0,0 +1,447 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 {
|
||||
Server as ClusterIcon,
|
||||
Db as DatastoreIcon,
|
||||
Folder as VmGroupIcon,
|
||||
Group as GroupIcon,
|
||||
HardDrive as HostIcon,
|
||||
BoxIso as ImageIcon,
|
||||
CloudDownload as MarketplaceAppIcon,
|
||||
SimpleCart as MarketplaceIcon,
|
||||
NetworkAlt as NetworkIcon,
|
||||
HistoricShield as SecurityGroupIcon,
|
||||
Packages as ServicesIcon,
|
||||
EmptyPage as TemplateIcon,
|
||||
User as UserIcon,
|
||||
List as VDCIcon,
|
||||
Shuffle as VRoutersIcons,
|
||||
ModernTv as VmsIcons,
|
||||
MinusPinAlt as ZoneIcon,
|
||||
Globe as AllIcon,
|
||||
ClockOutline as BackupJobsIcon,
|
||||
} from 'iconoir-react'
|
||||
|
||||
import PropTypes from 'prop-types'
|
||||
import { Component } from 'react'
|
||||
import { Typography, Tooltip } from '@mui/material'
|
||||
|
||||
import { ACL_USERS, T } from 'client/constants'
|
||||
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { rowStyles } from 'client/components/Tables/styles'
|
||||
import { aclStyles } from 'client/components/Cards/ACLCards/styles'
|
||||
|
||||
/**
|
||||
* ACLCardIcon component to display ACL details.
|
||||
*
|
||||
* @param {object} props - Component props
|
||||
* @param {object} props.acl - ACL details
|
||||
* @param {object} props.rootProps - Additional props for the root element
|
||||
* @returns {Component} UserCard component
|
||||
*/
|
||||
const ACLCardIcon = ({ acl, rootProps }) => {
|
||||
const {
|
||||
ID,
|
||||
idUserName,
|
||||
idUserType,
|
||||
resources,
|
||||
idResourceId,
|
||||
idResourceName,
|
||||
idResourceType,
|
||||
rights,
|
||||
zoneName,
|
||||
zoneType,
|
||||
} = acl
|
||||
|
||||
// Row styles
|
||||
const classes = rowStyles()
|
||||
|
||||
// ACL card styles
|
||||
const aclClasses = aclStyles()
|
||||
|
||||
return (
|
||||
<div {...rootProps} data-cy={`acl-${ID}`}>
|
||||
<div className={classes.main}>
|
||||
<div className={`${classes.title}`}>
|
||||
<Typography noWrap component="span" data-cy="acl-card-icons">
|
||||
<Tooltip title={Tr(T.VMs)}>
|
||||
<VmsIcons
|
||||
data-cy="acl-card-icon-VM"
|
||||
className={
|
||||
resources.includes('VM')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Hosts)}>
|
||||
<HostIcon
|
||||
data-cy="acl-card-icon-HOST"
|
||||
className={
|
||||
resources.includes('HOST')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Networks)}>
|
||||
<NetworkIcon
|
||||
data-cy="acl-card-icon-NET"
|
||||
className={
|
||||
resources.includes('NET')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Images)}>
|
||||
<ImageIcon
|
||||
data-cy="acl-card-icon-IMAGE"
|
||||
className={
|
||||
resources.includes('IMAGE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Users)}>
|
||||
<UserIcon
|
||||
data-cy="acl-card-icon-USER"
|
||||
className={
|
||||
resources.includes('USER')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Templates)}>
|
||||
<TemplateIcon
|
||||
data-cy="acl-card-icon-TEMPLATE"
|
||||
className={
|
||||
resources.includes('TEMPLATE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Groups)}>
|
||||
<GroupIcon
|
||||
data-cy="acl-card-icon-GROUP"
|
||||
className={
|
||||
resources.includes('GROUP')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Datastores)}>
|
||||
<DatastoreIcon
|
||||
data-cy="acl-card-icon-DATASTORE"
|
||||
className={
|
||||
resources.includes('DATASTORE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Clusters)}>
|
||||
<ClusterIcon
|
||||
data-cy="acl-card-icon-CLUSTER"
|
||||
className={
|
||||
resources.includes('CLUSTER')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Services)}>
|
||||
<ServicesIcon
|
||||
data-cy="acl-card-icon-DOCUMENT"
|
||||
className={
|
||||
resources.includes('DOCUMENT')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Zones)}>
|
||||
<ZoneIcon
|
||||
data-cy="acl-card-icon-ZONE"
|
||||
className={
|
||||
resources.includes('ZONE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.SecurityGroups)}>
|
||||
<SecurityGroupIcon
|
||||
data-cy="acl-card-icon-SECGROUP"
|
||||
className={
|
||||
resources.includes('SECGROUP')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.VDCs)}>
|
||||
<VDCIcon
|
||||
data-cy="acl-card-icon-VDC"
|
||||
className={
|
||||
resources.includes('VDC')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.VirtualRouters)}>
|
||||
<VRoutersIcons
|
||||
data-cy="acl-card-icon-VROUTER"
|
||||
className={
|
||||
resources.includes('VROUTER')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Marketplaces)}>
|
||||
<MarketplaceAppIcon
|
||||
data-cy="acl-card-icon-MARKETPLACE"
|
||||
className={
|
||||
resources.includes('MARKETPLACE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.Apps)}>
|
||||
<MarketplaceIcon
|
||||
data-cy="acl-card-icon-MARKETPLACEAPP"
|
||||
className={
|
||||
resources.includes('MARKETPLACEAPP')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.VMGroups)}>
|
||||
<VmGroupIcon
|
||||
data-cy="acl-card-icon-VMGROUP"
|
||||
className={
|
||||
resources.includes('VMGROUP')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.NetworkTemplates)}>
|
||||
<TemplateIcon
|
||||
data-cy="acl-card-icon-VNTEMPLATE"
|
||||
className={
|
||||
resources.includes('VNTEMPLATE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={Tr(T.BackupJob)}>
|
||||
<BackupJobsIcon
|
||||
data-cy="acl-card-icon-BACKUPJOB"
|
||||
className={
|
||||
resources.includes('BACKUPJOB')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span data-cy="acl-card-id">{`#${ID}`}</span>
|
||||
{idResourceType === ACL_USERS.INDIVIDUAL.type && (
|
||||
<Tooltip
|
||||
title={Tr([
|
||||
T['acls.table.card.resources.individual.tooltip'],
|
||||
idResourceId,
|
||||
])}
|
||||
>
|
||||
<span>
|
||||
<span data-cy="acl-card-resourcesIdentifier">
|
||||
{Tr(T.Identifier)} #{idResourceId}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idResourceType === ACL_USERS.GROUP.type && (
|
||||
<Tooltip
|
||||
title={Tr([
|
||||
T['acls.table.card.resources.group.tooltip'],
|
||||
idResourceName,
|
||||
])}
|
||||
>
|
||||
<span>
|
||||
<GroupIcon />
|
||||
<span data-cy="acl-card-resourcesIdentifier">
|
||||
{idResourceName}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idResourceType === ACL_USERS.CLUSTER.type && (
|
||||
<Tooltip
|
||||
title={Tr([
|
||||
T['acls.table.card.resources.cluster.tooltip'],
|
||||
idResourceName,
|
||||
])}
|
||||
>
|
||||
<span>
|
||||
<ClusterIcon />
|
||||
<span data-cy="acl-card-resourcesIdentifier">
|
||||
{idResourceName}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idResourceType === ACL_USERS.ALL.type && (
|
||||
<Tooltip title={Tr([T['acls.table.card.resources.all.tooltip']])}>
|
||||
<span>
|
||||
<AllIcon />
|
||||
<span data-cy="acl-card-resourcesIdentifier">{Tr(T.All)}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={aclClasses.contentWrapper}>
|
||||
<div className={classes.caption}>
|
||||
{idUserType === ACL_USERS.INDIVIDUAL.type && (
|
||||
<Tooltip
|
||||
title={Tr([T['acls.table.card.rule.user.tooltip'], idUserName])}
|
||||
>
|
||||
<span>
|
||||
<UserIcon />
|
||||
<span data-cy="acl-card-user">{idUserName}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idUserType === ACL_USERS.GROUP.type && (
|
||||
<Tooltip
|
||||
title={Tr([T['acls.table.card.rule.group.tooltip'], idUserName])}
|
||||
>
|
||||
<span>
|
||||
<GroupIcon />
|
||||
<span data-cy="acl-card-user">{idUserName}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idUserType === ACL_USERS.ALL.type && (
|
||||
<Tooltip title={Tr([T['acls.table.card.rule.all.tooltip']])}>
|
||||
<span>
|
||||
<AllIcon />
|
||||
<span data-cy="acl-card-user">{Tr(T.All)}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
{zoneType === ACL_USERS.INDIVIDUAL.type && (
|
||||
<Tooltip
|
||||
title={Tr([T['acls.table.card.rule.zone.tooltip'], zoneName])}
|
||||
>
|
||||
<span>
|
||||
<ZoneIcon />
|
||||
<span data-cy="acl-card-zone">{zoneName}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{zoneType === ACL_USERS.ALL.type && (
|
||||
<Tooltip title={Tr([T['acls.table.card.rule.zone.tooltip.all']])}>
|
||||
<span>
|
||||
<ZoneIcon />
|
||||
<span data-cy="acl-card-zone">{Tr(T.All)}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.caption} data-cy="acl-card-rights">
|
||||
<span
|
||||
data-cy="acl-card-rights-USE"
|
||||
className={
|
||||
rights.includes('USE')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Use)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-rights-MANAGE"
|
||||
className={
|
||||
rights.includes('MANAGE')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Manage)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-rights-ADMIN"
|
||||
className={
|
||||
rights.includes('ADMIN')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Admin)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-rights-CREATE"
|
||||
className={
|
||||
rights.includes('CREATE')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Create)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ACLCardIcon.propTypes = {
|
||||
acl: PropTypes.shape({
|
||||
ID: PropTypes.string.isRequired,
|
||||
idUserName: PropTypes.string,
|
||||
idUserType: PropTypes.string.isRequired,
|
||||
resources: PropTypes.array.isRequired,
|
||||
idResourceId: PropTypes.string,
|
||||
idResourceName: PropTypes.string,
|
||||
idResourceType: PropTypes.string.isRequired,
|
||||
rights: PropTypes.array.isRequired,
|
||||
zoneName: PropTypes.string,
|
||||
zoneType: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
rootProps: PropTypes.shape({
|
||||
className: PropTypes.string,
|
||||
}),
|
||||
}
|
||||
|
||||
ACLCardIcon.displayName = 'ACLCardIcon'
|
||||
|
||||
export default ACLCardIcon
|
@ -0,0 +1,432 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 {
|
||||
Server as ClusterIcon,
|
||||
Group as GroupIcon,
|
||||
User as UserIcon,
|
||||
MinusPinAlt as ZoneIcon,
|
||||
Globe as AllIcon,
|
||||
} from 'iconoir-react'
|
||||
|
||||
import PropTypes from 'prop-types'
|
||||
import { Component } from 'react'
|
||||
import { Tooltip } from '@mui/material'
|
||||
|
||||
import { ACL_USERS, T } from 'client/constants'
|
||||
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { rowStyles } from 'client/components/Tables/styles'
|
||||
import { aclStyles } from 'client/components/Cards/ACLCards/styles'
|
||||
|
||||
/**
|
||||
* ACLCardNames component to display ACL details.
|
||||
*
|
||||
* @param {object} props - Component props
|
||||
* @param {object} props.acl - ACL details
|
||||
* @param {object} props.rootProps - Additional props for the root element
|
||||
* @returns {Component} UserCard component
|
||||
*/
|
||||
const ACLCardNames = ({ acl, rootProps }) => {
|
||||
const {
|
||||
ID,
|
||||
idUserName,
|
||||
idUserType,
|
||||
resources,
|
||||
idResourceId,
|
||||
idResourceName,
|
||||
idResourceType,
|
||||
rights,
|
||||
zoneName,
|
||||
zoneType,
|
||||
} = acl
|
||||
|
||||
// Row styles
|
||||
const classes = rowStyles()
|
||||
|
||||
// ACL card styles
|
||||
const aclClasses = aclStyles()
|
||||
|
||||
return (
|
||||
<div {...rootProps} data-cy={`acl-${ID}`}>
|
||||
<div className={classes.main}>
|
||||
<div className={`${classes.caption}`} data-cy="acl-card-names">
|
||||
<span
|
||||
data-cy="acl-card-name-VM"
|
||||
className={
|
||||
resources.includes('VM')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.VMs)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-HOST"
|
||||
className={
|
||||
resources.includes('HOST')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Hosts)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-NET"
|
||||
className={
|
||||
resources.includes('NET')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Networks)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-IMAGE"
|
||||
className={
|
||||
resources.includes('IMAGE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Images)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-USER"
|
||||
className={
|
||||
resources.includes('USER')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Users)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-TEMPLATE"
|
||||
className={
|
||||
resources.includes('TEMPLATE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Templates)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-GROUP"
|
||||
className={
|
||||
resources.includes('GROUP')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Groups)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-DATASTORE"
|
||||
className={
|
||||
resources.includes('DATASTORE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Datastores)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-CLUSTER"
|
||||
className={
|
||||
resources.includes('CLUSTER')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Clusters)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-DOCUMENT"
|
||||
className={
|
||||
resources.includes('DOCUMENT')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Services)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-ZONE"
|
||||
className={
|
||||
resources.includes('ZONE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Zones)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-SECGROUP"
|
||||
className={
|
||||
resources.includes('SECGROUP')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.SecurityGroups)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-VDC"
|
||||
className={
|
||||
resources.includes('VDC')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.VDCs)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-VROUTER"
|
||||
className={
|
||||
resources.includes('VROUTER')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.VirtualRouters)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-MARKETPLACE"
|
||||
className={
|
||||
resources.includes('MARKETPLACE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Apps)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-MARKETPLACEAPP"
|
||||
className={
|
||||
resources.includes('MARKETPLACEAPP')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Marketplaces)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-VMGROUP"
|
||||
className={
|
||||
resources.includes('VMGROUP')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.VMGroups)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-VNTEMPLATE"
|
||||
className={
|
||||
resources.includes('VNTEMPLATE')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.NetworkTemplates)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-name-BACKUPJOB"
|
||||
className={
|
||||
resources.includes('BACKUPJOB')
|
||||
? aclClasses.aclApplies
|
||||
: aclClasses.aclNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.BackupJob)}
|
||||
</span>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span data-cy="acl-card-id">{`#${ID}`}</span>
|
||||
|
||||
{idResourceType === ACL_USERS.INDIVIDUAL.type && (
|
||||
<Tooltip
|
||||
title={Tr([
|
||||
T['acls.table.card.resources.individual.tooltip'],
|
||||
idResourceId,
|
||||
])}
|
||||
>
|
||||
<span>
|
||||
<span data-cy="acl-card-resourcesIdentifier">
|
||||
{Tr(T.Identifier)} #{idResourceId}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idResourceType === ACL_USERS.GROUP.type && (
|
||||
<Tooltip
|
||||
title={Tr([
|
||||
T['acls.table.card.resources.group.tooltip'],
|
||||
idResourceName,
|
||||
])}
|
||||
>
|
||||
<span>
|
||||
<GroupIcon />
|
||||
<span data-cy="acl-card-resourcesIdentifier">
|
||||
{idResourceName}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idResourceType === ACL_USERS.CLUSTER.type && (
|
||||
<Tooltip
|
||||
title={Tr([
|
||||
T['acls.table.card.resources.cluster.tooltip'],
|
||||
idResourceName,
|
||||
])}
|
||||
>
|
||||
<span>
|
||||
<ClusterIcon />
|
||||
<span data-cy="acl-card-resourcesIdentifier">
|
||||
{idResourceName}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idResourceType === ACL_USERS.ALL.type && (
|
||||
<Tooltip title={Tr([T['acls.table.card.resources.all.tooltip']])}>
|
||||
<span>
|
||||
<AllIcon />
|
||||
<span>{Tr(T.All)}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={aclClasses.contentWrapper}>
|
||||
<div className={classes.caption}>
|
||||
{idUserType === ACL_USERS.INDIVIDUAL.type && (
|
||||
<Tooltip
|
||||
title={Tr([T['acls.table.card.rule.user.tooltip'], idUserName])}
|
||||
>
|
||||
<span>
|
||||
<UserIcon />
|
||||
<span data-cy="acl-card-user">{idUserName}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idUserType === ACL_USERS.GROUP.type && (
|
||||
<Tooltip
|
||||
title={Tr([T['acls.table.card.rule.group.tooltip'], idUserName])}
|
||||
>
|
||||
<span>
|
||||
<GroupIcon />
|
||||
<span data-cy="acl-card-user">{idUserName}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idUserType === ACL_USERS.ALL.type && (
|
||||
<Tooltip title={Tr([T['acls.table.card.rule.all.tooltip']])}>
|
||||
<span>
|
||||
<AllIcon />
|
||||
<span data-cy="acl-card-user">{Tr(T.All)}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
{zoneType === ACL_USERS.INDIVIDUAL.type && (
|
||||
<Tooltip
|
||||
title={Tr([T['acls.table.card.rule.zone.tooltip'], zoneName])}
|
||||
>
|
||||
<span>
|
||||
<ZoneIcon />
|
||||
<span data-cy="acl-card-zone">{zoneName}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{zoneType === ACL_USERS.ALL.type && (
|
||||
<Tooltip title={Tr([T['acls.table.card.rule.zone.tooltip.all']])}>
|
||||
<span>
|
||||
<ZoneIcon />
|
||||
<span data-cy="acl-card-zone">{Tr(T.All)}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.caption} data-cy="acl-card-rights">
|
||||
<span
|
||||
data-cy="acl-card-rights-USE"
|
||||
className={
|
||||
rights.includes('USE')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Use)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-rights-MANAGE"
|
||||
className={
|
||||
rights.includes('MANAGE')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Manage)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-rights-ADMIN"
|
||||
className={
|
||||
rights.includes('ADMIN')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Admin)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-rights-CREATE"
|
||||
className={
|
||||
rights.includes('CREATE')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Create)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ACLCardNames.propTypes = {
|
||||
acl: PropTypes.shape({
|
||||
ID: PropTypes.string.isRequired,
|
||||
idUserName: PropTypes.string,
|
||||
idUserType: PropTypes.string.isRequired,
|
||||
resources: PropTypes.array.isRequired,
|
||||
idResourceId: PropTypes.string,
|
||||
idResourceName: PropTypes.string,
|
||||
idResourceType: PropTypes.string.isRequired,
|
||||
rights: PropTypes.array.isRequired,
|
||||
zoneName: PropTypes.string,
|
||||
zoneType: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
rootProps: PropTypes.shape({
|
||||
className: PropTypes.string,
|
||||
}),
|
||||
}
|
||||
|
||||
ACLCardNames.displayName = 'ACLCardNames'
|
||||
|
||||
export default ACLCardNames
|
@ -0,0 +1,63 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { Component } from 'react'
|
||||
import { rowStyles } from 'client/components/Tables/styles'
|
||||
|
||||
import { translateACL } from 'client/models/ACL'
|
||||
|
||||
/**
|
||||
* ACLCardReadableRule component to display ACL details.
|
||||
*
|
||||
* @param {object} props - Component props
|
||||
* @param {object} props.acl - ACL details
|
||||
* @param {object} props.rootProps - Additional props for the root element
|
||||
* @returns {Component} UserCard component
|
||||
*/
|
||||
const ACLCardReadableRule = ({ acl, rootProps }) => {
|
||||
const { ID, STRING } = acl
|
||||
|
||||
// Row styles
|
||||
const classes = rowStyles()
|
||||
|
||||
return (
|
||||
<div {...rootProps} data-cy={`acl-${ID}`}>
|
||||
<div className={classes.main}>
|
||||
<div className={classes.title}>
|
||||
<span data-cy="acl-card-readable">{translateACL(STRING)}</span>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span data-cy="acl-card-id">{`#${ID}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ACLCardReadableRule.propTypes = {
|
||||
acl: PropTypes.shape({
|
||||
ID: PropTypes.string.isRequired,
|
||||
STRING: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
rootProps: PropTypes.shape({
|
||||
className: PropTypes.string,
|
||||
}),
|
||||
}
|
||||
|
||||
ACLCardReadableRule.displayName = 'ACLCardCLI'
|
||||
|
||||
export default ACLCardReadableRule
|
@ -0,0 +1,410 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 {
|
||||
Server as ClusterIcon,
|
||||
Db as DatastoreIcon,
|
||||
Folder as VmGroupIcon,
|
||||
Group as GroupIcon,
|
||||
HardDrive as HostIcon,
|
||||
BoxIso as ImageIcon,
|
||||
CloudDownload as MarketplaceAppIcon,
|
||||
SimpleCart as MarketplaceIcon,
|
||||
NetworkAlt as NetworkIcon,
|
||||
HistoricShield as SecurityGroupIcon,
|
||||
Packages as ServicesIcon,
|
||||
EmptyPage as TemplateIcon,
|
||||
User as UserIcon,
|
||||
List as VDCIcon,
|
||||
Shuffle as VRoutersIcons,
|
||||
ModernTv as VmsIcons,
|
||||
MinusPinAlt as ZoneIcon,
|
||||
Globe as AllIcon,
|
||||
ClockOutline as BackupJobsIcon,
|
||||
} from 'iconoir-react'
|
||||
|
||||
import PropTypes from 'prop-types'
|
||||
import { Component } from 'react'
|
||||
import { Typography, Tooltip } from '@mui/material'
|
||||
|
||||
import { ACL_USERS, T } from 'client/constants'
|
||||
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { rowStyles } from 'client/components/Tables/styles'
|
||||
import { aclStyles } from 'client/components/Cards/ACLCards/styles'
|
||||
|
||||
/**
|
||||
* ACLCardIcon component to display ACL details.
|
||||
*
|
||||
* @param {object} props - Component props
|
||||
* @param {object} props.acl - ACL details
|
||||
* @param {object} props.rootProps - Additional props for the root element
|
||||
* @returns {Component} UserCard component
|
||||
*/
|
||||
const ACLCardIcon = ({ acl, rootProps }) => {
|
||||
const {
|
||||
ID,
|
||||
idUserName,
|
||||
idUserType,
|
||||
resources,
|
||||
idResourceId,
|
||||
idResourceName,
|
||||
idResourceType,
|
||||
rights,
|
||||
zoneName,
|
||||
zoneType,
|
||||
} = acl
|
||||
|
||||
// Row styles
|
||||
const classes = rowStyles()
|
||||
|
||||
// ACL card styles
|
||||
const aclClasses = aclStyles()
|
||||
|
||||
return (
|
||||
<div {...rootProps} data-cy={`acl-${ID}`}>
|
||||
<div className={classes.main}>
|
||||
<div className={`${classes.title}`}>
|
||||
<Typography noWrap component="span" data-cy="acl-card-icons">
|
||||
{resources.includes('VM') && (
|
||||
<Tooltip title={Tr(T.VMs)}>
|
||||
<VmsIcons
|
||||
data-cy="acl-card-icon-VM"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('HOST') && (
|
||||
<Tooltip title={Tr(T.Hosts)}>
|
||||
<HostIcon
|
||||
data-cy="acl-card-icon-HOST"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('NET') && (
|
||||
<Tooltip title={Tr(T.Networks)}>
|
||||
<NetworkIcon
|
||||
data-cy="acl-card-icon-NET"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('IMAGE') && (
|
||||
<Tooltip title={Tr(T.Images)}>
|
||||
<ImageIcon
|
||||
data-cy="acl-card-icon-IMAGE"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('USER') && (
|
||||
<Tooltip title={Tr(T.Users)}>
|
||||
<UserIcon
|
||||
data-cy="acl-card-icon-USER"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('TEMPLATE') && (
|
||||
<Tooltip title={Tr(T.Templates)}>
|
||||
<TemplateIcon
|
||||
data-cy="acl-card-icon-TEMPLATE"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('GROUP') && (
|
||||
<Tooltip title={Tr(T.Groups)}>
|
||||
<GroupIcon
|
||||
data-cy="acl-card-icon-GROUP"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('DATASTORE') && (
|
||||
<Tooltip title={Tr(T.Datastores)}>
|
||||
<DatastoreIcon
|
||||
data-cy="acl-card-icon-DATASTORE"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('CLUSTER') && (
|
||||
<Tooltip title={Tr(T.Clusters)}>
|
||||
<ClusterIcon
|
||||
data-cy="acl-card-icon-CLUSTER"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('DOCUMENT') && (
|
||||
<Tooltip title={Tr(T.Services)}>
|
||||
<ServicesIcon
|
||||
data-cy="acl-card-icon-DOCUMENT"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('ZONE') && (
|
||||
<Tooltip title={Tr(T.Zones)}>
|
||||
<ZoneIcon
|
||||
data-cy="acl-card-icon-ZONE"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('SECGROUP') && (
|
||||
<Tooltip title={Tr(T.SecurityGroups)}>
|
||||
<SecurityGroupIcon
|
||||
data-cy="acl-card-icon-SECGROUP"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('VDC') && (
|
||||
<Tooltip title={Tr(T.VDCs)}>
|
||||
<VDCIcon
|
||||
data-cy="acl-card-icon-VDC"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('VROUTER') && (
|
||||
<Tooltip title={Tr(T.VirtualRouters)}>
|
||||
<VRoutersIcons
|
||||
data-cy="acl-card-icon-VROUTER"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('MARKETPLACE') && (
|
||||
<Tooltip title={Tr(T.Marketplaces)}>
|
||||
<MarketplaceAppIcon
|
||||
data-cy="acl-card-icon-MARKETPLACE"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('MARKETPLACEAPP') && (
|
||||
<Tooltip title={Tr(T.Apps)}>
|
||||
<MarketplaceIcon
|
||||
data-cy="acl-card-icon-MARKETPLACEAPP"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('VMGROUP') && (
|
||||
<Tooltip title={Tr(T.VMGroups)}>
|
||||
<VmGroupIcon
|
||||
data-cy="acl-card-icon-VMGROUP"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('VNTEMPLATE') && (
|
||||
<Tooltip title={Tr(T.NetworkTemplates)}>
|
||||
<TemplateIcon
|
||||
data-cy="acl-card-icon-VNTEMPLATE"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{resources.includes('BACKUPJOB') && (
|
||||
<Tooltip title={Tr(T.BackupJob)}>
|
||||
<BackupJobsIcon
|
||||
data-cy="acl-card-icon-BACKUPJOB"
|
||||
className={aclClasses.aclApplies}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span data-cy="acl-card-id">{`#${ID}`}</span>
|
||||
|
||||
{idResourceType === ACL_USERS.INDIVIDUAL.type && (
|
||||
<Tooltip
|
||||
title={Tr([
|
||||
T['acls.table.card.resources.individual.tooltip'],
|
||||
idResourceId,
|
||||
])}
|
||||
>
|
||||
<span>
|
||||
<span data-cy="acl-card-resourcesIdentifier">
|
||||
{Tr(T.Identifier)} #{idResourceId}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idResourceType === ACL_USERS.GROUP.type && (
|
||||
<Tooltip
|
||||
title={Tr([
|
||||
T['acls.table.card.resources.group.tooltip'],
|
||||
idResourceName,
|
||||
])}
|
||||
>
|
||||
<span>
|
||||
<GroupIcon />
|
||||
<span data-cy="acl-card-resourcesIdentifier">
|
||||
{idResourceName}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idResourceType === ACL_USERS.CLUSTER.type && (
|
||||
<Tooltip
|
||||
title={Tr([
|
||||
T['acls.table.card.resources.cluster.tooltip'],
|
||||
idResourceName,
|
||||
])}
|
||||
>
|
||||
<span>
|
||||
<ClusterIcon />
|
||||
<span data-cy="acl-card-resourcesIdentifier">
|
||||
{idResourceName}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idResourceType === ACL_USERS.ALL.type && (
|
||||
<Tooltip title={Tr([T['acls.table.card.resources.all.tooltip']])}>
|
||||
<span>
|
||||
<AllIcon />
|
||||
<span data-cy="acl-card-resourcesIdentifier">{Tr(T.All)}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={aclClasses.contentWrapper}>
|
||||
<div className={classes.caption}>
|
||||
{idUserType === ACL_USERS.INDIVIDUAL.type && (
|
||||
<Tooltip
|
||||
title={Tr([T['acls.table.card.rule.user.tooltip'], idUserName])}
|
||||
>
|
||||
<span>
|
||||
<UserIcon />
|
||||
<span data-cy="acl-card-user">{idUserName}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idUserType === ACL_USERS.GROUP.type && (
|
||||
<Tooltip
|
||||
title={Tr([T['acls.table.card.rule.group.tooltip'], idUserName])}
|
||||
>
|
||||
<span>
|
||||
<GroupIcon />
|
||||
<span data-cy="acl-card-user">{idUserName}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{idUserType === ACL_USERS.ALL.type && (
|
||||
<Tooltip title={Tr([T['acls.table.card.rule.all.tooltip']])}>
|
||||
<span>
|
||||
<AllIcon />
|
||||
<span data-cy="acl-card-user">{Tr(T.All)}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
{zoneType === ACL_USERS.INDIVIDUAL.type && (
|
||||
<Tooltip
|
||||
title={Tr([T['acls.table.card.rule.zone.tooltip'], zoneName])}
|
||||
>
|
||||
<span>
|
||||
<ZoneIcon />
|
||||
<span data-cy="acl-card-zone">{zoneName}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{zoneType === ACL_USERS.ALL.type && (
|
||||
<Tooltip title={Tr([T['acls.table.card.rule.zone.tooltip.all']])}>
|
||||
<span>
|
||||
<ZoneIcon />
|
||||
<span data-cy="acl-card-zone">{Tr(T.All)}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.caption} data-cy="acl-card-rights">
|
||||
<span
|
||||
data-cy="acl-card-rights-USE"
|
||||
className={
|
||||
rights.includes('USE')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Use)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-rights-MANAGE"
|
||||
className={
|
||||
rights.includes('MANAGE')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Manage)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-rights-ADMIN"
|
||||
className={
|
||||
rights.includes('ADMIN')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Admin)}
|
||||
</span>
|
||||
<span
|
||||
data-cy="acl-card-rights-CREATE"
|
||||
className={
|
||||
rights.includes('CREATE')
|
||||
? aclClasses.rigthApplies
|
||||
: aclClasses.rigthNotApplies
|
||||
}
|
||||
>
|
||||
{Tr(T.Create)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ACLCardIcon.propTypes = {
|
||||
acl: PropTypes.shape({
|
||||
ID: PropTypes.string.isRequired,
|
||||
idUserName: PropTypes.string,
|
||||
idUserType: PropTypes.string.isRequired,
|
||||
resources: PropTypes.array.isRequired,
|
||||
idResourceId: PropTypes.string,
|
||||
idResourceName: PropTypes.string,
|
||||
idResourceType: PropTypes.string.isRequired,
|
||||
rights: PropTypes.array.isRequired,
|
||||
zoneName: PropTypes.string,
|
||||
zoneType: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
rootProps: PropTypes.shape({
|
||||
className: PropTypes.string,
|
||||
}),
|
||||
}
|
||||
|
||||
ACLCardIcon.displayName = 'ACLCardIcon'
|
||||
|
||||
export default ACLCardIcon
|
@ -0,0 +1,61 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { Component } from 'react'
|
||||
import { rowStyles } from 'client/components/Tables/styles'
|
||||
|
||||
/**
|
||||
* ACLCardCLI component to display ACL details.
|
||||
*
|
||||
* @param {object} props - Component props
|
||||
* @param {object} props.acl - ACL details
|
||||
* @param {object} props.rootProps - Additional props for the root element
|
||||
* @returns {Component} UserCard component
|
||||
*/
|
||||
const ACLCardCLI = ({ acl, rootProps }) => {
|
||||
const { ID, STRING } = acl
|
||||
|
||||
// Row styles
|
||||
const classes = rowStyles()
|
||||
|
||||
return (
|
||||
<div {...rootProps} data-cy={`acl-${ID}`}>
|
||||
<div className={classes.main}>
|
||||
<div className={classes.title}>
|
||||
<span data-cy="acl-card-string">{`${STRING}`}</span>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span data-cy="acl-card-id">{`#${ID}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ACLCardCLI.propTypes = {
|
||||
acl: PropTypes.shape({
|
||||
ID: PropTypes.string.isRequired,
|
||||
STRING: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
rootProps: PropTypes.shape({
|
||||
className: PropTypes.string,
|
||||
}),
|
||||
}
|
||||
|
||||
ACLCardCLI.displayName = 'ACLCardCLI'
|
||||
|
||||
export default ACLCardCLI
|
48
src/fireedge/src/client/components/Cards/ACLCards/styles.js
Normal file
48
src/fireedge/src/client/components/Cards/ACLCards/styles.js
Normal file
@ -0,0 +1,48 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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'
|
||||
import { SCHEMES } from 'client/constants'
|
||||
|
||||
export const aclStyles = makeStyles(({ palette }) => ({
|
||||
aclApplies: {
|
||||
margin: '0.2em',
|
||||
color: palette.mode === SCHEMES.LIGHT ? 'black' : 'white',
|
||||
},
|
||||
aclNotApplies: {
|
||||
margin: '0.2em',
|
||||
color: 'grey',
|
||||
},
|
||||
centeredContent: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'left',
|
||||
},
|
||||
rightContent: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'right',
|
||||
},
|
||||
rigthApplies: {
|
||||
color: palette.mode === SCHEMES.LIGHT ? 'black' : 'white',
|
||||
},
|
||||
rigthNotApplies: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-end',
|
||||
color: 'grey',
|
||||
},
|
||||
}))
|
@ -13,6 +13,12 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import ACLCardIcons from 'client/components/Cards/ACLCards/ACLCardIcons'
|
||||
import ACLCardNames from 'client/components/Cards/ACLCards/ACLCardNames'
|
||||
import ACLCardCLI from 'client/components/Cards/ACLCards/ACLCardCLI'
|
||||
import ACLCardResources from 'client/components/Cards/ACLCards/ACLCardResources'
|
||||
import ACLCardRule from 'client/components/Cards/ACLCards/ACLCardRule'
|
||||
import ACLCardReadableRule from 'client/components/Cards/ACLCards/ACLCardReadableRule'
|
||||
import AddressRangeCard from 'client/components/Cards/AddressRangeCard'
|
||||
import ApplicationCard from 'client/components/Cards/ApplicationCard'
|
||||
import ApplicationNetworkCard from 'client/components/Cards/ApplicationNetworkCard'
|
||||
@ -49,6 +55,12 @@ import VmTemplateCard from 'client/components/Cards/VmTemplateCard'
|
||||
import WavesCard from 'client/components/Cards/WavesCard'
|
||||
|
||||
export {
|
||||
ACLCardIcons,
|
||||
ACLCardNames,
|
||||
ACLCardCLI,
|
||||
ACLCardResources,
|
||||
ACLCardRule,
|
||||
ACLCardReadableRule,
|
||||
AddressRangeCard,
|
||||
ApplicationCard,
|
||||
ApplicationNetworkCard,
|
||||
|
@ -0,0 +1,68 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
import { T } from 'client/constants'
|
||||
import { SCHEMA, FIELDS } from './schema'
|
||||
import { Grid } from '@mui/material'
|
||||
import HelperACL from 'client/components/Forms/ACLs/CreateForm/Utils/helper'
|
||||
|
||||
export const STEP_ID = 'resources'
|
||||
|
||||
const Content = (users, groups, clusters, zones, version) => (
|
||||
<Grid mt={2} container>
|
||||
<Grid item xs={8}>
|
||||
<FormWithSchema id={STEP_ID} cy={`${STEP_ID}`} fields={FIELDS} />
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<HelperACL
|
||||
title={T['acls.form.create.resources.title']}
|
||||
text={T['acls.form.create.resources.info']}
|
||||
users={users}
|
||||
groups={groups}
|
||||
clusters={clusters}
|
||||
zones={zones}
|
||||
version={version}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
|
||||
/**
|
||||
* Resources ACL configuration.
|
||||
*
|
||||
* @param {object} props - Step props
|
||||
* @param {Array} props.users - List of users
|
||||
* @param {Array} props.groups - List of groups
|
||||
* @param {Array} props.clusters - List of clusters
|
||||
* @param {Array} props.zones - List of zones
|
||||
* @param {string} props.version - ONE version
|
||||
* @returns {object} Resources ACL configuration step
|
||||
*/
|
||||
const Resources = ({ users, groups, clusters, zones, version }) => ({
|
||||
id: STEP_ID,
|
||||
label: T['acls.form.create.resources.title'],
|
||||
resolver: SCHEMA,
|
||||
optionsValidate: { abortEarly: false },
|
||||
content: () => Content(users, groups, clusters, zones, version),
|
||||
})
|
||||
|
||||
Resources.propTypes = {
|
||||
data: PropTypes.object,
|
||||
setFormData: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Resources
|
@ -0,0 +1,196 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { INPUT_TYPES, T } from 'client/constants'
|
||||
import { getObjectSchemaFromFields } from 'client/utils'
|
||||
import { boolean } from 'yup'
|
||||
|
||||
const VM = {
|
||||
name: 'VM',
|
||||
label: T['acls.form.create.resources.vm'],
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const DOCUMENT = {
|
||||
name: 'DOCUMENT',
|
||||
label: T.Service,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const TEMPLATE = {
|
||||
name: 'TEMPLATE',
|
||||
label: T['acls.form.create.resources.vmtemplate'],
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const VMGROUP = {
|
||||
name: 'VMGROUP',
|
||||
label: T.VMGroup,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const DATASTORE = {
|
||||
name: 'DATASTORE',
|
||||
label: T.Datastore,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const IMAGE = {
|
||||
name: 'IMAGE',
|
||||
label: T.Image,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const MARKETPLACE = {
|
||||
name: 'MARKETPLACE',
|
||||
label: T.Marketplace,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const MARKETPLACEAPP = {
|
||||
name: 'MARKETPLACEAPP',
|
||||
label: T.Apps,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const BACKUPJOB = {
|
||||
name: 'BACKUPJOB',
|
||||
label: T.BackupJob,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const NET = {
|
||||
name: 'NET',
|
||||
label: T.VirtualNetwork,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const VNTEMPLATE = {
|
||||
name: 'VNTEMPLATE',
|
||||
label: T['acls.form.create.resources.vnettemplate'],
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const VROUTER = {
|
||||
name: 'VROUTER',
|
||||
label: T.VirtualRouter,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const SECURITY_GROUP = {
|
||||
name: 'SECGROUP',
|
||||
label: T.SecurityGroup,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const CLUSTER = {
|
||||
name: 'CLUSTER',
|
||||
label: T.Cluster,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const HOST = {
|
||||
name: 'HOST',
|
||||
label: T.Host,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const USER = {
|
||||
name: 'USER',
|
||||
label: T.User,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const GROUP = {
|
||||
name: 'GROUP',
|
||||
label: T.Group,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const VDC = {
|
||||
name: 'VDC',
|
||||
label: T.VDC,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const ZONE = {
|
||||
name: 'ZONE',
|
||||
label: T.Zone,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 4 },
|
||||
}
|
||||
|
||||
const FIELDS = [
|
||||
VM,
|
||||
DOCUMENT,
|
||||
TEMPLATE,
|
||||
VMGROUP,
|
||||
DATASTORE,
|
||||
IMAGE,
|
||||
MARKETPLACE,
|
||||
MARKETPLACEAPP,
|
||||
BACKUPJOB,
|
||||
NET,
|
||||
VNTEMPLATE,
|
||||
VROUTER,
|
||||
SECURITY_GROUP,
|
||||
CLUSTER,
|
||||
HOST,
|
||||
USER,
|
||||
GROUP,
|
||||
VDC,
|
||||
ZONE,
|
||||
]
|
||||
|
||||
const SCHEMA = getObjectSchemaFromFields(FIELDS)
|
||||
|
||||
export { SCHEMA, FIELDS }
|
@ -0,0 +1,68 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
import { T } from 'client/constants'
|
||||
import { SCHEMA, FIELDS } from './schema'
|
||||
import { Grid } from '@mui/material'
|
||||
import HelperACL from 'client/components/Forms/ACLs/CreateForm/Utils/helper'
|
||||
|
||||
export const STEP_ID = 'resourcesIdentifier'
|
||||
|
||||
const Content = (users, groups, clusters, zones, version) => (
|
||||
<Grid mt={2} container>
|
||||
<Grid item xs={8}>
|
||||
<FormWithSchema id={STEP_ID} cy={`${STEP_ID}`} fields={FIELDS} />
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<HelperACL
|
||||
title={T['acls.form.create.resourcesUser.title']}
|
||||
text={T['acls.form.create.resourcesUser.info']}
|
||||
users={users}
|
||||
groups={groups}
|
||||
clusters={clusters}
|
||||
zones={zones}
|
||||
version={version}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
|
||||
/**
|
||||
* Resources identifier ACL configuration.
|
||||
*
|
||||
* @param {object} props - Step props
|
||||
* @param {Array} props.users - List of users
|
||||
* @param {Array} props.groups - List of groups
|
||||
* @param {Array} props.clusters - List of clusters
|
||||
* @param {Array} props.zones - List of zones
|
||||
* @param {string} props.version - ONE version
|
||||
* @returns {object} Resources identifier ACL configuration step
|
||||
*/
|
||||
const ResourcesIdentifier = ({ users, groups, clusters, zones, version }) => ({
|
||||
id: STEP_ID,
|
||||
label: T['acls.form.create.resourcesUser.title'],
|
||||
resolver: SCHEMA,
|
||||
optionsValidate: { abortEarly: false },
|
||||
content: () => Content(users, groups, clusters, zones, version),
|
||||
})
|
||||
|
||||
ResourcesIdentifier.propTypes = {
|
||||
data: PropTypes.object,
|
||||
setFormData: PropTypes.func,
|
||||
}
|
||||
|
||||
export default ResourcesIdentifier
|
@ -0,0 +1,113 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { INPUT_TYPES, T } from 'client/constants'
|
||||
import { Field, getObjectSchemaFromFields, arrayToOptions } from 'client/utils'
|
||||
import { string } from 'yup'
|
||||
import { GroupsTable, ClustersTable } from 'client/components/Tables'
|
||||
|
||||
// Types of id definition
|
||||
export const ACL_TYPE_ID_TRANSLATIONS = {
|
||||
INDIVIDUAL: {
|
||||
value: 'INDIVIDUAL',
|
||||
text: T['acls.form.create.resourcesUser.identifier'],
|
||||
},
|
||||
GROUP: { value: 'GROUP', text: T.Group },
|
||||
ALL: { value: 'ALL', text: T.All },
|
||||
CLUSTER: { value: 'CLUSTER', text: T.Cluster },
|
||||
}
|
||||
|
||||
/** @type {Field} Type field */
|
||||
export const TYPE = {
|
||||
name: 'TYPE',
|
||||
type: INPUT_TYPES.TOGGLE,
|
||||
values: () =>
|
||||
arrayToOptions(Object.keys(ACL_TYPE_ID_TRANSLATIONS), {
|
||||
addEmpty: false,
|
||||
getText: (key) => ACL_TYPE_ID_TRANSLATIONS[key].text,
|
||||
getValue: (key) => ACL_TYPE_ID_TRANSLATIONS[key].value,
|
||||
}),
|
||||
validation: string()
|
||||
.trim()
|
||||
.required()
|
||||
.uppercase()
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
const INDIVIDUAL = {
|
||||
name: 'INDIVIDUAL',
|
||||
label: T['acls.form.create.resourcesUser.individual'],
|
||||
type: INPUT_TYPES.TEXT,
|
||||
dependOf: TYPE.name,
|
||||
htmlType: (type) =>
|
||||
(!type || type !== ACL_TYPE_ID_TRANSLATIONS.INDIVIDUAL.value) &&
|
||||
INPUT_TYPES.HIDDEN,
|
||||
validation: string()
|
||||
.trim()
|
||||
.when(TYPE.name, (type, schema) =>
|
||||
type !== ACL_TYPE_ID_TRANSLATIONS.INDIVIDUAL.value
|
||||
? schema.strip()
|
||||
: schema.required()
|
||||
)
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
const GROUP = {
|
||||
name: 'GROUP',
|
||||
label: T['acls.form.create.resourcesUser.group'],
|
||||
type: INPUT_TYPES.TABLE,
|
||||
dependOf: TYPE.name,
|
||||
htmlType: (type) =>
|
||||
(!type || type !== ACL_TYPE_ID_TRANSLATIONS.GROUP.value) &&
|
||||
INPUT_TYPES.HIDDEN,
|
||||
Table: () => GroupsTable,
|
||||
validation: string()
|
||||
.trim()
|
||||
.when(TYPE.name, (type, schema) =>
|
||||
type !== ACL_TYPE_ID_TRANSLATIONS.GROUP.value
|
||||
? schema.strip()
|
||||
: schema.required()
|
||||
)
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
const CLUSTER = {
|
||||
name: 'CLUSTER',
|
||||
label: T['acls.form.create.resourcesUser.cluster'],
|
||||
type: INPUT_TYPES.TABLE,
|
||||
dependOf: TYPE.name,
|
||||
htmlType: (type) =>
|
||||
(!type || type !== ACL_TYPE_ID_TRANSLATIONS.CLUSTER.value) &&
|
||||
INPUT_TYPES.HIDDEN,
|
||||
Table: () => ClustersTable,
|
||||
validation: string()
|
||||
.trim()
|
||||
.when(TYPE.name, (type, schema) =>
|
||||
type !== ACL_TYPE_ID_TRANSLATIONS.CLUSTER.value
|
||||
? schema.strip()
|
||||
: schema.required()
|
||||
)
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
const FIELDS = [TYPE, INDIVIDUAL, GROUP, CLUSTER]
|
||||
|
||||
const SCHEMA = getObjectSchemaFromFields(FIELDS)
|
||||
|
||||
export { SCHEMA, FIELDS }
|
@ -0,0 +1,68 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
import { T } from 'client/constants'
|
||||
import { SCHEMA, FIELDS } from './schema'
|
||||
import { Grid } from '@mui/material'
|
||||
import HelperACL from 'client/components/Forms/ACLs/CreateForm/Utils/helper'
|
||||
|
||||
export const STEP_ID = 'rights'
|
||||
|
||||
const Content = (users, groups, clusters, zones, version) => (
|
||||
<Grid mt={2} container>
|
||||
<Grid item xs={8}>
|
||||
<FormWithSchema id={STEP_ID} cy={`${STEP_ID}`} fields={FIELDS} />
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<HelperACL
|
||||
title={T['acls.form.create.rights.title']}
|
||||
text={T['acls.form.create.rights.info']}
|
||||
users={users}
|
||||
groups={groups}
|
||||
clusters={clusters}
|
||||
zones={zones}
|
||||
version={version}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
|
||||
/**
|
||||
* Rights ACL configuration.
|
||||
*
|
||||
* @param {object} props - Step props
|
||||
* @param {Array} props.users - List of users
|
||||
* @param {Array} props.groups - List of groups
|
||||
* @param {Array} props.clusters - List of clusters
|
||||
* @param {Array} props.zones - List of zones
|
||||
* @param {string} props.version - ONE version
|
||||
* @returns {object} Rights ACL configuration step
|
||||
*/
|
||||
const Rights = ({ users, groups, clusters, zones, version }) => ({
|
||||
id: STEP_ID,
|
||||
label: T['acls.form.create.rights.title'],
|
||||
resolver: SCHEMA,
|
||||
optionsValidate: { abortEarly: false },
|
||||
content: () => Content(users, groups, clusters, zones, version),
|
||||
})
|
||||
|
||||
Rights.propTypes = {
|
||||
data: PropTypes.object,
|
||||
setFormData: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Rights
|
@ -0,0 +1,56 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { INPUT_TYPES, T } from 'client/constants'
|
||||
import { getObjectSchemaFromFields } from 'client/utils'
|
||||
import { boolean } from 'yup'
|
||||
|
||||
const USE = {
|
||||
name: 'USE',
|
||||
label: T.Use,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 3 },
|
||||
}
|
||||
|
||||
const MANAGE = {
|
||||
name: 'MANAGE',
|
||||
label: T.Manage,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 3 },
|
||||
}
|
||||
|
||||
const ADMIN = {
|
||||
name: 'ADMIN',
|
||||
label: T.Admin,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 3 },
|
||||
}
|
||||
|
||||
const CREATE = {
|
||||
name: 'CREATE',
|
||||
label: T.Create,
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 3 },
|
||||
}
|
||||
|
||||
const FIELDS = [USE, MANAGE, ADMIN, CREATE]
|
||||
|
||||
const SCHEMA = getObjectSchemaFromFields(FIELDS)
|
||||
|
||||
export { SCHEMA, FIELDS }
|
@ -0,0 +1,155 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
import { T } from 'client/constants'
|
||||
import { SCHEMA, FIELDS } from './schema'
|
||||
import { Stack, Alert, Typography } from '@mui/material'
|
||||
import makeStyles from '@mui/styles/makeStyles'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useWatch } from 'react-hook-form'
|
||||
|
||||
import { translateACL, validACL } from 'client/models/ACL'
|
||||
|
||||
import { generateDocLink } from 'client/utils'
|
||||
|
||||
export const STEP_ID = 'stringEditor'
|
||||
|
||||
const Content = (version, users, groups, clusters, zones) => {
|
||||
const [ruleString, setRuleString] = useState('')
|
||||
|
||||
const watch = useWatch({
|
||||
name: 'stringEditor.RULE',
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
setRuleString(watch)
|
||||
}, [watch])
|
||||
|
||||
// Style for info message
|
||||
const useStyles = makeStyles(({ palette }) => ({
|
||||
groupInfo: {
|
||||
'&': {
|
||||
gridColumn: 'span 2',
|
||||
marginTop: '1em',
|
||||
backgroundColor: palette.background.paper,
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<Stack
|
||||
display="grid"
|
||||
gap="1em"
|
||||
sx={{
|
||||
gridTemplateColumns: { sm: '1fr', md: '1frs' },
|
||||
padding: '0.5 em',
|
||||
}}
|
||||
>
|
||||
<Alert severity="info" variant="outlined" className={classes.groupInfo}>
|
||||
{Tr(T['acls.form.create.stringEditor.info'])}
|
||||
<ul>
|
||||
<li>
|
||||
<b>{Tr(T['acls.form.create.stringEditor.info.user.title'])}</b>
|
||||
{Tr(T['acls.form.create.stringEditor.info.user.info'])}
|
||||
</li>
|
||||
<li>
|
||||
<b>{Tr(T['acls.form.create.stringEditor.info.resource.title'])}</b>
|
||||
{Tr(T['acls.form.create.stringEditor.info.resource.info'])}
|
||||
</li>
|
||||
<li>
|
||||
<b>{Tr(T['acls.form.create.stringEditor.info.rights.title'])}</b>
|
||||
{Tr(T['acls.form.create.stringEditor.info.rights.info'])}
|
||||
</li>
|
||||
<li>
|
||||
<b>{Tr(T['acls.form.create.stringEditor.info.zone.title'])}</b>
|
||||
{Tr(T['acls.form.create.stringEditor.info.zone.info'])}
|
||||
</li>
|
||||
</ul>
|
||||
{Tr(T['acls.form.create.stringEditor.info.more'])}
|
||||
<a
|
||||
target="_blank"
|
||||
href={generateDocLink(
|
||||
version,
|
||||
'management_and_operations/users_groups_management/chmod.html#manage-acl'
|
||||
)}
|
||||
rel="noreferrer"
|
||||
>
|
||||
{Tr(T['acls.form.create.stringEditor.info.more.link'])}
|
||||
</a>
|
||||
</Alert>
|
||||
<Stack
|
||||
display="grid"
|
||||
gap="1em"
|
||||
sx={{
|
||||
gridTemplateColumns: { sm: '1fr 1fr', md: '1fr' },
|
||||
padding: '0.5 em',
|
||||
}}
|
||||
>
|
||||
<FormWithSchema id={STEP_ID} cy={`${STEP_ID}`} fields={FIELDS} />
|
||||
<Typography>
|
||||
{validACL(ruleString) ? (
|
||||
<Alert
|
||||
severity="success"
|
||||
variant="outlined"
|
||||
className={classes.groupInfo}
|
||||
>
|
||||
{translateACL(ruleString, users, groups, clusters, zones)}
|
||||
</Alert>
|
||||
) : (
|
||||
<Alert
|
||||
severity="error"
|
||||
variant="outlined"
|
||||
className={classes.groupInfo}
|
||||
>
|
||||
{Tr(T['acls.translate.error'])}
|
||||
</Alert>
|
||||
)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* StringEditor ACL configuration.
|
||||
*
|
||||
* @param {object} props - Step props
|
||||
* @param {string} props.version - ONE version
|
||||
* @param {Array} props.users - List of users
|
||||
* @param {Array} props.groups - List of groups
|
||||
* @param {Array} props.clusters - List of clusters
|
||||
* @param {Array} props.zones - List of zones
|
||||
* @returns {object} StringEditor ACL configuration step
|
||||
*/
|
||||
const Resources = ({ version, users, groups, clusters, zones }) => ({
|
||||
id: STEP_ID,
|
||||
label: T['acls.form.create.stringEditor.title'],
|
||||
resolver: SCHEMA,
|
||||
optionsValidate: { abortEarly: false },
|
||||
content: () => Content(version, users, groups, clusters, zones),
|
||||
})
|
||||
|
||||
Resources.propTypes = {
|
||||
data: PropTypes.object,
|
||||
setFormData: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Resources
|
@ -0,0 +1,32 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { INPUT_TYPES, T } from 'client/constants'
|
||||
import { getObjectSchemaFromFields } from 'client/utils'
|
||||
import { string } from 'yup'
|
||||
|
||||
const RULE = {
|
||||
name: 'RULE',
|
||||
label: T.ACL,
|
||||
type: INPUT_TYPES.TEXT,
|
||||
validation: string().default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
const FIELDS = [RULE]
|
||||
|
||||
const SCHEMA = getObjectSchemaFromFields(FIELDS)
|
||||
|
||||
export { SCHEMA, FIELDS }
|
@ -0,0 +1,120 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { T, ACL_TYPE_ID, ACL_RESOURCES } from 'client/constants'
|
||||
import { Stack, Alert } from '@mui/material'
|
||||
import makeStyles from '@mui/styles/makeStyles'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { useFormContext } from 'react-hook-form'
|
||||
|
||||
import { createStringACL, translateACL } from 'client/models/ACL'
|
||||
import { object } from 'yup'
|
||||
|
||||
import { generateDocLink } from 'client/utils'
|
||||
export const STEP_ID = 'summary'
|
||||
|
||||
const Content = (version, users, groups, clusters, zones) => {
|
||||
const { getValues } = useFormContext()
|
||||
|
||||
const values = getValues()
|
||||
|
||||
const ruleString = createStringACL(
|
||||
ACL_TYPE_ID[values?.user?.TYPE],
|
||||
values?.user?.INDIVIDUAL ?? values?.user?.GROUP ?? values?.user?.CLUSTER,
|
||||
Object.keys(values?.resources)
|
||||
.filter((resource) => values?.resources[resource])
|
||||
.map((resource) => ACL_RESOURCES[resource]),
|
||||
ACL_TYPE_ID[values?.resourcesIdentifier?.TYPE],
|
||||
values?.resourcesIdentifier?.INDIVIDUAL ??
|
||||
values?.resourcesIdentifier?.GROUP ??
|
||||
values?.resourcesIdentifier?.CLUSTER,
|
||||
Object.keys(values?.rights).filter((key) => values?.rights[key]),
|
||||
values?.zone?.TYPE ? ACL_TYPE_ID[values?.zone?.TYPE] : undefined,
|
||||
values?.zone?.ZONE
|
||||
)
|
||||
|
||||
// Style for info message
|
||||
const useStyles = makeStyles(({ palette }) => ({
|
||||
groupInfo: {
|
||||
'&': {
|
||||
gridColumn: 'span 2',
|
||||
marginTop: '1em',
|
||||
backgroundColor: palette.background.paper,
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<Stack
|
||||
display="grid"
|
||||
gap="1em"
|
||||
sx={{
|
||||
gridTemplateColumns: { sm: '1fr', md: '1fr 1fr' },
|
||||
padding: '0.5 em',
|
||||
}}
|
||||
>
|
||||
<Alert severity="info" variant="outlined" className={classes.groupInfo}>
|
||||
{Tr(T['acls.form.create.summary.info.rule'])}
|
||||
<b data-cy="ruleString">{ruleString}</b>
|
||||
<br />
|
||||
<br />
|
||||
{Tr(T['acls.form.create.summary.info.translation'])}
|
||||
<b>{translateACL(ruleString, users, groups, clusters, zones)}</b>
|
||||
<br />
|
||||
<br />
|
||||
{Tr(T['acls.form.create.stringEditor.info.more'])}
|
||||
<a
|
||||
target="_blank"
|
||||
href={generateDocLink(
|
||||
version,
|
||||
'management_and_operations/users_groups_management/chmod.html#manage-acl#manage-acl'
|
||||
)}
|
||||
rel="noreferrer"
|
||||
>
|
||||
{Tr(T['acls.form.create.stringEditor.info.more.link'])}
|
||||
</a>
|
||||
</Alert>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary ACL configuration.
|
||||
*
|
||||
* @param {object} props - Step props
|
||||
* @param {string} props.version - ONE version
|
||||
* @param {Array} props.users - List of users
|
||||
* @param {Array} props.groups - List of groups
|
||||
* @param {Array} props.clusters - List of clusters
|
||||
* @param {Array} props.zones - List of zones
|
||||
* @returns {object} Summary ACL configuration step
|
||||
*/
|
||||
const Summary = ({ version, users, groups, clusters, zones }) => ({
|
||||
id: STEP_ID,
|
||||
label: T['acls.form.create.summary.title'],
|
||||
resolver: object(),
|
||||
optionsValidate: { abortEarly: false },
|
||||
content: () => Content(version, users, groups, clusters, zones),
|
||||
})
|
||||
|
||||
Summary.propTypes = {
|
||||
data: PropTypes.object,
|
||||
setFormData: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Summary
|
@ -0,0 +1,68 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
import { SCHEMA, FIELDS } from './schema'
|
||||
import { Grid } from '@mui/material'
|
||||
import { T } from 'client/constants'
|
||||
import HelperACL from 'client/components/Forms/ACLs/CreateForm/Utils/helper'
|
||||
|
||||
export const STEP_ID = 'user'
|
||||
|
||||
const Content = (users, groups, clusters, zones, version) => (
|
||||
<Grid mt={2} container>
|
||||
<Grid item xs={8}>
|
||||
<FormWithSchema id={STEP_ID} cy={`${STEP_ID}`} fields={FIELDS} />
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<HelperACL
|
||||
title={T['acls.form.create.user.title']}
|
||||
text={T['acls.form.create.user.info']}
|
||||
users={users}
|
||||
groups={groups}
|
||||
clusters={clusters}
|
||||
zones={zones}
|
||||
version={version}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
|
||||
/**
|
||||
* User ACL configuration.
|
||||
*
|
||||
* @param {object} props - Step props
|
||||
* @param {Array} props.users - List of users
|
||||
* @param {Array} props.groups - List of groups
|
||||
* @param {Array} props.clusters - List of clusters
|
||||
* @param {Array} props.zones - List of zones
|
||||
* @param {string} props.version - ONE version
|
||||
* @returns {object} User ACL configuration step
|
||||
*/
|
||||
const User = ({ users, groups, clusters, zones, version }) => ({
|
||||
id: STEP_ID,
|
||||
label: T['acls.form.create.user.title'],
|
||||
resolver: SCHEMA,
|
||||
optionsValidate: { abortEarly: false },
|
||||
content: () => Content(users, groups, clusters, zones, version),
|
||||
})
|
||||
|
||||
User.propTypes = {
|
||||
data: PropTypes.object,
|
||||
setFormData: PropTypes.func,
|
||||
}
|
||||
|
||||
export default User
|
@ -0,0 +1,89 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { INPUT_TYPES, T } from 'client/constants'
|
||||
import { Field, getObjectSchemaFromFields, arrayToOptions } from 'client/utils'
|
||||
import { string } from 'yup'
|
||||
import { UsersTable, GroupsTable } from 'client/components/Tables'
|
||||
|
||||
const ACL_TYPE_ID_USER_TRANSLATIONS = {
|
||||
INDIVIDUAL: { value: 'INDIVIDUAL', text: T.User },
|
||||
GROUP: { value: 'GROUP', text: T.Group },
|
||||
ALL: { value: 'ALL', text: T.All },
|
||||
}
|
||||
|
||||
/** @type {Field} Type field */
|
||||
export const TYPE = {
|
||||
name: 'TYPE',
|
||||
type: INPUT_TYPES.TOGGLE,
|
||||
values: () =>
|
||||
arrayToOptions(Object.keys(ACL_TYPE_ID_USER_TRANSLATIONS), {
|
||||
addEmpty: false,
|
||||
getText: (key) => ACL_TYPE_ID_USER_TRANSLATIONS[key].text,
|
||||
getValue: (key) => ACL_TYPE_ID_USER_TRANSLATIONS[key].value,
|
||||
}),
|
||||
validation: string()
|
||||
.trim()
|
||||
.required()
|
||||
.uppercase()
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
const INDIVIDUAL = {
|
||||
name: 'INDIVIDUAL',
|
||||
label: T['acls.form.create.user.individual'],
|
||||
type: INPUT_TYPES.TABLE,
|
||||
dependOf: TYPE.name,
|
||||
htmlType: (type) =>
|
||||
(!type || type !== ACL_TYPE_ID_USER_TRANSLATIONS.INDIVIDUAL.value) &&
|
||||
INPUT_TYPES.HIDDEN,
|
||||
Table: () => UsersTable,
|
||||
validation: string()
|
||||
.trim()
|
||||
.when(TYPE.name, (type, schema) =>
|
||||
type !== ACL_TYPE_ID_USER_TRANSLATIONS.INDIVIDUAL.value
|
||||
? schema.strip()
|
||||
: schema.required()
|
||||
)
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
const GROUP = {
|
||||
name: 'GROUP',
|
||||
label: T['acls.form.create.user.group'],
|
||||
type: INPUT_TYPES.TABLE,
|
||||
dependOf: TYPE.name,
|
||||
htmlType: (type) =>
|
||||
(!type || type !== ACL_TYPE_ID_USER_TRANSLATIONS.GROUP.value) &&
|
||||
INPUT_TYPES.HIDDEN,
|
||||
Table: () => GroupsTable,
|
||||
validation: string()
|
||||
.trim()
|
||||
.when(TYPE.name, (type, schema) =>
|
||||
type !== ACL_TYPE_ID_USER_TRANSLATIONS.GROUP.value
|
||||
? schema.strip()
|
||||
: schema.required()
|
||||
)
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
}
|
||||
|
||||
const FIELDS = [TYPE, INDIVIDUAL, GROUP]
|
||||
|
||||
const SCHEMA = getObjectSchemaFromFields(FIELDS)
|
||||
|
||||
export { SCHEMA, FIELDS }
|
@ -0,0 +1,73 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
import { T } from 'client/constants'
|
||||
import { SCHEMA, FIELDS } from './schema'
|
||||
import { Grid } from '@mui/material'
|
||||
import HelperACL from 'client/components/Forms/ACLs/CreateForm/Utils/helper'
|
||||
|
||||
export const STEP_ID = 'zone'
|
||||
|
||||
const Content = (oneConfig, users, groups, clusters, zones, version) => (
|
||||
<Grid mt={2} container>
|
||||
<Grid item xs={8}>
|
||||
<FormWithSchema
|
||||
id={STEP_ID}
|
||||
cy={`${STEP_ID}`}
|
||||
fields={FIELDS(oneConfig)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<HelperACL
|
||||
title={T['acls.form.create.zone.title']}
|
||||
text={T['acls.form.create.zone.info']}
|
||||
users={users}
|
||||
groups={groups}
|
||||
clusters={clusters}
|
||||
zones={zones}
|
||||
version={version}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
|
||||
/**
|
||||
* Zone ACL configuration.
|
||||
*
|
||||
* @param {object} props - Step props
|
||||
* @param {object} props.oneConfig - ONE config
|
||||
* @param {Array} props.users - List of users
|
||||
* @param {Array} props.groups - List of groups
|
||||
* @param {Array} props.clusters - List of clusters
|
||||
* @param {Array} props.zones - List of zones
|
||||
* @param {string} props.version - ONE version
|
||||
* @returns {object} Zone ACL configuration step
|
||||
*/
|
||||
const Zone = ({ oneConfig, users, groups, clusters, zones, version }) => ({
|
||||
id: STEP_ID,
|
||||
label: T['acls.form.create.zone.title'],
|
||||
resolver: SCHEMA(oneConfig),
|
||||
optionsValidate: { abortEarly: false },
|
||||
content: () => Content(oneConfig, users, groups, clusters, zones, version),
|
||||
})
|
||||
|
||||
Zone.propTypes = {
|
||||
data: PropTypes.object,
|
||||
setFormData: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Zone
|
@ -0,0 +1,87 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { INPUT_TYPES, T, FEDERATION_TYPE } from 'client/constants'
|
||||
import { Field, getObjectSchemaFromFields, arrayToOptions } from 'client/utils'
|
||||
import { string } from 'yup'
|
||||
import { ZonesTable } from 'client/components/Tables'
|
||||
|
||||
const ACL_TYPE_ZONE_TRANSLATIONS = {
|
||||
ALL: { value: 'ALL', text: T.All },
|
||||
INDIVIDUAL: { value: 'INDIVIDUAL', text: T.Zone },
|
||||
}
|
||||
|
||||
/** @type {Field} Type field */
|
||||
export const TYPE = (oneConfig) => ({
|
||||
name: 'TYPE',
|
||||
type: INPUT_TYPES.TOGGLE,
|
||||
values: () =>
|
||||
arrayToOptions(Object.keys(ACL_TYPE_ZONE_TRANSLATIONS), {
|
||||
addEmpty: false,
|
||||
getText: (key) => ACL_TYPE_ZONE_TRANSLATIONS[key].text,
|
||||
getValue: (key) => ACL_TYPE_ZONE_TRANSLATIONS[key].value,
|
||||
}),
|
||||
validation:
|
||||
oneConfig.FEDERATION.MODE === FEDERATION_TYPE.STANDALONE
|
||||
? string()
|
||||
: string().required(),
|
||||
grid: { md: 12 },
|
||||
})
|
||||
|
||||
const ZONE = (oneConfig) => ({
|
||||
name: 'ZONE',
|
||||
label: T['acls.form.create.zone.zone'],
|
||||
type: INPUT_TYPES.TABLE,
|
||||
dependOf: TYPE(oneConfig).name,
|
||||
htmlType: (type) =>
|
||||
(!type || type !== ACL_TYPE_ZONE_TRANSLATIONS.INDIVIDUAL.value) &&
|
||||
INPUT_TYPES.HIDDEN,
|
||||
Table: () => ZonesTable,
|
||||
validation: string()
|
||||
.trim()
|
||||
.when(TYPE(oneConfig).name, (type, schema) =>
|
||||
type !== ACL_TYPE_ZONE_TRANSLATIONS.INDIVIDUAL.value
|
||||
? schema.strip()
|
||||
: schema.required()
|
||||
)
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 },
|
||||
})
|
||||
|
||||
/**
|
||||
* Return all the fields for this schema.
|
||||
*
|
||||
* @param {object} oneConfig - . ONE config
|
||||
* @returns {Array} - The list of fields
|
||||
*/
|
||||
const FIELDS = (oneConfig) => {
|
||||
console.log(oneConfig)
|
||||
|
||||
return [TYPE(oneConfig), ZONE(oneConfig)]
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema.
|
||||
*
|
||||
* @param {object} oneConfig - . ONE config
|
||||
* @returns {object} - The schema
|
||||
*/
|
||||
const SCHEMA = (oneConfig) => {
|
||||
console.log(oneConfig)
|
||||
|
||||
return getObjectSchemaFromFields(FIELDS(oneConfig))
|
||||
}
|
||||
|
||||
export { SCHEMA, FIELDS }
|
@ -0,0 +1,103 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 User, {
|
||||
STEP_ID as USER_ID,
|
||||
} from 'client/components/Forms/ACLs/CreateForm/Steps/User'
|
||||
import Resources, {
|
||||
STEP_ID as RESOURCES_ID,
|
||||
} from 'client/components/Forms/ACLs/CreateForm/Steps/Resources'
|
||||
import ResourcesIdentifier, {
|
||||
STEP_ID as RESOURCES_IDENTIFIER_ID,
|
||||
} from 'client/components/Forms/ACLs/CreateForm/Steps/ResourcesIdentifier'
|
||||
import Rights, {
|
||||
STEP_ID as RIGHTS_ID,
|
||||
} from 'client/components/Forms/ACLs/CreateForm/Steps/Rights'
|
||||
import Zone, {
|
||||
STEP_ID as ZONE_ID,
|
||||
} from 'client/components/Forms/ACLs/CreateForm/Steps/Zone'
|
||||
|
||||
import Summary from 'client/components/Forms/ACLs/CreateForm/Steps/Summary'
|
||||
|
||||
import StringEditor, {
|
||||
STEP_ID as STRING_EDITOR_ID,
|
||||
} from 'client/components/Forms/ACLs/CreateForm/Steps/StringEditor'
|
||||
|
||||
import { createSteps } from 'client/utils'
|
||||
|
||||
import { ACL_TYPE_ID, ACL_RESOURCES } from 'client/constants'
|
||||
|
||||
import { createStringACL } from 'client/models/ACL'
|
||||
|
||||
/**
|
||||
* Create steps for ACL Create Form with wizard:
|
||||
* 1. User: User or users whom the rule will apply
|
||||
* 2. Resources: Affected resources by the rule
|
||||
* 3. ResourcesIdentifier: Identifier of the resources
|
||||
* 4. Rights: Operations that will be enabled
|
||||
* 5. Zone: Zone whom the rule will apply
|
||||
* 6. Summary: Resume of the rules
|
||||
* Create steps for ACL Create From from string:
|
||||
* 1. StringEditor: Enter the string rule to create it
|
||||
*/
|
||||
const Steps = createSteps(
|
||||
(stepProps) =>
|
||||
stepProps?.fromString
|
||||
? [StringEditor]
|
||||
: [User, Resources, ResourcesIdentifier, Rights, Zone, Summary],
|
||||
{
|
||||
transformBeforeSubmit: (formData) => {
|
||||
// Get data from steps
|
||||
const { [USER_ID]: userData } = formData
|
||||
const { [RESOURCES_ID]: resourcesData } = formData
|
||||
const { [RESOURCES_IDENTIFIER_ID]: resourcesIdentifierData } = formData
|
||||
const { [RIGHTS_ID]: rightsData } = formData
|
||||
const { [ZONE_ID]: zoneData } = formData
|
||||
|
||||
const { [STRING_EDITOR_ID]: stringEditorData } = formData
|
||||
|
||||
// In case of string editor, we only need the string rule
|
||||
if (stringEditorData) {
|
||||
// Return the string rule
|
||||
return {
|
||||
string: stringEditorData?.RULE,
|
||||
}
|
||||
} else {
|
||||
// Create the string rule from the data that the user enter on the wizard
|
||||
const rule = createStringACL(
|
||||
ACL_TYPE_ID[userData.TYPE],
|
||||
userData?.INDIVIDUAL ?? userData?.GROUP ?? userData?.CLUSTER,
|
||||
Object.keys(resourcesData)
|
||||
.filter((resource) => resourcesData[resource])
|
||||
.map((resource) => ACL_RESOURCES[resource]),
|
||||
ACL_TYPE_ID[resourcesIdentifierData?.TYPE],
|
||||
resourcesIdentifierData?.INDIVIDUAL ??
|
||||
resourcesIdentifierData?.GROUP ??
|
||||
resourcesIdentifierData?.CLUSTER,
|
||||
Object.keys(rightsData).filter((key) => rightsData[key]),
|
||||
zoneData?.TYPE ? ACL_TYPE_ID[zoneData?.TYPE] : undefined,
|
||||
zoneData?.ZONE
|
||||
)
|
||||
|
||||
// Return the string rule
|
||||
return {
|
||||
string: rule,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export default Steps
|
@ -0,0 +1,136 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { Card, CardContent, Typography } from '@mui/material'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, ACL_TYPE_ID, ACL_RESOURCES } from 'client/constants'
|
||||
import { useWatch } from 'react-hook-form'
|
||||
import { useEffect, useState, Component } from 'react'
|
||||
import { createStringACL, translateACL } from 'client/models/ACL'
|
||||
import { generateDocLink } from 'client/utils'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
/**
|
||||
* Card with help texts and the ACL rule in a readable language.
|
||||
*
|
||||
* @param {object} props - Component props
|
||||
* @param {string} props.title - Card title
|
||||
* @param {string} props.text - Card text
|
||||
* @param {Array} props.users - List of users
|
||||
* @param {Array} props.groups - List of groups
|
||||
* @param {Array} props.clusters - List of clusters
|
||||
* @param {Array} props.zones - List of zones
|
||||
* @param {string} props.version - ONE version
|
||||
* @returns {Component} The HelperACL component.
|
||||
*/
|
||||
const HelperACL = ({
|
||||
title,
|
||||
text,
|
||||
users,
|
||||
groups,
|
||||
clusters,
|
||||
zones,
|
||||
version,
|
||||
}) => {
|
||||
// Create rule
|
||||
const [rule, setRule] = useState('')
|
||||
|
||||
// Watch form
|
||||
const watch = useWatch()
|
||||
|
||||
// Create ACL when something changes on the form
|
||||
useEffect(() => {
|
||||
const ruleString = createStringACL(
|
||||
ACL_TYPE_ID[watch?.user?.TYPE],
|
||||
watch?.user?.INDIVIDUAL ?? watch?.user?.GROUP ?? watch?.user?.CLUSTER,
|
||||
Object.keys(watch?.resources)
|
||||
.filter((resource) => watch?.resources[resource])
|
||||
.map((resource) => ACL_RESOURCES[resource]),
|
||||
ACL_TYPE_ID[watch?.resourcesIdentifier?.TYPE],
|
||||
watch?.resourcesIdentifier?.INDIVIDUAL ??
|
||||
watch?.resourcesIdentifier?.GROUP ??
|
||||
watch?.resourcesIdentifier?.CLUSTER,
|
||||
Object.keys(watch?.rights).filter((key) => watch?.rights[key]),
|
||||
watch?.zone?.TYPE ? ACL_TYPE_ID[watch?.zone?.TYPE] : undefined,
|
||||
watch?.zone?.ZONE
|
||||
)
|
||||
|
||||
setRule(ruleString)
|
||||
}, [watch])
|
||||
|
||||
return (
|
||||
<Card
|
||||
elevation={2}
|
||||
sx={{
|
||||
height: '100%',
|
||||
minHeight: '630px',
|
||||
maxHeight: '630px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'auto',
|
||||
marginLeft: '1em',
|
||||
marginTop: '1rem',
|
||||
}}
|
||||
>
|
||||
<CardContent
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '1em',
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" component="div" gutterBottom>
|
||||
{Tr(title)}
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" gutterBottom>
|
||||
{Tr(text)}
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" gutterBottom>
|
||||
<b>{translateACL(rule, users, groups, clusters, zones)}</b>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" gutterBottom>
|
||||
{Tr(T['acls.form.create.stringEditor.info.more'])}
|
||||
<a
|
||||
target="_blank"
|
||||
href={generateDocLink(
|
||||
version,
|
||||
'management_and_operations/users_groups_management/chmod.html#manage-acl'
|
||||
)}
|
||||
rel="noreferrer"
|
||||
>
|
||||
{Tr(T['acls.form.create.stringEditor.info.more.link'])}
|
||||
</a>
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
HelperACL.displayName = 'HelperACL'
|
||||
HelperACL.propTypes = {
|
||||
title: PropTypes.string,
|
||||
text: PropTypes.string,
|
||||
users: PropTypes.array,
|
||||
groups: PropTypes.array,
|
||||
clusters: PropTypes.array,
|
||||
zones: PropTypes.array,
|
||||
version: PropTypes.string,
|
||||
}
|
||||
|
||||
export default HelperACL
|
@ -0,0 +1,16 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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/ACLs/CreateForm/Steps'
|
27
src/fireedge/src/client/components/Forms/ACLs/index.js
Normal file
27
src/fireedge/src/client/components/Forms/ACLs/index.js
Normal file
@ -0,0 +1,27 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { CreateStepsCallback } from 'client/utils/schema'
|
||||
|
||||
/**
|
||||
* @param {ConfigurationProps} configProps - Configuration
|
||||
* @returns {ReactElement|CreateStepsCallback} Asynchronous loaded form
|
||||
*/
|
||||
const CreateForm = (configProps) =>
|
||||
AsyncLoadForm({ formPath: 'ACLs/CreateForm' }, configProps)
|
||||
|
||||
export { CreateForm }
|
114
src/fireedge/src/client/components/Tables/ACLs/actions.js
Normal file
114
src/fireedge/src/client/components/Tables/ACLs/actions.js
Normal file
@ -0,0 +1,114 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { Typography } from '@mui/material'
|
||||
import { AddCircledOutline, DesignPencil, Trash } from 'iconoir-react'
|
||||
import { useMemo } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
|
||||
import { useViews } from 'client/features/Auth'
|
||||
import { useRemoveAclMutation } from 'client/features/OneApi/acl'
|
||||
|
||||
import {
|
||||
createActions,
|
||||
GlobalAction,
|
||||
} from 'client/components/Tables/Enhanced/Utils'
|
||||
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
import { RESOURCE_NAMES, T, ACL_ACTIONS } from 'client/constants'
|
||||
|
||||
const ListACLNames = ({ rows = [] }) =>
|
||||
rows?.map?.(({ id, original }) => {
|
||||
const { ID, NAME } = original
|
||||
|
||||
return (
|
||||
<Typography
|
||||
key={`acl-${id}`}
|
||||
variant="inherit"
|
||||
component="span"
|
||||
display="block"
|
||||
>
|
||||
{`#${ID} ${NAME}`}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
|
||||
const MessageToConfirmAction = (rows, description) => (
|
||||
<>
|
||||
<ListACLNames rows={rows} />
|
||||
{description && <Translate word={description} />}
|
||||
<Translate word={T.DoYouWantProceed} />
|
||||
</>
|
||||
)
|
||||
|
||||
MessageToConfirmAction.displayName = 'MessageToConfirmAction'
|
||||
|
||||
/**
|
||||
* Generates the actions to operate resources on ACL table.
|
||||
*
|
||||
* @returns {GlobalAction} - Actions
|
||||
*/
|
||||
const Actions = () => {
|
||||
const history = useHistory()
|
||||
const { view, getResourceView } = useViews()
|
||||
const [remove] = useRemoveAclMutation()
|
||||
|
||||
return useMemo(
|
||||
() =>
|
||||
createActions({
|
||||
filters: getResourceView(RESOURCE_NAMES.ACL)?.actions,
|
||||
actions: [
|
||||
{
|
||||
accessor: ACL_ACTIONS.CREATE_DIALOG,
|
||||
tooltip: T.Create,
|
||||
icon: AddCircledOutline,
|
||||
action: () => history.push(PATH.SYSTEM.ACLS.CREATE, false),
|
||||
},
|
||||
{
|
||||
accessor: ACL_ACTIONS.CREATE_DIALOG_STRING,
|
||||
tooltip: T['acls.table.actions.create.string'],
|
||||
icon: DesignPencil,
|
||||
action: () => history.push(PATH.SYSTEM.ACLS.CREATE, true),
|
||||
},
|
||||
{
|
||||
accessor: ACL_ACTIONS.DELETE,
|
||||
tooltip: T.Delete,
|
||||
icon: Trash,
|
||||
color: 'error',
|
||||
selected: { min: 1 },
|
||||
dataCy: `acl_${ACL_ACTIONS.DELETE}`,
|
||||
options: [
|
||||
{
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Delete,
|
||||
dataCy: `modal-${ACL_ACTIONS.DELETE}`,
|
||||
children: MessageToConfirmAction,
|
||||
},
|
||||
onSubmit: (rows) => async () => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map((id) => remove({ id })))
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
[view]
|
||||
)
|
||||
}
|
||||
|
||||
export default Actions
|
114
src/fireedge/src/client/components/Tables/ACLs/columns.js
Normal file
114
src/fireedge/src/client/components/Tables/ACLs/columns.js
Normal file
@ -0,0 +1,114 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 { CategoryFilter } from 'client/components/Tables/Enhanced/Utils'
|
||||
|
||||
import { T } from 'client/constants'
|
||||
|
||||
const COLUMNS = [
|
||||
{ Header: T.Identifier, id: 'ID', accessor: 'ID', sortType: 'number' },
|
||||
{
|
||||
Header: T['acls.table.filter.string'],
|
||||
id: 'STRING',
|
||||
accessor: 'STRING',
|
||||
sortType: 'number',
|
||||
},
|
||||
{
|
||||
Header: T['acls.table.filter.user.name'],
|
||||
id: 'idUserName',
|
||||
accessor: 'USER.name',
|
||||
sortType: 'number',
|
||||
},
|
||||
{
|
||||
Header: T['acls.table.filter.user.type'],
|
||||
id: 'idUserType',
|
||||
accessor: 'USER.type',
|
||||
sortType: 'number',
|
||||
},
|
||||
{
|
||||
Header: T['acls.table.filter.user.id'],
|
||||
id: 'idUserId',
|
||||
accessor: 'USER.id',
|
||||
sortType: 'number',
|
||||
},
|
||||
{
|
||||
Header: T.Resources,
|
||||
id: 'resources',
|
||||
accessor: 'RESOURCE.resources',
|
||||
sortType: 'string',
|
||||
disableFilters: false,
|
||||
Filter: ({ column }) =>
|
||||
CategoryFilter({
|
||||
column,
|
||||
multiple: true,
|
||||
title: 'Test',
|
||||
}),
|
||||
filter: 'arrIncludes',
|
||||
},
|
||||
{
|
||||
Header: T['acls.table.filter.resources.user.name'],
|
||||
id: 'idResourceName',
|
||||
accessor: 'RESOURCE.identifier.name',
|
||||
sortType: 'number',
|
||||
},
|
||||
{
|
||||
Header: T['acls.table.filter.resources.user.type'],
|
||||
id: 'idResourceType',
|
||||
accessor: 'RESOURCE.identifier.type',
|
||||
sortType: 'number',
|
||||
},
|
||||
{
|
||||
Header: T['acls.table.filter.resources.user.id'],
|
||||
id: 'idResourceId',
|
||||
accessor: 'RESOURCE.identifier.id',
|
||||
sortType: 'number',
|
||||
},
|
||||
{
|
||||
Header: T.Rights,
|
||||
id: 'rights',
|
||||
accessor: 'RIGHTS.rights',
|
||||
sortType: 'string',
|
||||
disableFilters: false,
|
||||
Filter: ({ column }) =>
|
||||
CategoryFilter({
|
||||
column,
|
||||
multiple: true,
|
||||
title: 'Test',
|
||||
}),
|
||||
filter: 'arrIncludes',
|
||||
},
|
||||
|
||||
{
|
||||
Header: T['acls.table.filter.zone.name'],
|
||||
id: 'zoneName',
|
||||
accessor: 'ZONE.name',
|
||||
sortType: 'number',
|
||||
},
|
||||
{
|
||||
Header: T['acls.table.filter.zone.type'],
|
||||
id: 'zoneType',
|
||||
accessor: 'ZONE.type',
|
||||
sortType: 'number',
|
||||
},
|
||||
{
|
||||
Header: T['acls.table.filter.zone.id'],
|
||||
id: 'zoneId',
|
||||
accessor: 'ZONE.id',
|
||||
sortType: 'number',
|
||||
},
|
||||
]
|
||||
|
||||
export default COLUMNS
|
94
src/fireedge/src/client/components/Tables/ACLs/index.js
Normal file
94
src/fireedge/src/client/components/Tables/ACLs/index.js
Normal file
@ -0,0 +1,94 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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, Component, useState } from 'react'
|
||||
import { useViews } from 'client/features/Auth'
|
||||
import { useGetAclsExtendedQuery } from 'client/features/OneApi/acl'
|
||||
|
||||
import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced'
|
||||
import ACLColumns from 'client/components/Tables/ACLs/columns'
|
||||
import ACLRow from 'client/components/Tables/ACLs/row'
|
||||
import { RESOURCE_NAMES, ACL_TABLE_VIEWS } from 'client/constants'
|
||||
|
||||
const DEFAULT_DATA_CY = 'acls'
|
||||
|
||||
/**
|
||||
* `ACLsTable` component displays a table of ACLs.
|
||||
*
|
||||
* @param {object} props - Component properties.
|
||||
* @param {object} [props.rootProps={}] - Root properties for the table.
|
||||
* @param {object} [props.searchProps={}] - Search properties for the table.
|
||||
* @param {Array} props.vdcGroups - Array of VDC groups.
|
||||
* @param {Array<string|number>} [props.secondaryGroups=[]] - Array of IDs of the secondary groups.
|
||||
* @param {object} props.rest - Rest of the properties.
|
||||
* @returns {Component} Rendered component.
|
||||
*/
|
||||
const ACLsTable = (props) => {
|
||||
const {
|
||||
rootProps = {},
|
||||
searchProps = {},
|
||||
vdcGroups,
|
||||
singleSelect = false,
|
||||
...rest
|
||||
} = props ?? {}
|
||||
|
||||
rootProps['data-cy'] ??= DEFAULT_DATA_CY
|
||||
searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}`
|
||||
|
||||
const { view, getResourceView } = useViews()
|
||||
|
||||
// Get data
|
||||
const { data = [], isFetching, refetch } = useGetAclsExtendedQuery()
|
||||
|
||||
const columns = useMemo(
|
||||
() =>
|
||||
createColumns({
|
||||
filters: getResourceView(RESOURCE_NAMES.ACL)?.filters,
|
||||
columns: ACLColumns,
|
||||
}),
|
||||
[view]
|
||||
)
|
||||
|
||||
// Variable to store the type of table
|
||||
const [viewType, setViewType] = useState(ACL_TABLE_VIEWS.ICONS.type)
|
||||
|
||||
// Define the type of views
|
||||
const tableViews = {
|
||||
views: ACL_TABLE_VIEWS,
|
||||
onClick: (name) => {
|
||||
setViewType(name)
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
data && (
|
||||
<EnhancedTable
|
||||
columns={columns}
|
||||
data={data}
|
||||
rootProps={rootProps}
|
||||
searchProps={searchProps}
|
||||
refetch={refetch}
|
||||
isLoading={isFetching}
|
||||
getRowId={(row) => String(row.ID)}
|
||||
RowComponent={useMemo(() => ACLRow(viewType), [viewType])}
|
||||
singleSelect={singleSelect}
|
||||
tableViews={tableViews}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export default ACLsTable
|
61
src/fireedge/src/client/components/Tables/ACLs/row.js
Normal file
61
src/fireedge/src/client/components/Tables/ACLs/row.js
Normal file
@ -0,0 +1,61 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import PropTypes from 'prop-types'
|
||||
import {
|
||||
ACLCardIcons,
|
||||
ACLCardNames,
|
||||
ACLCardCLI,
|
||||
ACLCardResources,
|
||||
ACLCardRule,
|
||||
ACLCardReadableRule,
|
||||
} from 'client/components/Cards'
|
||||
import { ACL_TABLE_VIEWS } from 'client/constants'
|
||||
|
||||
const Row = (viewType) => {
|
||||
const aclRow = ({ original, value, ...props }) => {
|
||||
// Check what view show in the table cards
|
||||
if (viewType === ACL_TABLE_VIEWS.NAMES.type) {
|
||||
return <ACLCardNames rootProps={props} acl={value} />
|
||||
} else if (viewType === ACL_TABLE_VIEWS.CLI.type) {
|
||||
return <ACLCardCLI rootProps={props} acl={value} />
|
||||
} else if (viewType === ACL_TABLE_VIEWS.RESOURCES.type) {
|
||||
return <ACLCardResources rootProps={props} acl={value} />
|
||||
} else if (viewType === ACL_TABLE_VIEWS.RULE.type) {
|
||||
return <ACLCardRule rootProps={props} acl={value} />
|
||||
} else if (viewType === ACL_TABLE_VIEWS.READABLERULE.type) {
|
||||
return <ACLCardReadableRule rootProps={props} acl={value} />
|
||||
} else {
|
||||
return <ACLCardIcons rootProps={props} acl={value} />
|
||||
}
|
||||
}
|
||||
|
||||
aclRow.displayName = 'aclRow'
|
||||
aclRow.propTypes = {
|
||||
original: PropTypes.object,
|
||||
value: PropTypes.object,
|
||||
}
|
||||
|
||||
return aclRow
|
||||
}
|
||||
|
||||
Row.displayName = 'Row'
|
||||
|
||||
Row.propTypes = {
|
||||
viewType: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Row
|
@ -71,7 +71,12 @@ const CategoryFilter = ({
|
||||
|
||||
preFilteredRows?.forEach((row) => {
|
||||
const rowValue = row.values[id]
|
||||
rowValue !== undefined && uniqueOptions.add(rowValue)
|
||||
|
||||
// If the row value is an array, we get all the values of the array
|
||||
rowValue !== undefined &&
|
||||
(Array.isArray(rowValue)
|
||||
? rowValue.forEach((value) => uniqueOptions.add(value))
|
||||
: uniqueOptions.add(rowValue))
|
||||
})
|
||||
|
||||
return [...uniqueOptions.values()]
|
||||
|
@ -0,0 +1,81 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { EyeAlt } from 'iconoir-react'
|
||||
import { MenuItem, MenuList, Stack } from '@mui/material'
|
||||
|
||||
import HeaderPopover from 'client/components/Header/Popover'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Render all selected sorters.
|
||||
*
|
||||
* @returns {object} Component JSX
|
||||
*/
|
||||
const ChangeViewTable = memo(({ tableViews = {} }) => {
|
||||
// Set click action
|
||||
const handleClick = (name) => {
|
||||
tableViews.onClick(name)
|
||||
}
|
||||
|
||||
// Get view types
|
||||
const typeViews = Object.entries(tableViews.views)
|
||||
|
||||
return (
|
||||
<Stack direction="row" gap="0.5em" flexWrap="wrap">
|
||||
<HeaderPopover
|
||||
id="changeviewtable-by-button"
|
||||
icon={<EyeAlt />}
|
||||
headerTitle={Tr(T['acls.table.types.title'])}
|
||||
buttonLabel={Tr(T['acls.table.types.button'])}
|
||||
buttonProps={{
|
||||
'data-cy': 'changeviewtable-by-button',
|
||||
disableElevation: true,
|
||||
variant: 'outlined',
|
||||
color: 'secondary',
|
||||
}}
|
||||
popperProps={{ placement: 'bottom-end' }}
|
||||
>
|
||||
{() => (
|
||||
<MenuList data-cy="change-view-list">
|
||||
{typeViews.map(([key, value]) => (
|
||||
<MenuItem
|
||||
key={key}
|
||||
onClick={() => handleClick(value.type)}
|
||||
data-cy={key}
|
||||
>
|
||||
{Tr(value.name)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>
|
||||
)}
|
||||
</HeaderPopover>
|
||||
</Stack>
|
||||
)
|
||||
})
|
||||
|
||||
ChangeViewTable.propTypes = {
|
||||
preFilteredRows: PropTypes.array,
|
||||
state: PropTypes.object,
|
||||
tableViews: PropTypes.object,
|
||||
}
|
||||
|
||||
ChangeViewTable.displayName = 'ChangeViewTable'
|
||||
|
||||
export default ChangeViewTable
|
@ -22,6 +22,7 @@ import GlobalFilter from 'client/components/Tables/Enhanced/Utils/GlobalFilter'
|
||||
import GlobalSearch from 'client/components/Tables/Enhanced/Utils/GlobalSearch'
|
||||
import GlobalSelectedRows from 'client/components/Tables/Enhanced/Utils/GlobalSelectedRows'
|
||||
import GlobalSort from 'client/components/Tables/Enhanced/Utils/GlobalSort'
|
||||
import ChangeViewTable from 'client/components/Tables/Enhanced/Utils/ChangeViewTable'
|
||||
import TimeFilter from 'client/components/Tables/Enhanced/Utils/TimeFilter'
|
||||
|
||||
export * from 'client/components/Tables/Enhanced/Utils/GlobalActions/Action'
|
||||
@ -37,6 +38,7 @@ export {
|
||||
GlobalSelectedRows,
|
||||
GlobalSort,
|
||||
TimeFilter,
|
||||
ChangeViewTable,
|
||||
// Constants
|
||||
LABEL_COLUMN_ID,
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import {
|
||||
GlobalSearch,
|
||||
GlobalSelectedRows,
|
||||
GlobalSort,
|
||||
ChangeViewTable,
|
||||
LABEL_COLUMN_ID,
|
||||
} from 'client/components/Tables/Enhanced/Utils'
|
||||
import Pagination from 'client/components/Tables/Enhanced/pagination'
|
||||
@ -76,6 +77,7 @@ const EnhancedTable = ({
|
||||
messages = [],
|
||||
dataDepend,
|
||||
readOnly = false,
|
||||
tableViews,
|
||||
}) => {
|
||||
const styles = EnhancedTableStyles({
|
||||
readOnly: readOnly,
|
||||
@ -295,6 +297,7 @@ const EnhancedTable = ({
|
||||
)}
|
||||
<GlobalFilter {...useTableProps} />
|
||||
{!disableGlobalSort && <GlobalSort {...useTableProps} />}
|
||||
{tableViews && <ChangeViewTable tableViews={tableViews} />}
|
||||
</div>
|
||||
{/* SELECTED ROWS */}
|
||||
{displaySelectedRows && !readOnly && (
|
||||
@ -431,6 +434,7 @@ EnhancedTable.propTypes = {
|
||||
messages: PropTypes.array,
|
||||
dataDepend: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
|
||||
readOnly: PropTypes.bool,
|
||||
tableViews: PropTypes.object,
|
||||
}
|
||||
|
||||
export * from 'client/components/Tables/Enhanced/Utils'
|
||||
|
@ -31,7 +31,7 @@ const Row = ({ original, value, ...props }) => {
|
||||
const { color: stateColor, name: stateName } = ZoneModel.getState(original)
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<div {...props} data-cy={`zone-${ID}`}>
|
||||
<div className={classes.main}>
|
||||
<div className={classes.title}>
|
||||
<StatusCircle color={stateColor} tooltip={stateName} />
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import ACLsTable from 'client/components/Tables/ACLs'
|
||||
import AllImagesTable from 'client/components/Tables/AllImages'
|
||||
import BackupJobsTable from 'client/components/Tables/BackupJobs'
|
||||
import BackupsTable from 'client/components/Tables/Backups'
|
||||
@ -46,6 +47,7 @@ import ZonesTable from 'client/components/Tables/Zones'
|
||||
export * from 'client/components/Tables/Enhanced/Utils'
|
||||
|
||||
export {
|
||||
ACLsTable,
|
||||
AllImagesTable,
|
||||
BackupJobsTable,
|
||||
BackupsTable,
|
||||
|
@ -14,7 +14,14 @@
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
// File with constants about ACLs
|
||||
import { T } from 'client/constants'
|
||||
|
||||
// ACL actions
|
||||
export const ACL_ACTIONS = {
|
||||
CREATE_DIALOG: 'create_dialog',
|
||||
CREATE_DIALOG_STRING: 'create_dialog_string',
|
||||
DELETE: 'delete',
|
||||
}
|
||||
|
||||
// Types of id definition
|
||||
export const ACL_TYPE_ID = {
|
||||
@ -32,6 +39,13 @@ export const ACL_ID = {
|
||||
'%': 0x800000000,
|
||||
}
|
||||
|
||||
export const ACL_USERS = {
|
||||
INDIVIDUAL: { type: 'INDIVIDUAL', id: '#', value: 0x100000000 },
|
||||
GROUP: { type: 'GROUP', id: '@', value: 0x200000000 },
|
||||
ALL: { type: 'ALL', id: '*', value: 0x400000000 },
|
||||
CLUSTER: { type: 'CLUSTER', id: '%', value: 0x800000000 },
|
||||
}
|
||||
|
||||
// Hex values for different resource types
|
||||
export const ACL_RESOURCES = {
|
||||
VM: { name: 'VM', value: 0x1000000000n },
|
||||
@ -62,3 +76,31 @@ export const ACL_RIGHTS = {
|
||||
ADMIN: { name: 'ADMIN', value: 0x4 },
|
||||
CREATE: { name: 'CREATE', value: 0x8 },
|
||||
}
|
||||
|
||||
// type of table views
|
||||
export const ACL_TABLE_VIEWS = {
|
||||
ICONS: {
|
||||
type: 'ICONS',
|
||||
name: T['acls.table.types.icons'],
|
||||
},
|
||||
NAMES: {
|
||||
type: 'NAMES',
|
||||
name: T['acls.table.types.names'],
|
||||
},
|
||||
CLI: {
|
||||
type: 'CLI',
|
||||
name: T['acls.table.types.cli'],
|
||||
},
|
||||
RESOURCES: {
|
||||
type: 'RESOURCES',
|
||||
name: T['acls.table.types.resources'],
|
||||
},
|
||||
RULE: {
|
||||
type: 'RULE',
|
||||
name: T['acls.table.types.rule'],
|
||||
},
|
||||
READABLERULE: {
|
||||
type: 'READABLERULE',
|
||||
name: T['acls.table.types.readablerule'],
|
||||
},
|
||||
}
|
||||
|
@ -141,6 +141,7 @@ export const INPUT_TYPES = {
|
||||
TOGGLE: 'toggle',
|
||||
DOCKERFILE: 'dockerfile',
|
||||
UNITS: 'units',
|
||||
LABEL: 'label',
|
||||
}
|
||||
|
||||
export const DEBUG_LEVEL = {
|
||||
@ -162,6 +163,7 @@ export const SOCKETS = {
|
||||
/** @enum {string} Names of resource */
|
||||
export const RESOURCE_NAMES = {
|
||||
APP: 'marketplace-app',
|
||||
ACL: 'acl',
|
||||
BACKUP: 'backup',
|
||||
CLUSTER: 'cluster',
|
||||
DATASTORE: 'datastore',
|
||||
|
@ -21,3 +21,9 @@ export const RESTRICTED_ATTRIBUTES_TYPE = {
|
||||
IMAGE: 'IMAGE_RESTRICTED_ATTR',
|
||||
VNET: 'VNET_RESTRICTED_ATTR',
|
||||
}
|
||||
|
||||
export const FEDERATION_TYPE = {
|
||||
STANDALONE: 'STANDALONE',
|
||||
MASTER: 'MASTER',
|
||||
SLAVE: 'SLAVE',
|
||||
}
|
||||
|
@ -396,8 +396,8 @@ module.exports = {
|
||||
/* sections - network */
|
||||
Network: 'Network',
|
||||
Networks: 'Networks',
|
||||
VirtualNetwork: 'Virtual network',
|
||||
VirtualNetworks: 'Virtual networks',
|
||||
VirtualNetwork: 'Virtual Network',
|
||||
VirtualNetworks: 'Virtual Networks',
|
||||
NetworkTemplate: 'Network Template',
|
||||
NetworkTemplates: 'Network Templates',
|
||||
NetworkTopology: 'Network topology',
|
||||
@ -1563,4 +1563,115 @@ module.exports = {
|
||||
'showback.button.calculateShowback': 'Calculate showback',
|
||||
'showback.button.help.paragraph.1':
|
||||
'Generate showback data to the interval selected in start and end date. After generate the showback data, you can access to the reports on the user or group Showback details. ',
|
||||
|
||||
/* system - acls */
|
||||
'acls.table.actions.create.string': 'Create from string',
|
||||
|
||||
'acls.table.types.icons': 'Icons',
|
||||
'acls.table.types.names': 'Names',
|
||||
'acls.table.types.cli': 'CLI',
|
||||
'acls.table.types.resources': 'Resources',
|
||||
'acls.table.types.rule': 'Rule',
|
||||
'acls.table.types.readablerule': 'Readable Rule',
|
||||
'acls.table.types.button': 'Table view',
|
||||
'acls.table.types.title': 'Change to view:',
|
||||
|
||||
'acls.table.card.rule.user.tooltip': 'Rule applies to user: %1$s',
|
||||
'acls.table.card.rule.group.tooltip': 'Rule applies to group: %1$s',
|
||||
'acls.table.card.rule.cluster.tooltip': 'Rule applies to cluster: %1$s',
|
||||
'acls.table.card.rule.all.tooltip': 'Rule applies to all',
|
||||
'acls.table.card.rule.zone.tooltip': 'Rule applies to zone: %1$s',
|
||||
'acls.table.card.rule.zone.tooltip.all': 'Rule applies to all zones',
|
||||
'acls.table.card.resources.individual.tooltip':
|
||||
'Resources with identifier: %1$s',
|
||||
'acls.table.card.resources.group.tooltip': 'Resources owned by group: %1$s',
|
||||
'acls.table.card.resources.cluster.tooltip':
|
||||
'Resources owned by cluster: %1$s',
|
||||
'acls.table.card.resources.all.tooltip': 'Resources owned by all',
|
||||
|
||||
'acls.table.filter.string': 'String rule',
|
||||
'acls.table.filter.resources.user.id': 'Resource identifier id',
|
||||
'acls.table.filter.resources.user.name': 'Resource identifier name',
|
||||
'acls.table.filter.resources.user.type': 'Resource identifier type',
|
||||
'acls.table.filter.user.id': 'User identifier id',
|
||||
'acls.table.filter.user.name': 'User identifier name',
|
||||
'acls.table.filter.user.type': 'User identifier type',
|
||||
'acls.table.filter.zone.id': 'Zone identifier id',
|
||||
'acls.table.filter.zone.name': 'Zone identifier name',
|
||||
'acls.table.filter.zone.type': 'Zone identifier type',
|
||||
|
||||
'acls.form.create.user.title': 'Users',
|
||||
'acls.form.create.user.info':
|
||||
'Select whom the rule will apply. Could be an individual user, a group of users or all users.',
|
||||
'acls.form.create.user.individual': 'Select which user to apply the rule to',
|
||||
'acls.form.create.user.group': 'Select which group to apply the rule to',
|
||||
|
||||
'acls.form.create.resources.title': 'Resources',
|
||||
'acls.form.create.resources.info': 'Select affected resources by the rule.',
|
||||
'acls.form.create.resources.vm': 'Virtual Machine',
|
||||
'acls.form.create.resources.vmtemplate': 'Virtual Machine Template',
|
||||
'acls.form.create.resources.vnettemplate': 'Virtual Network Template',
|
||||
|
||||
'acls.form.create.resourcesUser.title': 'Resource identifier',
|
||||
'acls.form.create.resourcesUser.info':
|
||||
'Select resource owners. Could be an individual user, a group of users, a cluster or all users.',
|
||||
'acls.form.create.resourcesUser.individual':
|
||||
'Enter the number of the identifier',
|
||||
'acls.form.create.resourcesUser.group':
|
||||
'Select which group is the owner of the resources',
|
||||
'acls.form.create.resourcesUser.cluster':
|
||||
'Select which cluster is the owner of the resources',
|
||||
'acls.form.create.resourcesUser.identifier': 'Identifier',
|
||||
|
||||
'acls.form.create.rights.title': 'Rights',
|
||||
'acls.form.create.rights.info':
|
||||
'Select the allowed operations that this rule will enable.',
|
||||
|
||||
'acls.form.create.zone.title': 'Zone',
|
||||
'acls.form.create.zone.info':
|
||||
'Select the zone where the rule will apply. Optional unless OpenNebula is configured in a federation.',
|
||||
'acls.form.create.zone.zone': 'Select which zone the rule will apply.',
|
||||
|
||||
'acls.form.create.summary.title': 'Summary',
|
||||
'acls.form.create.summary.info.rule': 'Rule that will be created: ',
|
||||
'acls.form.create.summary.info.translation': 'That means: ',
|
||||
|
||||
'acls.form.create.stringEditor.title': 'String ACL rule',
|
||||
'acls.form.create.stringEditor.info':
|
||||
'Enter the string rule that will be created. Remember that a rule it is composed by four different components:',
|
||||
'acls.form.create.stringEditor.info.user.title': 'User: ',
|
||||
'acls.form.create.stringEditor.info.user.info':
|
||||
'Composed by an ID definition (#<id> for individual user, @<id> for groups and * for all).',
|
||||
'acls.form.create.stringEditor.info.resource.title': 'Resources: ',
|
||||
'acls.form.create.stringEditor.info.resource.info':
|
||||
"Composed by a list of '+' separated resource types, '/' and an ID definition (#<id> for individual resource, @<id> for groups, %<id> for clusters and * for all).",
|
||||
'acls.form.create.stringEditor.info.rights.title': 'Rights: ',
|
||||
'acls.form.create.stringEditor.info.rights.info':
|
||||
"Is a list of operations (USE, MANAGE, ADMIN and CREATE) separated by the '+' character.",
|
||||
'acls.form.create.stringEditor.info.zone.title': 'Zone: ',
|
||||
'acls.form.create.stringEditor.info.zone.info':
|
||||
'is an ID definition (#<id> for a zone and * for all) of the zones where the rule applies. This last part is optional, and can be ignored unless OpenNebula is configured in a federation.',
|
||||
'acls.form.create.stringEditor.info.more':
|
||||
'See OpenNebula documentation to get more details ',
|
||||
'acls.form.create.stringEditor.info.more.link': 'about ACL rules.',
|
||||
|
||||
'acls.translate.rule': 'Rule',
|
||||
'acls.translate.user.id': 'allow user with id',
|
||||
'acls.translate.user.group': 'allows users in the group',
|
||||
'acls.translate.user.all': 'allows all users',
|
||||
'acls.translate.rights': 'the right to perform',
|
||||
'acls.translate.and': 'and',
|
||||
'acls.translate.operation': 'operation',
|
||||
'acls.translate.operations': 'operations',
|
||||
'acls.translate.over': 'over',
|
||||
'acls.translate.overall': 'over all',
|
||||
'acls.translate.resource.id': 'with identifier',
|
||||
'acls.translate.resource.group': 'in the group',
|
||||
'acls.translate.resource.cluster': 'in the cluster',
|
||||
'acls.translate.zone.id': 'in the zone',
|
||||
'acls.translate.zone.all': 'in all zones',
|
||||
'acls.translate.error': 'ACL rule is NOT valid',
|
||||
|
||||
Identifier: 'Identifier',
|
||||
Rights: 'Rights',
|
||||
}
|
||||
|
128
src/fireedge/src/client/containers/ACLs/Create.js
Normal file
128
src/fireedge/src/client/containers/ACLs/Create.js
Normal file
@ -0,0 +1,128 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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 {
|
||||
DefaultFormStepper,
|
||||
SkeletonStepsForm,
|
||||
} from 'client/components/FormStepper'
|
||||
import { CreateForm } from 'client/components/Forms/ACLs'
|
||||
import { createAclObjectFromString } from 'client/models/ACL'
|
||||
|
||||
import systemApi from 'client/features/OneApi/system'
|
||||
import { useAllocateAclMutation } from 'client/features/OneApi/acl'
|
||||
import { useGeneralApi } from 'client/features/General'
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
import { useHistory, useLocation } from 'react-router'
|
||||
|
||||
import { useGetUsersQuery } from 'client/features/OneApi/user'
|
||||
import { useGetGroupsQuery } from 'client/features/OneApi/group'
|
||||
import { useGetClustersQuery } from 'client/features/OneApi/cluster'
|
||||
import { useGetZonesQuery } from 'client/features/OneApi/zone'
|
||||
|
||||
import { useSystemData } from 'client/features/Auth'
|
||||
|
||||
const _ = require('lodash')
|
||||
|
||||
/**
|
||||
* Displays the creation form for a ACL rule.
|
||||
*
|
||||
* @returns {ReactElement} - The ACL form component
|
||||
*/
|
||||
function CreateACLs() {
|
||||
const { state: fromString } = useLocation()
|
||||
|
||||
// General api for enqueue
|
||||
const { enqueueSuccess, enqueueError } = useGeneralApi()
|
||||
|
||||
// Get ONE config
|
||||
const { oneConfig } = useSystemData()
|
||||
|
||||
// Get views
|
||||
const { data: views } = systemApi.useGetSunstoneAvalaibleViewsQuery()
|
||||
|
||||
// Get version to show links to documentation
|
||||
const { data: version } = systemApi.useGetOneVersionQuery()
|
||||
|
||||
// Get list of all users to add in the acl info the name of the user
|
||||
const { data: users } = useGetUsersQuery()
|
||||
|
||||
// Get list of all groups to add in the acl info the name of the group
|
||||
const { data: groups } = useGetGroupsQuery()
|
||||
|
||||
// Get list of all clusters to add in the acl info the name of the cluster
|
||||
const { data: clusters } = useGetClustersQuery()
|
||||
|
||||
// Get list of all zones to add in the acl info the name of the zone
|
||||
const { data: zones } = useGetZonesQuery()
|
||||
|
||||
// Operation to create ACL
|
||||
const [createAcl] = useAllocateAclMutation()
|
||||
|
||||
const history = useHistory()
|
||||
|
||||
const onSubmit = async (props) => {
|
||||
try {
|
||||
// Create acl rule
|
||||
const idAcl = await createAcl(
|
||||
createAclObjectFromString(props?.string)
|
||||
).unwrap()
|
||||
|
||||
if (idAcl) {
|
||||
// Success message
|
||||
enqueueSuccess(`ACL rule created - #${idAcl}`)
|
||||
|
||||
// Go to ACL list
|
||||
history.push(PATH.SYSTEM.ACLS.LIST)
|
||||
}
|
||||
} catch (error) {
|
||||
enqueueError('Error creating ACL rule')
|
||||
}
|
||||
}
|
||||
|
||||
return views &&
|
||||
version &&
|
||||
users &&
|
||||
groups &&
|
||||
clusters &&
|
||||
zones &&
|
||||
!_.isEmpty(oneConfig) ? (
|
||||
<CreateForm
|
||||
onSubmit={onSubmit}
|
||||
stepProps={{
|
||||
views,
|
||||
version,
|
||||
fromString,
|
||||
users,
|
||||
groups,
|
||||
clusters,
|
||||
zones,
|
||||
oneConfig,
|
||||
}}
|
||||
fallback={<SkeletonStepsForm />}
|
||||
>
|
||||
{(config) => <DefaultFormStepper {...config} />}
|
||||
</CreateForm>
|
||||
) : (
|
||||
<SkeletonStepsForm />
|
||||
)
|
||||
}
|
||||
|
||||
CreateACLs.propTypes = {
|
||||
string: PropTypes.string,
|
||||
}
|
||||
|
||||
export default CreateACLs
|
83
src/fireedge/src/client/containers/ACLs/index.js
Normal file
83
src/fireedge/src/client/containers/ACLs/index.js
Normal file
@ -0,0 +1,83 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Box, Stack, Chip } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import ACLActions from 'client/components/Tables/ACLs/actions'
|
||||
import { ACLsTable } from 'client/components/Tables'
|
||||
|
||||
/**
|
||||
* Displays a list of Groups with a split pane between the list and selected row(s).
|
||||
*
|
||||
* @returns {ReactElement} Groups list and selected row(s)
|
||||
*/
|
||||
function ACLs() {
|
||||
const [selectedRows, onSelectedRowsChange] = useState(() => [])
|
||||
|
||||
const hasSelectedRows = selectedRows?.length > 0
|
||||
|
||||
const actions = ACLActions()
|
||||
|
||||
return (
|
||||
<SplitPane gridTemplateRows="1fr auto 1fr">
|
||||
{({ getGridProps, GutterComponent }) => (
|
||||
<Box height={1} {...(hasSelectedRows && getGridProps())}>
|
||||
<ACLsTable
|
||||
onSelectedRowsChange={onSelectedRowsChange}
|
||||
globalActions={actions}
|
||||
/>
|
||||
|
||||
{hasSelectedRows && (
|
||||
<>
|
||||
<GutterComponent direction="row" track={1} />
|
||||
<GroupedTags tags={selectedRows} />
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</SplitPane>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a list of tags that represent the selected rows.
|
||||
*
|
||||
* @param {Row[]} tags - Row(s) to display as tags
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
/>
|
||||
</Stack>
|
||||
))
|
||||
|
||||
GroupedTags.propTypes = { tags: PropTypes.array }
|
||||
GroupedTags.displayName = 'GroupedTags'
|
||||
|
||||
export default ACLs
|
@ -36,7 +36,7 @@ import {
|
||||
import { CreateForm, UpdateForm } from 'client/components/Forms/Group'
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
|
||||
import { createStringACL, createAclObjectFromString } from 'client/models/acl'
|
||||
import { createStringACL, createAclObjectFromString } from 'client/models/ACL'
|
||||
import { ACL_RIGHTS, ACL_TYPE_ID } from 'client/constants'
|
||||
|
||||
import systemApi from 'client/features/OneApi/system'
|
||||
@ -159,7 +159,7 @@ function CreateGroup() {
|
||||
// Go to groups list
|
||||
history.push(PATH.SYSTEM.GROUPS.LIST)
|
||||
} catch (error) {
|
||||
enqueueError('Error creating group: ' + error.message)
|
||||
enqueueError('Error creating group')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,76 +15,152 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { Actions, Commands } from 'server/utils/constants/commands/acl'
|
||||
import { oneApi, ONE_RESOURCES_POOL } from 'client/features/OneApi'
|
||||
import userApi from 'client/features/OneApi/user'
|
||||
import groupApi from 'client/features/OneApi/group'
|
||||
import clusterApi from 'client/features/OneApi/cluster'
|
||||
import zoneApi from 'client/features/OneApi/zone'
|
||||
|
||||
import { Acl } from 'client/constants'
|
||||
import { aclFromString } from 'client/models/ACL'
|
||||
const _ = require('lodash')
|
||||
|
||||
const { ACL_POOL } = ONE_RESOURCES_POOL
|
||||
|
||||
const basicEndpoints = (builder) => ({
|
||||
getAcls: builder.query({
|
||||
/**
|
||||
* Retrieves information for all the acls in the pool.
|
||||
*
|
||||
* @returns {Acl[]} Get list of acls
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
query: () => {
|
||||
const name = Actions.ACL_INFO
|
||||
const command = { name, ...Commands[name] }
|
||||
|
||||
return { command }
|
||||
},
|
||||
transformResponse: (data) => [data?.ACL_POOL?.ACL ?? []].flat(),
|
||||
providesTags: (acls) =>
|
||||
acls
|
||||
? [...acls.map(({ ID }) => ({ type: ACL_POOL, id: `${ID}` })), ACL_POOL]
|
||||
: [ACL_POOL],
|
||||
}),
|
||||
allocateAcl: builder.mutation({
|
||||
/**
|
||||
* Allocates a new acl in OpenNebula.
|
||||
*
|
||||
* @param {object} params - Request parameters
|
||||
* @param {string} params.user - User for the new acl
|
||||
* @param {string} params.resource - Resources for the new acl
|
||||
* @param {string} params.right - Rights for the new acl
|
||||
* @returns {number} The allocated Acl id
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
query: (params) => {
|
||||
const name = Actions.ACL_ADDRULE
|
||||
const command = { name, ...Commands[name] }
|
||||
|
||||
return { params, command }
|
||||
},
|
||||
invalidatesTags: [ACL_POOL],
|
||||
}),
|
||||
removeAcl: builder.mutation({
|
||||
/**
|
||||
* Deletes the given acl from the pool.
|
||||
*
|
||||
* @param {object} params - Request parameters
|
||||
* @param {string|number} params.id - Acl id
|
||||
* @returns {number} Acl id
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
query: (params) => {
|
||||
const name = Actions.ACL_DELRULE
|
||||
const command = { name, ...Commands[name] }
|
||||
|
||||
return { params, command }
|
||||
},
|
||||
invalidatesTags: [ACL_POOL],
|
||||
}),
|
||||
})
|
||||
|
||||
const extendedEnpoints = (builder) => ({
|
||||
getAclsExtended: builder.query({
|
||||
/**
|
||||
* Retrieves information for all the acls in the pool adding the names of users, groups, clusters and zones.
|
||||
*
|
||||
* @param {object} params - Request parameters
|
||||
* @param {object} props - Utils to use on queryFn function
|
||||
* @param {Function} props.dispatch - Function to dispatch queries
|
||||
* @returns {Acl[]} Get list of acls
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
queryFn: async (params = {}, { dispatch }) => {
|
||||
try {
|
||||
// Get users
|
||||
const users = await dispatch(
|
||||
userApi.endpoints.getUsers.initiate(undefined, { forceRefetch: true })
|
||||
).unwrap()
|
||||
|
||||
// Get groups
|
||||
const groups = await dispatch(
|
||||
groupApi.endpoints.getGroups.initiate(undefined, {
|
||||
forceRefetch: true,
|
||||
})
|
||||
).unwrap()
|
||||
|
||||
// Get clusters
|
||||
const clusters = await dispatch(
|
||||
clusterApi.endpoints.getClusters.initiate(undefined, {
|
||||
forceRefetch: true,
|
||||
})
|
||||
).unwrap()
|
||||
|
||||
// Get zones
|
||||
const zones = await dispatch(
|
||||
zoneApi.endpoints.getZones.initiate(undefined, { forceRefetch: true })
|
||||
).unwrap()
|
||||
|
||||
// Get acls
|
||||
const acls = await dispatch(
|
||||
aclApi.endpoints.getAcls.initiate(undefined, { forceRefetch: true })
|
||||
).unwrap()
|
||||
|
||||
const data = _.orderBy(
|
||||
acls,
|
||||
[(item) => parseInt(item.ID)],
|
||||
['desc']
|
||||
).map((acl) => ({
|
||||
ID: acl.ID,
|
||||
...aclFromString(acl.STRING, users, groups, clusters, zones),
|
||||
}))
|
||||
|
||||
// Return data
|
||||
return {
|
||||
data,
|
||||
}
|
||||
} catch (error) {
|
||||
return { error }
|
||||
}
|
||||
},
|
||||
providesTags: (acls) =>
|
||||
acls
|
||||
? [...acls.map(({ ID }) => ({ type: ACL_POOL, id: `${ID}` })), ACL_POOL]
|
||||
: [ACL_POOL],
|
||||
}),
|
||||
})
|
||||
|
||||
const aclApi = oneApi.injectEndpoints({
|
||||
endpoints: (builder) => ({
|
||||
getAcls: builder.query({
|
||||
/**
|
||||
* Retrieves information for all the acls in the pool.
|
||||
*
|
||||
* @returns {Acl[]} Get list of acls
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
query: () => {
|
||||
const name = Actions.ACL_INFO
|
||||
const command = { name, ...Commands[name] }
|
||||
|
||||
return { command }
|
||||
},
|
||||
transformResponse: (data) => [data?.ACL_POOL?.ACL ?? []].flat(),
|
||||
providesTags: (groups) =>
|
||||
groups
|
||||
? [
|
||||
...groups.map(({ ID }) => ({ type: ACL_POOL, id: `${ID}` })),
|
||||
ACL_POOL,
|
||||
]
|
||||
: [ACL_POOL],
|
||||
}),
|
||||
allocateAcl: builder.mutation({
|
||||
/**
|
||||
* Allocates a new acl in OpenNebula.
|
||||
*
|
||||
* @param {object} params - Request parameters
|
||||
* @param {string} params.user - User for the new acl
|
||||
* @param {string} params.resource - Resources for the new acl
|
||||
* @param {string} params.right - Rights for the new acl
|
||||
* @returns {number} The allocated Acl id
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
query: (params) => {
|
||||
const name = Actions.ACL_ADDRULE
|
||||
const command = { name, ...Commands[name] }
|
||||
|
||||
return { params, command }
|
||||
},
|
||||
invalidatesTags: [ACL_POOL],
|
||||
}),
|
||||
removeAcl: builder.mutation({
|
||||
/**
|
||||
* Deletes the given acl from the pool.
|
||||
*
|
||||
* @param {object} params - Request parameters
|
||||
* @param {string|number} params.id - Acl id
|
||||
* @returns {number} Acl id
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
query: (params) => {
|
||||
const name = Actions.ACL_DELRULE
|
||||
const command = { name, ...Commands[name] }
|
||||
|
||||
return { params, command }
|
||||
},
|
||||
invalidatesTags: [ACL_POOL],
|
||||
}),
|
||||
...basicEndpoints(builder),
|
||||
...extendedEnpoints(builder),
|
||||
}),
|
||||
})
|
||||
|
||||
export const {
|
||||
// Queries
|
||||
useGetAclQuery,
|
||||
useGetAclsQuery,
|
||||
useGetAclsExtendedQuery,
|
||||
|
||||
// Mutations
|
||||
useAllocateAclMutation,
|
||||
|
453
src/fireedge/src/client/models/ACL.js
Normal file
453
src/fireedge/src/client/models/ACL.js
Normal file
@ -0,0 +1,453 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
// File to functions about ACL
|
||||
|
||||
import { ACL_TYPE_ID, ACL_RIGHTS, T, ACL_USERS } from 'client/constants'
|
||||
import { parseAcl } from 'client/utils'
|
||||
|
||||
import { Tr } from 'client/components/HOC'
|
||||
const _ = require('lodash')
|
||||
|
||||
/**
|
||||
* Create an ACL object to send to the API.
|
||||
*
|
||||
* @param {string} user - The user value in hex value
|
||||
* @param {string} resource - The resource value in hex value
|
||||
* @param {string} rights - The rights value in hex value
|
||||
* @param {string} zone - The zone value in hex value
|
||||
* @returns {object} - The object to send to the API
|
||||
*/
|
||||
export const createAclObject = (user, resource, rights, zone) => {
|
||||
// Create response
|
||||
const response = {
|
||||
user: user,
|
||||
resource: resource,
|
||||
right: rights,
|
||||
}
|
||||
|
||||
// Add zone if exists
|
||||
if (zone) {
|
||||
response.zone = zone
|
||||
}
|
||||
|
||||
// Return response
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ACL object to sent to the API from a string rule like #5 HOST+VM/@12 INFO+CREATE+DELETE *.
|
||||
*
|
||||
* @param {string} rule - String rule
|
||||
* @returns {object} - The object to send to the API
|
||||
*/
|
||||
export const createAclObjectFromString = (rule) => {
|
||||
// Parse the rule to get values
|
||||
const ret = parseAcl(rule)
|
||||
|
||||
// Create response
|
||||
const response = {
|
||||
user: ret[0],
|
||||
resource: ret[1],
|
||||
right: ret[2],
|
||||
}
|
||||
|
||||
// Add zone if exists
|
||||
if (ret.length === 4) {
|
||||
response.zone = ret[3]
|
||||
}
|
||||
|
||||
// Return response
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string rule using the values from a form.
|
||||
*
|
||||
* @param {string} userType - Type of user, e.g. "#"
|
||||
* @param {number} userId - The id of the user, e.g. 4
|
||||
* @param {Array} resources - List of resources, e.g. ["VM,"TEMPLATE",IMAGE"]
|
||||
* @param {string} resourcesIdType - The type of the resources identifier, e.g. "#"
|
||||
* @param {number} resourcesId - The id user of the resources, e.g. 4
|
||||
* @param {Array} rights - List of rights, e.g. ["CREATE","USE"]
|
||||
* @param {string} zoneType - Type of the zone, e.g. "#"
|
||||
* @param {number} zoneId - The id of the user zone, e.g. 3
|
||||
* @returns {string} - ACL string rule
|
||||
*/
|
||||
export const createStringACL = (
|
||||
userType,
|
||||
userId,
|
||||
resources,
|
||||
resourcesIdType,
|
||||
resourcesId,
|
||||
rights,
|
||||
zoneType,
|
||||
zoneId
|
||||
) => {
|
||||
// Define the string as empty string
|
||||
|
||||
let userString = ''
|
||||
let resourcesString = ''
|
||||
const resourcesIdentifierString = ''
|
||||
let rightsString = ''
|
||||
let zoneString
|
||||
|
||||
// User: Type of user identifier plus the user identifier, e.g. @105
|
||||
if (userType) {
|
||||
if (userType === ACL_TYPE_ID.ALL) {
|
||||
userString += userType
|
||||
} else if (
|
||||
userType === ACL_TYPE_ID.INDIVIDUAL ||
|
||||
userType === ACL_TYPE_ID.GROUP
|
||||
)
|
||||
userString += userType + (userId ?? '')
|
||||
}
|
||||
|
||||
// Resources: List of resources separated by '+' plus the resources ID definition, e.g. VM+NET+IMAGE+TEMPLATE/#104
|
||||
resources?.forEach((resource, index) => {
|
||||
if (index < resources.length - 1) resourcesString += resource.name + '+'
|
||||
else resourcesString += resource.name + '/'
|
||||
})
|
||||
|
||||
if (resourcesIdType) {
|
||||
if (resourcesIdType === ACL_TYPE_ID.ALL) {
|
||||
resourcesString += resourcesIdType
|
||||
} else if (
|
||||
resourcesIdType === ACL_TYPE_ID.INDIVIDUAL ||
|
||||
resourcesIdType === ACL_TYPE_ID.GROUP ||
|
||||
resourcesIdType === ACL_TYPE_ID.CLUSTER
|
||||
) {
|
||||
resourcesString += resourcesIdType + (resourcesId ?? '')
|
||||
}
|
||||
}
|
||||
|
||||
// Rights: List of rights separated by '+', e.g. CREATE+USE
|
||||
rights?.forEach((right, index) => {
|
||||
if (index < rights.length - 1) rightsString += ACL_RIGHTS[right].name + '+'
|
||||
else rightsString += ACL_RIGHTS[right].name
|
||||
})
|
||||
|
||||
// Zone: Type of zone identifier plus the zone identifier, e.g. #44
|
||||
if (zoneType) {
|
||||
zoneString = zoneType + (zoneId ?? '')
|
||||
}
|
||||
|
||||
// Return the ACL string
|
||||
return (
|
||||
userString +
|
||||
' ' +
|
||||
resourcesString +
|
||||
resourcesIdentifierString +
|
||||
' ' +
|
||||
rightsString +
|
||||
(zoneString ? ' ' + zoneString : '')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a ACL string has the correct format.
|
||||
*
|
||||
* @param {string} rule - ACL rule
|
||||
* @returns {boolean} - If the rule it's ok or not
|
||||
*/
|
||||
export const validACL = (rule) => {
|
||||
// Regular expression for user component
|
||||
const userRegex = /([#@]\d+|[*])/
|
||||
|
||||
// Regular expression for resources component
|
||||
const resourceTypePattern =
|
||||
/(VM|HOST|NET|IMAGE|USER|TEMPLATE|GROUP|DATASTORE|CLUSTER|DOCUMENT|ZONE|SECGROUP|VDC|VROUTER|MARKETPLACE|MARKETPLACEAPP|VMGROUP|VNTEMPLATE|BACKUPJOB)/
|
||||
const otherResourcesTypePattern = new RegExp(
|
||||
`(\\+${resourceTypePattern.source})*`
|
||||
)
|
||||
const resourcesUserRegex = /([#@%]\d+|[*])/
|
||||
const resourcesRegex = new RegExp(
|
||||
`${resourceTypePattern.source}${otherResourcesTypePattern.source}\\/${resourcesUserRegex.source}`
|
||||
)
|
||||
|
||||
// Regular expression for rights component
|
||||
const rightsTypePattern = /(USE|MANAGE|ADMIN|CREATE)/
|
||||
const otherRightsTypePattern = new RegExp(`(\\+${rightsTypePattern.source})*`)
|
||||
const rightsRegex = new RegExp(
|
||||
`${rightsTypePattern.source}${otherRightsTypePattern.source}`
|
||||
)
|
||||
|
||||
// Regular expression for zone component
|
||||
const zoneRegex = /(\*|#\d+)/
|
||||
|
||||
// ACL regular expression
|
||||
const aclRuleRegex = new RegExp(
|
||||
`^${userRegex.source}\\s${resourcesRegex.source}\\s${rightsRegex.source}(\\s${zoneRegex.source})?$`
|
||||
)
|
||||
|
||||
// Check rule
|
||||
return aclRuleRegex.test(rule)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a human readable message with the meaning of the rule.
|
||||
*
|
||||
* @param {string} rule - The ACL sring rule
|
||||
* @param {Array} users - List of users
|
||||
* @param {Array} groups - List of groups
|
||||
* @param {Array} clusters - List of clusters
|
||||
* @param {Array} zones - List of zones
|
||||
* @returns {string} - The meaning of the rule
|
||||
*/
|
||||
export const translateACL = (rule, users, groups, clusters, zones) => {
|
||||
// Create a readable object from the string rule
|
||||
const acl = aclFromString(rule, users, groups, clusters, zones)
|
||||
|
||||
// Define the message
|
||||
let message = Tr(T['acls.translate.rule']) + ' '
|
||||
|
||||
// User info
|
||||
if (
|
||||
acl.USER?.type &&
|
||||
acl.USER.type === ACL_USERS.INDIVIDUAL.type &&
|
||||
acl.USER?.id
|
||||
) {
|
||||
message += Tr(T['acls.translate.user.id']) + ' '
|
||||
if (acl.USER.id) {
|
||||
message += acl.USER.id + ' '
|
||||
}
|
||||
if (acl.USER.name) {
|
||||
message += ' (' + acl.USER.name + ') '
|
||||
}
|
||||
} else if (
|
||||
acl.USER?.type &&
|
||||
acl.USER.type === ACL_USERS.GROUP.type &&
|
||||
acl.USER?.id
|
||||
) {
|
||||
message += Tr(T['acls.translate.user.group']) + ' ' + acl.USER.id + ' '
|
||||
if (acl.USER.name) {
|
||||
message += ' (' + acl.USER.name + ') '
|
||||
}
|
||||
} else if (acl.USER?.type && acl.USER.type === ACL_USERS.ALL.type) {
|
||||
message += Tr(T['acls.translate.user.all']) + ' '
|
||||
}
|
||||
|
||||
// Rights info
|
||||
message += Tr(T['acls.translate.rights']) + ' '
|
||||
|
||||
const rights = acl.RIGHTS?.rights
|
||||
|
||||
rights?.forEach((right, index) => {
|
||||
if (index === rights.length - 1) {
|
||||
message += right
|
||||
} else {
|
||||
message += right + ' ' + Tr(T['acls.translate.and']) + ' '
|
||||
}
|
||||
})
|
||||
|
||||
if (rights?.length > 1) {
|
||||
message += ' ' + Tr(T['acls.translate.operations']) + ' '
|
||||
} else {
|
||||
message += ' ' + Tr(T['acls.translate.operation']) + ' '
|
||||
}
|
||||
|
||||
// Resources info
|
||||
if (
|
||||
acl.RESOURCE?.identifier.type &&
|
||||
acl.RESOURCE.identifier.type === ACL_USERS.INDIVIDUAL.type
|
||||
) {
|
||||
message += Tr(T['acls.translate.overall']) + ' '
|
||||
} else {
|
||||
message += Tr(T['acls.translate.over']) + ' '
|
||||
}
|
||||
|
||||
acl.RESOURCE?.resources.forEach((resource, index) => {
|
||||
if (index === acl.RESOURCE.resources.length - 1) {
|
||||
message += resource
|
||||
} else {
|
||||
message += resource + ' ' + Tr(T['acls.translate.and']) + ' '
|
||||
}
|
||||
})
|
||||
|
||||
// Resources identifier info
|
||||
if (
|
||||
acl.RESOURCE?.identifier.type &&
|
||||
acl.RESOURCE.identifier.type === ACL_USERS.INDIVIDUAL.type &&
|
||||
acl.RESOURCE?.identifier.id
|
||||
) {
|
||||
message +=
|
||||
' ' +
|
||||
Tr(T['acls.translate.resource.id']) +
|
||||
' ' +
|
||||
acl.RESOURCE.identifier.id
|
||||
} else if (
|
||||
acl.RESOURCE?.identifier.type &&
|
||||
acl.RESOURCE.identifier.type === ACL_USERS.GROUP.type &&
|
||||
acl.RESOURCE?.identifier.id
|
||||
) {
|
||||
message +=
|
||||
' ' +
|
||||
Tr(T['acls.translate.resource.group']) +
|
||||
' ' +
|
||||
acl.RESOURCE.identifier.id
|
||||
if (acl.RESOURCE.identifier.name) {
|
||||
message += ' (' + acl.RESOURCE.identifier.name + ')'
|
||||
}
|
||||
} else if (
|
||||
acl.RESOURCE?.identifier.type &&
|
||||
acl.RESOURCE.identifier.type === ACL_USERS.CLUSTER.type &&
|
||||
acl.RESOURCE?.identifier.id
|
||||
) {
|
||||
message +=
|
||||
' ' +
|
||||
Tr(T['acls.translate.resource.cluster']) +
|
||||
' ' +
|
||||
acl.RESOURCE.identifier.id
|
||||
if (acl.RESOURCE.identifier.name) {
|
||||
message += ' (' + acl.RESOURCE.identifier.name + ')'
|
||||
}
|
||||
}
|
||||
|
||||
// Zone info
|
||||
if (acl.ZONE?.type && acl.ZONE?.type === ACL_USERS.INDIVIDUAL.type) {
|
||||
message += ' ' + Tr(T['acls.translate.zone.id']) + ' ' + acl.ZONE.id
|
||||
if (acl.ZONE.name) {
|
||||
message += ' (' + acl.ZONE.name + ')'
|
||||
}
|
||||
} else if (acl.ZONE?.type === ACL_USERS.ALL.type) {
|
||||
message += ' ' + Tr(T['acls.translate.zone.all'])
|
||||
}
|
||||
|
||||
// Return message
|
||||
return message
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a readable object from an acl rule.
|
||||
*
|
||||
* @param {string} rule - ACL rule
|
||||
* @param {Array} users - List of users
|
||||
* @param {Array} groups - List of groups
|
||||
* @param {Array} clusters - List of clusters
|
||||
* @param {Array} zones - List of zones
|
||||
* @returns {object} The ACL rule in a readable object
|
||||
*/
|
||||
export const aclFromString = (rule, users, groups, clusters, zones) => {
|
||||
// Create object
|
||||
const acl = {
|
||||
STRING: rule,
|
||||
}
|
||||
|
||||
// Split rule
|
||||
const aclComponents = acl.STRING.split(' ')
|
||||
|
||||
// User
|
||||
if (aclComponents[0]) {
|
||||
// Get user info
|
||||
const user = aclComponents[0]
|
||||
|
||||
// Set user values
|
||||
const userType = _.find(ACL_USERS, { id: user.charAt(0) })?.type
|
||||
const userId = user.length > 1 ? user.substring(1) : undefined
|
||||
let username
|
||||
if (userType === ACL_USERS.INDIVIDUAL.type && users) {
|
||||
username = _.find(users, { ID: userId })?.NAME
|
||||
} else if (userType === ACL_USERS.GROUP.type && groups) {
|
||||
username = _.find(groups, { ID: userId })?.NAME
|
||||
}
|
||||
|
||||
// Create user object
|
||||
acl.USER = {
|
||||
type: userType,
|
||||
id: userId,
|
||||
string: aclComponents[0],
|
||||
name: username,
|
||||
}
|
||||
}
|
||||
|
||||
// Resources
|
||||
if (aclComponents[1]) {
|
||||
// Get resources info
|
||||
const resourcesComponents = aclComponents[1].split('/')
|
||||
const resources = resourcesComponents[0].split('+')
|
||||
const resourcesIdentifier = resourcesComponents[1]
|
||||
|
||||
// Set resource user values
|
||||
const resourceUserType = _.find(ACL_USERS, {
|
||||
id: resourcesIdentifier.charAt(0),
|
||||
})?.type
|
||||
const resourceId =
|
||||
resourcesIdentifier.length > 1
|
||||
? resourcesIdentifier.substring(1)
|
||||
: undefined
|
||||
let resourceUsername
|
||||
if (resourceUserType === ACL_USERS.GROUP.type && groups) {
|
||||
resourceUsername = _.find(groups, {
|
||||
ID: resourceId,
|
||||
})?.NAME
|
||||
} else if (resourceUserType === ACL_USERS.CLUSTER.type && clusters) {
|
||||
resourceUsername = _.find(clusters, {
|
||||
ID: resourceId,
|
||||
})?.NAME
|
||||
}
|
||||
|
||||
// Create resource object
|
||||
acl.RESOURCE = {
|
||||
resources: resources,
|
||||
identifier: {
|
||||
type: resourceUserType,
|
||||
id: resourceId,
|
||||
string: resourcesIdentifier,
|
||||
name: resourceUsername,
|
||||
},
|
||||
string: resourcesComponents,
|
||||
}
|
||||
}
|
||||
|
||||
// Rights
|
||||
if (aclComponents[2]) {
|
||||
// Get rights info
|
||||
const rights = aclComponents[2].split('+')
|
||||
acl.RIGHTS = {
|
||||
rights: rights,
|
||||
string: aclComponents[2],
|
||||
}
|
||||
}
|
||||
|
||||
// Zone
|
||||
if (aclComponents[3]) {
|
||||
// Create rights object
|
||||
const zone = aclComponents[3]
|
||||
|
||||
if (zone) {
|
||||
// Set zone values
|
||||
const zoneType = _.find(ACL_USERS, { id: zone.charAt(0) }).type
|
||||
const zoneId = zone.length > 1 ? zone.substring(1) : undefined
|
||||
|
||||
let zonename
|
||||
if (zoneType === ACL_USERS.INDIVIDUAL.type && zones) {
|
||||
zonename = _.find(zones, { ID: zoneId })?.NAME
|
||||
}
|
||||
|
||||
if (zone) {
|
||||
acl.ZONE = {
|
||||
type: zoneType,
|
||||
id: zoneId,
|
||||
string: zone,
|
||||
name: zonename,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return acl
|
||||
return acl
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2023, 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
// File to functions about ACL
|
||||
|
||||
import { ACL_TYPE_ID, ACL_RIGHTS } from 'client/constants'
|
||||
import { parseAcl } from 'client/utils'
|
||||
|
||||
/**
|
||||
* Create an ACL object to send to the API.
|
||||
*
|
||||
* @param {string} user - The user value in hex value
|
||||
* @param {string} resource - The resource value in hex value
|
||||
* @param {string} rights - The rights value in hex value
|
||||
* @param {string} zone - The zone value in hex value
|
||||
* @returns {object} - The object to send to the API
|
||||
*/
|
||||
export const createAclObject = (user, resource, rights, zone) => {
|
||||
// Create response
|
||||
const response = {
|
||||
user: user,
|
||||
resource: resource,
|
||||
right: rights,
|
||||
}
|
||||
|
||||
// Add zone if exists
|
||||
if (zone) {
|
||||
response.zone = zone
|
||||
}
|
||||
|
||||
// Return response
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ACL object to sent to the API from a string rule like #5 HOST+VM/@12 INFO+CREATE+DELETE *.
|
||||
*
|
||||
* @param {string} rule - String rule
|
||||
* @returns {object} - The object to send to the API
|
||||
*/
|
||||
export const createAclObjectFromString = (rule) => {
|
||||
// Parse the rule to get values
|
||||
const ret = parseAcl(rule)
|
||||
|
||||
// Create response
|
||||
const response = {
|
||||
user: ret[0],
|
||||
resource: ret[1],
|
||||
right: ret[2],
|
||||
}
|
||||
|
||||
// Add zone if exists
|
||||
if (ret.length === 4) {
|
||||
response.zone = ret[3]
|
||||
}
|
||||
|
||||
// Return response
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string rule using the values from a form.
|
||||
*
|
||||
* @param {string} userType - Type of user, e.g. "#"
|
||||
* @param {number} userId - The id of the user, e.g. 4
|
||||
* @param {Array} resources - List of resources, e.g. ["VM,"TEMPLATE",IMAGE"]
|
||||
* @param {string} resourcesIdType - The type of the resources identifier, e.g. "#"
|
||||
* @param {number} resourcesId - The id user of the resources, e.g. 4
|
||||
* @param {Array} rights - List of rights, e.g. ["CREATE","USE"]
|
||||
* @param {string} zoneType - Type of the zone, e.g. "#"
|
||||
* @param {number} zoneId - The id of the user zone, e.g. 3
|
||||
* @returns {string} - ACL string rule
|
||||
*/
|
||||
export const createStringACL = (
|
||||
userType,
|
||||
userId,
|
||||
resources,
|
||||
resourcesIdType,
|
||||
resourcesId,
|
||||
rights,
|
||||
zoneType,
|
||||
zoneId
|
||||
) => {
|
||||
// Define the string as empty string
|
||||
let acl = ''
|
||||
|
||||
// User: Type of user identifier plus the user identifier, e.g. @105
|
||||
acl += userType === ACL_TYPE_ID.ALL ? userType + ' ' : userType + userId + ' '
|
||||
|
||||
// Resources: List of resources separated by '+' plus the resources ID definition, e.g. VM+NET+IMAGE+TEMPLATE/#104
|
||||
resources.forEach((resource, index) => {
|
||||
if (index < resources.length - 1) acl += resource.name + '+'
|
||||
else acl += resource.name + '/'
|
||||
})
|
||||
|
||||
acl +=
|
||||
resourcesIdType === ACL_TYPE_ID.ALL
|
||||
? resourcesIdType + ' '
|
||||
: resourcesIdType + resourcesId + ' '
|
||||
|
||||
// Rights: List of rights separated by '+', e.g. CREATE+USE
|
||||
rights.forEach((right, index) => {
|
||||
if (index < rights.length - 1) acl += ACL_RIGHTS[right].name + '+'
|
||||
else
|
||||
acl +=
|
||||
zoneType && zoneId
|
||||
? ACL_RIGHTS[right].name + ' '
|
||||
: ACL_RIGHTS[right].name
|
||||
})
|
||||
|
||||
// Zone: Type of zone identifier plus the zone identifier, e.g. #44
|
||||
if (zoneType && zoneId) {
|
||||
acl += zoneType + zoneId
|
||||
}
|
||||
|
||||
// Return the ACL string
|
||||
return acl
|
||||
}
|
@ -17,7 +17,7 @@ import templateToObject from 'client/utils/parser/templateToObject'
|
||||
import parseApplicationToForm from 'client/utils/parser/parseApplicationToForm'
|
||||
import parseFormToApplication from 'client/utils/parser/parseFormToApplication'
|
||||
import parseFormToDeployApplication from 'client/utils/parser/parseFormToDeployApplication'
|
||||
import parseAcl from 'client/utils/parser/parseACL'
|
||||
import { parseAcl } from 'client/utils/parser/parseACL'
|
||||
|
||||
export {
|
||||
templateToObject,
|
||||
|
@ -25,7 +25,7 @@ import { ACL_ID, ACL_RESOURCES, ACL_RIGHTS } from 'client/constants'
|
||||
* @param {string} rule - The ACL rule
|
||||
* @returns {number} - The hex value for the four components of a rule (user, resources, rights and zone)
|
||||
*/
|
||||
const parseAcl = (rule) => {
|
||||
export const parseAcl = (rule) => {
|
||||
// Get each component
|
||||
const ruleComponents = rule.split(' ')
|
||||
|
||||
@ -140,6 +140,3 @@ const calculateIds = (id) => {
|
||||
// Return the integer id value
|
||||
return idValue
|
||||
}
|
||||
|
||||
// Export parseRule function
|
||||
export default parseAcl
|
||||
|
@ -47,6 +47,10 @@ module.exports = {
|
||||
from: postBody,
|
||||
default: '0x1',
|
||||
},
|
||||
zone: {
|
||||
from: postBody,
|
||||
default: '0x100000000',
|
||||
},
|
||||
},
|
||||
},
|
||||
[ACL_DELRULE]: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user