1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-23 22:50:09 +03:00

F #5422: Add collapse to list attributes (#2021)

This commit is contained in:
Sergio Betanzos 2022-05-11 13:25:26 +02:00 committed by GitHub
parent 0e03e3c8ed
commit f3285b3e30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 131 additions and 89 deletions

View File

@ -17,17 +17,15 @@ import { memo, useMemo } from 'react'
import PropTypes from 'prop-types'
import {
styled,
useMediaQuery,
Typography,
Box,
Paper,
Stack,
Accordion as MuiAccordion,
AccordionSummary as MuiAccordionSummary,
AccordionDetails as MuiAccordionDetails,
Accordion,
AccordionSummary,
AccordionDetails,
} from '@mui/material'
import { NavArrowRight } from 'iconoir-react'
import { rowStyles } from 'client/components/Tables/styles'
import { StatusChip } from 'client/components/Status'
@ -38,38 +36,6 @@ import { stringToBoolean } from 'client/models/Helper'
import { groupBy } from 'client/utils'
import { T, Nic, NicAlias, PrettySecurityGroupRule } from 'client/constants'
const Accordion = styled((props) => (
<MuiAccordion disableGutters elevation={0} square {...props} />
))(({ theme }) => ({
flexBasis: '100%',
border: `1px solid ${theme.palette.divider}`,
'&:before': { display: 'none' },
}))
const AccordionSummary = styled((props) => (
<MuiAccordionSummary expandIcon={<NavArrowRight />} {...props} />
))(({ theme }) => ({
backgroundColor:
theme.palette.mode === 'dark'
? 'rgba(255, 255, 255, .05)'
: 'rgba(0, 0, 0, .03)',
'&:not(:last-child)': {
borderBottom: 0,
},
flexDirection: 'row-reverse',
'& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
transform: 'rotate(90deg)',
},
'& .MuiAccordionSummary-content': {
marginLeft: theme.spacing(1),
},
}))
const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({
padding: theme.spacing(2),
borderTop: '1px solid rgba(0, 0, 0, .125)',
}))
const NicCard = memo(
({
nic = {},
@ -173,7 +139,7 @@ const NicCard = memo(
const rulesById = Object.entries(groupBy(SECURITY_GROUPS, 'ID'))
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<Accordion>
<AccordionSummary>
<Typography variant="body1">
<Translate word={T.SecurityGroups} />

View File

@ -89,6 +89,7 @@ const AttributePanel = memo(
handleAdd,
actions = [],
filtersSpecialAttributes = true,
collapse = false,
}) => {
const classes = useStyles()
@ -121,6 +122,7 @@ const AttributePanel = memo(
title={title}
list={formatAttributes}
handleAdd={actions?.includes?.(ADD) && handleAdd}
collapse={collapse}
/>
)
}
@ -134,6 +136,7 @@ AttributePanel.propTypes = {
handleDelete: PropTypes.func,
title: PropTypes.string,
filtersSpecialAttributes: PropTypes.bool,
collapse: PropTypes.bool,
}
AttributePanel.displayName = 'AttributePanel'

View File

@ -14,38 +14,43 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
/* eslint-disable jsdoc/require-jsdoc */
import { Fragment, isValidElement } from 'react'
import { useMemo, Fragment, isValidElement } from 'react'
import PropTypes from 'prop-types'
import clsx from 'clsx'
import { List as MList, ListItem, Typography, Paper } from '@mui/material'
import makeStyles from '@mui/styles/makeStyles'
import {
styled,
Accordion,
AccordionSummary,
AccordionDetails,
Box,
List,
ListItem,
Typography,
Paper,
} from '@mui/material'
import {
Attribute,
AttributePropTypes,
} from 'client/components/Tabs/Common/Attribute'
import AttributeCreateForm from 'client/components/Tabs/Common/AttributeCreateForm'
import { Tr } from 'client/components/HOC'
const useStyles = makeStyles((theme) => ({
title: {
fontWeight: theme.typography.fontWeightBold,
borderBottom: `1px solid ${theme.palette.divider}`,
const Title = styled(ListItem)(({ theme }) => ({
fontWeight: theme.typography.fontWeightBold,
borderBottom: `1px solid ${theme.palette.divider}`,
}))
const Item = styled(ListItem)(({ theme }) => ({
gap: '1em',
'& > *': {
flex: '1 1 50%',
overflow: 'hidden',
minHeight: '100%',
},
item: {
gap: '1em',
'& > *': {
flex: '1 1 50%',
overflow: 'hidden',
minHeight: '100%',
},
'&:hover': {
backgroundColor: theme.palette.action.hover,
},
'&:hover': {
backgroundColor: theme.palette.action.hover,
},
typo: theme.typography.body2,
}))
const AttributeList = ({
@ -56,8 +61,21 @@ const AttributeList = ({
itemProps = {},
listProps = {},
subListProps = {},
collapse = false,
}) => {
const classes = useStyles()
const RootElement = useMemo(() => (collapse ? Box : Paper), [collapse])
const ListElement = useMemo(() => (collapse ? Accordion : List), [collapse])
const TitleElement = useMemo(
() => (collapse ? AccordionSummary : Title),
[collapse]
)
const DetailsElement = useMemo(
() => (collapse ? AccordionDetails : Fragment),
[collapse]
)
const { className: itemClassName, ...restOfItemProps } = itemProps
const renderList = (attribute, parentPath = false) => {
@ -67,9 +85,9 @@ const AttributeList = ({
return (
<Fragment key={`${title}.${parentPath || name}`}>
<ListItem
<Item
sx={isReactElement ? { minHeight: '2.4em' } : { height: '2.4em' }}
className={clsx(classes.item, itemClassName)}
className={itemClassName}
{...restOfItemProps}
>
<Attribute
@ -77,44 +95,46 @@ const AttributeList = ({
{...attribute}
{...(isParent && { canEdit: false, value: undefined })}
/>
</ListItem>
</Item>
{isParent && (
<MList {...subListProps}>
<List {...subListProps}>
{Object.entries(value).map(([childName, childValue]) => {
const attributePath = `${parentPath || name}.${childName}`
const subAttributeProps = {
...attribute,
name: childName,
value: childValue,
}
const attributePath = `${parentPath || name}.${childName}`
return renderList(subAttributeProps, attributePath)
})}
</MList>
</List>
)}
</Fragment>
)
}
return (
<Paper variant="outlined" {...containerProps}>
<MList {...listProps}>
<RootElement variant="outlined" {...containerProps}>
<ListElement {...listProps}>
{/* TITLE */}
{title && (
<ListItem className={classes.title}>
<TitleElement>
<Typography noWrap>{Tr(title)}</Typography>
</ListItem>
</TitleElement>
)}
{/* LIST */}
{list.map((attr) => renderList(attr))}
{/* ADD ACTION */}
{handleAdd && (
<ListItem className={clsx(classes.item, itemClassName)}>
<AttributeCreateForm handleAdd={handleAdd} />
</ListItem>
)}
</MList>
</Paper>
<DetailsElement>
{/* LIST */}
{list.map((attr) => renderList(attr))}
{/* ADD ACTION */}
{handleAdd && (
<Item className={itemClassName}>
<AttributeCreateForm handleAdd={handleAdd} />
</Item>
)}
</DetailsElement>
</ListElement>
</RootElement>
)
}
@ -126,6 +146,7 @@ AttributeList.propTypes = {
list: PropTypes.arrayOf(PropTypes.shape(AttributePropTypes)),
listProps: PropTypes.object,
subListProps: PropTypes.object,
collapse: PropTypes.bool,
}
AttributeList.displayName = 'AttributeList'

View File

@ -43,7 +43,7 @@ const AppTemplateTab = ({ id }) => {
return (
<>
<Accordion TransitionProps={{ unmountOnExit: true }}>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Translate word={T.AppTemplate} />
</AccordionSummary>
@ -57,7 +57,7 @@ const AppTemplateTab = ({ id }) => {
</pre>
</AccordionDetails>
</Accordion>
<Accordion TransitionProps={{ unmountOnExit: true }}>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Translate word={T.VMTemplate} />
</AccordionSummary>

View File

@ -16,7 +16,6 @@
import { ReactElement } from 'react'
import PropTypes from 'prop-types'
import { Accordion, AccordionSummary, AccordionDetails } from '@mui/material'
import { NavArrowDown as ExpandMoreIcon } from 'iconoir-react'
import { useGetVmQuery } from 'client/features/OneApi/vm'
import { Translate } from 'client/components/HOC'
@ -35,8 +34,8 @@ const VmConfigurationTab = ({ id }) => {
return (
<div>
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Accordion>
<AccordionSummary>
<Translate word={T.UserTemplate} />
</AccordionSummary>
<AccordionDetails>
@ -47,8 +46,8 @@ const VmConfigurationTab = ({ id }) => {
</pre>
</AccordionDetails>
</Accordion>
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Accordion>
<AccordionSummary>
<Translate word={T.Template} />
</AccordionSummary>
<AccordionDetails>

View File

@ -183,6 +183,7 @@ const VmInfoTab = ({ tabProps = {}, id }) => {
{attributesPanel?.enabled && attributes && (
<AttributePanel
{...ATTRIBUTE_FUNCTION}
collapse
attributes={attributes}
actions={getActions(attributesPanel?.actions)}
title={`${Tr(T.Attributes)}`}
@ -191,6 +192,7 @@ const VmInfoTab = ({ tabProps = {}, id }) => {
{vcenterPanel?.enabled && vcenterAttributes && (
<AttributePanel
{...ATTRIBUTE_FUNCTION}
collapse
actions={getActions(vcenterPanel?.actions)}
attributes={vcenterAttributes}
title={`vCenter ${Tr(T.Information)}`}
@ -199,6 +201,7 @@ const VmInfoTab = ({ tabProps = {}, id }) => {
{lxcPanel?.enabled && lxcAttributes && (
<AttributePanel
{...ATTRIBUTE_FUNCTION}
collapse
actions={getActions(lxcPanel?.actions)}
attributes={lxcAttributes}
title={`LXC ${Tr(T.Information)}`}
@ -206,6 +209,7 @@ const VmInfoTab = ({ tabProps = {}, id }) => {
)}
{monitoringPanel?.enabled && monitoringAttributes && (
<AttributePanel
collapse
actions={getActions(monitoringPanel?.actions)}
attributes={monitoringAttributes}
title={`${Tr(T.Monitoring)}`}

View File

@ -30,7 +30,7 @@ const TemplateTab = ({ id }) => {
const { data: vmTemplate = {} } = useGetTemplateQuery({ id })
return (
<Accordion expanded TransitionProps={{ unmountOnExit: true }}>
<Accordion expanded>
<AccordionDetails>
<Box component="pre">
<Box

View File

@ -14,6 +14,11 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { createTheme, ThemeOptions, colors, alpha } from '@mui/material'
import { accordionSummaryClasses } from '@mui/material/AccordionSummary'
import { iconButtonClasses } from '@mui/material/IconButton'
import { buttonClasses } from '@mui/material/Button'
import { NavArrowDown as ExpandMoreIcon } from 'iconoir-react'
import { UbuntuFont } from 'client/theme/fonts'
import { SCHEMES } from 'client/constants'
@ -77,7 +82,7 @@ const buttonSvgStyle = {
* @param {SCHEMES} mode - Scheme type
* @returns {ThemeOptions} Material theme options
*/
export default (appTheme, mode = SCHEMES.DARK) => {
const createAppTheme = (appTheme, mode = SCHEMES.DARK) => {
const isDarkMode = `${mode}`.toLowerCase() === SCHEMES.DARK
const { primary = defaultPrimary, secondary } = appTheme?.palette || {}
@ -347,7 +352,7 @@ export default (appTheme, mode = SCHEMES.DARK) => {
borderWidth: 0,
borderBottomWidth: 'thin',
backgroundColor: primary.main,
'& .MuiIconButton-root, & .MuiButton-root': {
[`& .${iconButtonClasses.root}, & .${buttonClasses.root}`]: {
color: white,
border: 'none',
backgroundColor: 'transparent',
@ -456,6 +461,50 @@ export default (appTheme, mode = SCHEMES.DARK) => {
},
],
},
MuiAccordion: {
defaultProps: {
elevation: 0,
square: true,
disableGutters: true,
TransitionProps: { unmountOnExit: true },
},
styleOverrides: {
root: {
flexBasis: '100%',
border: `1px solid ${defaultTheme.palette.divider}`,
'&:before': { display: 'none' },
},
},
},
MuiAccordionDetails: {
styleOverrides: {
root: {
border: `1px solid ${defaultTheme.palette.divider}`,
},
},
},
MuiAccordionSummary: {
defaultProps: {
expandIcon: <ExpandMoreIcon />,
},
styleOverrides: {
flexDirection: 'row-reverse',
backgroundColor: isDarkMode
? 'rgba(255, 255, 255, .05)'
: 'rgba(0, 0, 0, .03)',
'&:not(:last-child)': {
borderBottom: 0,
},
[`& .${accordionSummaryClasses.expandIconWrapper}.Mui-expanded`]: {
transform: 'rotate(90deg)',
},
[`& .${accordionSummaryClasses.content}`]: {
marginLeft: '.5em',
},
},
},
},
}
}
export default createAppTheme