Skip to content

Commit

Permalink
F #6413: Add restricted attributes log (#3080)
Browse files Browse the repository at this point in the history
on the VM tabs

Signed-off-by: David Carracedo <dcarracedo@opennebula.io>
Co-authored-by: Tino Vázquez <cvazquez@opennebula.io>
  • Loading branch information
dcarracedo and tinova committed May 27, 2024
1 parent 1a320ba commit e92fec4
Show file tree
Hide file tree
Showing 23 changed files with 291 additions and 336 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ import { HYPERVISORS } from 'client/constants'
/**
* @param {object} props - Component props
* @param {HYPERVISORS} props.hypervisor - VM hypervisor
* @param {object} props.oneConfig - Config of oned.conf
* @param {boolean} props.adminGroup - User is admin or not
* @returns {ReactElement} OS section component
*/
const OsSection = ({ hypervisor }) => {
const sections = useMemo(() => SECTIONS({ hypervisor }), [hypervisor])
const OsSection = ({ hypervisor, oneConfig, adminGroup }) => {
const sections = useMemo(
() => SECTIONS({ hypervisor, oneConfig, adminGroup }),
[hypervisor]
)

return (
<Stack
Expand All @@ -42,6 +47,10 @@ const OsSection = ({ hypervisor }) => {
)
}

OsSection.propTypes = { hypervisor: PropTypes.string }
OsSection.propTypes = {
hypervisor: PropTypes.string,
oneConfig: PropTypes.object,
adminGroup: PropTypes.bool,
}

export default OsSection
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
Section,
getObjectSchemaFromFields,
filterFieldsByHypervisor,
disableFields,
} from 'client/utils'
import { T, HYPERVISORS, ATTR_CONF_CAN_BE_UPDATED } from 'client/constants'

Expand All @@ -36,24 +37,41 @@ const RAW_FIELDS = getFields(ATTR_CONF_CAN_BE_UPDATED.RAW)
/**
* @param {object} [formProps] - Form props
* @param {HYPERVISORS} [formProps.hypervisor] - VM hypervisor
* @param {object} formProps.oneConfig - Config of oned.conf
* @param {boolean} formProps.adminGroup - User is admin or not
* @returns {Section[]} Sections
*/
const SECTIONS = ({ hypervisor }) => [
const SECTIONS = ({ hypervisor, oneConfig, adminGroup }) => [
{
id: 'os-boot',
legend: T.Boot,
fields: filterFieldsByHypervisor(OS_FIELDS, hypervisor),
fields: disableFields(
filterFieldsByHypervisor(OS_FIELDS, hypervisor),
'OS',
oneConfig,
adminGroup
),
},
{
id: 'os-features',
legend: T.Features,
fields: filterFieldsByHypervisor(FEATURES_FIELDS, hypervisor),
fields: disableFields(
filterFieldsByHypervisor(FEATURES_FIELDS, hypervisor),
'OS',
oneConfig,
adminGroup
),
},
{
id: 'os-raw',
legend: T.RawData,
legendTooltip: T.RawDataConcept,
fields: filterFieldsByHypervisor(RAW_FIELDS, hypervisor),
fields: disableFields(
filterFieldsByHypervisor(RAW_FIELDS, hypervisor),
'OS',
oneConfig,
adminGroup
),
},
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,42 @@ import { T, HYPERVISORS } from 'client/constants'
/**
* @param {object} props - Component props
* @param {HYPERVISORS} props.hypervisor - VM hypervisor
* @param {object} props.oneConfig - Config of oned.conf
* @param {boolean} props.adminGroup - User is admin or not
* @returns {ReactElement} IO section component
*/
const InputOutput = ({ hypervisor }) => (
const InputOutput = ({ hypervisor, oneConfig, adminGroup }) => (
<Stack
display="grid"
gap="1em"
sx={{ gridTemplateColumns: { sm: '1fr', md: '1fr 1fr' } }}
>
<FormWithSchema
cy={'io-graphics'}
fields={useMemo(() => GRAPHICS_FIELDS({ hypervisor }), [hypervisor])}
fields={useMemo(
() => GRAPHICS_FIELDS({ hypervisor, oneConfig, adminGroup }),
[hypervisor]
)}
legend={T.Graphics}
/>
<InputsSection hypervisor={hypervisor} />
<VideoSection hypervisor={hypervisor} />
<InputsSection
hypervisor={hypervisor}
oneConfig={oneConfig}
adminGroup={adminGroup}
/>
<VideoSection
hypervisor={hypervisor}
oneConfig={oneConfig}
adminGroup={adminGroup}
/>
</Stack>
)

InputOutput.propTypes = { hypervisor: PropTypes.string }
InputOutput.propTypes = {
hypervisor: PropTypes.string,
oneConfig: PropTypes.object,
adminGroup: PropTypes.bool,
}
InputOutput.displayName = 'InputOutput'

export default InputOutput
8 changes: 7 additions & 1 deletion src/fireedge/src/client/components/Tabs/File/Info/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ import { cloneObject, set } from 'client/utils'
* @param {object} props - Props
* @param {object} props.tabProps - Tab information
* @param {string} props.id - Image id
* @param {object} props.oneConfig - OpenNEbula configuration
* @param {boolean} props.adminGroup - If the user is admin
* @returns {ReactElement} Information tab
*/
const ImageInfoTab = ({ tabProps = {}, id }) => {
const ImageInfoTab = ({ tabProps = {}, id, oneConfig, adminGroup }) => {
const {
information_panel: informationPanel,
permissions_panel: permissionsPanel,
Expand Down Expand Up @@ -96,6 +98,8 @@ const ImageInfoTab = ({ tabProps = {}, id }) => {
<Information
image={image}
actions={getActions(informationPanel?.actions)}
oneConfig={oneConfig}
adminGroup={adminGroup}
/>
)}
{permissionsPanel?.enabled && (
Expand Down Expand Up @@ -138,6 +142,8 @@ const ImageInfoTab = ({ tabProps = {}, id }) => {
ImageInfoTab.propTypes = {
tabProps: PropTypes.object,
id: PropTypes.string,
oneConfig: PropTypes.object,
adminGroup: PropTypes.bool,
}

ImageInfoTab.displayName = 'ImageInfoTab'
Expand Down
11 changes: 9 additions & 2 deletions src/fireedge/src/client/components/Tabs/File/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import PropTypes from 'prop-types'
import { memo, useMemo } from 'react'

import { RESOURCE_NAMES } from 'client/constants'
import { useViews } from 'client/features/Auth'
import { useViews, useSystemData } from 'client/features/Auth'
import { useGetImageQuery } from 'client/features/OneApi/image'
import { getAvailableInfoTabs } from 'client/models/Helper'

Expand All @@ -33,12 +33,19 @@ const getTabComponent = (tabName) =>
const FileTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isError, error, status, data } = useGetImageQuery({ id })
const { adminGroup, oneConfig } = useSystemData()

const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.IMAGE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}

return getAvailableInfoTabs(infoTabs, getTabComponent, id)
return getAvailableInfoTabs(
infoTabs,
getTabComponent,
id,
oneConfig,
adminGroup
)
}, [view, id])

if (isError) {
Expand Down
8 changes: 7 additions & 1 deletion src/fireedge/src/client/components/Tabs/Image/Info/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ import { cloneObject, set } from 'client/utils'
* @param {object} props - Props
* @param {object} props.tabProps - Tab information
* @param {string} props.id - Image id
* @param {object} props.oneConfig - OpenNEbula configuration
* @param {boolean} props.adminGroup - If the user is admin
* @returns {ReactElement} Information tab
*/
const ImageInfoTab = ({ tabProps = {}, id }) => {
const ImageInfoTab = ({ tabProps = {}, id, oneConfig, adminGroup }) => {
const {
information_panel: informationPanel,
permissions_panel: permissionsPanel,
Expand Down Expand Up @@ -96,6 +98,8 @@ const ImageInfoTab = ({ tabProps = {}, id }) => {
<Information
image={image}
actions={getActions(informationPanel?.actions)}
oneConfig={oneConfig}
adminGroup={adminGroup}
/>
)}
{permissionsPanel?.enabled && (
Expand Down Expand Up @@ -138,6 +142,8 @@ const ImageInfoTab = ({ tabProps = {}, id }) => {
ImageInfoTab.propTypes = {
tabProps: PropTypes.object,
id: PropTypes.string,
oneConfig: PropTypes.object,
adminGroup: PropTypes.bool,
}

ImageInfoTab.displayName = 'ImageInfoTab'
Expand Down
29 changes: 25 additions & 4 deletions src/fireedge/src/client/components/Tabs/Image/Info/information.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,18 @@ import {
booleanToString,
levelLockToString,
} from 'client/models/Helper'
import { arrayToOptions, prettyBytes } from 'client/utils'
import { T, Image, IMAGE_ACTIONS, IMAGE_TYPES } from 'client/constants'
import {
arrayToOptions,
prettyBytes,
isRestrictedAttributes,
} from 'client/utils'
import {
T,
Image,
IMAGE_ACTIONS,
IMAGE_TYPES,
RESTRICTED_ATTRIBUTES_TYPE,
} from 'client/constants'
import { PATH } from 'client/apps/sunstone/routesOne'

/**
Expand All @@ -41,9 +51,11 @@ import { PATH } from 'client/apps/sunstone/routesOne'
* @param {object} props - Props
* @param {Image} props.image - Image resource
* @param {string[]} props.actions - Available actions to information tab
* @param {object} props.oneConfig - Open Nebula configuration
* @param {boolean} props.adminGroup - If the user belongs to oneadmin group
* @returns {ReactElement} Information tab
*/
const InformationPanel = ({ image = {}, actions }) => {
const InformationPanel = ({ image = {}, actions, oneConfig, adminGroup }) => {
const [rename] = useRenameImageMutation()
const [changeType] = useChangeImageTypeMutation()
const [persistent] = usePersistentImageMutation()
Expand Down Expand Up @@ -91,7 +103,14 @@ const InformationPanel = ({ image = {}, actions }) => {
name: T.Name,
value: NAME,
dataCy: 'name',
canEdit: actions?.includes?.(IMAGE_ACTIONS.RENAME),
canEdit:
actions?.includes?.(IMAGE_ACTIONS.RENAME) &&
(adminGroup ||
!isRestrictedAttributes(
'NAME',
undefined,
oneConfig[RESTRICTED_ATTRIBUTES_TYPE.IMAGE]
)),
handleEdit: handleRename,
},
DATASTORE_ID && {
Expand Down Expand Up @@ -166,6 +185,8 @@ const InformationPanel = ({ image = {}, actions }) => {
InformationPanel.propTypes = {
image: PropTypes.object,
actions: PropTypes.arrayOf(PropTypes.string),
oneConfig: PropTypes.object,
adminGroup: PropTypes.bool,
}

InformationPanel.displayName = 'InformationPanel'
Expand Down
11 changes: 9 additions & 2 deletions src/fireedge/src/client/components/Tabs/Image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import PropTypes from 'prop-types'
import { memo, useMemo } from 'react'

import { RESOURCE_NAMES } from 'client/constants'
import { useViews } from 'client/features/Auth'
import { useViews, useSystemData } from 'client/features/Auth'
import { useGetImageQuery } from 'client/features/OneApi/image'
import { getAvailableInfoTabs } from 'client/models/Helper'

Expand All @@ -37,12 +37,19 @@ const getTabComponent = (tabName) =>
const ImageTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isError, error, status, data } = useGetImageQuery({ id })
const { adminGroup, oneConfig } = useSystemData()

const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.IMAGE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}

return getAvailableInfoTabs(infoTabs, getTabComponent, id)
return getAvailableInfoTabs(
infoTabs,
getTabComponent,
id,
oneConfig,
adminGroup
)
}, [view, id])

if (isError) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ const HIDDEN_ATTRIBUTES_REG =
* @param {object} props - Props
* @param {object} props.tabProps - Tab information
* @param {string} props.id - Virtual network id
* @param {object} props.oneConfig - OpenNebula configuration
* @param {boolean} props.adminGroup - If the user is admin
* @returns {ReactElement} Information tab
*/
const VNetworkInfoTab = ({ tabProps = {}, id }) => {
const VNetworkInfoTab = ({ tabProps = {}, id, oneConfig, adminGroup }) => {
const {
information_panel: informationPanel,
permissions_panel: permissionsPanel,
Expand Down Expand Up @@ -121,6 +123,8 @@ const VNetworkInfoTab = ({ tabProps = {}, id }) => {
<Information
vnet={vnet}
actions={getActions(informationPanel?.actions)}
oneConfig={oneConfig}
adminGroup={adminGroup}
/>
)}
{permissionsPanel?.enabled && (
Expand Down Expand Up @@ -183,6 +187,8 @@ const VNetworkInfoTab = ({ tabProps = {}, id }) => {
VNetworkInfoTab.propTypes = {
tabProps: PropTypes.object,
id: PropTypes.string,
oneConfig: PropTypes.object,
adminGroup: PropTypes.bool,
}

VNetworkInfoTab.displayName = 'VNetworkInfoTab'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,26 @@ import {
booleanToString,
} from 'client/models/Helper'
import { getState } from 'client/models/VirtualNetwork'
import { T, VNetwork, VN_ACTIONS } from 'client/constants'
import {
T,
VNetwork,
VN_ACTIONS,
RESTRICTED_ATTRIBUTES_TYPE,
} from 'client/constants'
import { PATH } from 'client/apps/sunstone/routesOne'
import { isRestrictedAttributes } from 'client/utils'

/**
* Renders mainly information tab.
*
* @param {object} props - Props
* @param {VNetwork} props.vnet - Virtual Network resource
* @param {string[]} props.actions - Available actions to information tab
* @param {object} props.oneConfig - Open Nebula configuration
* @param {boolean} props.adminGroup - If the user belongs to oneadmin group
* @returns {ReactElement} Information tab
*/
const InformationPanel = ({ vnet = {}, actions }) => {
const InformationPanel = ({ vnet = {}, actions, oneConfig, adminGroup }) => {
const [rename] = useRenameVNetMutation()
const {
ID,
Expand Down Expand Up @@ -73,7 +81,14 @@ const InformationPanel = ({ vnet = {}, actions }) => {
name: T.Name,
value: NAME,
dataCy: 'name',
canEdit: actions?.includes?.(VN_ACTIONS.RENAME),
canEdit:
actions?.includes?.(VN_ACTIONS.RENAME) &&
(adminGroup ||
!isRestrictedAttributes(
'NAME',
undefined,
oneConfig[RESTRICTED_ATTRIBUTES_TYPE.VNET]
)),
handleEdit: handleRename,
},
parentId && {
Expand Down Expand Up @@ -134,6 +149,8 @@ const InformationPanel = ({ vnet = {}, actions }) => {
InformationPanel.propTypes = {
vnet: PropTypes.object,
actions: PropTypes.arrayOf(PropTypes.string),
oneConfig: PropTypes.object,
adminGroup: PropTypes.bool,
}

InformationPanel.displayName = 'InformationPanel'
Expand Down
Loading

0 comments on commit e92fec4

Please sign in to comment.