mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-21 14:50:08 +03:00
* Fix sidebar component * Add responsive sidebar * Update internal grid layout
This commit is contained in:
parent
6ece4290cf
commit
26c076710f
@ -13,7 +13,7 @@
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { StaticRouter, BrowserRouter } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
@ -25,7 +25,7 @@ import { TranslateProvider } from 'client/components/HOC';
|
||||
import Router from 'client/router';
|
||||
|
||||
const App = ({ location, context, store }) => {
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const jssStyles = document.querySelector('#jss-server-side');
|
||||
if (jssStyles) {
|
||||
jssStyles.parentElement.removeChild(jssStyles);
|
||||
|
@ -1,10 +1,31 @@
|
||||
import { createMuiTheme, responsiveFontSizes } from '@material-ui/core';
|
||||
|
||||
const defaultBreakpoints = {
|
||||
xs: 0,
|
||||
sm: 600,
|
||||
md: 960,
|
||||
lg: 1280,
|
||||
xl: 1920,
|
||||
// DEVICES
|
||||
tablet: 640,
|
||||
laptop: 1024,
|
||||
desktop: 1280
|
||||
};
|
||||
|
||||
const theme = createMuiTheme({
|
||||
typography: {
|
||||
fontFamily: ['Ubuntu', 'Lato'].join(',')
|
||||
},
|
||||
overrides: {
|
||||
MuiDrawer: {
|
||||
paper: {
|
||||
width: 360,
|
||||
overflow: 'hidden',
|
||||
[`@media (max-width: ${defaultBreakpoints.tablet}px)`]: {
|
||||
width: '100%'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiFormControl: {
|
||||
root: {
|
||||
margin: '.5rem 0'
|
||||
@ -47,7 +68,7 @@ const theme = createMuiTheme({
|
||||
MuiCssBaseline: {
|
||||
'@global': {
|
||||
body: {
|
||||
height: '100vh'
|
||||
// height: '100vh'
|
||||
}
|
||||
// '@font-face': [UbuntuFont]
|
||||
}
|
||||
|
@ -14,22 +14,24 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
import React from 'react';
|
||||
import { Box, Link, useTheme } from '@material-ui/core';
|
||||
import classnames from 'classnames';
|
||||
import { Box, Link } from '@material-ui/core';
|
||||
|
||||
import footerStyles from 'client/components/Footer/styles';
|
||||
import { by } from 'client/constants';
|
||||
|
||||
const { text, url } = by;
|
||||
|
||||
const Footer = () => {
|
||||
const theme = useTheme();
|
||||
const Footer = React.memo(() => {
|
||||
const classes = footerStyles();
|
||||
|
||||
return (
|
||||
<Box color={theme.palette.primary.light} className={classnames('footer')}>
|
||||
<Box className={classes.footer} component="footer">
|
||||
{`❤️ by `}
|
||||
<Link href={url}>{text}</Link>
|
||||
<Link href={url} className={classes.link}>
|
||||
{text}
|
||||
</Link>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export default Footer;
|
||||
|
19
src/fireedge/src/public/components/Footer/styles.js
Normal file
19
src/fireedge/src/public/components/Footer/styles.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
|
||||
export default makeStyles(theme => ({
|
||||
footer: {
|
||||
color: theme.palette.primary.light,
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
left: 'auto',
|
||||
right: 0,
|
||||
width: '100%',
|
||||
zIndex: 1100,
|
||||
backgroundColor: theme.palette.grey[800],
|
||||
textAlign: 'center',
|
||||
padding: 5
|
||||
},
|
||||
link: {
|
||||
color: theme.palette.primary.light
|
||||
}
|
||||
}));
|
@ -13,7 +13,7 @@ const InputCode = ({ code, language, ...props }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Box border="1px solid lightgray">
|
||||
<Box border="1px solid lightgray" height="100%" minHeight={200}>
|
||||
<AceEditor
|
||||
wrapEnabled
|
||||
value={code}
|
||||
@ -21,10 +21,11 @@ const InputCode = ({ code, language, ...props }) => {
|
||||
mode="json"
|
||||
theme="github"
|
||||
width="100%"
|
||||
maxLines={Infinity}
|
||||
minLines={50}
|
||||
height="100%"
|
||||
// maxLines={Infinity}
|
||||
minLines={10}
|
||||
onChange={handleChange}
|
||||
name="UNIQUE_ID_OF_DIV"
|
||||
name="form-control-code"
|
||||
showPrintMargin={false}
|
||||
editorProps={{ $blockScrolling: true }}
|
||||
setOptions={{
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { makeStyles, CircularProgress, Button } from '@material-ui/core';
|
||||
|
||||
@ -12,7 +13,7 @@ const useStyles = makeStyles(theme => ({
|
||||
}
|
||||
}));
|
||||
|
||||
export default function ButtonSubmit({ isSubmitting, label, ...rest }) {
|
||||
const ButtonSubmit = ({ isSubmitting, label, ...rest }) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
@ -25,7 +26,19 @@ export default function ButtonSubmit({ isSubmitting, label, ...rest }) {
|
||||
{...rest}
|
||||
>
|
||||
{isSubmitting && <CircularProgress size={24} />}
|
||||
{!isSubmitting && (label ?? <Translate word={CONSTANT.default.Submit} />)}
|
||||
{!isSubmitting && <Translate word={label ?? CONSTANT.default.Submit} />}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ButtonSubmit.propTypes = {
|
||||
isSubmitting: PropTypes.bool,
|
||||
label: PropTypes.string
|
||||
};
|
||||
|
||||
ButtonSubmit.defaultProps = {
|
||||
isSubmitting: false,
|
||||
label: CONSTANT.default.Submit
|
||||
};
|
||||
|
||||
export default ButtonSubmit;
|
||||
|
@ -16,16 +16,45 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Box, Container } from '@material-ui/core';
|
||||
import { makeStyles, Box, Container } from '@material-ui/core';
|
||||
import { Skeleton } from '@material-ui/lab';
|
||||
|
||||
import useAuth from 'client/hooks/useAuth';
|
||||
import useOpenNebula from 'client/hooks/useOpennebula';
|
||||
import Header from 'client/components/Header';
|
||||
import Footer from 'client/components/Footer';
|
||||
import Sidebar from 'client/components/Sidebar';
|
||||
|
||||
const internalStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
width: '100%'
|
||||
},
|
||||
main: {
|
||||
paddingTop: 64,
|
||||
paddingBottom: 30,
|
||||
height: '100vh',
|
||||
width: '100vw'
|
||||
},
|
||||
scrollable: {
|
||||
paddingTop: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(2),
|
||||
height: '100%',
|
||||
overflow: 'auto',
|
||||
'&::-webkit-scrollbar': {
|
||||
width: 14
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
backgroundClip: 'content-box',
|
||||
border: '4px solid transparent',
|
||||
borderRadius: 7,
|
||||
boxShadow: 'inset 0 0 0 10px',
|
||||
color: theme.palette.primary.light
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
const InternalLayout = ({ children, title }) => {
|
||||
const classes = internalStyles();
|
||||
const { groups } = useOpenNebula();
|
||||
const { authUser } = useAuth();
|
||||
|
||||
@ -39,17 +68,15 @@ const InternalLayout = ({ children, title }) => {
|
||||
</Box>
|
||||
</Box>
|
||||
) : (
|
||||
<Box display="flex" width="100%">
|
||||
<>
|
||||
<Header title={title} />
|
||||
<Sidebar />
|
||||
<Container
|
||||
component="main"
|
||||
style={{ paddingTop: 96, paddingBottom: 96, height: '100vh' }}
|
||||
>
|
||||
{children}
|
||||
</Container>
|
||||
<Box component="main" className={classes.main}>
|
||||
<Container component="div" className={classes.scrollable}>
|
||||
{children}
|
||||
</Container>
|
||||
</Box>
|
||||
<Footer />
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -14,8 +14,7 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
import React, { useState, useRef, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
Popper,
|
||||
@ -29,19 +28,22 @@ import {
|
||||
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
|
||||
|
||||
import { Translate } from 'client/components/HOC';
|
||||
import { PATH } from 'client/router/endpoints';
|
||||
import { SignOut } from 'client/constants';
|
||||
import useAuth from 'client/hooks/useAuth';
|
||||
import FilterPoolSelect from './FilterPoolSelect';
|
||||
import FilterPoolSelect from 'client/components/Header/FilterPoolSelect';
|
||||
|
||||
const User = () => {
|
||||
const User = React.memo(() => {
|
||||
const history = useHistory();
|
||||
const { logout, authUser, isOneAdmin } = useAuth();
|
||||
const [open, setOpen] = useState(false);
|
||||
const anchorRef = useRef(null);
|
||||
const { current } = anchorRef;
|
||||
|
||||
const handleToggle = () => {
|
||||
setOpen(prevOpen => !prevOpen);
|
||||
};
|
||||
const handleToggle = () => setOpen(prevOpen => !prevOpen);
|
||||
|
||||
const handleLogout = () => logout();
|
||||
const handleGoToSettings = () => history.push(PATH.SETTINGS);
|
||||
|
||||
const handleClose = e => {
|
||||
if (current && current.contains(e.target)) {
|
||||
@ -50,11 +52,6 @@ const User = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const handleLogout = evt => {
|
||||
evt.preventDefault();
|
||||
logout();
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Button
|
||||
@ -66,6 +63,7 @@ const User = () => {
|
||||
data-cy="header-user-button"
|
||||
>
|
||||
<AccountCircleIcon />
|
||||
<span style={{ paddingLeft: 5 }}>{authUser?.NAME}</span>
|
||||
</Button>
|
||||
<Popper
|
||||
open={open}
|
||||
@ -85,11 +83,7 @@ const User = () => {
|
||||
<Paper>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<MenuList autoFocusItem={open} id="menu-list-grow">
|
||||
<MenuItem onClick={handleClose} data-cy="header-username">
|
||||
{authUser?.NAME}
|
||||
</MenuItem>
|
||||
<Divider />
|
||||
<MenuItem onClick={handleClose}>Settings</MenuItem>
|
||||
<MenuItem onClick={handleGoToSettings}>Settings</MenuItem>
|
||||
<Divider />
|
||||
<MenuItem
|
||||
onClick={handleLogout}
|
||||
@ -113,10 +107,6 @@ const User = () => {
|
||||
</Popper>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
User.propTypes = {};
|
||||
|
||||
User.defaultProps = {};
|
||||
});
|
||||
|
||||
export default User;
|
||||
|
@ -13,7 +13,7 @@
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
import React, { useState, useRef, Fragment } from 'react';
|
||||
import React, { useState, useRef } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Popper,
|
||||
@ -21,15 +21,11 @@ import {
|
||||
Paper,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
ClickAwayListener,
|
||||
Divider
|
||||
ClickAwayListener
|
||||
} from '@material-ui/core';
|
||||
import LanguageIcon from '@material-ui/icons/Language';
|
||||
|
||||
import { Translate } from 'client/components/HOC';
|
||||
import { SignOut, Groups } from 'client/constants';
|
||||
|
||||
const Zone = () => {
|
||||
const Zone = React.memo(() => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const anchorRef = useRef(null);
|
||||
const { current } = anchorRef;
|
||||
@ -46,7 +42,7 @@ const Zone = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<>
|
||||
<Button
|
||||
ref={anchorRef}
|
||||
color="inherit"
|
||||
@ -81,12 +77,8 @@ const Zone = () => {
|
||||
</Grow>
|
||||
)}
|
||||
</Popper>
|
||||
</Fragment>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Zone.propTypes = {};
|
||||
|
||||
Zone.defaultProps = {};
|
||||
});
|
||||
|
||||
export default Zone;
|
||||
|
@ -0,0 +1,52 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { List, Collapse, ListItem, ListItemText } from '@material-ui/core';
|
||||
import ExpandLessIcon from '@material-ui/icons/ExpandLess';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
|
||||
import SidebarLink from 'client/components/Sidebar/SidebarLink';
|
||||
|
||||
const SidebarCollapseItem = ({ label, routes }) => {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
const handleExpand = () => setExpanded(!expanded);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListItem button onClick={handleExpand}>
|
||||
<ListItemText primary={label} />
|
||||
{expanded ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
</ListItem>
|
||||
{routes?.map((subItem, index) => (
|
||||
<Collapse
|
||||
key={`subitem-${index}`}
|
||||
in={expanded}
|
||||
timeout="auto"
|
||||
unmountOnExit
|
||||
>
|
||||
<List component="div" disablePadding>
|
||||
<SidebarLink {...subItem} />
|
||||
</List>
|
||||
</Collapse>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
SidebarCollapseItem.propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
routes: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
label: PropTypes.string,
|
||||
path: PropTypes.string
|
||||
})
|
||||
)
|
||||
};
|
||||
|
||||
SidebarCollapseItem.defaultProps = {
|
||||
label: '',
|
||||
routes: []
|
||||
};
|
||||
|
||||
export default SidebarCollapseItem;
|
63
src/fireedge/src/public/components/Sidebar/SidebarLink.js
Normal file
63
src/fireedge/src/public/components/Sidebar/SidebarLink.js
Normal file
@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
withStyles,
|
||||
Badge,
|
||||
Typography,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
useMediaQuery
|
||||
} from '@material-ui/core';
|
||||
|
||||
import useGeneral from 'client/hooks/useGeneral';
|
||||
|
||||
const StyledBadge = withStyles(() => ({
|
||||
badge: {
|
||||
right: -25,
|
||||
top: 13,
|
||||
fontSize: '0.7rem'
|
||||
}
|
||||
}))(Badge);
|
||||
|
||||
const SidebarLink = ({ label, path, devMode }) => {
|
||||
const history = useHistory();
|
||||
const isDesktop = useMediaQuery(theme => theme.breakpoints.up('sm'));
|
||||
const { openMenu } = useGeneral();
|
||||
|
||||
const handleClick = () => {
|
||||
history.push(path);
|
||||
!isDesktop && openMenu(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<ListItem button onClick={handleClick}>
|
||||
<ListItemText
|
||||
primary={
|
||||
devMode ? (
|
||||
<StyledBadge badgeContent="DEV" color="primary">
|
||||
<Typography>{label}</Typography>
|
||||
</StyledBadge>
|
||||
) : (
|
||||
label
|
||||
)
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
};
|
||||
|
||||
SidebarLink.propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
path: PropTypes.string.isRequired,
|
||||
devMode: PropTypes.bool
|
||||
};
|
||||
|
||||
SidebarLink.defaultProps = {
|
||||
label: '',
|
||||
path: '/',
|
||||
devMode: false
|
||||
};
|
||||
|
||||
export default SidebarLink;
|
@ -13,61 +13,30 @@
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
Grid,
|
||||
List,
|
||||
Drawer,
|
||||
Divider,
|
||||
Collapse,
|
||||
ListItem,
|
||||
ListItemText
|
||||
} from '@material-ui/core';
|
||||
import ExpandLessIcon from '@material-ui/icons/ExpandLess';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import { List, Drawer, Divider, Box } from '@material-ui/core';
|
||||
|
||||
import sidebarStyles from 'client/components/Sidebar/styles';
|
||||
import useGeneral from 'client/hooks/useGeneral';
|
||||
import endpoints from 'client/router/endpoints';
|
||||
|
||||
const LinkItem = React.memo(({ label, path }) => {
|
||||
const history = useHistory();
|
||||
import sidebarStyles from 'client/components/Sidebar/styles';
|
||||
import SidebarLink from 'client/components/Sidebar/SidebarLink';
|
||||
import SidebarCollapseItem from 'client/components/Sidebar/SidebarCollapseItem';
|
||||
|
||||
return (
|
||||
<ListItem button onClick={() => history.push(path)}>
|
||||
<ListItemText primary={label} />
|
||||
</ListItem>
|
||||
);
|
||||
});
|
||||
|
||||
const CollapseItem = React.memo(({ label, routes }) => {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
const handleExpand = () => setExpanded(!expanded);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListItem button onClick={handleExpand}>
|
||||
<ListItemText primary={label} />
|
||||
{expanded ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
</ListItem>
|
||||
{routes?.map((subItem, index) => (
|
||||
<Collapse
|
||||
key={`subitem-${index}`}
|
||||
in={expanded}
|
||||
timeout="auto"
|
||||
unmountOnExit
|
||||
>
|
||||
<List component="div" disablePadding>
|
||||
<LinkItem {...subItem} />
|
||||
</List>
|
||||
</Collapse>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
});
|
||||
const Endpoints = React.memo(() =>
|
||||
endpoints
|
||||
?.filter(
|
||||
({ authenticated = true, header = false }) => authenticated && !header
|
||||
)
|
||||
?.map((endpoint, index) =>
|
||||
endpoint.routes ? (
|
||||
<SidebarCollapseItem key={`item-${index}`} {...endpoint} />
|
||||
) : (
|
||||
<SidebarLink key={`item-${index}`} {...endpoint} />
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const Sidebar = () => {
|
||||
const classes = sidebarStyles();
|
||||
@ -76,29 +45,19 @@ const Sidebar = () => {
|
||||
return React.useMemo(
|
||||
() => (
|
||||
<Drawer anchor="left" open={isOpenMenu} onClose={() => openMenu(false)}>
|
||||
<div className={classes.menu}>
|
||||
<Grid container>
|
||||
<Grid item className={classes.logoWrapper}>
|
||||
<img
|
||||
className={classes.logo}
|
||||
src="/static/logo.png"
|
||||
alt="Opennebula"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Divider />
|
||||
<List>
|
||||
{endpoints
|
||||
?.filter(({ authenticated = true }) => authenticated)
|
||||
?.map((endpoint, index) =>
|
||||
endpoint.routes ? (
|
||||
<CollapseItem key={`item-${index}`} {...endpoint} />
|
||||
) : (
|
||||
<LinkItem key={`item-${index}`} {...endpoint} />
|
||||
)
|
||||
)}
|
||||
<Box item className={classes.logo}>
|
||||
<img
|
||||
className={classes.img}
|
||||
src="/static/logo.png"
|
||||
alt="Opennebula"
|
||||
/>
|
||||
</Box>
|
||||
<Divider />
|
||||
<Box className={classes.menu}>
|
||||
<List className={classes.list}>
|
||||
<Endpoints />
|
||||
</List>
|
||||
</div>
|
||||
</Box>
|
||||
</Drawer>
|
||||
),
|
||||
[isOpenMenu, openMenu]
|
||||
|
@ -2,21 +2,38 @@ import { makeStyles } from '@material-ui/core';
|
||||
|
||||
export default makeStyles(theme => ({
|
||||
menu: {
|
||||
width: '15rem',
|
||||
overflow: 'auto',
|
||||
textTransform: 'capitalize',
|
||||
color: theme.palette.secondary.dark
|
||||
color: 'transparent',
|
||||
transition: 'color 0.3s',
|
||||
'&:hover': {
|
||||
color: theme.palette.primary.light
|
||||
},
|
||||
'&::-webkit-scrollbar': {
|
||||
width: 14
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
backgroundClip: 'content-box',
|
||||
border: '4px solid transparent',
|
||||
borderRadius: 7,
|
||||
boxShadow: 'inset 0 0 0 10px'
|
||||
},
|
||||
'&::-webkit-scrollbar-button': {
|
||||
width: 0,
|
||||
height: 0,
|
||||
display: 'none'
|
||||
},
|
||||
'&::-webkit-scrollbar-corner': {
|
||||
backgroundColor: 'transparent'
|
||||
}
|
||||
},
|
||||
logoWrapper: {
|
||||
padding: '1rem 2rem'
|
||||
list: {
|
||||
color: theme.palette.common.black
|
||||
},
|
||||
logo: {
|
||||
padding: '1rem 2rem'
|
||||
},
|
||||
img: {
|
||||
width: '100%'
|
||||
},
|
||||
nav: {
|
||||
paddingtop: 0,
|
||||
paddingBottom: 0
|
||||
},
|
||||
subitem: {
|
||||
paddingLeft: theme.spacing(4)
|
||||
}
|
||||
}));
|
||||
|
@ -15,12 +15,25 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Box, Typography } from '@material-ui/core';
|
||||
import { makeStyles, Box, Typography } from '@material-ui/core';
|
||||
|
||||
const dashboardStyles = makeStyles(theme => ({
|
||||
root: {},
|
||||
title: {
|
||||
color: theme.palette.common.black
|
||||
}
|
||||
}));
|
||||
|
||||
function Dashboard() {
|
||||
const classes = dashboardStyles();
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h2" data-cy="dashboard-title">
|
||||
<Typography
|
||||
variant="h2"
|
||||
className={classes.title}
|
||||
data-cy="dashboard-title"
|
||||
>
|
||||
Dashboard
|
||||
</Typography>
|
||||
</Box>
|
||||
|
@ -65,6 +65,7 @@ function FormUser({ classes, onSubmit, error }) {
|
||||
required
|
||||
name="pass"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
label={Tr(Password)}
|
||||
variant="outlined"
|
||||
inputRef={register}
|
||||
|
@ -10,7 +10,8 @@ export default makeStyles(theme =>
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center'
|
||||
justifyContent: 'center',
|
||||
height: '100vh'
|
||||
},
|
||||
paper: {
|
||||
overflow: 'hidden',
|
||||
|
@ -1,12 +1,11 @@
|
||||
import React from 'react';
|
||||
import { object, string, shape, func } from 'prop-types';
|
||||
import { string, func, objectOf, object } from 'prop-types';
|
||||
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import {
|
||||
TextField,
|
||||
Grid,
|
||||
Typography,
|
||||
Box,
|
||||
FormControlLabel,
|
||||
Checkbox
|
||||
} from '@material-ui/core';
|
||||
@ -34,15 +33,19 @@ const ResponseForm = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<Box width="100%">
|
||||
<Typography component="h2" variant="h2" style={{ padding: '16px 0' }}>
|
||||
<>
|
||||
<Typography
|
||||
color="textPrimary"
|
||||
component="h2"
|
||||
variant="h2"
|
||||
style={{ padding: '16px 0' }}
|
||||
>
|
||||
{name || 'Request'}
|
||||
</Typography>
|
||||
<Grid
|
||||
container
|
||||
spacing={3}
|
||||
justify="flex-start"
|
||||
style={{ height: '100%' }}
|
||||
component="form"
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
autoComplete="off"
|
||||
@ -77,25 +80,23 @@ const ResponseForm = ({
|
||||
<ButtonSubmit isSubmitting={formState.isSubmitting} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ResponseForm.propTypes = {
|
||||
command: shape({
|
||||
command: objectOf({
|
||||
name: string.isRequired,
|
||||
httpMethod: string.isRequired,
|
||||
schema: object,
|
||||
params: object
|
||||
params: object.isRequired
|
||||
}).isRequired,
|
||||
handleChangeResponse: func
|
||||
handleChangeResponse: func.isRequired
|
||||
};
|
||||
|
||||
ResponseForm.defaultProps = {
|
||||
command: {
|
||||
name: '',
|
||||
httpMethod: 'GET',
|
||||
schema: {},
|
||||
params: {}
|
||||
},
|
||||
handleChangeResponse: () => undefined
|
||||
|
@ -16,7 +16,7 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { TextField, Grid, MenuItem } from '@material-ui/core';
|
||||
import Commands from 'server/utils/constants/commands';
|
||||
import { Translate } from 'client/components/HOC';
|
||||
import { Translate, Tr } from 'client/components/HOC';
|
||||
import InputCode from 'client/components/FormControl/InputCode';
|
||||
import ResponseForm from 'client/containers/TestApi/ResponseForm';
|
||||
|
||||
@ -33,7 +33,7 @@ const TestApi = () => {
|
||||
fullWidth
|
||||
select
|
||||
variant="outlined"
|
||||
label={<Translate word="Select request" />}
|
||||
label={Tr('Select request')}
|
||||
value={name}
|
||||
onChange={handleChangeCommand}
|
||||
>
|
||||
@ -62,7 +62,7 @@ const TestApi = () => {
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<InputCode code={response} />
|
||||
<InputCode code={response} readOnly />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
@ -57,11 +57,13 @@ export default [
|
||||
{
|
||||
label: 'settings',
|
||||
path: PATH.SETTINGS,
|
||||
header: true,
|
||||
component: Settings
|
||||
},
|
||||
{
|
||||
label: 'test api',
|
||||
path: PATH.TEST_API,
|
||||
devMode: true,
|
||||
component: TestApi
|
||||
},
|
||||
{
|
||||
|
@ -16,48 +16,49 @@
|
||||
import React from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import { AuthLayout, GuessLayout } from 'client/components/HOC';
|
||||
import InternalLayout from 'client/components/HOC/InternalLayout';
|
||||
import { AuthLayout, GuessLayout, InternalLayout } from 'client/components/HOC';
|
||||
import Error404 from 'client/containers/Error404';
|
||||
import Sidebar from 'client/components/Sidebar';
|
||||
|
||||
import endpoints from './endpoints';
|
||||
import endpoints from 'client/router/endpoints';
|
||||
|
||||
function Router() {
|
||||
const renderRoute = ({
|
||||
label = '',
|
||||
path = '',
|
||||
authenticated = true,
|
||||
component: Component
|
||||
}) => (
|
||||
<Route
|
||||
key={`key-${label.replace(' ', '-')}`}
|
||||
exact
|
||||
path={path}
|
||||
component={() =>
|
||||
authenticated ? (
|
||||
<AuthLayout>
|
||||
<InternalLayout title={label}>
|
||||
<Component />
|
||||
</InternalLayout>
|
||||
</AuthLayout>
|
||||
) : (
|
||||
<GuessLayout>
|
||||
const renderRoute = ({
|
||||
label = '',
|
||||
path = '',
|
||||
authenticated = true,
|
||||
component: Component
|
||||
}) => (
|
||||
<Route
|
||||
key={`key-${label.replace(' ', '-')}`}
|
||||
exact
|
||||
path={path}
|
||||
component={() =>
|
||||
authenticated ? (
|
||||
<AuthLayout>
|
||||
<InternalLayout title={label}>
|
||||
<Component />
|
||||
</GuessLayout>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
</InternalLayout>
|
||||
</AuthLayout>
|
||||
) : (
|
||||
<GuessLayout>
|
||||
<Component />
|
||||
</GuessLayout>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
const Router = () => (
|
||||
<>
|
||||
<Sidebar />
|
||||
<Switch>
|
||||
{endpoints?.map(({ routes, ...endpoint }) =>
|
||||
endpoint.path ? renderRoute(endpoint) : routes?.map(renderRoute)
|
||||
)}
|
||||
<Route component={Error404} />
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
</>
|
||||
);
|
||||
|
||||
export default Router;
|
||||
export { endpoints };
|
||||
|
@ -1,18 +0,0 @@
|
||||
/* Copyright 2002-2019, 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. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
.content{
|
||||
background-color: $tertiary;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/* Copyright 2002-2019, 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. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: auto;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
z-index: 1100;
|
||||
background-color: $quaternary;
|
||||
text-align: center;
|
||||
padding: .5rem;
|
||||
a{
|
||||
color: $secondary
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
/* Copyright 2002-2019, 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. */
|
||||
/* -------------------------------------------------------------------------- */
|
@ -13,14 +13,6 @@
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
$primary: #C7C9C8;
|
||||
$secondary: #FFF;
|
||||
$tertiary: #FAFAFA;
|
||||
$quaternary: #353735;
|
||||
|
||||
$font_primary: #353735;
|
||||
$font_secondary: red;
|
||||
|
||||
@font-face {
|
||||
font-family: 'LatoWeb';
|
||||
src: url('fonts/Lato-Regular.eot'); /* IE9 Compat Modes */
|
||||
@ -32,24 +24,3 @@ $font_secondary: red;
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
@import "login";
|
||||
@import "footer";
|
||||
@import "menu";
|
||||
@import "content";
|
||||
|
||||
html, body{
|
||||
font-family: 'LatoWeb';
|
||||
background-color: $secondary;
|
||||
color: $font_primary;
|
||||
min-height: 100vh;
|
||||
margin: 0px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
#root{
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/* Copyright 2002-2019, 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. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
.menu{
|
||||
color: $secondary;
|
||||
width: 15rem;
|
||||
|
||||
.link{
|
||||
text-transform: capitalize;
|
||||
color: $font_primary;
|
||||
}
|
||||
.logo-wrapper{
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
.logo{
|
||||
width: 100%;
|
||||
}
|
||||
.internalNav{
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user