diff --git a/src/fireedge/src/client/components/Cards/WavesCard.js b/src/fireedge/src/client/components/Cards/WavesCard.js index f6fdd4f6f6..8813263824 100644 --- a/src/fireedge/src/client/components/Cards/WavesCard.js +++ b/src/fireedge/src/client/components/Cards/WavesCard.js @@ -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 ( - - - {text} - - - {value} - - - - {Icon && ( - - - - )} - - ) +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 }) => ( + + + {text} + + + {value} + + + + {Icon && ( + + + + )} + + ), (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' diff --git a/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js b/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js index e622c3138f..2e515f5b5c 100644 --- a/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js +++ b/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js @@ -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 ( - - - - - - - + + + goTo(PATH.INSTANCE.VMS.LIST))} + /> + goTo(PATH.TEMPLATE.VMS.LIST))} + /> + goTo(PATH.STORAGE.IMAGES.LIST))} + /> + goTo(PATH.NETWORK.VNETS.LIST))} + /> + + ) } diff --git a/src/fireedge/src/client/features/Auth/hooks.js b/src/fireedge/src/client/features/Auth/hooks.js index c7178caceb..9a71b91798 100644 --- a/src/fireedge/src/client/features/Auth/hooks.js +++ b/src/fireedge/src/client/features/Auth/hooks.js @@ -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,