mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-21 14:50:08 +03:00
parent
169b072a32
commit
aa1166ced0
@ -1,99 +0,0 @@
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
|
||||
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
|
||||
|
||||
function FormList({ step, data, setFormData }) {
|
||||
const { errors } = useFormContext();
|
||||
const [dialogFormData, setDialogFormData] = useState({});
|
||||
const [showDialog, setShowDialog] = useState(false);
|
||||
|
||||
const { id, preRender, ListComponent, DialogComponent, DEFAULT_DATA } = step;
|
||||
|
||||
useEffect(() => {
|
||||
if (preRender) preRender();
|
||||
}, []);
|
||||
|
||||
const handleSubmit = values => {
|
||||
setFormData(prevData => ({
|
||||
...prevData,
|
||||
[id]: Object.assign(prevData[id], {
|
||||
[dialogFormData.index]: values
|
||||
})
|
||||
}));
|
||||
|
||||
setShowDialog(false);
|
||||
};
|
||||
|
||||
const handleOpen = (index = data?.length) => {
|
||||
const openData = data[index] ?? DEFAULT_DATA;
|
||||
|
||||
setDialogFormData({ index, data: openData });
|
||||
setShowDialog(true);
|
||||
};
|
||||
|
||||
const handleClone = index => {
|
||||
const item = data[index];
|
||||
const cloneItem = { ...item, name: `${item?.name}_clone` };
|
||||
const cloneData = [...data];
|
||||
cloneData.splice(index + 1, 0, cloneItem);
|
||||
|
||||
setFormData(prevData => ({ ...prevData, [id]: cloneData }));
|
||||
};
|
||||
|
||||
const handleRemove = indexRemove => {
|
||||
// TODO confirmation??
|
||||
setFormData(prevData => ({
|
||||
...prevData,
|
||||
[id]: prevData[id]?.filter((_, index) => index !== indexRemove)
|
||||
}));
|
||||
};
|
||||
|
||||
const handleClose = () => setShowDialog(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
{typeof errors[id]?.message === 'string' && (
|
||||
<ErrorHelper label={errors[id]?.message} />
|
||||
)}
|
||||
{useMemo(
|
||||
() => (
|
||||
<ListComponent
|
||||
list={data}
|
||||
handleCreate={() => handleOpen()}
|
||||
itemsProps={({ index }) => ({
|
||||
handleEdit: () => handleOpen(index),
|
||||
handleClone: () => handleClone(index),
|
||||
handleRemove: () => handleRemove(index)
|
||||
})}
|
||||
/>
|
||||
),
|
||||
[data, handleOpen, handleClone, handleRemove]
|
||||
)}
|
||||
{showDialog && DialogComponent && (
|
||||
<DialogComponent
|
||||
open={showDialog}
|
||||
values={dialogFormData?.data}
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={handleClose}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
FormList.propTypes = {
|
||||
step: PropTypes.objectOf(PropTypes.any).isRequired,
|
||||
data: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
setFormData: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
FormList.defaultProps = {
|
||||
step: {},
|
||||
data: [],
|
||||
setFormData: data => data
|
||||
};
|
||||
|
||||
export default FormList;
|
@ -1,69 +0,0 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Grid } from '@material-ui/core';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
|
||||
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
|
||||
import { EmptyCard } from 'client/components/Cards';
|
||||
|
||||
function FormListSelect({ step, data, setFormData }) {
|
||||
const { errors } = useFormContext();
|
||||
const { id, multiple, preRender, list, ItemComponent } = step;
|
||||
|
||||
useEffect(() => {
|
||||
if (preRender) preRender();
|
||||
}, []);
|
||||
|
||||
const handleSelect = index =>
|
||||
setFormData(prevData => ({
|
||||
...prevData,
|
||||
[id]: multiple ? [...prevData[id], index] : [index]
|
||||
}));
|
||||
|
||||
const handleUnselect = indexRemove =>
|
||||
setFormData(prevData => ({
|
||||
...prevData,
|
||||
[id]: prevData[id]?.filter(index => index !== indexRemove)
|
||||
}));
|
||||
|
||||
return (
|
||||
<Grid container spacing={3}>
|
||||
{typeof errors[id]?.message === 'string' && (
|
||||
<Grid item xs={12}>
|
||||
<ErrorHelper label={errors[id]?.message} />
|
||||
</Grid>
|
||||
)}
|
||||
{list?.length === 0 ? (
|
||||
<Grid item xs={6} sm={4} md={3} lg={1}>
|
||||
<EmptyCard name={id} />
|
||||
</Grid>
|
||||
) : (
|
||||
list?.map((info, index) => (
|
||||
<Grid key={`${id}-${index}`} item xs={6} sm={4} md={3} lg={1}>
|
||||
<ItemComponent
|
||||
value={info}
|
||||
isSelected={data?.some(selected => selected === info?.ID)}
|
||||
handleSelect={handleSelect}
|
||||
handleUnselect={handleUnselect}
|
||||
/>
|
||||
</Grid>
|
||||
))
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
FormListSelect.propTypes = {
|
||||
step: PropTypes.objectOf(PropTypes.any).isRequired,
|
||||
data: PropTypes.arrayOf(PropTypes.any).isRequired,
|
||||
setFormData: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
FormListSelect.defaultProps = {
|
||||
step: {},
|
||||
data: [],
|
||||
setFormData: data => data
|
||||
};
|
||||
|
||||
export default FormListSelect;
|
@ -1,63 +0,0 @@
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
|
||||
import ErrorHelper from 'client/components/FormControl/ErrorHelper';
|
||||
|
||||
function FormStep({ step, data, setFormData }) {
|
||||
const { errors } = useFormContext();
|
||||
const [showDialog, setShowDialog] = useState(false);
|
||||
const { id, preRender, FormComponent, DialogComponent } = step;
|
||||
|
||||
useEffect(() => {
|
||||
if (preRender) preRender();
|
||||
}, []);
|
||||
|
||||
const handleOpen = () => setShowDialog(true);
|
||||
const handleClose = () => setShowDialog(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
{typeof errors[id]?.message === 'string' && (
|
||||
<ErrorHelper label={errors[id]?.message} />
|
||||
)}
|
||||
{useMemo(
|
||||
() => (
|
||||
<FormComponent
|
||||
id={id}
|
||||
values={data}
|
||||
setFormData={setFormData}
|
||||
handleClick={handleOpen}
|
||||
/>
|
||||
),
|
||||
[id, handleOpen, setFormData, data]
|
||||
)}
|
||||
{showDialog && DialogComponent && (
|
||||
<DialogComponent
|
||||
open={showDialog}
|
||||
values={data}
|
||||
onCancel={handleClose}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
FormStep.propTypes = {
|
||||
step: PropTypes.objectOf(PropTypes.any).isRequired,
|
||||
data: PropTypes.oneOfType([
|
||||
PropTypes.array,
|
||||
PropTypes.object,
|
||||
PropTypes.string
|
||||
]).isRequired,
|
||||
setFormData: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
FormStep.defaultProps = {
|
||||
step: {},
|
||||
data: {},
|
||||
setFormData: data => data
|
||||
};
|
||||
|
||||
export default FormStep;
|
@ -6,12 +6,13 @@ 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';
|
||||
|
||||
const FIRST_STEP = 0;
|
||||
|
||||
const FormStepper = ({ steps, initialValue, onSubmit }) => {
|
||||
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'));
|
||||
const { watch, trigger, reset } = useFormContext();
|
||||
const { watch, trigger, reset, errors } = useFormContext();
|
||||
|
||||
const [activeStep, setActiveStep] = useState(FIRST_STEP);
|
||||
const [formData, setFormData] = useState(initialValue);
|
||||
@ -73,14 +74,15 @@ const FormStepper = ({ steps, initialValue, onSubmit }) => {
|
||||
|
||||
return (
|
||||
Content && (
|
||||
<Content
|
||||
step={steps[activeStep]}
|
||||
data={formData[id]}
|
||||
setFormData={setFormData}
|
||||
/>
|
||||
<>
|
||||
{typeof errors[id]?.message === 'string' && (
|
||||
<ErrorHelper label={errors[id]?.message} />
|
||||
)}
|
||||
<Content data={formData[id]} setFormData={setFormData} />
|
||||
</>
|
||||
)
|
||||
);
|
||||
}, [steps, formData, activeStep, setFormData])}
|
||||
}, [steps, errors, formData, activeStep, setFormData])}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -90,7 +92,7 @@ FormStepper.propTypes = {
|
||||
PropTypes.shape({
|
||||
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
content: PropTypes.func.isRequired
|
||||
content: PropTypes.any.isRequired
|
||||
})
|
||||
),
|
||||
initialValue: PropTypes.objectOf(PropTypes.any),
|
||||
|
@ -42,7 +42,7 @@ function ListCards({ handleCreate, list, CardComponent, cardsProps }) {
|
||||
{Array.isArray(list) &&
|
||||
list?.map((value, index) => (
|
||||
<Grid key={`card-${index}`} item xs={12} sm={4} md={3} lg={2}>
|
||||
<CardComponent value={value} {...cardsProps({ index })} />
|
||||
<CardComponent value={value} {...cardsProps({ value, index })} />
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
|
@ -1,22 +1,19 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import FormStep from 'client/components/FormStepper/FormStep';
|
||||
import FormWithSchema from 'client/components/Forms/FormWithSchema';
|
||||
|
||||
import { FORM_FIELDS, STEP_FORM_SCHEMA } from './schema';
|
||||
|
||||
const BasicConfiguration = () => {
|
||||
const STEP_ID = 'application';
|
||||
export const STEP_ID = 'application';
|
||||
|
||||
return {
|
||||
id: STEP_ID,
|
||||
label: 'Application Overview',
|
||||
content: FormStep,
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
FormComponent: () => (
|
||||
<FormWithSchema cy="form-flow" fields={FORM_FIELDS} id={STEP_ID} />
|
||||
)
|
||||
};
|
||||
};
|
||||
const BasicConfiguration = () => ({
|
||||
id: STEP_ID,
|
||||
label: 'Application Overview',
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
content: useCallback(
|
||||
() => <FormWithSchema cy="form-flow" fields={FORM_FIELDS} id={STEP_ID} />,
|
||||
[]
|
||||
)
|
||||
});
|
||||
|
||||
export default BasicConfiguration;
|
||||
|
@ -1,28 +1,46 @@
|
||||
import { useMemo } from 'react';
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
|
||||
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 FormListSelect from 'client/components/FormStepper/FormListSelect';
|
||||
|
||||
import { STEP_FORM_SCHEMA } from './schema';
|
||||
|
||||
const Clusters = () => {
|
||||
const STEP_ID = 'clusters';
|
||||
const { clusters, getClusters } = useOpennebula();
|
||||
export const STEP_ID = 'clusters';
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
id: STEP_ID,
|
||||
label: 'Where will it run?',
|
||||
content: FormListSelect,
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
preRender: getClusters,
|
||||
list: clusters?.sort((a, b) => a.ID - b.ID),
|
||||
ItemComponent: ClusterCard
|
||||
}),
|
||||
[getClusters, clusters]
|
||||
);
|
||||
};
|
||||
const Clusters = () => ({
|
||||
id: STEP_ID,
|
||||
label: 'Where will it run?',
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
content: useCallback(({ data, setFormData }) => {
|
||||
const { clusters, getClusters } = useOpennebula();
|
||||
const { handleSelect, handleUnselect } = useListForm({
|
||||
key: STEP_ID,
|
||||
setList: setFormData
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
getClusters();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ListCards
|
||||
list={clusters}
|
||||
CardComponent={ClusterCard}
|
||||
cardsProps={({ value }) => {
|
||||
const { ID } = value;
|
||||
|
||||
return {
|
||||
isSelected: data?.some(selected => selected === ID),
|
||||
handleSelect: () => handleSelect(ID),
|
||||
handleUnselect: () => handleUnselect(ID)
|
||||
};
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}, [])
|
||||
});
|
||||
|
||||
export default Clusters;
|
||||
|
@ -1,52 +1,79 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
|
||||
import useOpennebula from 'client/hooks/useOpennebula';
|
||||
|
||||
import { DialogForm } from 'client/components/Dialogs';
|
||||
import { NetworkCard } from 'client/components/Cards';
|
||||
|
||||
import FormList from 'client/components/FormStepper/FormList';
|
||||
import useListForm from 'client/hooks/useListForm';
|
||||
import FormWithSchema from 'client/components/Forms/FormWithSchema';
|
||||
import ListCards from 'client/components/List/ListCards';
|
||||
|
||||
import { FORM_FIELDS, NETWORK_FORM_SCHEMA, STEP_FORM_SCHEMA } from './schema';
|
||||
|
||||
const Networks = () => {
|
||||
const STEP_ID = 'networking';
|
||||
const { getVNetworks, getVNetworksTemplates } = useOpennebula();
|
||||
export const STEP_ID = 'networking';
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
id: STEP_ID,
|
||||
label: 'Configure Networking',
|
||||
content: FormList,
|
||||
preRender: () => {
|
||||
getVNetworks();
|
||||
getVNetworksTemplates();
|
||||
},
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
DEFAULT_DATA: NETWORK_FORM_SCHEMA.default(),
|
||||
ListComponent: ({ list, handleCreate, itemsProps }) => (
|
||||
const Networks = () => ({
|
||||
id: STEP_ID,
|
||||
label: 'Configure Networking',
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
content: useCallback(({ data, setFormData }) => {
|
||||
const [showDialog, setShowDialog] = useState(false);
|
||||
const { getVNetworks, getVNetworksTemplates } = useOpennebula();
|
||||
const {
|
||||
editingData,
|
||||
handleSave,
|
||||
handleEdit,
|
||||
handleClone,
|
||||
handleRemove
|
||||
} = useListForm({
|
||||
key: STEP_ID,
|
||||
list: data,
|
||||
setList: setFormData,
|
||||
defaultValue: NETWORK_FORM_SCHEMA.default()
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
getVNetworks();
|
||||
getVNetworksTemplates();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListCards
|
||||
list={list}
|
||||
handleCreate={handleCreate}
|
||||
list={data}
|
||||
CardComponent={NetworkCard}
|
||||
cardsProps={itemsProps}
|
||||
handleCreate={() => {
|
||||
handleEdit();
|
||||
setShowDialog(true);
|
||||
}}
|
||||
cardsProps={({ index }) => ({
|
||||
handleEdit: () => {
|
||||
handleEdit(index);
|
||||
setShowDialog(true);
|
||||
},
|
||||
handleClone: () => handleClone(index),
|
||||
handleRemove: () => handleRemove(index)
|
||||
})}
|
||||
/>
|
||||
),
|
||||
ItemComponent: NetworkCard,
|
||||
DialogComponent: props => (
|
||||
<DialogForm
|
||||
title={'Network form'}
|
||||
resolver={NETWORK_FORM_SCHEMA}
|
||||
{...props}
|
||||
>
|
||||
<FormWithSchema cy="form-dg-network" fields={FORM_FIELDS} />
|
||||
</DialogForm>
|
||||
)
|
||||
}),
|
||||
[getVNetworks, getVNetworksTemplates]
|
||||
);
|
||||
};
|
||||
{showDialog && (
|
||||
<DialogForm
|
||||
title={'Network form'}
|
||||
resolver={NETWORK_FORM_SCHEMA}
|
||||
open={showDialog}
|
||||
values={editingData?.data}
|
||||
onSubmit={values => {
|
||||
handleSave(values);
|
||||
setShowDialog(false);
|
||||
}}
|
||||
onCancel={() => setShowDialog(false)}
|
||||
>
|
||||
<FormWithSchema cy="form-dg-network" fields={FORM_FIELDS} />
|
||||
</DialogForm>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}, [])
|
||||
});
|
||||
|
||||
export default Networks;
|
||||
|
@ -81,22 +81,15 @@ export const FORM_FIELDS = [
|
||||
},
|
||||
validation: yup
|
||||
.string()
|
||||
.when('type', {
|
||||
is: type =>
|
||||
TYPES_NETWORKS.some(
|
||||
({ value, select }) => type === value && select === SELECT.network
|
||||
),
|
||||
then: yup
|
||||
.string()
|
||||
.trim()
|
||||
.required('Network is required field'),
|
||||
otherwise: yup
|
||||
.string()
|
||||
.trim()
|
||||
.required('Network template is required field')
|
||||
})
|
||||
.required()
|
||||
.default(null)
|
||||
.trim()
|
||||
.when('type', (type, schema) =>
|
||||
TYPES_NETWORKS.some(
|
||||
({ value, select }) => type === value && select === SELECT.network
|
||||
)
|
||||
? schema.required('Network is required field')
|
||||
: schema.required('Network template is required field')
|
||||
)
|
||||
.default(undefined)
|
||||
},
|
||||
{
|
||||
name: 'extra',
|
||||
|
@ -1,22 +1,19 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import FormStep from 'client/components/FormStepper/FormStep';
|
||||
import FormWithSchema from 'client/components/Forms/FormWithSchema';
|
||||
|
||||
import { FORM_FIELDS, STEP_FORM_SCHEMA } from './schema';
|
||||
|
||||
const BasicConfiguration = () => {
|
||||
const STEP_ID = 'role';
|
||||
export const STEP_ID = 'role';
|
||||
|
||||
return {
|
||||
id: STEP_ID,
|
||||
label: 'Configuration',
|
||||
content: FormStep,
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
FormComponent: () => (
|
||||
<FormWithSchema cy="form-flow" fields={FORM_FIELDS} id={STEP_ID} />
|
||||
)
|
||||
};
|
||||
};
|
||||
const BasicConfiguration = () => ({
|
||||
id: STEP_ID,
|
||||
label: 'Configuration',
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
content: useCallback(
|
||||
() => <FormWithSchema cy="form-tier" fields={FORM_FIELDS} id={STEP_ID} />,
|
||||
[]
|
||||
)
|
||||
});
|
||||
|
||||
export default BasicConfiguration;
|
||||
|
@ -0,0 +1,44 @@
|
||||
import React, { useCallback, useContext } from 'react';
|
||||
|
||||
import useListForm from 'client/hooks/useListForm';
|
||||
import ListCards from 'client/components/List/ListCards';
|
||||
|
||||
import { STEP_ID as NETWORKING } from 'client/containers/Application/Create/Steps/Networking';
|
||||
import { Context } from 'client/containers/Application/Create/Steps/Roles';
|
||||
import { STEP_FORM_SCHEMA } from './schema';
|
||||
|
||||
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 { handleSelect, handleUnselect } = useListForm({
|
||||
key: STEP_ID,
|
||||
multiple: true,
|
||||
setList: setFormData
|
||||
});
|
||||
|
||||
console.log('list', list);
|
||||
|
||||
return (
|
||||
<ListCards
|
||||
list={list[NETWORKING]}
|
||||
CardComponent={() => <h1>hi</h1>}
|
||||
cardsProps={({ value }) => {
|
||||
const { ID } = value;
|
||||
|
||||
return {
|
||||
isSelected: data?.some(selected => selected === ID),
|
||||
handleSelect: () => handleSelect(ID),
|
||||
handleUnselect: () => handleUnselect(ID)
|
||||
};
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}, [])
|
||||
});
|
||||
|
||||
export default Networks;
|
@ -0,0 +1,6 @@
|
||||
import * as yup from 'yup';
|
||||
|
||||
export const STEP_FORM_SCHEMA = yup
|
||||
.array()
|
||||
.of(yup.string().trim())
|
||||
.default(undefined);
|
@ -1,44 +1,50 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import TemplateIcon from '@material-ui/icons/InsertDriveFileOutlined';
|
||||
import MarketplaceIcon from '@material-ui/icons/ShoppingCartOutlined';
|
||||
import DockerLogo from 'client/icons/docker';
|
||||
|
||||
import ProcessScreen from 'client/components/ProcessScreen';
|
||||
import FormStep from 'client/components/FormStepper/FormStep';
|
||||
|
||||
import ListTemplates from './List/Templates';
|
||||
import ListMarketApps from './List/MarketApps';
|
||||
import DockerFile from './List/Docker';
|
||||
import { STEP_FORM_SCHEMA } from './schema';
|
||||
|
||||
const Template = () => {
|
||||
const STEP_ID = 'template';
|
||||
const SCREENS = [
|
||||
{
|
||||
id: 'template',
|
||||
button: <TemplateIcon style={{ fontSize: 100 }} />,
|
||||
screen: ListTemplates
|
||||
},
|
||||
{
|
||||
id: 'app',
|
||||
button: <MarketplaceIcon style={{ fontSize: 100 }} />,
|
||||
screen: ListMarketApps
|
||||
},
|
||||
{
|
||||
id: 'docker',
|
||||
button: <DockerLogo width="100" height="100%" color="#066da5" />,
|
||||
screen: DockerFile
|
||||
}
|
||||
];
|
||||
export const STEP_ID = 'template';
|
||||
|
||||
return {
|
||||
id: STEP_ID,
|
||||
label: 'Template',
|
||||
content: FormStep,
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
FormComponent: props => ProcessScreen({ screens: SCREENS, ...props })
|
||||
};
|
||||
};
|
||||
const SCREENS = [
|
||||
{
|
||||
id: 'template',
|
||||
button: <TemplateIcon style={{ fontSize: 100 }} />,
|
||||
screen: ListTemplates
|
||||
},
|
||||
{
|
||||
id: 'app',
|
||||
button: <MarketplaceIcon style={{ fontSize: 100 }} />,
|
||||
screen: ListMarketApps
|
||||
},
|
||||
{
|
||||
id: 'docker',
|
||||
button: <DockerLogo width="100" height="100%" color="#066da5" />,
|
||||
screen: DockerFile
|
||||
}
|
||||
];
|
||||
|
||||
const Template = () => ({
|
||||
id: STEP_ID,
|
||||
label: 'Template',
|
||||
resolver: STEP_FORM_SCHEMA,
|
||||
content: useCallback(
|
||||
({ data, setFormData }) =>
|
||||
ProcessScreen({
|
||||
screens: SCREENS,
|
||||
id: STEP_ID,
|
||||
values: data ?? {},
|
||||
setFormData
|
||||
}),
|
||||
[]
|
||||
)
|
||||
});
|
||||
|
||||
export default Template;
|
||||
|
@ -1,61 +1,125 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import * as yup from 'yup';
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
|
||||
import * as yup from 'yup';
|
||||
import { useWatch } from 'react-hook-form';
|
||||
|
||||
import useListForm from 'client/hooks/useListForm';
|
||||
import FormStepper from 'client/components/FormStepper';
|
||||
import { DialogForm } from 'client/components/Dialogs';
|
||||
import FormList from 'client/components/FormStepper/FormList';
|
||||
import FlowWithFAB from 'client/components/Flows/FlowWithFAB';
|
||||
|
||||
import Steps from './Steps';
|
||||
|
||||
export const Context = React.createContext({});
|
||||
export const STEP_ID = 'tiers';
|
||||
|
||||
const Roles = () => {
|
||||
const STEP_ID = 'tiers';
|
||||
const { steps, defaultValues, resolvers } = Steps();
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
id: STEP_ID,
|
||||
label: 'Tier Definition',
|
||||
content: FormList,
|
||||
DEFAULT_DATA: defaultValues,
|
||||
resolver: yup
|
||||
.array()
|
||||
.of(resolvers)
|
||||
.min(1)
|
||||
.required()
|
||||
.default([]),
|
||||
ListComponent: ({ list, handleCreate }) => (
|
||||
<div>
|
||||
<button onClick={handleCreate}>Add role</button>
|
||||
<div>{JSON.stringify(list)}</div>
|
||||
</div>
|
||||
),
|
||||
DialogComponent: ({ values, onSubmit, onCancel, ...props }) => (
|
||||
<DialogForm
|
||||
title={'Role form'}
|
||||
resolver={resolvers}
|
||||
values={values}
|
||||
onCancel={onCancel}
|
||||
{...props}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%'
|
||||
}}
|
||||
>
|
||||
<FormStepper
|
||||
steps={steps}
|
||||
initialValue={values}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
return {
|
||||
id: STEP_ID,
|
||||
label: 'Tier Definition',
|
||||
DEFAULT_DATA: defaultValues,
|
||||
resolver: yup
|
||||
.array()
|
||||
.of(resolvers)
|
||||
.min(1)
|
||||
.required()
|
||||
.default([]),
|
||||
content: useCallback(({ data, setFormData }) => {
|
||||
const [showDialog, setShowDialog] = useState(false);
|
||||
const [nestedForm, setNestedForm] = useState({});
|
||||
const form = useWatch({});
|
||||
|
||||
const { editingData, handleEdit, handleSave } = useListForm({
|
||||
key: STEP_ID,
|
||||
list: data,
|
||||
setList: setFormData,
|
||||
defaultValue: defaultValues
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setNestedForm(form);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
handleEdit();
|
||||
setShowDialog(true);
|
||||
}}
|
||||
>
|
||||
Add role
|
||||
</button>
|
||||
<div>{JSON.stringify(data)}</div>
|
||||
</div>
|
||||
</DialogForm>
|
||||
)
|
||||
}),
|
||||
[]
|
||||
);
|
||||
{showDialog && (
|
||||
<Context.Provider value={{ nestedForm }}>
|
||||
<DialogForm
|
||||
open={showDialog}
|
||||
title={'Tier form'}
|
||||
resolver={resolvers}
|
||||
values={editingData.data}
|
||||
onCancel={() => setShowDialog(false)}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%'
|
||||
}}
|
||||
>
|
||||
<FormStepper
|
||||
steps={steps}
|
||||
initialValue={editingData.data}
|
||||
onSubmit={values => {
|
||||
handleSave(values);
|
||||
setShowDialog(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</DialogForm>
|
||||
</Context.Provider>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}, [])
|
||||
/* DialogComponent: ({ values, onSubmit, onCancel, ...props }) => {
|
||||
const form = useWatch({});
|
||||
const [nestedForm, setNestedForm] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
setNestedForm(form);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Context.Provider value={{ nestedForm }}>
|
||||
<DialogForm
|
||||
title={'Tier form'}
|
||||
resolver={resolvers}
|
||||
values={values}
|
||||
onCancel={onCancel}
|
||||
{...props}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%'
|
||||
}}
|
||||
>
|
||||
<FormStepper
|
||||
steps={steps}
|
||||
initialValue={values}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
</div>
|
||||
</DialogForm>
|
||||
</Context.Provider>
|
||||
); */
|
||||
};
|
||||
};
|
||||
|
||||
export default Roles;
|
||||
|
61
src/fireedge/src/public/hooks/useListForm.js
Normal file
61
src/fireedge/src/public/hooks/useListForm.js
Normal file
@ -0,0 +1,61 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
const useListSelect = ({ multiple, key, list, setList, defaultValue }) => {
|
||||
const [editingData, setEditingData] = useState({});
|
||||
|
||||
const handleSelect = index =>
|
||||
setList(prevData => ({
|
||||
...prevData,
|
||||
[key]: multiple ? [...prevData[key], index] : [index]
|
||||
}));
|
||||
|
||||
const handleUnselect = indexRemove =>
|
||||
setList(prevData => ({
|
||||
...prevData,
|
||||
[key]: prevData[key]?.filter(index => index !== indexRemove)
|
||||
}));
|
||||
|
||||
const handleSave = values => {
|
||||
setList(prevData => ({
|
||||
...prevData,
|
||||
[key]: Object.assign(prevData[key], {
|
||||
[editingData.index]: values
|
||||
})
|
||||
}));
|
||||
};
|
||||
|
||||
const handleEdit = (index = list?.length) => {
|
||||
const openData = list[index] ?? defaultValue;
|
||||
|
||||
setEditingData({ index, data: openData });
|
||||
};
|
||||
|
||||
const handleClone = index => {
|
||||
const item = list[index];
|
||||
const cloneItem = { ...item, name: `${item?.name}_clone` };
|
||||
const cloneData = [...list];
|
||||
cloneData.splice(index + 1, 0, cloneItem);
|
||||
|
||||
setList(prevData => ({ ...prevData, [key]: cloneData }));
|
||||
};
|
||||
|
||||
const handleRemove = indexRemove => {
|
||||
// TODO confirmation??
|
||||
setList(prevData => ({
|
||||
...prevData,
|
||||
[key]: prevData[key]?.filter((_, index) => index !== indexRemove)
|
||||
}));
|
||||
};
|
||||
|
||||
return {
|
||||
editingData,
|
||||
handleSelect,
|
||||
handleUnselect,
|
||||
handleSave,
|
||||
handleEdit,
|
||||
handleClone,
|
||||
handleRemove
|
||||
};
|
||||
};
|
||||
|
||||
export default useListSelect;
|
Loading…
x
Reference in New Issue
Block a user