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

F #3951: Add linter (#320)

* Add linter standardjs
This commit is contained in:
Sergio Betanzos 2020-10-14 17:20:11 +02:00 committed by GitHub
parent 5ac2aa9b76
commit 70564d9ac1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
137 changed files with 2192 additions and 2156 deletions

View File

@ -1,2 +1 @@
src/**/*.css
*.md
src/client/assets/languages/**

View File

@ -1,14 +1,21 @@
{
"extends": [
"./node_modules/jloboescalona-eslint-config/index.js",
"plugin:cypress/recommended"
],
"parser": "babel-eslint",
"env": {
"browser": true,
"es2021": true,
"node": true
},
"plugins": [],
"extends": [
"plugin:react/recommended",
"standard"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["react"],
"rules": {
"import/no-extraneous-dependencies": [
"error",
@ -21,6 +28,9 @@
"default-case": 0
},
"settings": {
"react" : {
"version": "detect"
},
"import/resolver": {
"alias": {
"map": [

View File

@ -12,7 +12,8 @@
"cypress:open": "cypress open",
"cypress:run": "cypress run --headless --browser chrome --spec \"cypress/integration/**/*.spec.js\"",
"pot": "node potfile.js",
"po2json": "node po2json.js"
"po2json": "node po2json.js",
"lint": "eslint ./src/client/"
},
"author": "opennebula.io",
"license": "ISC",
@ -26,16 +27,20 @@
],
"devDependencies": {
"cypress": "^5.3.0",
"eslint": "^6.1.0",
"eslint": "^7.11.0",
"eslint-config-prettier": "^6.11.0",
"eslint-config-standard": "^14.1.1",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-webpack": "^0.13.0",
"eslint-plugin-babel": "^5.3.1",
"eslint-plugin-cypress": "^2.11.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-react": "^7.21.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.21.4",
"eslint-plugin-standard": "^4.0.1",
"fireedge-genpotfile": "^1.0.0",
"fireedge-pojson": "^1.0.2",
"jloboescalona-eslint-config": "^1.1.0"
"fireedge-pojson": "^1.0.2"
},
"dependencies": {
"@babel/cli": "^7.10.4",

View File

@ -1,11 +1,11 @@
const CHANGE_ZONE = 'CHANGE_ZONE';
const DISPLAY_LOADING = 'DISPLAY_LOADING';
const TOGGLE_MENU = 'TOGGLE_MENU';
const FIX_MENU = 'FIX_MENU';
const CHANGE_ZONE = 'CHANGE_ZONE'
const DISPLAY_LOADING = 'DISPLAY_LOADING'
const TOGGLE_MENU = 'TOGGLE_MENU'
const FIX_MENU = 'FIX_MENU'
const ENQUEUE_SNACKBAR = 'ENQUEUE_SNACKBAR';
const CLOSE_SNACKBAR = 'CLOSE_SNACKBAR';
const REMOVE_SNACKBAR = 'REMOVE_SNACKBAR';
const ENQUEUE_SNACKBAR = 'ENQUEUE_SNACKBAR'
const CLOSE_SNACKBAR = 'CLOSE_SNACKBAR'
const REMOVE_SNACKBAR = 'REMOVE_SNACKBAR'
const Actions = {
CHANGE_ZONE,
@ -15,7 +15,7 @@ const Actions = {
ENQUEUE_SNACKBAR,
CLOSE_SNACKBAR,
REMOVE_SNACKBAR
};
}
module.exports = {
Actions,
@ -36,7 +36,7 @@ module.exports = {
isFixed
}),
enqueueSnackbar: notification => {
const key = notification.options && notification.options.key;
const key = notification.options && notification.options.key
return {
type: ENQUEUE_SNACKBAR,
@ -44,7 +44,7 @@ module.exports = {
...notification,
key: key || new Date().getTime() + Math.random()
}
};
}
},
enqueueError: message => ({
type: ENQUEUE_SNACKBAR,
@ -71,4 +71,4 @@ module.exports = {
type: REMOVE_SNACKBAR,
key
})
};
}

View File

@ -1,12 +1,12 @@
const START_ONE_REQUEST = 'START_ONE_REQUEST';
const SUCCESS_ONE_REQUEST = 'SUCCESS_ONE_REQUEST';
const FAILURE_ONE_REQUEST = 'FAILURE_ONE_REQUEST';
const START_ONE_REQUEST = 'START_ONE_REQUEST'
const SUCCESS_ONE_REQUEST = 'SUCCESS_ONE_REQUEST'
const FAILURE_ONE_REQUEST = 'FAILURE_ONE_REQUEST'
const Actions = {
START_ONE_REQUEST,
SUCCESS_ONE_REQUEST,
FAILURE_ONE_REQUEST
};
}
module.exports = {
Actions,
@ -101,4 +101,4 @@ module.exports = {
type: FAILURE_ONE_REQUEST,
payload: { error }
})
};
}

View File

@ -1,8 +1,8 @@
const START_AUTH = 'START_AUTH';
const SELECT_FILTER_GROUP = 'SELECT_FILTER_GROUP';
const SUCCESS_AUTH = 'SUCCESS_AUTH';
const FAILURE_AUTH = 'FAILURE_AUTH';
const LOGOUT = 'LOGOUT';
const START_AUTH = 'START_AUTH'
const SELECT_FILTER_GROUP = 'SELECT_FILTER_GROUP'
const SUCCESS_AUTH = 'SUCCESS_AUTH'
const FAILURE_AUTH = 'FAILURE_AUTH'
const LOGOUT = 'LOGOUT'
const Actions = {
START_AUTH,
@ -10,7 +10,7 @@ const Actions = {
SUCCESS_AUTH,
FAILURE_AUTH,
LOGOUT
};
}
module.exports = {
Actions,
@ -32,4 +32,4 @@ module.exports = {
logout: () => ({
type: LOGOUT
})
};
}

View File

@ -13,17 +13,17 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import PropTypes from 'prop-types';
import React from 'react'
import PropTypes from 'prop-types'
import { StaticRouter, BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { StaticRouter, BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import MuiProvider from 'client/providers/muiProvider';
import NotistackProvider from 'client/providers/notistackProvider';
import { TranslateProvider } from 'client/components/HOC';
import MuiProvider from 'client/providers/muiProvider'
import NotistackProvider from 'client/providers/notistackProvider'
import { TranslateProvider } from 'client/components/HOC'
import Router from 'client/router';
import Router from 'client/router'
const App = ({ location, context, store }) => (
<MuiProvider>
@ -45,18 +45,18 @@ const App = ({ location, context, store }) => (
</NotistackProvider>
</Provider>
</MuiProvider>
);
)
App.propTypes = {
location: PropTypes.string,
context: PropTypes.shape({}),
store: PropTypes.shape({})
};
}
App.defaultProps = {
location: '',
context: {},
store: {}
};
}
export default App;
export default App

View File

@ -8,19 +8,19 @@ export const breakpoints = {
tablet: 640,
laptop: 1024,
desktop: 1280
};
}
export const toolbar = {
regular: 56,
xs: 48,
sm: 64
};
}
export const footer = {
regular: 30
};
}
export const sidebar = {
minified: 60,
fixed: 240
};
}

View File

@ -10,6 +10,6 @@ const UbuntuFont = {
url(/client/assets/fonts/Ubuntu/ubuntu.ttf) format('truetype'),
url(/client/assets/fonts/Ubuntu/ubuntu.svg#Ubuntu) format('svg');
`
};
}
export default UbuntuFont;
export default UbuntuFont

View File

@ -2,16 +2,16 @@ import {
createMuiTheme,
responsiveFontSizes,
createGenerateClassName
} from '@material-ui/core';
} from '@material-ui/core'
import UbuntuFont from 'client/assets/theme/fonts';
import { toolbar, breakpoints } from 'client/assets/theme/defaults';
import UbuntuFont from 'client/assets/theme/fonts'
import { toolbar, breakpoints } from 'client/assets/theme/defaults'
const { xs, sm } = breakpoints;
const { xs, sm } = breakpoints
export const generateClassName = createGenerateClassName({
productionPrefix: 'one-'
});
})
export default responsiveFontSizes(
createMuiTheme({
@ -117,4 +117,4 @@ export default responsiveFontSizes(
}
}
})
);
)

View File

@ -1,4 +1,5 @@
import React, { memo } from 'react';
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import {
makeStyles,
@ -10,12 +11,12 @@ import {
CardHeader,
CardContent,
CardActions
} from '@material-ui/core';
import FileIcon from '@material-ui/icons/Description';
import VideogameAssetIcon from '@material-ui/icons/VideogameAsset';
import AccountTreeIcon from '@material-ui/icons/AccountTree';
} from '@material-ui/core'
import FileIcon from '@material-ui/icons/Description'
import VideogameAssetIcon from '@material-ui/icons/VideogameAsset'
import AccountTreeIcon from '@material-ui/icons/AccountTree'
import { Tr } from 'client/components/HOC';
import { Tr } from 'client/components/HOC'
const useStyles = makeStyles(theme => ({
root: {
@ -42,18 +43,18 @@ const useStyles = makeStyles(theme => ({
},
badge: {},
icon: {}
}));
}))
const ApplicationTemplateCard = memo(
({ value, handleEdit, handleDeploy, handleShow, handleRemove }) => {
const classes = useStyles();
const { ID, NAME, TEMPLATE } = value;
const { description, networks = [], roles = [] } = TEMPLATE.BODY;
const classes = useStyles()
const { NAME, TEMPLATE } = value
const { description, networks = [], roles = [] } = TEMPLATE.BODY
const numberOfNetworks = Object.keys(networks)?.length ?? 0;
const numberOfTiers = Object.keys(roles)?.length ?? 0;
const numberOfTiers = roles?.length ?? 0
const numberOfNetworks = Object.keys(networks)?.length ?? 0
const badgePosition = { vertical: 'top', horizontal: 'right' };
const badgePosition = { vertical: 'top', horizontal: 'right' }
return (
<Fade in unmountOnExit={false}>
@ -124,8 +125,36 @@ const ApplicationTemplateCard = memo(
</CardActions>
</Card>
</Fade>
);
)
}
);
)
export default ApplicationTemplateCard;
ApplicationTemplateCard.propTypes = {
value: PropTypes.shape({
ID: PropTypes.string,
NAME: PropTypes.string.isRequired,
TEMPLATE: PropTypes.shape({
BODY: PropTypes.shape({
description: PropTypes.string,
networks: PropTypes.object,
roles: PropTypes.arrayOf(PropTypes.object)
}).isRequired
}).isRequired
}),
handleEdit: PropTypes.func,
handleDeploy: PropTypes.func,
handleShow: PropTypes.func,
handleRemove: PropTypes.func
}
ApplicationTemplateCard.defaultProps = {
value: {},
handleEdit: undefined,
handleDeploy: undefined,
handleShow: undefined,
handleRemove: undefined
}
ApplicationTemplateCard.displayName = 'Application TemplateCard'
export default ApplicationTemplateCard

View File

@ -1,6 +1,7 @@
import React from 'react';
import clsx from 'clsx';
import React from 'react'
import PropTypes from 'prop-types'
import clsx from 'clsx'
import {
makeStyles,
Card,
@ -10,13 +11,13 @@ import {
CardContent,
Badge,
Box
} from '@material-ui/core';
import StorageIcon from '@material-ui/icons/Storage';
import VideogameAssetIcon from '@material-ui/icons/VideogameAsset';
import AccountTreeIcon from '@material-ui/icons/AccountTree';
import FolderOpenIcon from '@material-ui/icons/FolderOpen';
} from '@material-ui/core'
import StorageIcon from '@material-ui/icons/Storage'
import VideogameAssetIcon from '@material-ui/icons/VideogameAsset'
import AccountTreeIcon from '@material-ui/icons/AccountTree'
import FolderOpenIcon from '@material-ui/icons/FolderOpen'
import { Tr } from 'client/components/HOC';
import { Tr } from 'client/components/HOC'
const useStyles = makeStyles(theme => ({
root: {
@ -54,18 +55,18 @@ const useStyles = makeStyles(theme => ({
},
badge: {},
icon: {}
}));
}))
const ClusterCard = React.memo(
({ value, isSelected, handleSelect, handleUnselect }) => {
const classes = useStyles();
const { ID, NAME, HOSTS, VNETS, DATASTORES } = value;
const classes = useStyles()
const { NAME, HOSTS, VNETS, DATASTORES } = value
const hosts = [HOSTS?.ID ?? []].flat();
const vnets = [VNETS?.ID ?? []].flat();
const datastores = [DATASTORES?.ID ?? []].flat();
const hosts = [HOSTS?.ID ?? []].flat()
const vnets = [VNETS?.ID ?? []].flat()
const datastores = [DATASTORES?.ID ?? []].flat()
const badgePosition = { vertical: 'top', horizontal: 'right' };
const badgePosition = { vertical: 'top', horizontal: 'right' }
return (
<Fade in unmountOnExit={false}>
@ -124,8 +125,39 @@ const ClusterCard = React.memo(
</CardActionArea>
</Card>
</Fade>
);
)
}
);
)
export default ClusterCard;
ClusterCard.propTypes = {
value: PropTypes.shape({
ID: PropTypes.string,
NAME: PropTypes.string.isRequired,
HOSTS: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
]),
VNETS: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
]),
DATASTORES: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
])
}),
isSelected: PropTypes.bool,
handleSelect: PropTypes.func,
handleUnselect: PropTypes.func
}
ClusterCard.defaultProps = {
value: {},
isSelected: false,
handleSelect: undefined,
handleUnselect: undefined
}
ClusterCard.displayName = 'ClusterCard'
export default ClusterCard

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import React from 'react'
import PropTypes from 'prop-types'
import { Card, CardHeader, Fade, makeStyles } from '@material-ui/core';
import { Card, CardHeader, Fade, makeStyles } from '@material-ui/core'
const useStyles = makeStyles(theme => ({
root: {
@ -13,10 +13,10 @@ const useStyles = makeStyles(theme => ({
padding: theme.spacing(1),
textAlign: 'center'
}
}));
}))
const EmptyCard = React.memo(({ name }) => {
const classes = useStyles();
const classes = useStyles()
return (
<Fade in unmountOnExit>
@ -27,15 +27,17 @@ const EmptyCard = React.memo(({ name }) => {
/>
</Card>
</Fade>
);
});
)
})
EmptyCard.propTypes = {
name: PropTypes.string
};
}
EmptyCard.defaultProps = {
name: undefined
};
}
export default EmptyCard;
EmptyCard.displayName = 'EmptyCard'
export default EmptyCard

View File

@ -1,4 +1,5 @@
import React from 'react';
import React from 'react'
import PropTypes from 'prop-types'
import {
makeStyles,
@ -7,9 +8,9 @@ import {
CardHeader,
CardActions,
Fade
} from '@material-ui/core';
} from '@material-ui/core'
import { Tr } from 'client/components/HOC';
import { Tr } from 'client/components/HOC'
const useStyles = makeStyles(theme => ({
root: {
@ -33,12 +34,12 @@ const useStyles = makeStyles(theme => ({
remove: {
backgroundColor: theme.palette.error.dark
}
}));
}))
const NetworkCard = React.memo(
({ value, handleEdit, handleClone, handleRemove }) => {
const classes = useStyles();
const { mandatory, name, description, type, id, extra } = value;
const classes = useStyles()
const { mandatory, name, description } = value
return (
<Fade in unmountOnExit={false}>
@ -80,8 +81,31 @@ const NetworkCard = React.memo(
</CardActions>
</Card>
</Fade>
);
)
}
);
)
export default NetworkCard;
NetworkCard.propTypes = {
value: PropTypes.shape({
mandatory: PropTypes.bool,
name: PropTypes.string.isRequired,
description: PropTypes.string,
type: PropTypes.string,
id: PropTypes.string,
extra: PropTypes.string
}),
handleEdit: PropTypes.func,
handleClone: PropTypes.func,
handleRemove: PropTypes.func
}
NetworkCard.defaultProps = {
value: {},
handleEdit: undefined,
handleClone: undefined,
handleRemove: undefined
}
NetworkCard.displayName = 'NetworkCard'
export default NetworkCard

View File

@ -1,11 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import { Card, CardActionArea, Fade, makeStyles } from '@material-ui/core';
import { Skeleton } from '@material-ui/lab';
import clsx from 'clsx'
import { Card, CardActionArea, Fade, makeStyles } from '@material-ui/core'
import { Skeleton } from '@material-ui/lab'
import useNearScreen from 'client/hooks/useNearScreen';
import useNearScreen from 'client/hooks/useNearScreen'
const useStyles = makeStyles(theme => ({
root: {
@ -20,29 +20,22 @@ const useStyles = makeStyles(theme => ({
minHeight: 140,
padding: theme.spacing(1)
}
}));
}))
const SelectCard = React.memo(
({ isSelected, handleSelect, handleUnselect, ID, NAME }) => {
const classes = useStyles();
const SelectCard = memo(
({ title, isSelected, handleClick }) => {
const classes = useStyles()
const { isNearScreen, fromRef } = useNearScreen({
distance: '100px'
});
})
return (
<div ref={fromRef}>
{isNearScreen ? (
<Fade in={isNearScreen}>
<Card
className={clsx(classes.root, { [classes.selected]: isSelected })}
>
<CardActionArea
className={classes.actionArea}
onClick={() =>
isSelected ? handleUnselect(ID) : handleSelect(ID)
}
>
<span>{`📦 ${NAME}`}</span>
<Card className={clsx(classes.root, { [classes.selected]: isSelected })}>
<CardActionArea className={classes.actionArea} onClick={handleClick}>
<span>{title}</span>
</CardActionArea>
</Card>
</Fade>
@ -50,24 +43,22 @@ const SelectCard = React.memo(
<Skeleton variant="rect" width="100%" height={140} />
)}
</div>
);
)
}
);
)
SelectCard.propTypes = {
title: PropTypes.string,
isSelected: PropTypes.bool,
handleSelect: PropTypes.func,
handleUnselect: PropTypes.func,
ID: PropTypes.string,
NAME: PropTypes.string
};
handleClick: PropTypes.func
}
SelectCard.defaultProps = {
title: undefined,
isSelected: false,
handleSelect: () => undefined,
handleUnselect: () => undefined,
ID: undefined,
NAME: undefined
};
handleClick: () => undefined
}
export default SelectCard;
SelectCard.displayName = 'SelectCard'
export default SelectCard

View File

@ -1,4 +1,5 @@
import React from 'react';
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import {
makeStyles,
@ -7,10 +8,10 @@ import {
CardHeader,
CardActions,
Badge
} from '@material-ui/core';
import DesktopWindowsIcon from '@material-ui/icons/DesktopWindows';
} from '@material-ui/core'
import DesktopWindowsIcon from '@material-ui/icons/DesktopWindows'
import { Tr } from 'client/components/HOC';
import { Tr } from 'client/components/HOC'
const useStyles = makeStyles(() => ({
root: {
@ -32,12 +33,12 @@ const useStyles = makeStyles(() => ({
lineClamp: 2,
boxOrient: 'vertical'
}
}));
}))
const TierCard = React.memo(
const TierCard = memo(
({ values, handleEdit, handleClone, handleRemove, cardProps }) => {
const classes = useStyles();
const { name = 'Tier name', cardinality } = values;
const classes = useStyles()
const { name, cardinality } = values
return (
<Card className={classes.root} {...cardProps}>
@ -82,8 +83,32 @@ const TierCard = React.memo(
)}
</CardActions>
</Card>
);
)
}
);
)
export default TierCard;
TierCard.propTypes = {
values: PropTypes.shape({
name: PropTypes.string,
cardinality: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
])
}),
handleEdit: PropTypes.func,
handleClone: PropTypes.func,
handleRemove: PropTypes.func,
cardProps: PropTypes.object
}
TierCard.defaultProps = {
values: {},
handleEdit: undefined,
handleClone: undefined,
handleRemove: undefined,
cardProps: undefined
}
TierCard.displayName = 'TierCard'
export default TierCard

View File

@ -1,9 +1,9 @@
import ClusterCard from 'client/components/Cards/ClusterCard';
import NetworkCard from 'client/components/Cards/NetworkCard';
import TierCard from 'client/components/Cards/TierCard';
import EmptyCard from 'client/components/Cards/EmptyCard';
import SelectCard from 'client/components/Cards/SelectCard';
import ApplicationTemplateCard from 'client/components/Cards/ApplicationTemplateCard';
import ClusterCard from 'client/components/Cards/ClusterCard'
import NetworkCard from 'client/components/Cards/NetworkCard'
import TierCard from 'client/components/Cards/TierCard'
import EmptyCard from 'client/components/Cards/EmptyCard'
import SelectCard from 'client/components/Cards/SelectCard'
import ApplicationTemplateCard from 'client/components/Cards/ApplicationTemplateCard'
export {
ClusterCard,
@ -12,4 +12,4 @@ export {
EmptyCard,
SelectCard,
ApplicationTemplateCard
};
}

View File

@ -1,5 +1,5 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import {
useMediaQuery,
@ -8,22 +8,22 @@ import {
DialogTitle,
DialogContent,
DialogActions
} from '@material-ui/core';
import { useForm, FormProvider } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers';
} from '@material-ui/core'
import { useForm, FormProvider } from 'react-hook-form'
import { yupResolver } from '@hookform/resolvers'
import { Tr } from 'client/components/HOC';
import { Tr } from 'client/components/HOC'
const DialogForm = memo(
({ open, title, values, resolver, onSubmit, onCancel, children }) => {
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'));
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'))
const { handleSubmit, ...methods } = useForm({
mode: 'onChange',
reValidateMode: 'onSubmit',
defaultValues: values,
resolver: yupResolver(resolver)
});
})
return (
<Dialog
@ -63,9 +63,9 @@ const DialogForm = memo(
</DialogActions>
)}
</Dialog>
);
)
}
);
)
DialogForm.propTypes = {
open: PropTypes.bool.isRequired,
@ -81,7 +81,7 @@ DialogForm.propTypes = {
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
])
};
}
DialogForm.defaultProps = {
open: true,
@ -91,6 +91,6 @@ DialogForm.defaultProps = {
onSubmit: undefined,
onCancel: undefined,
children: null
};
}
export default DialogForm;
export default DialogForm

View File

@ -1,3 +1,3 @@
import DialogForm from 'client/components/Dialogs/DialogForm';
import DialogForm from 'client/components/Dialogs/DialogForm'
export { DialogForm };
export { DialogForm }

View File

@ -1,28 +1,14 @@
/* 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. */
/* -------------------------------------------------------------------------- */
import React, { memo } from 'react'
import React from 'react';
import { Box, Link, Typography } from '@material-ui/core';
import { Box, Link, Typography } from '@material-ui/core'
import footerStyles from 'client/components/Footer/styles';
import { by } from 'client/constants';
import footerStyles from 'client/components/Footer/styles'
import { by } from 'client/constants'
const { text, url } = by;
const { text, url } = by
const Footer = React.memo(() => {
const classes = footerStyles();
const Footer = memo(() => {
const classes = footerStyles()
return (
<Box className={classes.footer} component="footer">
@ -37,7 +23,9 @@ const Footer = React.memo(() => {
</Link>
</Typography>
</Box>
);
});
)
})
export default Footer;
Footer.displayName = 'Footer'
export default Footer

View File

@ -1,4 +1,4 @@
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core'
export default makeStyles(theme => ({
footer: {
@ -21,4 +21,4 @@ export default makeStyles(theme => ({
color: theme.palette.primary.light,
marginLeft: theme.spacing(1)
}
}));
}))

View File

@ -1,12 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import React from 'react'
import PropTypes from 'prop-types'
import { TextField } from '@material-ui/core';
import { Autocomplete } from '@material-ui/lab';
import { Controller } from 'react-hook-form';
import { TextField } from '@material-ui/core'
import { Autocomplete } from '@material-ui/lab'
import { Controller } from 'react-hook-form'
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
import { Tr } from 'client/components/HOC/Translate';
import ErrorHelper from 'client/components/FormControl/ErrorHelper'
import { Tr } from 'client/components/HOC/Translate'
const AutocompleteController = ({
control,
@ -18,7 +18,7 @@ const AutocompleteController = ({
}) => (
<Controller
render={({ value: val, onBlur, onChange }) => {
const selected = values.find(({ value }) => value === val) ?? null;
const selected = values.find(({ value }) => value === val) ?? null
return (
<Autocomplete
@ -42,12 +42,12 @@ const AutocompleteController = ({
/>
)}
/>
);
)
}}
name={name}
control={control}
/>
);
)
AutocompleteController.propTypes = {
control: PropTypes.object,
@ -59,7 +59,7 @@ AutocompleteController.propTypes = {
PropTypes.bool,
PropTypes.objectOf(PropTypes.any)
])
};
}
AutocompleteController.defaultProps = {
control: {},
@ -68,6 +68,6 @@ AutocompleteController.defaultProps = {
label: '',
values: [],
error: false
};
}
export default AutocompleteController;
export default AutocompleteController

View File

@ -1,16 +1,16 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import {
FormControl,
FormControlLabel,
Checkbox,
Tooltip
} from '@material-ui/core';
import { Controller } from 'react-hook-form';
} from '@material-ui/core'
import { Controller } from 'react-hook-form'
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
import { Tr } from 'client/components/HOC/Translate';
import ErrorHelper from 'client/components/FormControl/ErrorHelper'
import { Tr } from 'client/components/HOC/Translate'
const CheckboxController = memo(
({ control, cy, name, label, tooltip, error }) => (
@ -40,7 +40,7 @@ const CheckboxController = memo(
/>
),
(prevProps, nextProps) => prevProps.error === nextProps.error
);
)
CheckboxController.propTypes = {
control: PropTypes.object,
@ -52,7 +52,7 @@ CheckboxController.propTypes = {
PropTypes.bool,
PropTypes.objectOf(PropTypes.any)
])
};
}
CheckboxController.defaultProps = {
control: {},
@ -62,6 +62,8 @@ CheckboxController.defaultProps = {
tooltip: undefined,
values: [],
error: false
};
}
export default CheckboxController;
CheckboxController.displayName = 'CheckboxController'
export default CheckboxController

View File

@ -1,39 +1,28 @@
import React from 'react';
import { string } from 'prop-types';
import React from 'react'
import { string } from 'prop-types'
import {
Box,
darken,
lighten,
makeStyles,
Typography
} from '@material-ui/core';
import { Info as InfoIcon } from '@material-ui/icons';
import { Tr } from 'client/components/HOC/Translate';
import { Box, makeStyles, Typography } from '@material-ui/core'
import { Info as InfoIcon } from '@material-ui/icons'
import { Tr } from 'client/components/HOC/Translate'
const useStyles = makeStyles(theme => {
const getColor = theme.palette.type === 'light' ? darken : lighten;
const getBackgroundColor = theme.palette.type === 'light' ? lighten : darken;
return {
root: {
color: theme.palette.error.dark,
display: 'flex',
alignItems: 'center'
},
icon: {
fontSize: 16
},
text: {
...theme.typography.body1,
paddingLeft: theme.spacing(1),
overflowWrap: 'anywhere'
}
};
});
const useStyles = makeStyles(theme => ({
root: {
color: theme.palette.error.dark,
display: 'flex',
alignItems: 'center'
},
icon: {
fontSize: 16
},
text: {
...theme.typography.body1,
paddingLeft: theme.spacing(1),
overflowWrap: 'anywhere'
}
}))
const ErrorHelper = ({ label, ...rest }) => {
const classes = useStyles();
const classes = useStyles()
return (
<Box component="span" className={classes.root} {...rest}>
@ -46,15 +35,15 @@ const ErrorHelper = ({ label, ...rest }) => {
{Tr(label)}
</Typography>
</Box>
);
};
)
}
ErrorHelper.propTypes = {
label: string
};
}
ErrorHelper.defaultProps = {
label: 'Error'
};
}
export default ErrorHelper;
export default ErrorHelper

View File

@ -13,19 +13,19 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import React from 'react'
import { MenuItem, TextField } from '@material-ui/core';
import { FilterVintage } from '@material-ui/icons';
import { MenuItem, TextField } from '@material-ui/core'
import { FilterVintage } from '@material-ui/icons'
import useAuth from 'client/hooks/useAuth';
import useOpennebula from 'client/hooks/useOpennebula';
import { Tr } from 'client/components/HOC';
import { FILTER_POOL } from 'client/constants';
import useAuth from 'client/hooks/useAuth'
import useOpennebula from 'client/hooks/useOpennebula'
import { Tr } from 'client/components/HOC'
import { FILTER_POOL } from 'client/constants'
const GroupSelect = props => {
const { filterPool, authUser } = useAuth();
const { groups } = useOpennebula();
const { filterPool, authUser } = useAuth()
const { groups } = useOpennebula()
const defaultValue = React.useMemo(
() =>
@ -33,7 +33,7 @@ const GroupSelect = props => {
? FILTER_POOL.ALL_RESOURCES
: authUser?.GID,
[filterPool]
);
)
const orderGroups = React.useMemo(
() =>
@ -53,7 +53,7 @@ const GroupSelect = props => {
</MenuItem>
)),
[groups]
);
)
return (
<TextField
@ -69,11 +69,11 @@ const GroupSelect = props => {
<MenuItem value={FILTER_POOL.ALL_RESOURCES}>{Tr('Show all')}</MenuItem>
{orderGroups}
</TextField>
);
};
)
}
GroupSelect.propTypes = {};
GroupSelect.propTypes = {}
GroupSelect.defaultProps = {};
GroupSelect.defaultProps = {}
export default GroupSelect;
export default GroupSelect

View File

@ -1,16 +1,16 @@
import React from 'react';
import { Box } from '@material-ui/core';
import AceEditor from 'react-ace';
import PropTypes from 'prop-types';
import 'ace-builds/src-noconflict/mode-json';
import 'ace-builds/src-noconflict/theme-github';
import React from 'react'
import { Box } from '@material-ui/core'
import AceEditor from 'react-ace'
import PropTypes from 'prop-types'
import 'ace-builds/src-noconflict/mode-json'
import 'ace-builds/src-noconflict/theme-github'
const { string } = PropTypes;
const { string } = PropTypes
const InputCode = ({ code, language, ...props }) => {
const handleChange = newValue => {
console.log('change', newValue);
};
console.log('change', newValue)
}
return (
<Box height="100%" minHeight={200}>
@ -36,17 +36,17 @@ const InputCode = ({ code, language, ...props }) => {
{...props}
/>
</Box>
);
};
)
}
InputCode.propTypes = {
code: string,
language: string
};
}
InputCode.defaultProps = {
code: '',
language: 'json'
};
}
export default InputCode;
export default InputCode

View File

@ -1,11 +1,11 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import { TextField, MenuItem } from '@material-ui/core';
import { Controller } from 'react-hook-form';
import { TextField, MenuItem } from '@material-ui/core'
import { Controller } from 'react-hook-form'
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
import { Tr } from 'client/components/HOC/Translate';
import ErrorHelper from 'client/components/FormControl/ErrorHelper'
import { Tr } from 'client/components/HOC/Translate'
const SelectController = memo(
({ control, cy, name, label, values, error }) => (
@ -34,7 +34,7 @@ const SelectController = memo(
/>
),
(prevProps, nextProps) => prevProps.error === nextProps.error
);
)
SelectController.propTypes = {
control: PropTypes.object,
@ -46,7 +46,7 @@ SelectController.propTypes = {
PropTypes.bool,
PropTypes.objectOf(PropTypes.any)
])
};
}
SelectController.defaultProps = {
control: {},
@ -55,6 +55,8 @@ SelectController.defaultProps = {
label: '',
values: [],
error: false
};
}
export default SelectController;
SelectController.displayName = 'SelectController'
export default SelectController

View File

@ -1,20 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import React from 'react'
import PropTypes from 'prop-types'
import { makeStyles, CircularProgress, Button } from '@material-ui/core';
import { makeStyles, CircularProgress, Button } from '@material-ui/core'
import { Submit } from 'client/constants/translates';
import { Tr } from 'client/components/HOC';
import { Submit } from 'client/constants/translates'
import { Tr } from 'client/components/HOC'
const useStyles = makeStyles(theme => ({
button: {
transition: 'disabled 0.5s ease',
margin: theme.spacing(3, 0, 2)
}
}));
}))
const SubmitButton = ({ isSubmitting, label, ...rest }) => {
const classes = useStyles();
const classes = useStyles()
return (
<Button
@ -28,17 +28,17 @@ const SubmitButton = ({ isSubmitting, label, ...rest }) => {
{isSubmitting && <CircularProgress size={24} />}
{!isSubmitting && (label ?? Tr(Submit))}
</Button>
);
};
)
}
SubmitButton.propTypes = {
isSubmitting: PropTypes.bool,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node])
};
}
SubmitButton.defaultProps = {
isSubmitting: false,
label: undefined
};
}
export default SubmitButton;
export default SubmitButton

View File

@ -1,11 +1,11 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import { TextField } from '@material-ui/core';
import { Controller } from 'react-hook-form';
import { Tr } from 'client/components/HOC';
import { TextField } from '@material-ui/core'
import { Controller } from 'react-hook-form'
import { Tr } from 'client/components/HOC'
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
import ErrorHelper from 'client/components/FormControl/ErrorHelper'
const TextController = memo(
({ control, cy, type, name, label, error }) => (
@ -26,7 +26,7 @@ const TextController = memo(
/>
),
(prevProps, nextProps) => prevProps.error === nextProps.error
);
)
TextController.propTypes = {
control: PropTypes.object,
@ -38,7 +38,7 @@ TextController.propTypes = {
PropTypes.bool,
PropTypes.objectOf(PropTypes.any)
])
};
}
TextController.defaultProps = {
control: {},
@ -47,6 +47,8 @@ TextController.defaultProps = {
name: '',
label: '',
error: false
};
}
export default TextController;
TextController.displayName = 'TextController'
export default TextController

View File

@ -1,10 +1,10 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import { styled, Button, MobileStepper } from '@material-ui/core';
import { KeyboardArrowLeft, KeyboardArrowRight } from '@material-ui/icons';
import { styled, Button, MobileStepper } from '@material-ui/core'
import { KeyboardArrowLeft, KeyboardArrowRight } from '@material-ui/icons'
import { Tr } from 'client/components/HOC';
import { Tr } from 'client/components/HOC'
const StickyMobileStepper = styled(MobileStepper)({
position: 'sticky',
@ -12,7 +12,7 @@ const StickyMobileStepper = styled(MobileStepper)({
backdropFilter: 'blur(5px)',
background: '#fafafa9c',
zIndex: 1
});
})
const CustomMobileStepper = memo(
({
@ -42,7 +42,7 @@ const CustomMobileStepper = memo(
/>
),
(prev, next) => prev.activeStep === next.activeStep
);
)
CustomMobileStepper.propTypes = {
totalSteps: PropTypes.number,
@ -51,7 +51,7 @@ CustomMobileStepper.propTypes = {
disabledBack: PropTypes.bool,
handleNext: PropTypes.func,
handleBack: PropTypes.func
};
}
CustomMobileStepper.defaultProps = {
totalSteps: 0,
@ -60,6 +60,8 @@ CustomMobileStepper.defaultProps = {
disabledBack: false,
handleNext: () => undefined,
handleBack: () => undefined
};
}
export default CustomMobileStepper;
CustomMobileStepper.displayName = 'MobileStepper'
export default CustomMobileStepper

View File

@ -1,5 +1,5 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import {
styled,
@ -8,9 +8,9 @@ import {
Step,
StepLabel,
Box
} from '@material-ui/core';
} from '@material-ui/core'
import { Tr } from 'client/components/HOC';
import { Tr } from 'client/components/HOC'
const StickyStepper = styled(Stepper)({
position: 'sticky',
@ -18,7 +18,7 @@ const StickyStepper = styled(Stepper)({
backdropFilter: 'blur(5px)',
background: '#fafafa9c',
zIndex: 1
});
})
const CustomStepper = memo(
({ steps, activeStep, lastStep, disabledBack, handleNext, handleBack }) => (
@ -41,7 +41,7 @@ const CustomStepper = memo(
</>
),
(prev, next) => prev.activeStep === next.activeStep
);
)
CustomStepper.propTypes = {
steps: PropTypes.arrayOf(
@ -55,7 +55,7 @@ CustomStepper.propTypes = {
disabledBack: PropTypes.bool.isRequired,
handleNext: PropTypes.func,
handleBack: PropTypes.func
};
}
CustomStepper.defaultProps = {
steps: [],
@ -64,6 +64,8 @@ CustomStepper.defaultProps = {
disabledBack: false,
handleNext: () => undefined,
handleBack: () => undefined
};
}
export default CustomStepper;
CustomStepper.displayName = 'Stepper'
export default CustomStepper

View File

@ -1,60 +1,60 @@
import React, { useState, useMemo, useCallback, useEffect } from 'react';
import PropTypes from 'prop-types';
import React, { useState, useMemo, useCallback, useEffect } from 'react'
import PropTypes from 'prop-types'
import { useFormContext } from 'react-hook-form';
import { useMediaQuery } from '@material-ui/core';
import { useFormContext } from 'react-hook-form'
import { useMediaQuery } from '@material-ui/core'
import CustomMobileStepper from 'client/components/FormStepper/MobileStepper';
import CustomStepper from 'client/components/FormStepper/Stepper';
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
import CustomMobileStepper from 'client/components/FormStepper/MobileStepper'
import CustomStepper from 'client/components/FormStepper/Stepper'
import ErrorHelper from 'client/components/FormControl/ErrorHelper'
const FIRST_STEP = 0;
const FIRST_STEP = 0
const FormStepper = ({ steps, schema, onSubmit }) => {
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'));
const { watch, trigger, reset, errors } = useFormContext();
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'))
const { watch, trigger, reset, errors } = useFormContext()
const [formData, setFormData] = useState(() => watch());
const [activeStep, setActiveStep] = useState(FIRST_STEP);
const [formData, setFormData] = useState(() => watch())
const [activeStep, setActiveStep] = useState(FIRST_STEP)
const totalSteps = useMemo(() => steps?.length, [steps]);
const lastStep = useMemo(() => totalSteps - 1, [totalSteps]);
const disabledBack = useMemo(() => activeStep === FIRST_STEP, [activeStep]);
const totalSteps = useMemo(() => steps?.length, [steps])
const lastStep = useMemo(() => totalSteps - 1, [totalSteps])
const disabledBack = useMemo(() => activeStep === FIRST_STEP, [activeStep])
useEffect(() => {
reset({ ...formData }, { errors: false });
}, [formData]);
reset({ ...formData }, { errors: false })
}, [formData])
const handleNext = () => {
const { id, resolver } = steps[activeStep];
const currentData = watch()[id];
const { id, resolver } = steps[activeStep]
const currentData = watch()[id]
resolver
.validate(currentData)
.then(() => {
const validateData = { ...formData, [id]: currentData };
const validateData = { ...formData, [id]: currentData }
if (activeStep === lastStep) {
onSubmit(schema.cast(validateData));
onSubmit(schema.cast(validateData))
} else {
setFormData(validateData);
setActiveStep(prevActiveStep => prevActiveStep + 1);
setFormData(validateData)
setActiveStep(prevActiveStep => prevActiveStep + 1)
}
})
.catch(() => trigger(id));
};
.catch(() => trigger(id))
}
const handleBack = useCallback(() => {
if (activeStep <= FIRST_STEP) return;
if (activeStep <= FIRST_STEP) return
setActiveStep(prevActiveStep => prevActiveStep - 1);
}, [activeStep]);
setActiveStep(prevActiveStep => prevActiveStep - 1)
}, [activeStep])
const { id, content: Content } = useMemo(() => steps[activeStep], [
formData,
activeStep,
setFormData
]);
])
return (
<>
@ -84,8 +84,8 @@ const FormStepper = ({ steps, schema, onSubmit }) => {
)}
{Content && <Content data={formData[id]} setFormData={setFormData} />}
</>
);
};
)
}
FormStepper.propTypes = {
steps: PropTypes.arrayOf(
@ -99,12 +99,12 @@ FormStepper.propTypes = {
),
schema: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
onSubmit: PropTypes.func
};
}
FormStepper.defaultProps = {
steps: [],
schema: {},
onSubmit: console.log
};
}
export default FormStepper;
export default FormStepper

View File

@ -1,36 +1,36 @@
import React from 'react';
import PropTypes from 'prop-types';
import React from 'react'
import PropTypes from 'prop-types'
import { Grid } from '@material-ui/core';
import { useFormContext, useWatch } from 'react-hook-form';
import { Grid } from '@material-ui/core'
import { useFormContext, useWatch } from 'react-hook-form'
import { TYPE_INPUT } from 'client/constants';
import TextController from 'client/components/FormControl/TextController';
import SelectController from 'client/components/FormControl/SelectController';
import CheckboxController from 'client/components/FormControl/CheckboxController';
import AutocompleteController from 'client/components/FormControl/AutocompleteController';
import { TYPE_INPUT } from 'client/constants'
import TextController from 'client/components/FormControl/TextController'
import SelectController from 'client/components/FormControl/SelectController'
import CheckboxController from 'client/components/FormControl/CheckboxController'
import AutocompleteController from 'client/components/FormControl/AutocompleteController'
const InputController = {
[TYPE_INPUT.TEXT]: TextController,
[TYPE_INPUT.SELECT]: SelectController,
[TYPE_INPUT.CHECKBOX]: CheckboxController,
[TYPE_INPUT.AUTOCOMPLETE]: AutocompleteController
};
}
const FormWithSchema = ({ id, cy, fields }) => {
const { control, errors } = useFormContext();
const { control, errors } = useFormContext()
return (
<Grid container spacing={1}>
{fields?.map(
({ name, type, htmlType, label, values, dependOf, tooltip, grid }) => {
const dataCy = `${cy}-${name}`;
const inputName = id ? `${id}.${name}` : name;
const formError = id ? errors[id] : errors;
const inputError = formError ? formError[name] : false;
const dataCy = `${cy}-${name}`
const inputName = id ? `${id}.${name}` : name
const formError = id ? errors[id] : errors
const inputError = formError ? formError[name] : false
const dependValue = dependOf
? useWatch({ control, name: id ? `${id}.${dependOf}` : dependOf })
: null;
: null
return (
InputController[type] && (
@ -47,23 +47,17 @@ const FormWithSchema = ({ id, cy, fields }) => {
})}
</Grid>
)
);
)
}
)}
</Grid>
);
};
)
}
FormWithSchema.propTypes = {
id: PropTypes.string,
cy: PropTypes.string,
fields: PropTypes.arrayOf(PropTypes.object)
};
}
FormWithSchema.defaultProps = {
id: '',
cy: 'form',
fields: []
};
export default FormWithSchema;
export default FormWithSchema

View File

@ -1,3 +1,3 @@
import FormWithSchema from 'client/components/Forms/FormWithSchema';
import FormWithSchema from 'client/components/Forms/FormWithSchema'
export { FormWithSchema };
export { FormWithSchema }

View File

@ -13,21 +13,21 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import React from 'react'
import PropTypes from 'prop-types'
import clsx from 'clsx'
import { Box, Container } from '@material-ui/core';
import { CSSTransition } from 'react-transition-group';
import { Box, Container } from '@material-ui/core'
import { CSSTransition } from 'react-transition-group'
import useGeneral from 'client/hooks/useGeneral';
import Footer from 'client/components/Footer';
import Header from 'client/components/Header';
import internalStyles from 'client/components/HOC/InternalLayout/styles';
import useGeneral from 'client/hooks/useGeneral'
import Footer from 'client/components/Footer'
import Header from 'client/components/Header'
import internalStyles from 'client/components/HOC/InternalLayout/styles'
const InternalLayout = ({ authRoute, label, children }) => {
const classes = internalStyles();
const { isFixMenu } = useGeneral();
const classes = internalStyles()
const { isFixMenu } = useGeneral()
return authRoute ? (
<Box className={clsx(classes.root, { [classes.isDrawerFixed]: isFixMenu })}>
@ -57,8 +57,8 @@ const InternalLayout = ({ authRoute, label, children }) => {
</Box>
) : (
children
);
};
)
}
InternalLayout.propTypes = {
children: PropTypes.oneOfType([
@ -68,12 +68,12 @@ InternalLayout.propTypes = {
]),
authRoute: PropTypes.bool.isRequired,
label: PropTypes.string
};
}
InternalLayout.defaultProps = {
children: [],
authRoute: false,
label: null
};
}
export default InternalLayout;
export default InternalLayout

View File

@ -1,5 +1,5 @@
import { makeStyles } from '@material-ui/core';
import { sidebar, toolbar, footer } from 'client/assets/theme/defaults';
import { makeStyles } from '@material-ui/core'
import { sidebar, toolbar, footer } from 'client/assets/theme/defaults'
export default makeStyles(theme => ({
root: {
@ -70,4 +70,4 @@ export default makeStyles(theme => ({
},
enterDone: {},
exitDone: {}
}));
}))

View File

@ -13,51 +13,51 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useLocation, Redirect } from 'react-router-dom';
import React, { useEffect } from 'react'
import PropTypes from 'prop-types'
import { useLocation, Redirect } from 'react-router-dom'
import useAuth from 'client/hooks/useAuth';
import useOpennebula from 'client/hooks/useOpennebula';
import useAuth from 'client/hooks/useAuth'
import useOpennebula from 'client/hooks/useOpennebula'
import LoadingScreen from 'client/components/LoadingScreen';
import Sidebar from 'client/components/Sidebar';
import Notifier from 'client/components/Notifier';
import { PATH, findRouteByPathname } from 'client/router/endpoints';
import LoadingScreen from 'client/components/LoadingScreen'
import Sidebar from 'client/components/Sidebar'
import Notifier from 'client/components/Notifier'
import { PATH, findRouteByPathname } from 'client/router/endpoints'
const MainLayout = ({ children }) => {
const { pathname } = useLocation();
const { groups } = useOpennebula();
const { pathname } = useLocation()
const { groups } = useOpennebula()
const {
isLogged,
isLoginInProcess,
getAuthInfo,
authUser,
firstRender
} = useAuth();
} = useAuth()
useEffect(() => {
if (isLogged && !isLoginInProcess) {
getAuthInfo();
getAuthInfo()
}
}, [isLogged, isLoginInProcess]);
}, [isLogged, isLoginInProcess])
const { authenticated } = findRouteByPathname(pathname);
const authRoute = Boolean(authenticated);
const { authenticated } = findRouteByPathname(pathname)
const authRoute = Boolean(authenticated)
// PENDING TO AUTHENTICATING OR FIRST RENDERING
if (firstRender || (isLogged && authRoute && !authUser && !groups?.length)) {
return <LoadingScreen />;
return <LoadingScreen />
}
// PROTECTED ROUTE
if (authRoute && !isLogged && !isLoginInProcess) {
return <Redirect to={PATH.LOGIN} />;
return <Redirect to={PATH.LOGIN} />
}
// PUBLIC ROUTE
if (!authRoute && isLogged && !isLoginInProcess) {
return <Redirect to={PATH.DASHBOARD} />;
return <Redirect to={PATH.DASHBOARD} />
}
return (
@ -66,8 +66,8 @@ const MainLayout = ({ children }) => {
{children}
<Notifier />
</>
);
};
)
}
MainLayout.propTypes = {
children: PropTypes.oneOfType([
@ -75,10 +75,10 @@ MainLayout.propTypes = {
PropTypes.node,
PropTypes.string
])
};
}
MainLayout.defaultProps = {
children: ''
};
}
export default MainLayout;
export default MainLayout

View File

@ -13,18 +13,18 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React, { useContext, useState, useEffect, createContext } from 'react';
import PropTypes from 'prop-types';
import { Select } from '@material-ui/core';
import { sprintf } from 'sprintf-js';
import root from 'window-or-global';
import { defaultLang } from 'server/utils/constants/defaults';
import React, { useContext, useState, useEffect, createContext } from 'react'
import PropTypes from 'prop-types'
import { Select } from '@material-ui/core'
import { sprintf } from 'sprintf-js'
import root from 'window-or-global'
import { defaultLang } from 'server/utils/constants/defaults'
const defaultFunction = () => undefined;
const TranslateContext = createContext();
const document = root.document;
const defaultFunction = () => undefined
const TranslateContext = createContext()
const document = root.document
let languageScript =
document && document.createElement && document.createElement('script');
document && document.createElement && document.createElement('script')
const GenerateScript = (
language = defaultLang,
@ -32,84 +32,84 @@ const GenerateScript = (
setHash = defaultFunction
) => {
try {
const script = document.createElement('script');
script.src = `/client/assets/languages/${language}.js`;
script.async = true;
const script = document.createElement('script')
script.src = `/client/assets/languages/${language}.js`
script.async = true
script.onload = () => {
setLang(language);
setHash(root.locale);
};
document.body.appendChild(script);
languageScript = script;
setLang(language)
setHash(root.locale)
}
document.body.appendChild(script)
languageScript = script
// eslint-disable-next-line no-empty
} catch (error) {}
};
}
const RemoveScript = () => {
document.body.removeChild(languageScript);
};
document.body.removeChild(languageScript)
}
const TranslateProvider = ({ children }) => {
const [lang, setLang] = useState(defaultLang);
const [hash, setHash] = useState({});
const [lang, setLang] = useState(defaultLang)
const [hash, setHash] = useState({})
useEffect(() => {
GenerateScript(lang, setLang, setHash);
GenerateScript(lang, setLang, setHash)
return () => {
RemoveScript();
};
}, []);
RemoveScript()
}
}, [])
const changeLang = (language = defaultLang) => {
RemoveScript();
GenerateScript(language, setLang, setHash);
};
RemoveScript()
GenerateScript(language, setLang, setHash)
}
const value = {
lang,
hash,
changeLang
};
}
return (
<TranslateContext.Provider value={value}>
{children}
</TranslateContext.Provider>
);
};
)
}
const translate = (str = '', values) => {
const context = useContext(TranslateContext);
let key = str;
const context = useContext(TranslateContext)
let key = str
if (context?.hash[key]) {
key = context.hash[key];
key = context.hash[key]
}
if (!!values && Array.isArray(values)) {
key = sprintf(key, ...values);
key = sprintf(key, ...values)
}
return key;
};
return key
}
const Tr = (str = '') => {
let key = str;
let values;
let key = str
let values
if (Array.isArray(str)) {
key = str[0] || '';
values = str[1];
key = str[0] || ''
values = str[1]
}
const valuesTr = !!values && !Array.isArray(values) ? [values] : values;
const valuesTr = !!values && !Array.isArray(values) ? [values] : values
return translate(key, valuesTr);
};
return translate(key, valuesTr)
}
const SelectTranslate = () => {
const context = useContext(TranslateContext);
const context = useContext(TranslateContext)
const languages =
root && root.langs && Array.isArray(root.langs) ? root.langs : [];
root && root.langs && Array.isArray(root.langs) ? root.langs : []
const handleChange = (e, changeLang) => {
if (
e &&
@ -118,9 +118,9 @@ const SelectTranslate = () => {
changeLang &&
typeof changeLang === 'function'
) {
changeLang(e.target.value);
changeLang(e.target.value)
}
};
}
return (
<Select
@ -135,33 +135,33 @@ const SelectTranslate = () => {
</option>
))}
</Select>
);
};
)
}
const Translate = ({ word = '', values }) => {
const valuesTr = !!values && !Array.isArray(values) ? [values] : values;
return translate(word, valuesTr);
};
const valuesTr = !!values && !Array.isArray(values) ? [values] : values
return translate(word, valuesTr)
}
TranslateProvider.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
])
};
}
TranslateProvider.defaultProps = {
children: []
};
}
Translate.propTypes = {
word: PropTypes.string,
values: PropTypes.oneOfType([PropTypes.string, PropTypes.array])
};
}
Translate.defaultProps = {
word: '',
values: ''
};
}
export { TranslateContext, TranslateProvider, SelectTranslate, Translate, Tr };
export { TranslateContext, TranslateProvider, SelectTranslate, Translate, Tr }

View File

@ -13,15 +13,15 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import InternalLayout from 'client/components/HOC/InternalLayout';
import MainLayout from 'client/components/HOC/MainLayout';
import InternalLayout from 'client/components/HOC/InternalLayout'
import MainLayout from 'client/components/HOC/MainLayout'
import {
TranslateContext,
TranslateProvider,
Translate,
Tr,
SelectTranslate
} from 'client/components/HOC/Translate';
} from 'client/components/HOC/Translate'
export {
InternalLayout,
@ -31,4 +31,4 @@ export {
Translate,
Tr,
SelectTranslate
};
}

View File

@ -1,32 +1,32 @@
import React from 'react';
import React from 'react'
import { Button } from '@material-ui/core';
import FilterIcon from '@material-ui/icons/FilterDrama';
import SelectedIcon from '@material-ui/icons/FilterVintage';
import { Button } from '@material-ui/core'
import FilterIcon from '@material-ui/icons/FilterDrama'
import SelectedIcon from '@material-ui/icons/FilterVintage'
import useAuth from 'client/hooks/useAuth';
import useOpennebula from 'client/hooks/useOpennebula';
import Search from 'client/components/Search';
import useAuth from 'client/hooks/useAuth'
import useOpennebula from 'client/hooks/useOpennebula'
import Search from 'client/components/Search'
import { FILTER_POOL } from 'client/constants';
import HeaderPopover from 'client/components/Header/Popover';
import headerStyles from 'client/components/Header/styles';
import { FILTER_POOL } from 'client/constants'
import HeaderPopover from 'client/components/Header/Popover'
import headerStyles from 'client/components/Header/styles'
const { ALL_RESOURCES, PRIMARY_GROUP_RESOURCES } = FILTER_POOL;
const { ALL_RESOURCES, PRIMARY_GROUP_RESOURCES } = FILTER_POOL
const Group = () => {
const classes = headerStyles();
const { authUser, filterPool, setPrimaryGroup } = useAuth();
const { groups } = useOpennebula();
const classes = headerStyles()
const { authUser, filterPool, setPrimaryGroup } = useAuth()
const { groups } = useOpennebula()
const handleChangeGroup = group => {
group && setPrimaryGroup({ group });
};
group && setPrimaryGroup({ group })
}
const renderResult = ({ ID, NAME }, handleClose) => {
const isSelected =
(filterPool === ALL_RESOURCES && ALL_RESOURCES === ID) ||
(filterPool === PRIMARY_GROUP_RESOURCES && authUser?.GID === ID);
(filterPool === PRIMARY_GROUP_RESOURCES && authUser?.GID === ID)
return (
<Button
@ -34,28 +34,28 @@ const Group = () => {
fullWidth
className={classes.groupButton}
onClick={() => {
handleChangeGroup(ID);
handleClose();
handleChangeGroup(ID)
handleClose()
}}
>
{NAME}
{isSelected && <SelectedIcon className={classes.groupSelectedIcon} />}
</Button>
);
};
)
}
const sortGroupAsMainFirst = (a, b) => {
if (a.ID === authUser?.GUID) {
return -1;
return -1
} else if (b.ID === authUser?.GUID) {
return 1;
return 1
}
return 0;
};
return 0
}
const sortMainGroupFirst = groups
?.concat({ ID: ALL_RESOURCES, NAME: 'Show All' })
?.sort(sortGroupAsMainFirst);
?.sort(sortGroupAsMainFirst)
return (
<HeaderPopover
@ -77,7 +77,7 @@ const Group = () => {
/>
)}
</HeaderPopover>
);
};
)
}
export default Group;
export default Group

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import {
Box,
@ -8,18 +8,18 @@ import {
Popover,
Typography,
Button
} from '@material-ui/core';
import CloseIcon from '@material-ui/icons/Close';
} from '@material-ui/core'
import CloseIcon from '@material-ui/icons/Close'
import { Tr } from 'client/components/HOC';
import { Tr } from 'client/components/HOC'
import headerStyles from 'client/components/Header/styles';
import clsx from 'clsx';
import headerStyles from 'client/components/Header/styles'
import clsx from 'clsx'
const typeButton = {
button: Button,
iconButton: IconButton
};
}
const HeaderPopover = ({
id,
@ -30,21 +30,21 @@ const HeaderPopover = ({
disablePadding,
children
}) => {
const classes = headerStyles();
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'));
const classes = headerStyles()
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'))
const [anchorEl, setAnchorEl] = useState(null);
const [anchorEl, setAnchorEl] = useState(null)
const handleOpen = event => setAnchorEl(event.currentTarget);
const handleClose = () => setAnchorEl(null);
const handleOpen = event => setAnchorEl(event.currentTarget)
const handleClose = () => setAnchorEl(null)
const open = Boolean(anchorEl);
const anchorId = open ? id : undefined;
const open = Boolean(anchorEl)
const anchorId = open ? id : undefined
const ButtonComponent = React.useMemo(
() => (buttonLabel ? typeButton.button : typeButton.iconButton),
[buttonLabel]
);
)
return (
<>
@ -98,8 +98,8 @@ const HeaderPopover = ({
{children({ handleClose })}
</Popover>
</>
);
};
)
}
HeaderPopover.propTypes = {
id: PropTypes.string,
@ -109,7 +109,7 @@ HeaderPopover.propTypes = {
headerTitle: PropTypes.string,
disablePadding: PropTypes.bool,
children: PropTypes.func
};
}
HeaderPopover.defaultProps = {
id: 'id-popover',
@ -119,6 +119,6 @@ HeaderPopover.defaultProps = {
headerTitle: null,
disablePadding: false,
children: () => undefined
};
}
export default HeaderPopover;
export default HeaderPopover

View File

@ -1,21 +1,22 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import { MenuItem, MenuList, Divider } from '@material-ui/core';
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
import React from 'react'
import useAuth from 'client/hooks/useAuth';
import { Tr, SelectTranslate } from 'client/components/HOC';
import { useHistory } from 'react-router-dom'
import { MenuItem, MenuList, Divider } from '@material-ui/core'
import AccountCircleIcon from '@material-ui/icons/AccountCircle'
import { SignOut } from 'client/constants/translates';
import { PATH } from 'client/router/endpoints';
import HeaderPopover from 'client/components/Header/Popover';
import useAuth from 'client/hooks/useAuth'
import { Tr, SelectTranslate } from 'client/components/HOC'
import { SignOut } from 'client/constants/translates'
import { PATH } from 'client/router/endpoints'
import HeaderPopover from 'client/components/Header/Popover'
const User = React.memo(() => {
const history = useHistory();
const { logout, authUser } = useAuth();
const history = useHistory()
const { logout, authUser } = useAuth()
const handleLogout = () => logout();
const handleGoToSettings = () => history.push(PATH.SETTINGS);
const handleLogout = () => logout()
const handleGoToSettings = () => history.push(PATH.SETTINGS)
return (
<HeaderPopover
@ -38,7 +39,9 @@ const User = React.memo(() => {
</MenuList>
)}
</HeaderPopover>
);
});
)
})
export default User;
User.displayName = 'UserHeaderComponent'
export default User

View File

@ -1,25 +1,10 @@
/* 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. */
/* -------------------------------------------------------------------------- */
import React from 'react'
import React from 'react';
import { MenuItem, MenuList } from '@material-ui/core'
import LanguageIcon from '@material-ui/icons/Language'
import { MenuItem, MenuList } from '@material-ui/core';
import LanguageIcon from '@material-ui/icons/Language';
import { Tr } from 'client/components/HOC';
import HeaderPopover from 'client/components/Header/Popover';
import { Tr } from 'client/components/HOC'
import HeaderPopover from 'client/components/Header/Popover'
const Zone = React.memo(() => (
<HeaderPopover
@ -34,6 +19,8 @@ const Zone = React.memo(() => (
</MenuList>
)}
</HeaderPopover>
));
))
export default Zone;
Zone.displayName = 'ZoneHeaderComponent'
export default Zone

View File

@ -13,8 +13,8 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import PropTypes from 'prop-types';
import React from 'react'
import PropTypes from 'prop-types'
import {
AppBar,
@ -22,23 +22,23 @@ import {
Typography,
IconButton,
useMediaQuery
} from '@material-ui/core';
import MenuIcon from '@material-ui/icons/Menu';
} from '@material-ui/core'
import MenuIcon from '@material-ui/icons/Menu'
import useAuth from 'client/hooks/useAuth';
import useGeneral from 'client/hooks/useGeneral';
import User from 'client/components/Header/User';
import Group from 'client/components/Header/Group';
import Zone from 'client/components/Header/Zone';
import headerStyles from 'client/components/Header/styles';
import useAuth from 'client/hooks/useAuth'
import useGeneral from 'client/hooks/useGeneral'
import User from 'client/components/Header/User'
import Group from 'client/components/Header/Group'
import Zone from 'client/components/Header/Zone'
import headerStyles from 'client/components/Header/styles'
const Header = ({ title }) => {
const { isOneAdmin } = useAuth();
const { isFixMenu, fixMenu } = useGeneral();
const classes = headerStyles();
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'));
const { isOneAdmin } = useAuth()
const { isFixMenu, fixMenu } = useGeneral()
const classes = headerStyles()
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'))
const handleFixMenu = () => fixMenu(true);
const handleFixMenu = () => fixMenu(true)
return React.useMemo(
() => (
@ -63,15 +63,15 @@ const Header = ({ title }) => {
</AppBar>
),
[isFixMenu, fixMenu, isUpLg, isOneAdmin]
);
};
)
}
Header.propTypes = {
title: PropTypes.string
};
}
Header.defaultProps = {
title: ''
};
}
export default Header;
export default Header

View File

@ -1,4 +1,4 @@
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core'
export default makeStyles(theme => ({
title: {
@ -40,4 +40,4 @@ export default makeStyles(theme => ({
fontSize: '1rem',
margin: theme.spacing(0, 2)
}
}));
}))

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import React, { useMemo } from 'react'
import PropTypes from 'prop-types'
import {
makeStyles,
@ -7,8 +7,8 @@ import {
CardContent,
Card,
Grid
} from '@material-ui/core';
import AddIcon from '@material-ui/icons/Add';
} from '@material-ui/core'
import AddIcon from '@material-ui/icons/Add'
const useStyles = makeStyles(() => ({
cardPlus: {
@ -17,10 +17,10 @@ const useStyles = makeStyles(() => ({
display: 'flex',
textAlign: 'center'
}
}));
}))
function ListCards({ handleCreate, list, CardComponent, cardsProps }) {
const classes = useStyles();
function ListCards ({ handleCreate, list, CardComponent, cardsProps }) {
const classes = useStyles()
return (
<Grid container spacing={3}>
@ -46,7 +46,7 @@ function ListCards({ handleCreate, list, CardComponent, cardsProps }) {
</Grid>
))}
</Grid>
);
)
}
ListCards.propTypes = {
@ -58,13 +58,13 @@ ListCards.propTypes = {
PropTypes.element
]),
cardsProps: PropTypes.func
};
}
ListCards.defaultProps = {
list: [],
handleCreate: undefined,
CardComponent: null,
cardsProps: () => undefined
};
}
export default ListCards;
export default ListCards

View File

@ -1,40 +1,40 @@
import React, { useRef, useEffect, useCallback, createRef } from 'react';
import PropTypes from 'prop-types';
import React, { useRef, useEffect, useCallback, createRef } from 'react'
import PropTypes from 'prop-types'
import { debounce, LinearProgress } from '@material-ui/core';
import { debounce, LinearProgress } from '@material-ui/core'
import useNearScreen from 'client/hooks/useNearScreen';
import useList from 'client/hooks/useList';
import useNearScreen from 'client/hooks/useNearScreen'
import useList from 'client/hooks/useList'
const ListInfiniteScroll = ({ list, renderResult }) => {
const gridRef = createRef();
const gridRef = createRef()
const { loading, shortList, finish, reset, setLength } = useList({
list,
initLength: 50
});
})
const loaderRef = useRef();
const loaderRef = useRef()
const { isNearScreen } = useNearScreen({
distance: '100px',
externalRef: loading ? null : loaderRef,
once: false
});
})
useEffect(() => {
reset(list);
gridRef.current.scrollIntoView({ block: 'start' });
}, [list]);
reset(list)
gridRef.current.scrollIntoView({ block: 'start' })
}, [list])
const debounceHandleNextPage = useCallback(
debounce(() => {
setLength(prevLength => prevLength + 20);
setLength(prevLength => prevLength + 20)
}, 200),
[setLength]
);
)
useEffect(() => {
if (isNearScreen && !finish) debounceHandleNextPage();
}, [isNearScreen, finish, debounceHandleNextPage]);
if (isNearScreen && !finish) debounceHandleNextPage()
}, [isNearScreen, finish, debounceHandleNextPage])
return (
<div style={{ overflowY: 'auto', padding: 10 }}>
@ -55,17 +55,17 @@ const ListInfiniteScroll = ({ list, renderResult }) => {
/>
)}
</div>
);
};
)
}
ListInfiniteScroll.propTypes = {
list: PropTypes.arrayOf(PropTypes.any),
renderResult: PropTypes.func
};
}
ListInfiniteScroll.defaultProps = {
list: [],
renderResult: () => null
};
}
export default ListInfiniteScroll;
export default ListInfiniteScroll

View File

@ -1,7 +1,7 @@
import React from 'react';
import React from 'react'
import { Box } from '@material-ui/core';
import Logo from 'client/icons/logo';
import { Box } from '@material-ui/core'
import Logo from 'client/icons/logo'
const LoadingScreen = () => (
<Box
@ -18,6 +18,6 @@ const LoadingScreen = () => (
>
<Logo width={360} height={360} spinner withText />
</Box>
);
)
export default LoadingScreen;
export default LoadingScreen

View File

@ -1,61 +1,74 @@
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useSnackbar } from 'notistack';
import { IconButton } from '@material-ui/core';
import CloseIcon from '@material-ui/icons/Close';
import { removeSnackbar } from 'client/actions/general';
import React, { useEffect } from 'react'
import PropTypes from 'prop-types'
let displayed = [];
import { useDispatch, useSelector } from 'react-redux'
import { useSnackbar } from 'notistack'
import { IconButton } from '@material-ui/core'
import CloseIcon from '@material-ui/icons/Close'
import { removeSnackbar } from 'client/actions/general'
const CloseButton = ({ handleClick }) => (
<IconButton onClick={handleClick} component="span">
<CloseIcon fontSize="small" />
</IconButton>
)
let displayed = []
const Notifier = () => {
const dispatch = useDispatch();
const notifications = useSelector(store => store.General.notifications || []);
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
const dispatch = useDispatch()
const notifications = useSelector(store => store.General.notifications || [])
const { enqueueSnackbar, closeSnackbar } = useSnackbar()
const storeDisplayed = id => {
displayed = [...displayed, id];
};
displayed = [...displayed, id]
}
const removeDisplayed = id => {
displayed = [...displayed.filter(key => id !== key)];
};
displayed = [...displayed.filter(key => id !== key)]
}
useEffect(() => {
notifications.forEach(
({ key, message, options = {}, dismissed = false }) => {
if (dismissed) {
closeSnackbar(key);
return;
closeSnackbar(key)
return
}
if (displayed.includes(key)) return;
if (displayed.includes(key)) return
enqueueSnackbar(message, {
key,
...options,
action: () => (
<IconButton onClick={() => closeSnackbar(key)} component="span">
<CloseIcon fontSize="small" />
</IconButton>
),
action: CloseButton({ handleClick: () => closeSnackbar(key) }),
onClose: (event, reason, myKey) => {
if (options.onClose) {
options.onClose(event, reason, myKey);
options.onClose(event, reason, myKey)
}
},
onExited: (_, myKey) => {
dispatch(removeSnackbar(myKey));
removeDisplayed(myKey);
dispatch(removeSnackbar(myKey))
removeDisplayed(myKey)
}
});
})
// keep track of snackbars that we've displayed
storeDisplayed(key);
storeDisplayed(key)
}
);
}, [notifications, closeSnackbar, enqueueSnackbar, dispatch]);
)
}, [notifications, closeSnackbar, enqueueSnackbar, dispatch])
return null;
};
return null
}
export default Notifier;
CloseButton.propTypes = {
handleClick: PropTypes.func
}
CloseButton.defaultProps = {
handleClick: undefined
}
export default Notifier

View File

@ -1,10 +1,10 @@
import React, { useState, useMemo } from 'react';
import PropTypes from 'prop-types';
import React, { useState, useMemo } from 'react'
import PropTypes from 'prop-types'
import Fuse from 'fuse.js';
import { TextField, Box, debounce } from '@material-ui/core';
import Fuse from 'fuse.js'
import { TextField, Box, debounce } from '@material-ui/core'
import ListInfiniteScroll from 'client/components/List/ListInfiniteScroll';
import ListInfiniteScroll from 'client/components/List/ListInfiniteScroll'
const Search = ({
list,
@ -13,28 +13,28 @@ const Search = ({
startAdornment,
searchBoxProps
}) => {
const [query, setQuery] = useState('');
const [result, setResult] = useState(undefined);
const [query, setQuery] = useState('')
const [result, setResult] = useState(undefined)
const listFuse = useMemo(
() => new Fuse(list, listOptions, Fuse.createIndex(listOptions.keys, list)),
[list, listOptions]
);
)
const debounceResult = React.useCallback(
debounce(value => {
const search = listFuse.search(value)?.map(({ item }) => item);
const search = listFuse.search(value)?.map(({ item }) => item)
setResult(value ? search : undefined);
setResult(value ? search : undefined)
}, 1000),
[list]
);
)
const handleChange = event => {
const { value: nextValue } = event?.target;
const { value: nextValue } = event?.target
setQuery(nextValue);
debounceResult(nextValue);
};
setQuery(nextValue)
debounceResult(nextValue)
}
return (
<>
@ -49,13 +49,13 @@ const Search = ({
/>
</Box>
{result?.length === 0 ? (
<h4>{`Your search did not match`}</h4>
<h4>{'Your search did not match'}</h4>
) : (
<ListInfiniteScroll list={result ?? list} renderResult={renderResult} />
)}
</>
);
};
)
}
Search.propTypes = {
list: PropTypes.arrayOf(PropTypes.object).isRequired,
@ -68,7 +68,7 @@ Search.propTypes = {
renderResult: PropTypes.func,
startAdornment: PropTypes.objectOf(PropTypes.any),
searchBoxProps: PropTypes.objectOf(PropTypes.any)
};
}
Search.defaultProps = {
list: [],
@ -76,6 +76,6 @@ Search.defaultProps = {
renderResult: item => item,
startAdornment: undefined,
searchBoxProps: undefined
};
}
export default Search;
export default Search

View File

@ -1,4 +1,4 @@
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core'
export default makeStyles(theme => ({
backdrop: {
@ -16,4 +16,4 @@ export default makeStyles(theme => ({
header: { display: 'flex', alignItems: 'center' },
title: { flexGrow: 1 },
button: { justifyContent: 'start' }
}));
}))

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import clsx from 'clsx'
import {
List,
@ -9,21 +9,21 @@ import {
ListItemText,
ListItemIcon,
useMediaQuery
} from '@material-ui/core';
import ExpandLessIcon from '@material-ui/icons/ExpandLess';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
} from '@material-ui/core'
import ExpandLessIcon from '@material-ui/icons/ExpandLess'
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
import useGeneral from 'client/hooks/useGeneral';
import SidebarLink from 'client/components/Sidebar/SidebarLink';
import sidebarStyles from 'client/components/Sidebar/styles';
import useGeneral from 'client/hooks/useGeneral'
import SidebarLink from 'client/components/Sidebar/SidebarLink'
import sidebarStyles from 'client/components/Sidebar/styles'
const SidebarCollapseItem = ({ label, routes, icon: Icon }) => {
const classes = sidebarStyles();
const { isFixMenu } = useGeneral();
const [expanded, setExpanded] = useState(false);
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'));
const classes = sidebarStyles()
const { isFixMenu } = useGeneral()
const [expanded, setExpanded] = useState(false)
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'))
const handleExpand = () => setExpanded(!expanded);
const handleExpand = () => setExpanded(!expanded)
return (
<>
@ -58,8 +58,8 @@ const SidebarCollapseItem = ({ label, routes, icon: Icon }) => {
</Collapse>
))}
</>
);
};
)
}
SidebarCollapseItem.propTypes = {
label: PropTypes.string.isRequired,
@ -70,12 +70,12 @@ SidebarCollapseItem.propTypes = {
path: PropTypes.string
})
)
};
}
SidebarCollapseItem.defaultProps = {
label: '',
icon: null,
routes: []
};
}
export default SidebarCollapseItem;
export default SidebarCollapseItem

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useHistory, useLocation } from 'react-router-dom';
import clsx from 'clsx';
import React from 'react'
import PropTypes from 'prop-types'
import { useHistory, useLocation } from 'react-router-dom'
import clsx from 'clsx'
import {
withStyles,
@ -11,10 +11,10 @@ import {
ListItemIcon,
ListItemText,
useMediaQuery
} from '@material-ui/core';
} from '@material-ui/core'
import useGeneral from 'client/hooks/useGeneral';
import sidebarStyles from 'client/components/Sidebar/styles';
import useGeneral from 'client/hooks/useGeneral'
import sidebarStyles from 'client/components/Sidebar/styles'
const StyledBadge = withStyles(() => ({
badge: {
@ -22,21 +22,21 @@ const StyledBadge = withStyles(() => ({
top: 13,
fontSize: '0.7rem'
}
}))(Badge);
}))(Badge)
const SidebarLink = ({ label, path, icon: Icon, devMode, isSubItem }) => {
const classes = sidebarStyles();
const history = useHistory();
const { pathname } = useLocation();
const { fixMenu } = useGeneral();
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'));
const classes = sidebarStyles()
const history = useHistory()
const { pathname } = useLocation()
const { fixMenu } = useGeneral()
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'))
const handleClick = () => {
history.push(path);
!isUpLg && fixMenu(false);
};
history.push(path)
!isUpLg && fixMenu(false)
}
const isCurrentPathname = pathname === path;
const isCurrentPathname = pathname === path
return (
<ListItem
@ -63,8 +63,8 @@ const SidebarLink = ({ label, path, icon: Icon, devMode, isSubItem }) => {
}
/>
</ListItem>
);
};
)
}
SidebarLink.propTypes = {
label: PropTypes.string.isRequired,
@ -79,7 +79,7 @@ SidebarLink.propTypes = {
]),
devMode: PropTypes.bool,
isSubItem: PropTypes.bool
};
}
SidebarLink.defaultProps = {
label: '',
@ -87,6 +87,6 @@ SidebarLink.defaultProps = {
icon: undefined,
devMode: false,
isSubItem: false
};
}
export default SidebarLink;
export default SidebarLink

View File

@ -13,8 +13,8 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React, { useMemo } from 'react';
import clsx from 'clsx';
import React, { useMemo } from 'react'
import clsx from 'clsx'
import {
List,
Drawer,
@ -22,23 +22,23 @@ import {
Box,
IconButton,
useMediaQuery
} from '@material-ui/core';
import { Menu as MenuIcon, Close as CloseIcon } from '@material-ui/icons';
} from '@material-ui/core'
import { Menu as MenuIcon, Close as CloseIcon } from '@material-ui/icons'
import useGeneral from 'client/hooks/useGeneral';
import endpoints from 'client/router/endpoints';
import useGeneral from 'client/hooks/useGeneral'
import endpoints from 'client/router/endpoints'
import sidebarStyles from 'client/components/Sidebar/styles';
import SidebarLink from 'client/components/Sidebar/SidebarLink';
import SidebarCollapseItem from 'client/components/Sidebar/SidebarCollapseItem';
import Logo from 'client/icons/logo';
import sidebarStyles from 'client/components/Sidebar/styles'
import SidebarLink from 'client/components/Sidebar/SidebarLink'
import SidebarCollapseItem from 'client/components/Sidebar/SidebarCollapseItem'
import Logo from 'client/icons/logo'
const Sidebar = () => {
const classes = sidebarStyles();
const { isFixMenu, fixMenu } = useGeneral();
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'));
const classes = sidebarStyles()
const { isFixMenu, fixMenu } = useGeneral()
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'))
const handleSwapMenu = () => fixMenu(!isFixMenu);
const handleSwapMenu = () => fixMenu(!isFixMenu)
const SidebarEndpoints = useMemo(
() =>
@ -54,7 +54,7 @@ const Sidebar = () => {
)
),
[endpoints]
);
)
return useMemo(
() => (
@ -93,7 +93,7 @@ const Sidebar = () => {
</Drawer>
),
[isFixMenu, fixMenu, isUpLg]
);
};
)
}
export default Sidebar;
export default Sidebar

View File

@ -1,5 +1,5 @@
import { makeStyles } from '@material-ui/core';
import { sidebar, toolbar } from 'client/assets/theme/defaults';
import { makeStyles } from '@material-ui/core'
import { sidebar, toolbar } from 'client/assets/theme/defaults'
export default makeStyles(theme => ({
// -------------------------------
@ -127,4 +127,4 @@ export default makeStyles(theme => ({
backgroundColor: theme.palette.primary.light
}
}
}));
}))

View File

@ -1,8 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import React from 'react'
import PropTypes from 'prop-types'
import { SpeedDial, SpeedDialIcon, SpeedDialAction } from '@material-ui/lab';
import { makeStyles } from '@material-ui/core/styles';
import { SpeedDial, SpeedDialIcon, SpeedDialAction } from '@material-ui/lab'
import { makeStyles } from '@material-ui/core/styles'
const useStyles = makeStyles(theme => ({
root: {
@ -16,19 +16,19 @@ const useStyles = makeStyles(theme => ({
left: theme.spacing(2)
}
}
}));
}))
const SpeedDials = ({ hidden = false, actions = [] }) => {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const classes = useStyles()
const [open, setOpen] = React.useState(false)
const handleClose = () => {
setOpen(false);
};
setOpen(false)
}
const handleOpen = () => {
setOpen(true);
};
setOpen(true)
}
return (
<SpeedDial
@ -50,8 +50,8 @@ const SpeedDials = ({ hidden = false, actions = [] }) => {
/>
))}
</SpeedDial>
);
};
)
}
SpeedDials.propTypes = {
hidden: PropTypes.bool,
@ -62,11 +62,11 @@ SpeedDials.propTypes = {
handleClick: PropTypes.func
})
)
};
}
SpeedDials.defaultProps = {
hidden: false,
actions: []
};
}
export default SpeedDials;
export default SpeedDials

View File

@ -36,4 +36,4 @@ module.exports = {
CHECKBOX: 'checkbox',
AUTOCOMPLETE: 'autocomplete'
}
};
}

View File

@ -10,4 +10,4 @@ module.exports = {
SignOut: 'Sign Out',
Submit: 'Submit',
Response: 'Response'
};
}

View File

@ -1,27 +1,26 @@
import React, { useEffect } from 'react';
import React, { useEffect } from 'react'
import useGeneral from 'client/hooks/useGeneral';
import useApplication from 'client/hooks/useApplication';
import useApplication from 'client/hooks/useApplication'
import ListCards from 'client/components/List/ListCards';
import { ClusterCard } from 'client/components/Cards';
import ListCards from 'client/components/List/ListCards'
import { ClusterCard } from 'client/components/Cards'
const ApplicationsDeployed = () => {
const { applications, getApplications } = useApplication();
const { applications, getApplications } = useApplication()
useEffect(() => {
getApplications();
}, []);
getApplications()
}, [])
return (
<ListCards
list={applications}
CardComponent={ClusterCard}
cardsProps={({ value }) => {
console.log(value);
console.log(value)
}}
/>
);
};
)
}
export default ApplicationsDeployed;
export default ApplicationsDeployed

View File

@ -1,26 +1,26 @@
import React, { useEffect } from 'react';
import React, { useEffect } from 'react'
import { useHistory } from 'react-router-dom';
import { Box, LinearProgress } from '@material-ui/core';
import { Alert } from '@material-ui/lab';
import { useHistory } from 'react-router-dom'
import { Box, LinearProgress } from '@material-ui/core'
import { Alert } from '@material-ui/lab'
import useApplication from 'client/hooks/useApplication';
import useFetch from 'client/hooks/useFetch';
import useApplication from 'client/hooks/useApplication'
import useFetch from 'client/hooks/useFetch'
import ListCards from 'client/components/List/ListCards';
import { ApplicationTemplateCard } from 'client/components/Cards';
import { PATH } from 'client/router/endpoints';
import ListCards from 'client/components/List/ListCards'
import { ApplicationTemplateCard } from 'client/components/Cards'
import { PATH } from 'client/router/endpoints'
import { Tr } from 'client/components/HOC';
import { Tr } from 'client/components/HOC'
const ApplicationsTemplatesList = () => {
const history = useHistory();
const { applicationsTemplates, getApplicationsTemplates } = useApplication();
const { fetchRequest, loading, error } = useFetch(getApplicationsTemplates);
const history = useHistory()
const { applicationsTemplates, getApplicationsTemplates } = useApplication()
const { fetchRequest, loading, error } = useFetch(getApplicationsTemplates)
useEffect(() => {
fetchRequest();
}, []);
fetchRequest()
}, [])
if (error) {
return (
@ -29,28 +29,28 @@ const ApplicationsTemplatesList = () => {
{Tr('Cannot connect to OneFlow server')}
</Alert>
</Box>
);
)
}
if (loading) {
return <LinearProgress />;
return <LinearProgress />
}
return (
<Box p={3}>
<ListCards
list={applicationsTemplates}
handleCreate={() => history.push(PATH.APPLICATION_TEMPLATE.CREATE)}
handleCreate={() => history.push(PATH.APPLICATIONS_TEMPLATES.CREATE)}
CardComponent={ApplicationTemplateCard}
cardsProps={({ value: { ID } }) => ({
handleEdit: () =>
history.push(PATH.APPLICATION_TEMPLATE.EDIT.replace(':id', ID)),
history.push(PATH.APPLICATIONS_TEMPLATES.EDIT.replace(':id', ID)),
handleDeploy: undefined,
handleRemove: undefined
})}
/>
</Box>
);
};
)
}
export default ApplicationsTemplatesList;
export default ApplicationsTemplatesList

View File

@ -1,73 +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. */
/* -------------------------------------------------------------------------- */
import React, { useState } from 'react';
import { Tab, Tabs, Paper, Container } from '@material-ui/core';
import ApplicationsTemplatesList from './Templates';
import ApplicationsDeployed from './Deployed';
const TABS = {
TEMPLATES: 'templates',
APPLICATIONS: 'applications'
};
function Applications() {
const [value, setValue] = useState(TABS.TEMPLATES);
const handleChange = (_, newValue) => {
setValue(newValue);
};
return (
<Container
disableGutters
style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
>
<Paper>
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
>
<Tab
value={TABS.TEMPLATES}
label="Applications templates"
id={`tab-${TABS.TEMPLATES}`}
/>
<Tab
value={TABS.APPLICATIONS}
label="Applications deployed"
id={`tab-${TABS.APPLICATIONS}`}
/>
</Tabs>
</Paper>
<div hidden={value !== TABS.TEMPLATES}>
{value === TABS.TEMPLATES && <ApplicationsTemplatesList />}
</div>
<div hidden={value !== TABS.APPLICATIONS}>
{value === TABS.APPLICATIONS && <ApplicationsDeployed />}
</div>
</Container>
);
}
Applications.propTypes = {};
Applications.defaultProps = {};
export default Applications;

View File

@ -1,27 +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. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import PropTypes from 'prop-types';
function ApplicationManage() {
return <div>Manage</div>;
}
ApplicationManage.propTypes = {};
ApplicationManage.defaultProps = {};
export default ApplicationManage;

View File

@ -1,4 +1,73 @@
import ApplicationsList from 'client/containers/Applications/List';
import ApplicationsManage from 'client/containers/Applications/Manage';
/* 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. */
/* -------------------------------------------------------------------------- */
export { ApplicationsList, ApplicationsManage };
import React, { useState } from 'react'
import { Tab, Tabs, Paper, Container } from '@material-ui/core'
import ApplicationsTemplatesList from 'client/containers/Applications/List/Templates'
import ApplicationsDeployed from 'client/containers/Applications/List/Deployed'
const TABS = {
TEMPLATES: 'templates',
APPLICATIONS: 'applications'
}
function Applications () {
const [value, setValue] = useState(TABS.TEMPLATES)
const handleChange = (_, newValue) => {
setValue(newValue)
}
return (
<Container
disableGutters
style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
>
<Paper>
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
>
<Tab
value={TABS.TEMPLATES}
label="Applications templates"
id={`tab-${TABS.TEMPLATES}`}
/>
<Tab
value={TABS.APPLICATIONS}
label="Applications deployed"
id={`tab-${TABS.APPLICATIONS}`}
/>
</Tabs>
</Paper>
<div hidden={value !== TABS.TEMPLATES}>
{value === TABS.TEMPLATES && <ApplicationsTemplatesList />}
</div>
<div hidden={value !== TABS.APPLICATIONS}>
{value === TABS.APPLICATIONS && <ApplicationsDeployed />}
</div>
</Container>
)
}
Applications.propTypes = {}
Applications.defaultProps = {}
export default Applications

View File

@ -1,10 +1,10 @@
import React, { useCallback } from 'react';
import React, { useCallback } from 'react'
import FormWithSchema from 'client/components/Forms/FormWithSchema';
import FormWithSchema from 'client/components/Forms/FormWithSchema'
import { FORM_FIELDS, STEP_FORM_SCHEMA } from './schema';
import { FORM_FIELDS, STEP_FORM_SCHEMA } from './schema'
export const STEP_ID = 'application';
export const STEP_ID = 'application'
const BasicConfiguration = () => ({
id: STEP_ID,
@ -14,6 +14,6 @@ const BasicConfiguration = () => ({
() => <FormWithSchema cy="form-flow" fields={FORM_FIELDS} id={STEP_ID} />,
[]
)
});
})
export default BasicConfiguration;
export default BasicConfiguration

View File

@ -1,17 +1,17 @@
import * as yup from 'yup';
import { TYPE_INPUT } from 'client/constants';
import { getValidationFromFields } from 'client/utils/helpers';
import * as yup from 'yup'
import { TYPE_INPUT } from 'client/constants'
import { getValidationFromFields } from 'client/utils/helpers'
const STRATEGIES_DEPLOY = [
{ text: 'None', value: 'none' },
{ text: 'Straight', value: 'straight' }
];
]
const SHUTDOWN_ACTIONS = [
{ text: 'None', value: 'none' },
{ text: 'Terminate', value: 'terminate' },
{ text: 'Terminate hard', value: 'terminate-hard' }
];
]
export const FORM_FIELDS = [
{
@ -66,8 +66,8 @@ export const FORM_FIELDS = [
type: TYPE_INPUT.CHECKBOX,
validation: yup.boolean().default(false)
}
];
]
export const STEP_FORM_SCHEMA = yup.object(
getValidationFromFields(FORM_FIELDS)
);
)

View File

@ -1,46 +1,46 @@
import React, { useEffect, useCallback } from 'react';
import React, { useEffect, useCallback } from 'react'
import useOpennebula from 'client/hooks/useOpennebula';
import useOpennebula from 'client/hooks/useOpennebula'
import useListForm from 'client/hooks/useListForm';
import ListCards from 'client/components/List/ListCards';
import { ClusterCard } from 'client/components/Cards';
import useListForm from 'client/hooks/useListForm'
import ListCards from 'client/components/List/ListCards'
import { ClusterCard } from 'client/components/Cards'
import { STEP_FORM_SCHEMA } from './schema';
import { STEP_FORM_SCHEMA } from './schema'
export const STEP_ID = 'clusters';
export const STEP_ID = 'clusters'
const Clusters = () => ({
id: STEP_ID,
label: 'Where will it run?',
resolver: STEP_FORM_SCHEMA,
content: useCallback(({ data, setFormData }) => {
const { clusters, getClusters } = useOpennebula();
const { clusters, getClusters } = useOpennebula()
const { handleSelect, handleUnselect } = useListForm({
key: STEP_ID,
setList: setFormData
});
})
useEffect(() => {
getClusters();
}, []);
getClusters()
}, [])
return (
<ListCards
list={clusters}
CardComponent={ClusterCard}
cardsProps={({ value }) => {
const { ID } = value;
const { ID } = value
return {
isSelected: data?.some(selected => selected === ID),
handleSelect: () => handleSelect(ID),
handleUnselect: () => handleUnselect(ID)
};
}
}}
/>
);
)
}, [])
});
})
export default Clusters;
export default Clusters

View File

@ -1,8 +1,8 @@
import * as yup from 'yup';
import * as yup from 'yup'
export const STEP_FORM_SCHEMA = yup
.array(yup.string().trim())
.min(1, 'Select cluster')
.max(1, 'Max. one cluster selected')
.required('Cluster field is required')
.default([]);
.default([])

View File

@ -1,27 +1,27 @@
import React, { useState, useEffect, useCallback } from 'react';
import React, { useState, useEffect, useCallback } from 'react'
import { useWatch } from 'react-hook-form';
import { useWatch } from 'react-hook-form'
import useOpennebula from 'client/hooks/useOpennebula';
import useListForm from 'client/hooks/useListForm';
import FormWithSchema from 'client/components/Forms/FormWithSchema';
import ListCards from 'client/components/List/ListCards';
import { DialogForm } from 'client/components/Dialogs';
import { NetworkCard } from 'client/components/Cards';
import useOpennebula from 'client/hooks/useOpennebula'
import useListForm from 'client/hooks/useListForm'
import FormWithSchema from 'client/components/Forms/FormWithSchema'
import ListCards from 'client/components/List/ListCards'
import { DialogForm } from 'client/components/Dialogs'
import { NetworkCard } from 'client/components/Cards'
import { STEP_ID as TIERS_ID } from 'client/containers/ApplicationsTemplates/Create/Steps/Tiers';
import { FORM_FIELDS, NETWORK_FORM_SCHEMA, STEP_FORM_SCHEMA } from './schema';
import { STEP_ID as TIERS_ID } from 'client/containers/ApplicationsTemplates/Create/Steps/Tiers'
import { FORM_FIELDS, NETWORK_FORM_SCHEMA, STEP_FORM_SCHEMA } from './schema'
export const STEP_ID = 'networking';
export const STEP_ID = 'networking'
const Networks = () => ({
id: STEP_ID,
label: 'Configure Networking',
resolver: STEP_FORM_SCHEMA,
content: useCallback(({ data, setFormData }) => {
const form = useWatch({});
const [showDialog, setShowDialog] = useState(false);
const { getVNetworks, getVNetworksTemplates } = useOpennebula();
const form = useWatch({})
const [showDialog, setShowDialog] = useState(false)
const { getVNetworks, getVNetworksTemplates } = useOpennebula()
const {
editingData,
handleSave,
@ -33,12 +33,12 @@ const Networks = () => ({
list: data,
setList: setFormData,
defaultValue: NETWORK_FORM_SCHEMA.default()
});
})
useEffect(() => {
getVNetworks();
getVNetworksTemplates();
}, []);
getVNetworks()
getVNetworksTemplates()
}, [])
return (
<>
@ -46,22 +46,22 @@ const Networks = () => ({
list={data}
CardComponent={NetworkCard}
handleCreate={() => {
handleEdit();
setShowDialog(true);
handleEdit()
setShowDialog(true)
}}
cardsProps={({ value: { id } }) => {
const isUsed = form[TIERS_ID].some(({ networks }) =>
networks?.includes(id)
);
)
return {
handleEdit: () => {
handleEdit(id);
setShowDialog(true);
handleEdit(id)
setShowDialog(true)
},
handleClone: () => handleClone(id),
handleRemove: !isUsed ? () => handleRemove(id) : undefined
};
}
}}
/>
{showDialog && (
@ -71,8 +71,8 @@ const Networks = () => ({
open={showDialog}
values={editingData}
onSubmit={values => {
handleSave(values);
setShowDialog(false);
handleSave(values)
setShowDialog(false)
}}
onCancel={() => setShowDialog(false)}
>
@ -80,8 +80,8 @@ const Networks = () => ({
</DialogForm>
)}
</>
);
)
}, [])
});
})
export default Networks;
export default Networks

View File

@ -1,19 +1,19 @@
import * as yup from 'yup';
import { v4 as uuidv4 } from 'uuid';
import { TYPE_INPUT } from 'client/constants';
import { getValidationFromFields } from 'client/utils/helpers';
import useOpennebula from 'client/hooks/useOpennebula';
import * as yup from 'yup'
import { v4 as uuidv4 } from 'uuid'
import { TYPE_INPUT } from 'client/constants'
import { getValidationFromFields } from 'client/utils/helpers'
import useOpennebula from 'client/hooks/useOpennebula'
const SELECT = {
template: 'template',
network: 'network'
};
}
const TYPES_NETWORKS = [
{ text: 'Create', value: 'template_id', select: SELECT.template },
{ text: 'Reserve', value: 'reserve_from', select: SELECT.network },
{ text: 'Existing', value: 'id', select: SELECT.network }
];
]
const ID = {
name: 'id',
@ -26,7 +26,7 @@ const ID = {
.required()
.default(uuidv4),
grid: { style: { display: 'none' } }
};
}
const MANDATORY = {
name: 'mandatory',
@ -37,7 +37,7 @@ const MANDATORY = {
.required('Mandatory field is required')
.default(false),
grid: { md: 12 }
};
}
const NAME = {
name: 'name',
@ -49,7 +49,7 @@ const NAME = {
.matches(/^[\w+\s*]+$/g, { message: 'Invalid characters' })
.required('Name field is required')
.default('')
};
}
const DESCRIPTION = {
name: 'description',
@ -60,7 +60,7 @@ const DESCRIPTION = {
.string()
.trim()
.default('')
};
}
const TYPE = {
name: 'type',
@ -72,23 +72,23 @@ const TYPE = {
.oneOf(TYPES_NETWORKS.map(({ value }) => value))
.required('Type field is required')
.default(TYPES_NETWORKS[0].value)
};
}
const ID_VNET = {
name: 'idVnet',
label: `Select a network`,
label: 'Select a network',
type: TYPE_INPUT.AUTOCOMPLETE,
dependOf: TYPE.name,
values: dependValue => {
const { vNetworks, vNetworksTemplates } = useOpennebula();
const type = TYPES_NETWORKS.find(({ value }) => value === dependValue);
const { vNetworks, vNetworksTemplates } = useOpennebula()
const type = TYPES_NETWORKS.find(({ value }) => value === dependValue)
const values =
type?.select === SELECT.network ? vNetworks : vNetworksTemplates;
type?.select === SELECT.network ? vNetworks : vNetworksTemplates
return values
.map(({ ID: value, NAME: text }) => ({ text, value }))
.sort((a, b) => a.value - b.value);
.sort((a, b) => a.value - b.value)
},
validation: yup
.string()
@ -101,7 +101,7 @@ const ID_VNET = {
: schema.required('Network template field is required')
)
.default(undefined)
};
}
const EXTRA = {
name: 'extra',
@ -112,7 +112,7 @@ const EXTRA = {
.string()
.trim()
.default('')
};
}
export const FORM_FIELDS = [
ID,
@ -122,13 +122,13 @@ export const FORM_FIELDS = [
TYPE,
ID_VNET,
EXTRA
];
]
export const NETWORK_FORM_SCHEMA = yup.object(
getValidationFromFields(FORM_FIELDS)
);
)
export const STEP_FORM_SCHEMA = yup
.array()
.of(NETWORK_FORM_SCHEMA)
.default([]);
.default([])

View File

@ -1,72 +1,72 @@
import React, { memo, useCallback } from 'react';
import PropTypes from 'prop-types';
import React, { memo, useCallback } from 'react'
import PropTypes from 'prop-types'
import {
Handle,
useStoreState,
getOutgoers,
addEdge
} from 'react-flow-renderer';
} from 'react-flow-renderer'
import { TierCard } from 'client/components/Cards';
import { TierCard } from 'client/components/Cards'
const CustomNode = memo(({ data, selected, ...nodeProps }) => {
const { tier, handleEdit } = data;
const elements = useStoreState(state => state.elements);
const nodes = useStoreState(state => state.nodes);
const { tier, handleEdit } = data
const elements = useStoreState(state => state.elements)
const nodes = useStoreState(state => state.nodes)
const detectCycleUtil = useCallback(
(node, elementsTemp, visited, recStack) => {
const { id: nodeId } = node.data;
const { id: nodeId } = node.data
if (!visited[nodeId]) {
visited[nodeId] = true;
recStack[nodeId] = true;
visited[nodeId] = true
recStack[nodeId] = true
const children = getOutgoers(node, elementsTemp);
const children = getOutgoers(node, elementsTemp)
for (let index = 0; index < children.length; index += 1) {
const child = children[index];
const { id: childId } = child.data;
const child = children[index]
const { id: childId } = child.data
if (
!visited[childId] &&
detectCycleUtil(child, elementsTemp, visited, recStack)
) {
return true;
return true
} else if (recStack[childId]) {
return true;
return true
}
}
}
recStack[nodeId] = false;
return false;
recStack[nodeId] = false
return false
},
[]
);
)
const detectCycle = useCallback(
params => {
const elementsTemp = addEdge(params, elements);
const visited = {};
const recStack = {};
const elementsTemp = addEdge(params, elements)
const visited = {}
const recStack = {}
for (let index = 0; index < nodes.length; index += 1) {
const node = nodes[index];
const node = nodes[index]
if (detectCycleUtil(node, elementsTemp, visited, recStack)) {
return false;
return false
}
}
return true;
return true
},
[nodes, elements, detectCycleUtil]
);
)
const isValidConnection = useCallback(
({ source, target }) =>
source !== target ? detectCycle({ source, target }) : false,
[detectCycle]
);
)
return (
<>
@ -89,17 +89,19 @@ const CustomNode = memo(({ data, selected, ...nodeProps }) => {
isValidConnection={isValidConnection}
/>
</>
);
});
)
})
CustomNode.propTypes = {
data: PropTypes.objectOf(PropTypes.any),
selected: PropTypes.bool
};
}
CustomNode.defaultProps = {
data: {},
selected: false
};
}
export default CustomNode;
CustomNode.displayName = 'CustomFlowNode'
export default CustomNode

View File

@ -1,18 +1,18 @@
import React, { memo, useEffect, useMemo } from 'react';
import PropTypes from 'prop-types';
import React, { memo, useEffect, useMemo } from 'react'
import PropTypes from 'prop-types'
import { makeStyles, Box } from '@material-ui/core';
import { Add as AddIcon, SelectAll as SelectAllIcon } from '@material-ui/icons';
import ReactFlow, { Background } from 'react-flow-renderer';
import { useFormContext } from 'react-hook-form';
import { makeStyles } from '@material-ui/core'
import { Add as AddIcon, SelectAll as SelectAllIcon } from '@material-ui/icons'
import ReactFlow, { Background } from 'react-flow-renderer'
import { useFormContext } from 'react-hook-form'
import SpeedDials from 'client/components/SpeedDials';
import { STEP_ID as TIER_ID } from 'client/containers/ApplicationsTemplates/Create/Steps/Tiers';
import SpeedDials from 'client/components/SpeedDials'
import { STEP_ID as TIER_ID } from 'client/containers/ApplicationsTemplates/Create/Steps/Tiers'
import CustomNode from './CustomNode';
import useFlowGraph from './useFlowGraph';
import CustomNode from './CustomNode'
import useFlowGraph from './useFlowGraph'
const NOT_KEY_CODE = -1;
const NOT_KEY_CODE = -1
const useStyles = makeStyles(() => ({
root: {
@ -26,11 +26,11 @@ const useStyles = makeStyles(() => ({
}
}
}
}));
}))
const Flow = memo(({ dataFields, handleCreate, handleEdit, handleSetData }) => {
const { watch } = useFormContext();
const classes = useStyles();
const { watch } = useFormContext()
const classes = useStyles()
const {
flow,
handleRefreshFlow,
@ -38,13 +38,13 @@ const Flow = memo(({ dataFields, handleCreate, handleEdit, handleSetData }) => {
handleConnect,
handleUpdatePosition,
handleSelectAll
} = useFlowGraph({ nodeFields: dataFields, setList: handleSetData });
} = useFlowGraph({ nodeFields: dataFields, setList: handleSetData })
useEffect(() => {
handleRefreshFlow(watch(TIER_ID), ({ id }) => ({
handleEdit: () => handleEdit(id)
}));
}, [watch]);
}))
}, [watch])
const actions = useMemo(
() => [
@ -60,7 +60,7 @@ const Flow = memo(({ dataFields, handleCreate, handleEdit, handleSetData }) => {
}
],
[handleCreate, handleSelectAll]
);
)
return (
<ReactFlow
@ -75,21 +75,21 @@ const Flow = memo(({ dataFields, handleCreate, handleEdit, handleSetData }) => {
<SpeedDials actions={actions} />
<Background color="#aaa" gap={16} />
</ReactFlow>
);
});
)
})
Flow.propTypes = {
dataFields: PropTypes.arrayOf(PropTypes.string),
handleCreate: PropTypes.func,
handleEdit: PropTypes.func,
handleSetData: PropTypes.func
};
}
Flow.defaultProps = {
dataFields: [],
handleCreate: undefined,
handleEdit: undefined,
handleSetData: undefined
};
}
export default Flow;
export default Flow

View File

@ -1,4 +1,4 @@
import { useCallback, useState } from 'react';
import { useCallback, useState } from 'react'
import {
isNode,
@ -6,19 +6,19 @@ import {
addEdge,
removeElements,
useStoreActions
} from 'react-flow-renderer';
} from 'react-flow-renderer'
const useFlowGraph = ({ nodeFields, setList }) => {
const [flow, setFlow] = useState([]);
const [flow, setFlow] = useState([])
const setSelectedElements = useStoreActions(
actions => actions.setSelectedElements
);
)
const getParents = (currentFlow, childId) =>
currentFlow
.filter(isEdge)
.filter(({ target }) => childId === target)
.map(({ source }) => source);
.map(({ source }) => source)
const getList = currentFlow =>
currentFlow?.filter(isNode)?.map(({ data: nodeData, position }) =>
@ -33,7 +33,7 @@ const useFlowGraph = ({ nodeFields, setList }) => {
}),
{}
)
);
)
const handleRefreshFlow = useCallback((data, extraItemProps) => {
setFlow(
@ -55,35 +55,35 @@ const useFlowGraph = ({ nodeFields, setList }) => {
],
[]
)
);
}, []);
)
}, [])
const updateList = newFlow => {
const list = getList(newFlow);
setList(list);
};
const list = getList(newFlow)
setList(list)
}
const handleRemoveElements = elements => {
const newFlow = removeElements(elements, flow);
updateList(newFlow);
};
const newFlow = removeElements(elements, flow)
updateList(newFlow)
}
const handleConnect = params => {
const newFlow = addEdge({ ...params, animated: true }, flow);
updateList(newFlow);
};
const newFlow = addEdge({ ...params, animated: true }, flow)
updateList(newFlow)
}
const handleUpdatePosition = (_, node) => {
const newFlow = flow.map(element =>
element.id === node.id ? node : element
);
updateList(newFlow);
};
)
updateList(newFlow)
}
const handleSelectAll = useCallback(() => {
const nodes = flow.filter(isNode);
setSelectedElements(nodes.map(({ id, type }) => ({ id, type })));
}, [flow]);
const nodes = flow.filter(isNode)
setSelectedElements(nodes.map(({ id, type }) => ({ id, type })))
}, [flow])
return {
flow,
@ -92,7 +92,7 @@ const useFlowGraph = ({ nodeFields, setList }) => {
handleConnect,
handleUpdatePosition,
handleSelectAll
};
};
}
}
export default useFlowGraph;
export default useFlowGraph

View File

@ -1,10 +1,10 @@
import React, { useCallback } from 'react';
import React, { useCallback } from 'react'
import FormWithSchema from 'client/components/Forms/FormWithSchema';
import FormWithSchema from 'client/components/Forms/FormWithSchema'
import { FORM_FIELDS, STEP_FORM_SCHEMA } from './schema';
import { FORM_FIELDS, STEP_FORM_SCHEMA } from './schema'
export const STEP_ID = 'tier';
export const STEP_ID = 'tier'
const BasicConfiguration = () => ({
id: STEP_ID,
@ -14,6 +14,6 @@ const BasicConfiguration = () => ({
() => <FormWithSchema cy="form-tier" fields={FORM_FIELDS} id={STEP_ID} />,
[]
)
});
})
export default BasicConfiguration;
export default BasicConfiguration

View File

@ -1,12 +1,12 @@
import * as yup from 'yup';
import { TYPE_INPUT } from 'client/constants';
import { getValidationFromFields } from 'client/utils/helpers';
import * as yup from 'yup'
import { TYPE_INPUT } from 'client/constants'
import { getValidationFromFields } from 'client/utils/helpers'
const SHUTDOWN_ACTIONS = [
{ text: 'None', value: 'none' },
{ text: 'Shutdown', value: 'shutdown' },
{ text: 'Shutdown hard', value: 'shutdown-hard' }
];
]
export const FORM_FIELDS = [
{
@ -41,8 +41,8 @@ export const FORM_FIELDS = [
.oneOf(SHUTDOWN_ACTIONS.map(({ value }) => value))
.default(SHUTDOWN_ACTIONS[0].value)
}
];
]
export const STEP_FORM_SCHEMA = yup.object(
getValidationFromFields(FORM_FIELDS)
);
)

View File

@ -1,41 +1,43 @@
import React, { useCallback, useContext } from 'react';
import React, { useCallback, useContext } from 'react'
import useListForm from 'client/hooks/useListForm';
import ListCards from 'client/components/List/ListCards';
import { SelectCard } from 'client/components/Cards';
import useListForm from 'client/hooks/useListForm'
import ListCards from 'client/components/List/ListCards'
import { SelectCard } from 'client/components/Cards'
import { STEP_ID as NETWORKING } from 'client/containers/ApplicationsTemplates/Create/Steps/Networking';
import { Context } from 'client/containers/ApplicationsTemplates/Create/Steps/Tiers';
import { STEP_FORM_SCHEMA } from './schema';
import { STEP_ID as NETWORKING } from 'client/containers/ApplicationsTemplates/Create/Steps/Networking'
import { Context } from 'client/containers/ApplicationsTemplates/Create/Steps/Tiers'
import { STEP_FORM_SCHEMA } from './schema'
export const STEP_ID = 'networks';
export const STEP_ID = 'networks'
const Networks = () => ({
id: STEP_ID,
label: 'Networks',
resolver: STEP_FORM_SCHEMA,
content: useCallback(({ data, setFormData }) => {
const { nestedForm: list } = useContext(Context);
const { nestedForm: list } = useContext(Context)
const { handleSelect, handleUnselect } = useListForm({
key: STEP_ID,
multiple: true,
setList: setFormData
});
})
return (
<ListCards
list={list[NETWORKING]}
CardComponent={SelectCard}
cardsProps={({ value: { id, name } }) => ({
ID: id,
NAME: name,
isSelected: data?.some(selected => selected === id),
handleSelect: () => handleSelect(id),
handleUnselect: () => handleUnselect(id)
})}
/>
);
}, [])
});
cardsProps={({ value: { id, name } }) => {
const isSelected = data?.some(selected => selected === id)
export default Networks;
return {
title: name,
isSelected,
handleClick: () => isSelected ? handleSelect(id) : handleUnselect(id)
}
}}
/>
)
}, [])
})
export default Networks

View File

@ -1,3 +1,3 @@
import * as yup from 'yup';
import * as yup from 'yup'
export const STEP_FORM_SCHEMA = yup.array(yup.string().trim()).default([]);
export const STEP_FORM_SCHEMA = yup.array(yup.string().trim()).default([])

View File

@ -1,10 +1,10 @@
import React, { useCallback } from 'react';
import React, { useCallback } from 'react'
import FormWithSchema from 'client/components/Forms/FormWithSchema';
import FormWithSchema from 'client/components/Forms/FormWithSchema'
import { FORM_FIELDS, STEP_FORM_SCHEMA } from './schema';
import { FORM_FIELDS, STEP_FORM_SCHEMA } from './schema'
export const STEP_ID = 'policies';
export const STEP_ID = 'policies'
const Policies = () => ({
id: STEP_ID,
@ -16,6 +16,6 @@ const Policies = () => ({
),
[]
)
});
})
export default Policies;
export default Policies

View File

@ -1,6 +1,6 @@
import * as yup from 'yup';
import { TYPE_INPUT } from 'client/constants';
import { getValidationFromFields } from 'client/utils/helpers';
import * as yup from 'yup'
import { TYPE_INPUT } from 'client/constants'
import { getValidationFromFields } from 'client/utils/helpers'
export const FORM_FIELDS = [
{
@ -21,8 +21,8 @@ export const FORM_FIELDS = [
.trim()
.default('')
}
];
]
export const STEP_FORM_SCHEMA = yup.object(
getValidationFromFields(FORM_FIELDS)
);
)

View File

@ -1,14 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
import React from 'react'
import PropTypes from 'prop-types'
import AceEditor from 'react-ace';
import 'ace-builds/src-noconflict/mode-dockerfile';
import 'ace-builds/src-noconflict/theme-github';
import AceEditor from 'react-ace'
import 'ace-builds/src-noconflict/mode-dockerfile'
import 'ace-builds/src-noconflict/theme-github'
const DockerFile = ({ backButton, handleSetData, currentValue, ...props }) => {
const handleChange = newValue => {
handleSetData(newValue);
};
handleSetData(newValue)
}
return (
<>
@ -37,19 +37,19 @@ const DockerFile = ({ backButton, handleSetData, currentValue, ...props }) => {
{...props}
/>
</>
);
};
)
}
DockerFile.propTypes = {
backButton: PropTypes.node,
currentValue: PropTypes.string,
handleSetData: PropTypes.func
};
}
DockerFile.defaultProps = {
backButton: null,
currentValue: undefined,
handleSetData: PropTypes.func
};
}
export default DockerFile;
export default DockerFile

View File

@ -1,38 +1,34 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import React, { useEffect } from 'react'
import PropTypes from 'prop-types'
import useOpennebula from 'client/hooks/useOpennebula';
import Search from 'client/components/Search';
import { SelectCard } from 'client/components/Cards';
import useOpennebula from 'client/hooks/useOpennebula'
import Search from 'client/components/Search'
import { SelectCard } from 'client/components/Cards'
const sortByID = (a, b) => a.ID - b.ID;
const sortByID = (a, b) => a.ID - b.ID
const ListMarketApp = ({ backButton, currentValue, handleSetData }) => {
const { apps, getMarketApps } = useOpennebula();
const { apps, getMarketApps } = useOpennebula()
useEffect(() => {
getMarketApps();
}, []);
const handleSelect = index => handleSetData(index);
const handleUnselect = () => handleSetData();
const renderApp = app => (
<SelectCard
key={`app-${app.ID}`}
isSelected={app.ID === String(currentValue)}
handleSelect={handleSelect}
handleUnselect={handleUnselect}
{...app}
/>
);
getMarketApps()
}, [])
return (
<Search
list={apps?.sort(sortByID)}
listOptions={{ shouldSort: true, sortFn: sortByID, keys: ['NAME'] }}
renderResult={renderApp}
startAdornment={backButton}
renderResult={({ ID, NAME }) => {
const isSelected = ID === String(currentValue)
return <SelectCard
key={`app-${ID}`}
title={`📦 ${NAME}`}
isSelected={isSelected}
handleClick={() => handleSetData(!isSelected && ID)}
/>
}}
searchBoxProps={{
style: {
display: 'flex',
@ -41,19 +37,19 @@ const ListMarketApp = ({ backButton, currentValue, handleSetData }) => {
}
}}
/>
);
};
)
}
ListMarketApp.propTypes = {
backButton: PropTypes.node,
currentValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
handleSetData: PropTypes.func
};
}
ListMarketApp.defaultProps = {
backButton: null,
currentValue: undefined,
handleSetData: () => undefined
};
}
export default ListMarketApp;
export default ListMarketApp

View File

@ -1,38 +1,34 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import React, { useEffect } from 'react'
import PropTypes from 'prop-types'
import useOpennebula from 'client/hooks/useOpennebula';
import Search from 'client/components/Search';
import { SelectCard } from 'client/components/Cards';
import useOpennebula from 'client/hooks/useOpennebula'
import Search from 'client/components/Search'
import { SelectCard } from 'client/components/Cards'
const sortByID = (a, b) => a.ID - b.ID;
const sortByID = (a, b) => a.ID - b.ID
const ListTemplates = ({ backButton, currentValue, handleSetData }) => {
const { templates, getTemplates } = useOpennebula();
const { templates, getTemplates } = useOpennebula()
useEffect(() => {
getTemplates();
}, []);
const handleSelect = index => handleSetData(index);
const handleUnselect = () => handleSetData();
const renderTemplate = tmp => (
<SelectCard
key={`tmp-${tmp.ID}`}
isSelected={tmp.ID === String(currentValue)}
handleSelect={handleSelect}
handleUnselect={handleUnselect}
{...tmp}
/>
);
getTemplates()
}, [])
return (
<Search
list={templates?.sort(sortByID)}
listOptions={{ shouldSort: true, sortFn: sortByID, keys: ['NAME'] }}
renderResult={renderTemplate}
startAdornment={backButton}
renderResult={({ ID, NAME }) => {
const isSelected = ID === String(currentValue)
return <SelectCard
key={`tmp-${ID}`}
title={`📁 ${NAME}`}
isSelected={isSelected}
handleClick={() => handleSetData(!isSelected && ID)}
/>
}}
searchBoxProps={{
style: {
display: 'flex',
@ -41,19 +37,19 @@ const ListTemplates = ({ backButton, currentValue, handleSetData }) => {
}
}}
/>
);
};
)
}
ListTemplates.propTypes = {
backButton: PropTypes.node,
currentValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
handleSetData: PropTypes.func
};
}
ListTemplates.defaultProps = {
backButton: null,
currentValue: undefined,
handleSetData: () => undefined
};
}
export default ListTemplates;
export default ListTemplates

View File

@ -1,23 +1,23 @@
import React, { useCallback, useState, useEffect, useMemo } from 'react';
import React, { useCallback, useState, useEffect, useMemo } from 'react'
import {
ArrowBackIosOutlined as BackIcon,
ShoppingCartOutlined as MarketplaceIcon,
InsertDriveFileOutlined as TemplateIcon
} from '@material-ui/icons';
import { makeStyles, IconButton, Button, Fade } from '@material-ui/core';
import DockerLogo from 'client/icons/docker';
} from '@material-ui/icons'
import { makeStyles, IconButton, Button, Fade } from '@material-ui/core'
import DockerLogo from 'client/icons/docker'
import ListTemplates from './List/Templates';
import ListMarketApps from './List/MarketApps';
import DockerFile from './List/Docker';
import { STEP_FORM_SCHEMA } from './schema';
import ListTemplates from './List/Templates'
import ListMarketApps from './List/MarketApps'
import DockerFile from './List/Docker'
import { STEP_FORM_SCHEMA } from './schema'
export const STEP_ID = 'template';
export const STEP_ID = 'template'
const SCREENS = [
{
id: 'template',
id: 'id',
button: <TemplateIcon style={{ fontSize: 100 }} />,
content: ListTemplates
},
@ -31,7 +31,7 @@ const SCREENS = [
button: <DockerLogo width="100" height="100%" color="#066da5" />,
content: DockerFile
}
];
]
const useStyles = makeStyles(() => ({
root: {
@ -45,35 +45,35 @@ const useStyles = makeStyles(() => ({
flexWrap: 'wrap'
},
button: { backgroundColor: '#fff' }
}));
}))
const Template = () => ({
id: STEP_ID,
label: 'Template',
resolver: STEP_FORM_SCHEMA,
content: useCallback(({ data = {}, setFormData }) => {
const classes = useStyles();
const [screen, setScreen] = useState(undefined);
const classes = useStyles()
const [screen, setScreen] = useState(undefined)
useEffect(() => {
if (Object.keys(data).length > 0) {
const currentScreen = Object.keys(data)[0];
setScreen(SCREENS.find(src => src.id === currentScreen));
const currentScreen = Object.keys(data)[0]
setScreen(SCREENS.find(src => src.id === currentScreen))
}
}, []);
}, [])
const handleSetTemplate = template =>
setFormData(prevData => ({
...prevData,
[STEP_ID]: template ? { [screen.id]: template } : undefined
}));
}))
const handleBack = () => {
setScreen(undefined);
handleSetTemplate();
};
setScreen(undefined)
handleSetTemplate()
}
const Content = useMemo(() => screen?.content, [screen]);
const Content = useMemo(() => screen?.content, [screen])
return screen !== undefined ? (
<Content
@ -101,8 +101,8 @@ const Template = () => ({
))}
</div>
</div>
);
)
}, [])
});
})
export default Template;
export default Template

View File

@ -1,9 +1,9 @@
import * as yup from 'yup';
import { getValidationFromFields } from 'client/utils/helpers';
import * as yup from 'yup'
import { getValidationFromFields } from 'client/utils/helpers'
export const FORM_FIELDS = [
{
name: 'template',
name: 'id',
validation: yup.number().min(0, 'Invalid template')
},
{
@ -14,9 +14,9 @@ export const FORM_FIELDS = [
name: 'docker',
validation: yup.string().trim()
}
];
]
export const STEP_FORM_SCHEMA = yup
.object(getValidationFromFields(FORM_FIELDS))
.required('Template is required')
.default(undefined);
.default(undefined)

View File

@ -1,18 +1,18 @@
import * as yup from 'yup';
import { v4 as uuidv4 } from 'uuid';
import * as yup from 'yup'
import { v4 as uuidv4 } from 'uuid'
import BasicConfiguration from './BasicConfiguration';
import Networks from './Networks';
import Template from './Template';
import Policies from './Policies';
import BasicConfiguration from './BasicConfiguration'
import Networks from './Networks'
import Template from './Template'
import Policies from './Policies'
const Steps = () => {
const basic = BasicConfiguration();
const networks = Networks();
const template = Template();
const policies = Policies();
const basic = BasicConfiguration()
const networks = Networks()
const template = Template()
const policies = Policies()
const steps = [basic, networks, template, policies];
const steps = [basic, networks, template, policies]
const resolvers = yup.object({
id: yup
@ -28,11 +28,11 @@ const Steps = () => {
x: yup.number().default(0),
y: yup.number().default(0)
})
});
})
const defaultValues = () => resolvers.default();
const defaultValues = () => resolvers.default()
return { steps, defaultValues, resolvers };
};
return { steps, defaultValues, resolvers }
}
export default Steps;
export default Steps

View File

@ -1,25 +1,25 @@
import React, { useEffect, useState, useCallback, createContext } from 'react';
import React, { useEffect, useState, useCallback, createContext } from 'react'
import * as yup from 'yup';
import { useWatch } from 'react-hook-form';
import * as yup from 'yup'
import { useWatch } from 'react-hook-form'
import { ReactFlowProvider } from 'react-flow-renderer';
import { Box } from '@material-ui/core';
import { ReactFlowProvider } from 'react-flow-renderer'
import { Box } from '@material-ui/core'
import useListForm from 'client/hooks/useListForm';
import FormStepper from 'client/components/FormStepper';
import { DialogForm } from 'client/components/Dialogs';
import { STEP_ID as NETWORKING_ID } from 'client/containers/ApplicationsTemplates/Create/Steps/Networking';
import { STEP_ID as NETWORKS_ID } from 'client/containers/ApplicationsTemplates/Create/Steps/Tiers/Steps/Networks';
import useListForm from 'client/hooks/useListForm'
import FormStepper from 'client/components/FormStepper'
import { DialogForm } from 'client/components/Dialogs'
import { STEP_ID as NETWORKING_ID } from 'client/containers/ApplicationsTemplates/Create/Steps/Networking'
import { STEP_ID as NETWORKS_ID } from 'client/containers/ApplicationsTemplates/Create/Steps/Tiers/Steps/Networks'
import Steps from './Steps';
import Flow from './Flow';
import Steps from './Steps'
import Flow from './Flow'
export const Context = createContext({});
export const STEP_ID = 'tiers';
export const Context = createContext({})
export const STEP_ID = 'tiers'
const Tiers = () => {
const { steps, defaultValues, resolvers } = Steps();
const { steps, defaultValues, resolvers } = Steps()
return {
id: STEP_ID,
@ -30,9 +30,9 @@ const Tiers = () => {
.required('Tiers field is required')
.default([]),
content: useCallback(({ data, setFormData }) => {
const [showDialog, setShowDialog] = useState(false);
const [nestedForm, setNestedForm] = useState({});
const form = useWatch({});
const [showDialog, setShowDialog] = useState(false)
const [nestedForm, setNestedForm] = useState({})
const form = useWatch({})
const {
editingData,
@ -44,24 +44,24 @@ const Tiers = () => {
list: data,
setList: setFormData,
defaultValue: defaultValues()
});
})
const handleEditTier = id => {
handleEdit(id);
setShowDialog(true);
};
handleEdit(id)
setShowDialog(true)
}
useEffect(() => {
setNestedForm(form);
}, []);
setNestedForm(form)
}, [])
const formSteps = React.useMemo(() => {
const networking = nestedForm[NETWORKING_ID] ?? [];
const networking = nestedForm[NETWORKING_ID] ?? []
return steps.filter(
({ id }) => id !== NETWORKS_ID || networking.length !== 0
);
}, [nestedForm]);
)
}, [nestedForm])
return (
<>
@ -89,8 +89,8 @@ const Tiers = () => {
steps={formSteps}
schema={resolvers}
onSubmit={values => {
handleSave(values);
setShowDialog(false);
handleSave(values)
setShowDialog(false)
}}
/>
</Box>
@ -98,9 +98,9 @@ const Tiers = () => {
</Context.Provider>
)}
</>
);
)
}, [])
};
};
}
}
export default Tiers;
export default Tiers

View File

@ -1,28 +1,28 @@
import * as yup from 'yup';
import * as yup from 'yup'
import BasicConfiguration from './BasicConfiguration';
import Clusters from './Clusters';
import Networking from './Networking';
import Tiers from './Tiers';
import BasicConfiguration from './BasicConfiguration'
import Clusters from './Clusters'
import Networking from './Networking'
import Tiers from './Tiers'
const Steps = () => {
const basic = BasicConfiguration();
const clusters = Clusters();
const networking = Networking();
const tiers = Tiers();
const basic = BasicConfiguration()
const clusters = Clusters()
const networking = Networking()
const tiers = Tiers()
const steps = [basic, clusters, networking, tiers];
const steps = [basic, clusters, networking, tiers]
const resolvers = yup.object({
[basic.id]: basic.resolver,
[clusters.id]: clusters.resolver,
[networking.id]: networking.resolver,
[tiers.id]: tiers.resolver
});
})
const defaultValues = resolvers.default();
const defaultValues = resolvers.default()
return { steps, defaultValues, resolvers };
};
return { steps, defaultValues, resolvers }
}
export default Steps;
export default Steps

View File

@ -1,72 +1,73 @@
import React, { useEffect } from 'react';
import { Redirect, useHistory, useParams } from 'react-router-dom';
import React, { useEffect } from 'react'
import { Redirect, useHistory, useParams } from 'react-router-dom'
import { Container } from '@material-ui/core';
import { useForm, FormProvider } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers';
import { Container } from '@material-ui/core'
import { useForm, FormProvider } from 'react-hook-form'
import { yupResolver } from '@hookform/resolvers'
import FormStepper from 'client/components/FormStepper';
import Steps from 'client/containers/ApplicationsTemplates/Create/Steps';
import FormStepper from 'client/components/FormStepper'
import Steps from 'client/containers/ApplicationsTemplates/Create/Steps'
import { PATH } from 'client/router/endpoints';
import useFetch from 'client/hooks/useFetch';
import useApplication from 'client/hooks/useApplication';
import mapApplicationToForm from 'client/utils/parser/toApplicationForm';
import mapFormToApplication from 'client/utils/parser/toApplicationTemplate';
import { PATH } from 'client/router/endpoints'
import useFetch from 'client/hooks/useFetch'
import useApplication from 'client/hooks/useApplication'
import mapApplicationToForm from 'client/utils/parser/toApplicationForm'
import mapFormToApplication from 'client/utils/parser/toApplicationTemplate'
function ApplicationCreate() {
const history = useHistory();
const { id } = useParams();
const { steps, defaultValues, resolvers } = Steps();
function ApplicationCreate () {
const history = useHistory()
const { id } = useParams()
const { steps, defaultValues, resolvers } = Steps()
const {
getApplicationTemplate,
createApplicationTemplate,
updateApplicationTemplate
} = useApplication();
} = useApplication()
const { data, fetchRequest, loading, error } = useFetch(
getApplicationTemplate
);
)
const methods = useForm({
mode: 'onSubmit',
defaultValues,
resolver: yupResolver(resolvers)
});
})
const onSubmit = formData => {
const application = mapFormToApplication(formData);
const application = mapFormToApplication(formData)
if (id)
if (id) {
updateApplicationTemplate({ id, data: application }).then(
res => res && history.push(PATH.APPLICATION.LIST)
);
else
res => res && history.push(PATH.APPLICATIONS)
)
} else {
createApplicationTemplate({ data: application }).then(
res => res && history.push(PATH.APPLICATION.LIST)
);
};
res => res && history.push(PATH.APPLICATIONS)
)
}
}
useEffect(() => {
try {
if (id) {
const idNumber = parseInt(id, 10);
if (idNumber < 0) throw new Error();
const idNumber = parseInt(id, 10)
if (idNumber < 0) throw new Error()
fetchRequest({ id: idNumber });
fetchRequest({ id: idNumber })
}
} catch {
// show error
history.push(PATH.DASHBOARD);
history.push(PATH.DASHBOARD)
}
}, [id]);
}, [id])
useEffect(() => {
const formData = data ? mapApplicationToForm(data) : {};
methods.reset(resolvers.cast(formData), { errors: false });
}, [data]);
const formData = data ? mapApplicationToForm(data) : {}
methods.reset(resolvers.cast(formData), { errors: false })
}, [data])
if (error) {
return <Redirect to={PATH.DASHBOARD} />;
return <Redirect to={PATH.DASHBOARD} />
}
return (
@ -82,11 +83,11 @@ function ApplicationCreate() {
</FormProvider>
)}
</Container>
);
)
}
ApplicationCreate.propTypes = {};
ApplicationCreate.propTypes = {}
ApplicationCreate.defaultProps = {};
ApplicationCreate.defaultProps = {}
export default ApplicationCreate;
export default ApplicationCreate

View File

@ -1,3 +1,3 @@
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core'
export default makeStyles(theme => ({}));
export default makeStyles(theme => ({}))

View File

@ -1,3 +1,3 @@
import ApplicationsTemplatesCreate from 'client/containers/ApplicationsTemplates/Create';
import ApplicationsTemplatesCreate from 'client/containers/ApplicationsTemplates/Create'
export { ApplicationsTemplatesCreate };
export { ApplicationsTemplatesCreate }

View File

@ -13,14 +13,14 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import React from 'react'
import { Box, Typography } from '@material-ui/core';
import { Box, Typography } from '@material-ui/core'
import dashboardStyles from 'client/containers/Dashboard/styles';
import dashboardStyles from 'client/containers/Dashboard/styles'
function Dashboard() {
const classes = dashboardStyles();
function Dashboard () {
const classes = dashboardStyles()
return (
<Box>
@ -32,7 +32,7 @@ function Dashboard() {
Dashboard
</Typography>
</Box>
);
)
}
export default Dashboard;
export default Dashboard

View File

@ -1,8 +1,8 @@
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core'
export default makeStyles(theme => ({
root: {},
title: {
color: theme.palette.common.black
}
}));
}))

View File

@ -13,21 +13,21 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React, { Fragment } from 'react';
import React, { Fragment } from 'react'
import { Translate } from 'client/components/HOC/Translate';
import { NotFound } from 'client/constants/translates';
import { Translate } from 'client/components/HOC/Translate'
import { NotFound } from 'client/constants/translates'
function Error404() {
function Error404 () {
return (
<Fragment>
<Translate word={NotFound} />
</Fragment>
);
)
}
Error404.propTypes = {};
Error404.propTypes = {}
Error404.defaultProps = {};
Error404.defaultProps = {}
export default Error404;
export default Error404

View File

@ -1,8 +1,8 @@
import React from 'react';
import { Typography, Link } from '@material-ui/core';
import React from 'react'
import { Typography, Link } from '@material-ui/core'
const Copyright = () => {
const year = new Date().getFullYear();
const year = new Date().getFullYear()
return (
<Typography variant="body2" color="textSecondary" align="center">
@ -12,7 +12,7 @@ const Copyright = () => {
</Link>
{` ${year}. `}
</Typography>
);
)
}
export default Copyright;
export default Copyright

View File

@ -1,20 +1,20 @@
import React from 'react';
import { func, string } from 'prop-types';
import React from 'react'
import { func, string } from 'prop-types'
import { Box, Button, TextField } from '@material-ui/core';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers';
import * as yup from 'yup';
import { Box, Button, TextField } from '@material-ui/core'
import { useForm } from 'react-hook-form'
import { yupResolver } from '@hookform/resolvers'
import * as yup from 'yup'
import { Token2FA, Next } from 'client/constants/translates';
import loginStyles from 'client/containers/Login/styles';
import { Token2FA, Next } from 'client/constants/translates'
import loginStyles from 'client/containers/Login/styles'
import { Tr } from 'client/components/HOC';
import ButtonSubmit from 'client/components/FormControl/SubmitButton';
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
import { Tr } from 'client/components/HOC'
import ButtonSubmit from 'client/components/FormControl/SubmitButton'
import ErrorHelper from 'client/components/FormControl/ErrorHelper'
const Form2fa = ({ onBack, onSubmit, error }) => {
const classes = loginStyles();
const classes = loginStyles()
const { register, handleSubmit, errors } = useForm({
reValidateMode: 'onSubmit',
@ -23,9 +23,9 @@ const Form2fa = ({ onBack, onSubmit, error }) => {
token2fa: yup.string().required('Authenticator is a required field')
})
)
});
})
const tokenError = Boolean(errors.token || error);
const tokenError = Boolean(errors.token || error)
return (
<Box
@ -59,19 +59,19 @@ const Form2fa = ({ onBack, onSubmit, error }) => {
/>
</Box>
</Box>
);
};
)
}
Form2fa.propTypes = {
onBack: func.isRequired,
onSubmit: func.isRequired,
error: string
};
}
Form2fa.defaultProps = {
onBack: () => undefined,
onSubmit: () => undefined,
error: null
};
}
export default Form2fa;
export default Form2fa

View File

@ -1,18 +1,18 @@
import React from 'react';
import { func } from 'prop-types';
import React from 'react'
import { func } from 'prop-types'
import { Box, Button } from '@material-ui/core';
import { useForm, Controller } from 'react-hook-form';
import { Box, Button } from '@material-ui/core'
import { useForm, Controller } from 'react-hook-form'
import GroupSelect from 'client/components/FormControl/GroupSelect';
import ButtonSubmit from 'client/components/FormControl/SubmitButton';
import { Tr } from 'client/components/HOC';
import loginStyles from 'client/containers/Login/styles';
import { Next } from 'client/constants/translates';
import GroupSelect from 'client/components/FormControl/GroupSelect'
import ButtonSubmit from 'client/components/FormControl/SubmitButton'
import { Tr } from 'client/components/HOC'
import loginStyles from 'client/containers/Login/styles'
import { Next } from 'client/constants/translates'
function FormGroup({ onBack, onSubmit }) {
const classes = loginStyles();
const { control, handleSubmit } = useForm();
function FormGroup ({ onBack, onSubmit }) {
const classes = loginStyles()
const { control, handleSubmit } = useForm()
return (
<Box
@ -28,21 +28,21 @@ function FormGroup({ onBack, onSubmit }) {
label={Tr(Next)}
/>
</Box>
);
)
}
FormGroup.propTypes = {
onBack: func.isRequired,
onSubmit: func.isRequired
};
}
FormGroup.defaultProps = {
onBack: () => undefined,
onSubmit: () => undefined
};
}
FormGroup.propTypes = {};
FormGroup.propTypes = {}
FormGroup.defaultProps = {};
FormGroup.defaultProps = {}
export default FormGroup;
export default FormGroup

View File

@ -1,23 +1,23 @@
import React from 'react';
import { func, string } from 'prop-types';
import { Box, Checkbox, TextField, FormControlLabel } from '@material-ui/core';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers';
import * as yup from 'yup';
import React from 'react'
import { func, string } from 'prop-types'
import { Box, Checkbox, TextField, FormControlLabel } from '@material-ui/core'
import { useForm } from 'react-hook-form'
import { yupResolver } from '@hookform/resolvers'
import * as yup from 'yup'
import {
SignIn,
Username,
Password,
KeepLoggedIn
} from 'client/constants/translates';
import { Tr } from 'client/components/HOC';
import ButtonSubmit from 'client/components/FormControl/SubmitButton';
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
import loginStyles from 'client/containers/Login/styles';
} from 'client/constants/translates'
import { Tr } from 'client/components/HOC'
import ButtonSubmit from 'client/components/FormControl/SubmitButton'
import ErrorHelper from 'client/components/FormControl/ErrorHelper'
import loginStyles from 'client/containers/Login/styles'
function FormUser({ onSubmit, error }) {
const classes = loginStyles();
function FormUser ({ onSubmit, error }) {
const classes = loginStyles()
const { register, handleSubmit, errors } = useForm({
reValidateMode: 'onSubmit',
@ -28,10 +28,10 @@ function FormUser({ onSubmit, error }) {
remember: yup.boolean()
})
)
});
})
const userError = Boolean(errors.user || error);
const passError = Boolean(errors.pass);
const userError = Boolean(errors.user || error)
const passError = Boolean(errors.pass)
return (
<Box
@ -88,17 +88,17 @@ function FormUser({ onSubmit, error }) {
label={Tr(SignIn)}
/>
</Box>
);
)
}
FormUser.propTypes = {
onSubmit: func.isRequired,
error: string
};
}
FormUser.defaultProps = {
onSubmit: () => undefined,
error: null
};
}
export default FormUser;
export default FormUser

View File

@ -1,19 +1,4 @@
/* 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. */
/* -------------------------------------------------------------------------- */
import React, { useState, useEffect } from 'react';
import React, { useState } from 'react'
import {
Paper,
Box,
@ -21,28 +6,28 @@ import {
Slide,
LinearProgress,
useMediaQuery
} from '@material-ui/core';
} from '@material-ui/core'
import useAuth from 'client/hooks/useAuth';
import useAuth from 'client/hooks/useAuth'
import FormUser from 'client/containers/Login/Forms/FormUser';
import Form2fa from 'client/containers/Login/Forms/Form2fa';
import FormGroup from 'client/containers/Login/Forms/FormGroup';
import loginStyles from 'client/containers/Login/styles';
import Logo from 'client/icons/logo';
import { ONEADMIN_ID } from 'client/constants';
import FormUser from 'client/containers/Login/Forms/FormUser'
import Form2fa from 'client/containers/Login/Forms/Form2fa'
import FormGroup from 'client/containers/Login/Forms/FormGroup'
import loginStyles from 'client/containers/Login/styles'
import Logo from 'client/icons/logo'
import { ONEADMIN_ID } from 'client/constants'
const STEP = {
USER_FORM: 0,
FA2_FORM: 1,
GROUP_FORM: 2
};
}
function Login() {
const classes = loginStyles();
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'));
const [user, setUser] = useState(undefined);
const [step, setStep] = useState(STEP.USER_FORM);
function Login () {
const classes = loginStyles()
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'))
const [user, setUser] = useState(undefined)
const [step, setStep] = useState(STEP.USER_FORM)
const {
isLoading,
error,
@ -50,30 +35,28 @@ function Login() {
logout,
getAuthInfo,
setPrimaryGroup
} = useAuth();
} = useAuth()
const handleSubmitUser = dataForm => {
login({ ...user, ...dataForm }).then(data => {
console.log('-->', data);
if (data?.token) {
getAuthInfo().then(() => {
// eslint-disable-next-line no-unused-expressions
data?.id !== ONEADMIN_ID && setStep(STEP.GROUP_FORM);
});
data?.id !== ONEADMIN_ID && setStep(STEP.GROUP_FORM)
})
} else {
setStep(data ? STEP.FA2_FORM : step);
setUser(data ? dataForm : user);
setStep(data ? STEP.FA2_FORM : step)
setUser(data ? dataForm : user)
}
});
};
})
}
const handleSubmitGroup = dataForm => setPrimaryGroup(dataForm);
const handleSubmitGroup = dataForm => setPrimaryGroup(dataForm)
const handleBack = () => {
logout();
setUser(undefined);
setStep(STEP.USER_FORM);
};
logout()
setUser(undefined)
setStep(STEP.USER_FORM)
}
return (
<Container
@ -131,11 +114,11 @@ function Login() {
</Box>
</Paper>
</Container>
);
)
}
Login.propTypes = {};
Login.propTypes = {}
Login.defaultProps = {};
Login.defaultProps = {}
export default Login;
export default Login

View File

@ -1,10 +1,10 @@
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core'
export default makeStyles(theme =>
// const getColor = theme.palette.type === 'light' ? darken : lighten;
// const getBackgroundColor = theme.palette.type === 'light' ? lighten : darken;
// color: getColor(theme.palette.error.main, 0.6),
// backgroundColor: getBackgroundColor(theme.palette.error.main, 0.9)
// const getColor = theme.palette.type === 'light' ? darken : lighten;
// const getBackgroundColor = theme.palette.type === 'light' ? lighten : darken;
// color: getColor(theme.palette.error.main, 0.6),
// backgroundColor: getBackgroundColor(theme.palette.error.main, 0.9)
({
root: {
@ -40,4 +40,4 @@ export default makeStyles(theme =>
animation: '1s ease-out 0s 1'
}
})
);
)

View File

@ -13,15 +13,15 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import { Translate } from 'client/components/HOC';
import constants from 'client/constants';
import React from 'react'
import { Translate } from 'client/components/HOC'
import constants from 'client/constants'
const { settings } = constants;
const { settings } = constants
const Settings = () => (
<div>
<Translate word={settings} />
</div>
);
)
export default Settings;
export default Settings

View File

@ -1,36 +1,36 @@
import React from 'react';
import { string, func, shape, object } from 'prop-types';
import React from 'react'
import { string, func, shape, object } from 'prop-types'
import { useForm, Controller } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form'
import {
TextField,
Grid,
Typography,
FormControlLabel,
Checkbox
} from '@material-ui/core';
} from '@material-ui/core'
import ButtonSubmit from 'client/components/FormControl/SubmitButton';
import { requestData, requestParams } from 'client/utils';
import ButtonSubmit from 'client/components/FormControl/SubmitButton'
import { requestData, requestParams } from 'client/utils'
const ResponseForm = ({
handleChangeResponse,
command: { name, httpMethod, params }
}) => {
const { control, handleSubmit, errors, formState } = useForm();
const { control, handleSubmit, errors, formState } = useForm()
const onSubmit = dataForm => {
const { url, options } = requestParams(dataForm, {
name,
httpMethod,
params
});
})
requestData(url, options).then(({ id, ...res }) => {
id === 401 && console.log('ERROR');
id === 200 && handleChangeResponse(JSON.stringify(res, null, '\t'));
});
};
id === 401 && console.log('ERROR')
id === 200 && handleChangeResponse(JSON.stringify(res, null, '\t'))
})
}
return (
<>
@ -81,8 +81,8 @@ const ResponseForm = ({
</Grid>
</Grid>
</>
);
};
)
}
ResponseForm.propTypes = {
command: shape({
@ -91,7 +91,7 @@ ResponseForm.propTypes = {
params: object.isRequired
}).isRequired,
handleChangeResponse: func.isRequired
};
}
ResponseForm.defaultProps = {
command: {
@ -100,5 +100,5 @@ ResponseForm.defaultProps = {
params: {}
},
handleChangeResponse: () => undefined
};
export default ResponseForm;
}
export default ResponseForm

Some files were not shown because too many files have changed in this diff Show More