mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-20 10:50:08 +03:00
Co-authored-by: Tino Vázquez <cvazquez@opennebula.io>
This commit is contained in:
parent
9ab5aa7869
commit
d311a95a8f
@ -16,93 +16,95 @@
|
||||
import { memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import clsx from 'clsx'
|
||||
import { Paper, Typography, lighten, darken } from '@mui/material'
|
||||
import makeStyles from '@mui/styles/makeStyles'
|
||||
import { styled, keyframes, lighten, darken } from '@mui/material'
|
||||
import Paper from '@mui/material/Paper'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
import { addOpacityToColor } from 'client/utils'
|
||||
import { SCHEMES } from 'client/constants'
|
||||
|
||||
const useStyles = makeStyles((theme) => {
|
||||
const Card = styled(Paper)(({ theme, bgcolor, onClick }) => {
|
||||
const getBackgroundColor =
|
||||
theme.palette.mode === SCHEMES.DARK ? darken : lighten
|
||||
const getContrastBackgroundColor =
|
||||
theme.palette.mode === SCHEMES.LIGHT ? darken : lighten
|
||||
|
||||
return {
|
||||
root: {
|
||||
padding: '2em',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: ({ bgColor }) => getBackgroundColor(bgColor, 0.3),
|
||||
[theme.breakpoints.only('xs')]: {
|
||||
display: 'flex',
|
||||
alignItems: 'baseline',
|
||||
gap: '1em',
|
||||
padding: '2em',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: getBackgroundColor(bgcolor, 0.3),
|
||||
...(onClick && {
|
||||
'&:hover': {
|
||||
backgroundColor: getBackgroundColor(bgcolor, 0.4),
|
||||
boxShadow: theme.shadows[10],
|
||||
cursor: 'pointer',
|
||||
},
|
||||
},
|
||||
icon: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
textAlign: 'end',
|
||||
'& > svg': {
|
||||
color: addOpacityToColor(theme.palette.common.white, 0.2),
|
||||
height: '100%',
|
||||
width: '30%',
|
||||
},
|
||||
},
|
||||
wave: {
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
opacity: 0.4,
|
||||
top: '-5%',
|
||||
left: '50%',
|
||||
width: 220,
|
||||
height: 220,
|
||||
borderRadius: '43%',
|
||||
},
|
||||
wave1: {
|
||||
backgroundColor: ({ bgColor }) =>
|
||||
getContrastBackgroundColor(bgColor, 0.3),
|
||||
animation: '$drift 7s infinite linear',
|
||||
},
|
||||
wave2: {
|
||||
backgroundColor: ({ bgColor }) =>
|
||||
getContrastBackgroundColor(bgColor, 0.5),
|
||||
animation: '$drift 5s infinite linear',
|
||||
},
|
||||
'@keyframes drift': {
|
||||
from: { transform: 'rotate(0deg)' },
|
||||
to: { transform: 'rotate(360deg)' },
|
||||
}),
|
||||
[theme.breakpoints.only('xs')]: {
|
||||
display: 'flex',
|
||||
alignItems: 'baseline',
|
||||
gap: '1em',
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const WavesCard = memo(
|
||||
({ text, value, bgColor, icon: Icon }) => {
|
||||
const classes = useStyles({ bgColor })
|
||||
|
||||
return (
|
||||
<Paper className={classes.root}>
|
||||
<Typography variant="h6" zIndex={2}>
|
||||
{text}
|
||||
</Typography>
|
||||
<Typography variant="h4" zIndex={2}>
|
||||
{value}
|
||||
</Typography>
|
||||
<span className={clsx(classes.wave, classes.wave1)} />
|
||||
<span className={clsx(classes.wave, classes.wave2)} />
|
||||
{Icon && (
|
||||
<span className={classes.icon}>
|
||||
<Icon />
|
||||
</span>
|
||||
)}
|
||||
</Paper>
|
||||
)
|
||||
const OverSizeIcon = styled('span')(({ theme }) => ({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
textAlign: 'end',
|
||||
'& > svg': {
|
||||
color: theme.palette.action.active,
|
||||
height: '100%',
|
||||
width: '30%',
|
||||
},
|
||||
}))
|
||||
|
||||
const drift = keyframes`
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
`
|
||||
|
||||
const Wave = styled('span')(({ theme, bgcolor, duration = 1 }) => {
|
||||
const getContrastBackgroundColor =
|
||||
theme.palette.mode === SCHEMES.DARK ? lighten : darken
|
||||
|
||||
return {
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
opacity: 0.4,
|
||||
top: '-5%',
|
||||
left: '50%',
|
||||
width: 220,
|
||||
height: 220,
|
||||
borderRadius: '43%',
|
||||
backgroundColor: getContrastBackgroundColor(bgcolor, duration / 10),
|
||||
animation: `${drift} ${duration}s infinite linear`,
|
||||
}
|
||||
})
|
||||
|
||||
const WavesCard = memo(
|
||||
({ text, value, bgColor, icon: Icon, onClick }) => (
|
||||
<Card bgcolor={bgColor} onClick={onClick || undefined}>
|
||||
<Typography variant="h6" zIndex={2}>
|
||||
{text}
|
||||
</Typography>
|
||||
<Typography variant="h4" zIndex={2}>
|
||||
{value}
|
||||
</Typography>
|
||||
<Wave bgcolor={bgColor} duration={7} />
|
||||
<Wave bgcolor={bgColor} duration={5} />
|
||||
{Icon && (
|
||||
<OverSizeIcon>
|
||||
<Icon />
|
||||
</OverSizeIcon>
|
||||
)}
|
||||
</Card>
|
||||
),
|
||||
(prev, next) => prev.value === next.value
|
||||
)
|
||||
|
||||
@ -115,6 +117,7 @@ WavesCard.propTypes = {
|
||||
]),
|
||||
bgColor: PropTypes.string,
|
||||
icon: PropTypes.any,
|
||||
onClick: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
|
||||
}
|
||||
|
||||
WavesCard.defaultProps = {
|
||||
@ -122,6 +125,7 @@ WavesCard.defaultProps = {
|
||||
value: undefined,
|
||||
bgColor: '#ffffff00',
|
||||
icon: undefined,
|
||||
onClick: undefined,
|
||||
}
|
||||
|
||||
WavesCard.displayName = 'WavesCard'
|
||||
|
@ -13,9 +13,10 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { memo, ReactElement } from 'react'
|
||||
import { memo, useMemo, ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Box, CircularProgress, Grid } from '@mui/material'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { Container, Box, CircularProgress, Grid } from '@mui/material'
|
||||
import {
|
||||
ModernTv as VmsIcons,
|
||||
List as TemplatesIcon,
|
||||
@ -23,19 +24,30 @@ import {
|
||||
NetworkAlt as NetworkIcon,
|
||||
} from 'iconoir-react'
|
||||
|
||||
import { useAuth } from 'client/features/Auth'
|
||||
import { useAuth, useViews } from 'client/features/Auth'
|
||||
import { useGetVmsQuery } from 'client/features/OneApi/vm'
|
||||
import { useGetTemplatesQuery } from 'client/features/OneApi/vmTemplate'
|
||||
import { useGetImagesQuery } from 'client/features/OneApi/image'
|
||||
import { useGetVNetworksQuery } from 'client/features/OneApi/network'
|
||||
|
||||
import NumberEasing from 'client/components/NumberEasing'
|
||||
import WavesCard from 'client/components/Cards/WavesCard'
|
||||
import { stringToBoolean } from 'client/models/Helper'
|
||||
import { T } from 'client/constants'
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
import { T, RESOURCE_NAMES } from 'client/constants'
|
||||
|
||||
const { VM, VM_TEMPLATE, IMAGE, VNET } = RESOURCE_NAMES
|
||||
|
||||
/** @returns {ReactElement} Sunstone dashboard container */
|
||||
function SunstoneDashboard() {
|
||||
const { settings: { DISABLE_ANIMATIONS } = {} } = useAuth()
|
||||
const { view, hasAccessToResource } = useViews()
|
||||
const { push: goTo } = useHistory()
|
||||
|
||||
const vmAccess = useMemo(() => hasAccessToResource(VM), [view])
|
||||
const templateAccess = useMemo(() => hasAccessToResource(VM_TEMPLATE), [view])
|
||||
const imageAccess = useMemo(() => hasAccessToResource(IMAGE), [view])
|
||||
const vnetAccess = useMemo(() => hasAccessToResource(VNET), [view])
|
||||
|
||||
return (
|
||||
<Box
|
||||
@ -48,37 +60,42 @@ function SunstoneDashboard() {
|
||||
},
|
||||
})}
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
data-cy="dashboard-widget-total-sunstone-resources"
|
||||
spacing={3}
|
||||
>
|
||||
<ResourceWidget
|
||||
query={useGetVmsQuery}
|
||||
bgColor="#fa7892"
|
||||
text={T.VMs}
|
||||
icon={VmsIcons}
|
||||
/>
|
||||
<ResourceWidget
|
||||
query={useGetTemplatesQuery}
|
||||
bgColor="#b25aff"
|
||||
text={T.VMTemplates}
|
||||
icon={TemplatesIcon}
|
||||
/>
|
||||
<ResourceWidget
|
||||
query={useGetImagesQuery}
|
||||
bgColor="#1fbbc6"
|
||||
text={T.Images}
|
||||
icon={ImageIcon}
|
||||
/>
|
||||
<ResourceWidget
|
||||
query={useGetVNetworksQuery}
|
||||
bgColor="#f09d42"
|
||||
text={T.VirtualNetworks}
|
||||
icon={NetworkIcon}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
<Box py={3}>
|
||||
<Grid
|
||||
container
|
||||
data-cy="dashboard-widget-total-sunstone-resources"
|
||||
spacing={3}
|
||||
>
|
||||
<ResourceWidget
|
||||
query={useGetVmsQuery}
|
||||
bgColor="#fa7892"
|
||||
text={T.VMs}
|
||||
icon={VmsIcons}
|
||||
onClick={vmAccess && (() => goTo(PATH.INSTANCE.VMS.LIST))}
|
||||
/>
|
||||
<ResourceWidget
|
||||
query={useGetTemplatesQuery}
|
||||
bgColor="#b25aff"
|
||||
text={T.VMTemplates}
|
||||
icon={TemplatesIcon}
|
||||
onClick={templateAccess && (() => goTo(PATH.TEMPLATE.VMS.LIST))}
|
||||
/>
|
||||
<ResourceWidget
|
||||
query={useGetImagesQuery}
|
||||
bgColor="#1fbbc6"
|
||||
text={T.Images}
|
||||
icon={ImageIcon}
|
||||
onClick={imageAccess && (() => goTo(PATH.STORAGE.IMAGES.LIST))}
|
||||
/>
|
||||
<ResourceWidget
|
||||
query={useGetVNetworksQuery}
|
||||
bgColor="#f09d42"
|
||||
text={T.VirtualNetworks}
|
||||
icon={NetworkIcon}
|
||||
onClick={vnetAccess && (() => goTo(PATH.NETWORK.VNETS.LIST))}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -125,6 +125,17 @@ export const useViews = () => {
|
||||
[view]
|
||||
)
|
||||
|
||||
/**
|
||||
* Check if user has a view for a resource.
|
||||
*
|
||||
* @param {RESOURCE_NAMES} resourceName - Name of resource
|
||||
* @returns {boolean} Returns true if user has a view for a resource
|
||||
*/
|
||||
const hasAccessToResource = useCallback(
|
||||
(resourceName) => !!getResourceView(resourceName),
|
||||
[view]
|
||||
)
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
...Object.values(RESOURCE_NAMES).reduce(
|
||||
@ -134,6 +145,7 @@ export const useViews = () => {
|
||||
}),
|
||||
{}
|
||||
),
|
||||
hasAccessToResource,
|
||||
getResourceView,
|
||||
views,
|
||||
view,
|
||||
|
Loading…
x
Reference in New Issue
Block a user