From 52ccdc307ab0e87acf96fb11e55464de704f1cc3 Mon Sep 17 00:00:00 2001 From: Sergio Betanzos Date: Fri, 18 Sep 2020 17:21:25 +0200 Subject: [PATCH] F #3951: Add policies & network in role form (#228) --- .../public/components/Cards/ClusterCard.js | 2 +- .../public/components/FormStepper/index.js | 32 +++---- .../public/components/ProcessScreen/index.js | 86 ----------------- .../Steps/Roles/Steps/Networks/index.js | 21 ++--- .../Steps/Roles/Steps/Policies/index.js | 21 +++++ .../Steps/Roles/Steps/Policies/schema.js | 30 ++++++ .../Steps/Roles/Steps/Template/List/Docker.js | 14 ++- .../Roles/Steps/Template/List/MarketApps.js | 4 +- .../Roles/Steps/Template/List/Templates.js | 4 +- .../Steps/Roles/Steps/Template/index.js | 94 +++++++++++++++---- .../Create/Steps/Roles/Steps/index.js | 13 ++- src/fireedge/src/public/hooks/useListForm.js | 2 +- 12 files changed, 171 insertions(+), 152 deletions(-) delete mode 100644 src/fireedge/src/public/components/ProcessScreen/index.js create mode 100644 src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Policies/schema.js diff --git a/src/fireedge/src/public/components/Cards/ClusterCard.js b/src/fireedge/src/public/components/Cards/ClusterCard.js index b75170eaf6..a2299615e9 100644 --- a/src/fireedge/src/public/components/Cards/ClusterCard.js +++ b/src/fireedge/src/public/components/Cards/ClusterCard.js @@ -74,7 +74,7 @@ const ClusterCard = React.memo( > (isSelected ? handleUnselect(ID) : handleSelect(ID))} + onClick={() => (isSelected ? handleUnselect() : handleSelect())} > } diff --git a/src/fireedge/src/public/components/FormStepper/index.js b/src/fireedge/src/public/components/FormStepper/index.js index f6e7972436..5c9802632b 100644 --- a/src/fireedge/src/public/components/FormStepper/index.js +++ b/src/fireedge/src/public/components/FormStepper/index.js @@ -22,7 +22,7 @@ const FormStepper = ({ steps, initialValue, onSubmit }) => { const disabledBack = useMemo(() => activeStep === FIRST_STEP, [activeStep]); useEffect(() => { - reset({ ...formData }, { errors: true }); + reset({ ...formData }, { errors: false }); }, [formData]); const handleNext = () => { @@ -31,10 +31,12 @@ const FormStepper = ({ steps, initialValue, onSubmit }) => { trigger(id).then(isValid => { if (!isValid) return; + const data = { ...formData, ...watch() }; + if (activeStep === lastStep) { - onSubmit(formData); + onSubmit(data); } else { - setFormData(prevData => ({ ...prevData, ...watch() })); + setFormData(data); setActiveStep(prevActiveStep => prevActiveStep + 1); } }); @@ -46,6 +48,12 @@ const FormStepper = ({ steps, initialValue, onSubmit }) => { setActiveStep(prevActiveStep => prevActiveStep - 1); }, [activeStep]); + const { id, content: Content } = React.useMemo(() => steps[activeStep], [ + formData, + activeStep, + setFormData + ]); + return ( <> {/* STEPPER */} @@ -69,20 +77,10 @@ const FormStepper = ({ steps, initialValue, onSubmit }) => { /> )} {/* FORM CONTENT */} - {React.useMemo(() => { - const { id, content: Content } = steps[activeStep]; - - return ( - Content && ( - <> - {typeof errors[id]?.message === 'string' && ( - - )} - - - ) - ); - }, [steps, errors, formData, activeStep, setFormData])} + {typeof errors[id]?.message === 'string' && ( + + )} + {Content && } ); }; diff --git a/src/fireedge/src/public/components/ProcessScreen/index.js b/src/fireedge/src/public/components/ProcessScreen/index.js deleted file mode 100644 index 91608c4fa3..0000000000 --- a/src/fireedge/src/public/components/ProcessScreen/index.js +++ /dev/null @@ -1,86 +0,0 @@ -import React, { useState, useEffect, createElement } from 'react'; -import PropTypes from 'prop-types'; - -import { Fade, Button, IconButton } from '@material-ui/core'; -import BackIcon from '@material-ui/icons/ArrowBackIosOutlined'; - -function ProcessScreen({ screens, id, values, setFormData }) { - const [process, setProcess] = useState(undefined); - - useEffect(() => { - const keyValues = Object.keys(values); - - if (keyValues.length > 0) { - const currentScreen = keyValues[0]; - const index = screens.findIndex(scr => scr.id === currentScreen); - if (index !== -1) setProcess(index); - } - }, []); - - const handleSetData = data => - setFormData(prevData => ({ - ...prevData, - [id]: data ? { [screens[process]?.id]: data } : undefined - })); - - const handleBack = () => { - setProcess(undefined); - handleSetData(); - }; - - return ( - <> - {process !== undefined ? ( - createElement(screens[process]?.screen, { - backButton: ( - - - - ), - handleSetData, - currentValue: values[screens[process]?.id] - }) - ) : ( -
-
- {screens?.map(({ id, button }, index) => ( - - - - ))} -
-
- )} - - ); -} - -ProcessScreen.propTypes = { - screens: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string, - button: PropTypes.element, - screen: PropTypes.func - }) - ) -}; - -ProcessScreen.defaultProps = { - screens: [] -}; - -export default ProcessScreen; diff --git a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Networks/index.js b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Networks/index.js index 7e10120cf6..bb67ae262f 100644 --- a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Networks/index.js +++ b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Networks/index.js @@ -2,6 +2,7 @@ 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 { STEP_ID as NETWORKING } from 'client/containers/Application/Create/Steps/Networking'; import { Context } from 'client/containers/Application/Create/Steps/Roles'; @@ -21,21 +22,17 @@ const Networks = () => ({ setList: setFormData }); - console.log('list', list); - return (

hi

} - cardsProps={({ value }) => { - const { ID } = value; - - return { - isSelected: data?.some(selected => selected === ID), - handleSelect: () => handleSelect(ID), - handleUnselect: () => handleUnselect(ID) - }; - }} + CardComponent={SelectCard} + cardsProps={({ value, index }) => ({ + ID: String(index), + NAME: value?.name, + isSelected: data?.some(selected => selected === index), + handleSelect: () => handleSelect(index), + handleUnselect: () => handleUnselect(index) + })} /> ); }, []) diff --git a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Policies/index.js b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Policies/index.js index e69de29bb2..fb8603f2c6 100644 --- a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Policies/index.js +++ b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Policies/index.js @@ -0,0 +1,21 @@ +import React, { useCallback } from 'react'; + +import FormWithSchema from 'client/components/Forms/FormWithSchema'; + +import { FORM_FIELDS, STEP_FORM_SCHEMA } from './schema'; + +export const STEP_ID = 'policies'; + +const Policies = () => ({ + id: STEP_ID, + label: 'Policies', + resolver: STEP_FORM_SCHEMA, + content: useCallback( + () => ( + + ), + [] + ) +}); + +export default Policies; diff --git a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Policies/schema.js b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Policies/schema.js new file mode 100644 index 0000000000..49cdc984bd --- /dev/null +++ b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Policies/schema.js @@ -0,0 +1,30 @@ +import * as yup from 'yup'; +import { TYPE_INPUT } from 'client/constants'; +import { getValidationFromFields } from 'client/utils/helpers'; + +export const FORM_FIELDS = [ + { + name: 'elasticity', + label: 'Elasticity', + type: TYPE_INPUT.TEXT, + validation: yup + .string() + .trim() + .required() + .default('') + }, + { + name: 'scheduled', + label: 'Scheduled', + type: TYPE_INPUT.TEXT, + validation: yup + .string() + .trim() + .required() + .default('') + } +]; + +export const STEP_FORM_SCHEMA = yup.object( + getValidationFromFields(FORM_FIELDS) +); diff --git a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/Docker.js b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/Docker.js index a85d8b1cb3..d118176045 100644 --- a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/Docker.js +++ b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/Docker.js @@ -1,14 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; -function ImportDockerFile({ backButton }) { - return ( -
- {backButton} -

Docker file

-
- ); -} +const ImportDockerFile = ({ backButton }) => ( +
+ {backButton} +

Docker file

+
+); ImportDockerFile.propTypes = { backButton: PropTypes.node diff --git a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/MarketApps.js b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/MarketApps.js index b95f7ba388..7ad8b9d134 100644 --- a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/MarketApps.js +++ b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/MarketApps.js @@ -7,7 +7,7 @@ import { SelectCard } from 'client/components/Cards'; const sortByID = (a, b) => a.ID - b.ID; -function ListMarketApp({ backButton, currentValue, handleSetData }) { +const ListMarketApp = ({ backButton, currentValue, handleSetData }) => { const { apps, getMarketApps } = useOpennebula(); useEffect(() => { @@ -42,7 +42,7 @@ function ListMarketApp({ backButton, currentValue, handleSetData }) { }} /> ); -} +}; ListMarketApp.propTypes = { backButton: PropTypes.node, diff --git a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/Templates.js b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/Templates.js index 079d561209..5d19ae10e5 100644 --- a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/Templates.js +++ b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/List/Templates.js @@ -7,7 +7,7 @@ import { SelectCard } from 'client/components/Cards'; const sortByID = (a, b) => a.ID - b.ID; -function ListTemplates({ backButton, currentValue, handleSetData }) { +const ListTemplates = ({ backButton, currentValue, handleSetData }) => { const { templates, getTemplates } = useOpennebula(); useEffect(() => { @@ -42,7 +42,7 @@ function ListTemplates({ backButton, currentValue, handleSetData }) { }} /> ); -} +}; ListTemplates.propTypes = { backButton: PropTypes.node, diff --git a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/index.js b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/index.js index 259291748d..2b68f3fefb 100644 --- a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/index.js +++ b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/Template/index.js @@ -1,11 +1,13 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useState, useEffect, useMemo } from 'react'; -import TemplateIcon from '@material-ui/icons/InsertDriveFileOutlined'; -import MarketplaceIcon from '@material-ui/icons/ShoppingCartOutlined'; +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'; -import ProcessScreen from 'client/components/ProcessScreen'; - import ListTemplates from './List/Templates'; import ListMarketApps from './List/MarketApps'; import DockerFile from './List/Docker'; @@ -17,34 +19,90 @@ const SCREENS = [ { id: 'template', button: , - screen: ListTemplates + content: ListTemplates }, { id: 'app', button: , - screen: ListMarketApps + content: ListMarketApps }, { id: 'docker', button: , - screen: DockerFile + content: DockerFile } ]; +const useStyles = makeStyles(() => ({ + root: { + flexGrow: 1 + }, + wrapper: { + height: '100%', + display: 'flex', + justifyContent: 'space-around', + alignItems: 'center', + flexWrap: 'wrap' + }, + button: { backgroundColor: '#fff' } +})); + const Template = () => ({ id: STEP_ID, label: 'Template', resolver: STEP_FORM_SCHEMA, - content: useCallback( - ({ data, setFormData }) => - ProcessScreen({ - screens: SCREENS, - id: STEP_ID, - values: data ?? {}, - setFormData - }), - [] - ) + content: useCallback(({ data = {}, setFormData }) => { + 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.id)); + } + }, []); + + const handleSetTemplate = template => + setFormData(prevData => ({ + ...prevData, + [STEP_ID]: template ? { [screen.id]: template } : undefined + })); + + const handleBack = () => { + setScreen(undefined); + handleSetTemplate(); + }; + + const Content = useMemo(() => screen?.content, [screen]); + + return screen !== undefined ? ( + + + + } + handleSetData={handleSetTemplate} + currentValue={data[screen.id]} + /> + ) : ( +
+
+ {SCREENS?.map(scr => ( + + + + ))} +
+
+ ); + }, []) }); export default Template; diff --git a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/index.js b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/index.js index 68bcd3c0ef..1befb29856 100644 --- a/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/index.js +++ b/src/fireedge/src/public/containers/Application/Create/Steps/Roles/Steps/index.js @@ -1,20 +1,23 @@ import * as yup from 'yup'; import BasicConfiguration from './BasicConfiguration'; +import Networks from './Networks'; import Template from './Template'; -// import Policies from './Policies'; +import Policies from './Policies'; const Steps = () => { const basic = BasicConfiguration(); + const networks = Networks(); const template = Template(); - // const policies = Policies(); + const policies = Policies(); - const steps = [basic, template]; + const steps = [basic, networks, template, policies]; const resolvers = yup.object({ [basic.id]: basic.resolver, - [template.id]: template.resolver - // [policies.id]: policies.resolver + [networks.id]: networks.resolver, + [template.id]: template.resolver, + [policies.id]: policies.resolver }); const defaultValues = resolvers.default(); diff --git a/src/fireedge/src/public/hooks/useListForm.js b/src/fireedge/src/public/hooks/useListForm.js index 1ec736e1e6..49bcfbf356 100644 --- a/src/fireedge/src/public/hooks/useListForm.js +++ b/src/fireedge/src/public/hooks/useListForm.js @@ -6,7 +6,7 @@ const useListSelect = ({ multiple, key, list, setList, defaultValue }) => { const handleSelect = index => setList(prevData => ({ ...prevData, - [key]: multiple ? [...prevData[key], index] : [index] + [key]: multiple ? [...(prevData[key] ?? []), index] : [index] })); const handleUnselect = indexRemove =>