From 3aec4b7ff30c59b4db2b5cf9488518cf109f3b28 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 01:06:55 +0530 Subject: [PATCH 01/29] feat(frontend): marked entry and volume names as required in volume modal --- services/frontend/src/components/Modal/volume/General.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/Modal/volume/General.tsx b/services/frontend/src/components/Modal/volume/General.tsx index d2985ae..44855c5 100644 --- a/services/frontend/src/components/Modal/volume/General.tsx +++ b/services/frontend/src/components/Modal/volume/General.tsx @@ -11,8 +11,8 @@ const Root = styled("div")` const General = () => { return ( - - + + ); }; From c225f6ae10827ccca1a7b2ae15ef8435f454e0a2 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 01:07:59 +0530 Subject: [PATCH 02/29] refactor(frontend): renamed `Service` to `service` --- .../src/components/Modal/{Service => service}/Create.tsx | 0 .../src/components/Modal/{Service => service}/Edit.tsx | 0 .../src/components/Modal/{Service => service}/Environment.tsx | 0 .../src/components/Modal/{Service => service}/General.tsx | 0 .../src/components/Modal/{Service => service}/Labels.tsx | 0 .../src/components/Modal/{Service => service}/Volumes.tsx | 0 .../src/components/Modal/{Service => service}/form-utils.ts | 0 services/frontend/src/components/Project/index.tsx | 4 ++-- 8 files changed, 2 insertions(+), 2 deletions(-) rename services/frontend/src/components/Modal/{Service => service}/Create.tsx (100%) rename services/frontend/src/components/Modal/{Service => service}/Edit.tsx (100%) rename services/frontend/src/components/Modal/{Service => service}/Environment.tsx (100%) rename services/frontend/src/components/Modal/{Service => service}/General.tsx (100%) rename services/frontend/src/components/Modal/{Service => service}/Labels.tsx (100%) rename services/frontend/src/components/Modal/{Service => service}/Volumes.tsx (100%) rename services/frontend/src/components/Modal/{Service => service}/form-utils.ts (100%) diff --git a/services/frontend/src/components/Modal/Service/Create.tsx b/services/frontend/src/components/Modal/service/Create.tsx similarity index 100% rename from services/frontend/src/components/Modal/Service/Create.tsx rename to services/frontend/src/components/Modal/service/Create.tsx diff --git a/services/frontend/src/components/Modal/Service/Edit.tsx b/services/frontend/src/components/Modal/service/Edit.tsx similarity index 100% rename from services/frontend/src/components/Modal/Service/Edit.tsx rename to services/frontend/src/components/Modal/service/Edit.tsx diff --git a/services/frontend/src/components/Modal/Service/Environment.tsx b/services/frontend/src/components/Modal/service/Environment.tsx similarity index 100% rename from services/frontend/src/components/Modal/Service/Environment.tsx rename to services/frontend/src/components/Modal/service/Environment.tsx diff --git a/services/frontend/src/components/Modal/Service/General.tsx b/services/frontend/src/components/Modal/service/General.tsx similarity index 100% rename from services/frontend/src/components/Modal/Service/General.tsx rename to services/frontend/src/components/Modal/service/General.tsx diff --git a/services/frontend/src/components/Modal/Service/Labels.tsx b/services/frontend/src/components/Modal/service/Labels.tsx similarity index 100% rename from services/frontend/src/components/Modal/Service/Labels.tsx rename to services/frontend/src/components/Modal/service/Labels.tsx diff --git a/services/frontend/src/components/Modal/Service/Volumes.tsx b/services/frontend/src/components/Modal/service/Volumes.tsx similarity index 100% rename from services/frontend/src/components/Modal/Service/Volumes.tsx rename to services/frontend/src/components/Modal/service/Volumes.tsx diff --git a/services/frontend/src/components/Modal/Service/form-utils.ts b/services/frontend/src/components/Modal/service/form-utils.ts similarity index 100% rename from services/frontend/src/components/Modal/Service/form-utils.ts rename to services/frontend/src/components/Modal/service/form-utils.ts diff --git a/services/frontend/src/components/Project/index.tsx b/services/frontend/src/components/Project/index.tsx index dabbb8a..0eb91b4 100644 --- a/services/frontend/src/components/Project/index.tsx +++ b/services/frontend/src/components/Project/index.tsx @@ -33,8 +33,8 @@ import { generateHttp } from "../../services/generate"; import { Canvas } from "../Canvas"; import Spinner from "../global/Spinner"; import ModalConfirmDelete from "../Modal/ConfirmDelete"; -import ModalServiceCreate from "../Modal/Service/Create"; -import ModalServiceEdit from "../Modal/Service/Edit"; +import ModalServiceCreate from "../Modal/service/Create"; +import ModalServiceEdit from "../Modal/service/Edit"; import ModalNetwork from "../Modal/Network"; import CreateVolumeModal from "../Modal/volume/CreateVolumeModal"; import EditVolumeModal from "../Modal/volume/EditVolumeModal"; From 749c25784a5208873c6de121638bcf7f324be429 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 01:10:29 +0530 Subject: [PATCH 03/29] refactor(frontend): renamed `Network` to `network` --- .../src/components/Modal/{Network => network}/Create.tsx | 0 .../frontend/src/components/Modal/{Network => network}/Edit.tsx | 0 .../src/components/Modal/{Network => network}/General.tsx | 0 .../frontend/src/components/Modal/{Network => network}/IPam.tsx | 0 .../src/components/Modal/{Network => network}/Labels.tsx | 0 .../src/components/Modal/{Network => network}/index.tsx | 0 services/frontend/src/components/Project/index.tsx | 2 +- 7 files changed, 1 insertion(+), 1 deletion(-) rename services/frontend/src/components/Modal/{Network => network}/Create.tsx (100%) rename services/frontend/src/components/Modal/{Network => network}/Edit.tsx (100%) rename services/frontend/src/components/Modal/{Network => network}/General.tsx (100%) rename services/frontend/src/components/Modal/{Network => network}/IPam.tsx (100%) rename services/frontend/src/components/Modal/{Network => network}/Labels.tsx (100%) rename services/frontend/src/components/Modal/{Network => network}/index.tsx (100%) diff --git a/services/frontend/src/components/Modal/Network/Create.tsx b/services/frontend/src/components/Modal/network/Create.tsx similarity index 100% rename from services/frontend/src/components/Modal/Network/Create.tsx rename to services/frontend/src/components/Modal/network/Create.tsx diff --git a/services/frontend/src/components/Modal/Network/Edit.tsx b/services/frontend/src/components/Modal/network/Edit.tsx similarity index 100% rename from services/frontend/src/components/Modal/Network/Edit.tsx rename to services/frontend/src/components/Modal/network/Edit.tsx diff --git a/services/frontend/src/components/Modal/Network/General.tsx b/services/frontend/src/components/Modal/network/General.tsx similarity index 100% rename from services/frontend/src/components/Modal/Network/General.tsx rename to services/frontend/src/components/Modal/network/General.tsx diff --git a/services/frontend/src/components/Modal/Network/IPam.tsx b/services/frontend/src/components/Modal/network/IPam.tsx similarity index 100% rename from services/frontend/src/components/Modal/Network/IPam.tsx rename to services/frontend/src/components/Modal/network/IPam.tsx diff --git a/services/frontend/src/components/Modal/Network/Labels.tsx b/services/frontend/src/components/Modal/network/Labels.tsx similarity index 100% rename from services/frontend/src/components/Modal/Network/Labels.tsx rename to services/frontend/src/components/Modal/network/Labels.tsx diff --git a/services/frontend/src/components/Modal/Network/index.tsx b/services/frontend/src/components/Modal/network/index.tsx similarity index 100% rename from services/frontend/src/components/Modal/Network/index.tsx rename to services/frontend/src/components/Modal/network/index.tsx diff --git a/services/frontend/src/components/Project/index.tsx b/services/frontend/src/components/Project/index.tsx index 0eb91b4..c79e207 100644 --- a/services/frontend/src/components/Project/index.tsx +++ b/services/frontend/src/components/Project/index.tsx @@ -35,7 +35,7 @@ import Spinner from "../global/Spinner"; import ModalConfirmDelete from "../Modal/ConfirmDelete"; import ModalServiceCreate from "../Modal/service/Create"; import ModalServiceEdit from "../Modal/service/Edit"; -import ModalNetwork from "../Modal/Network"; +import ModalNetwork from "../Modal/network"; import CreateVolumeModal from "../Modal/volume/CreateVolumeModal"; import EditVolumeModal from "../Modal/volume/EditVolumeModal"; import CodeEditor from "../CodeEditor"; From e45d3c434f038ccdac9bd3af2de306e4d34af48b Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 01:12:09 +0530 Subject: [PATCH 04/29] refactor(frontend): renamed `NetworkCreate` to `CreateNetworkModal` --- .../Modal/network/{Create.tsx => CreateNetworkModal.tsx} | 4 ++-- services/frontend/src/components/Modal/network/index.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename services/frontend/src/components/Modal/network/{Create.tsx => CreateNetworkModal.tsx} (97%) diff --git a/services/frontend/src/components/Modal/network/Create.tsx b/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx similarity index 97% rename from services/frontend/src/components/Modal/network/Create.tsx rename to services/frontend/src/components/Modal/network/CreateNetworkModal.tsx index df9aac3..1da5b5a 100644 --- a/services/frontend/src/components/Modal/network/Create.tsx +++ b/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx @@ -14,7 +14,7 @@ interface INetworkCreateProps { onCreateNetwork: CallbackFunction; } -const NetworkCreate = (props: INetworkCreateProps) => { +const CreateNetworkModal = (props: INetworkCreateProps) => { const { onCreateNetwork } = props; const [openTab, setOpenTab] = useState("General"); const handleCreate = (values: any, formik: any) => { @@ -130,4 +130,4 @@ const NetworkCreate = (props: INetworkCreateProps) => { ); }; -export default NetworkCreate; +export default CreateNetworkModal; diff --git a/services/frontend/src/components/Modal/network/index.tsx b/services/frontend/src/components/Modal/network/index.tsx index 43fb0ea..706d24f 100644 --- a/services/frontend/src/components/Modal/network/index.tsx +++ b/services/frontend/src/components/Modal/network/index.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; import { XIcon } from "@heroicons/react/outline"; -import NetworkCreate from "./Create"; +import CreateNetworkModal from "./CreateNetworkModal"; import { CallbackFunction } from "../../../types"; import NetworkEdit from "./Edit"; import { attachUUID } from "../../../utils"; @@ -98,7 +98,7 @@ const ModalNetwork = (props: IModalNetworkProps) => { )} {!selectedNetwork && ( - + )} {selectedNetwork && ( From 07f56a4211135866b93440175044622d0ffa4a7c Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 01:13:24 +0530 Subject: [PATCH 05/29] refactor(frontend): renamed `NetworkEdit` to `EditNetworkModal` --- .../Modal/network/{Edit.tsx => EditNetworkModal.tsx} | 6 +++--- services/frontend/src/components/Modal/network/index.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename services/frontend/src/components/Modal/network/{Edit.tsx => EditNetworkModal.tsx} (96%) diff --git a/services/frontend/src/components/Modal/network/Edit.tsx b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx similarity index 96% rename from services/frontend/src/components/Modal/network/Edit.tsx rename to services/frontend/src/components/Modal/network/EditNetworkModal.tsx index 40cafa8..1ee9632 100644 --- a/services/frontend/src/components/Modal/network/Edit.tsx +++ b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx @@ -11,13 +11,13 @@ import { INetworkTopLevel } from "../../../types"; -interface INetworkEditProps { +interface IEditNetworkModalProps { onUpdateNetwork: CallbackFunction; onDeleteNetwork: CallbackFunction; network: any; } -const NetworkEdit = (props: INetworkEditProps) => { +const EditNetworkModal = (props: IEditNetworkModalProps) => { const { onUpdateNetwork, onDeleteNetwork, network } = props; const [openTab, setOpenTab] = useState("General"); const handleUpdate = (values: any) => { @@ -141,4 +141,4 @@ const NetworkEdit = (props: INetworkEditProps) => { ); }; -export default NetworkEdit; +export default EditNetworkModal; diff --git a/services/frontend/src/components/Modal/network/index.tsx b/services/frontend/src/components/Modal/network/index.tsx index 706d24f..f531cfe 100644 --- a/services/frontend/src/components/Modal/network/index.tsx +++ b/services/frontend/src/components/Modal/network/index.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { XIcon } from "@heroicons/react/outline"; import CreateNetworkModal from "./CreateNetworkModal"; import { CallbackFunction } from "../../../types"; -import NetworkEdit from "./Edit"; +import EditNetworkModal from "./EditNetworkModal"; import { attachUUID } from "../../../utils"; interface IModalNetworkProps { @@ -102,7 +102,7 @@ const ModalNetwork = (props: IModalNetworkProps) => { )} {selectedNetwork && ( - Date: Wed, 27 Jul 2022 16:17:24 +0530 Subject: [PATCH 06/29] feat(frontend): created `classNames` utility --- services/frontend/src/utils/styles.tsx | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 services/frontend/src/utils/styles.tsx diff --git a/services/frontend/src/utils/styles.tsx b/services/frontend/src/utils/styles.tsx new file mode 100644 index 0000000..1d73932 --- /dev/null +++ b/services/frontend/src/utils/styles.tsx @@ -0,0 +1,3 @@ +export const classNames = (...classes: string[]) => { + return classes.filter(Boolean).join(" "); +}; From 241d16c16def8fb614be9fd0c3b57f45f57214e9 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 16:18:09 +0530 Subject: [PATCH 07/29] feat(frontend): created `IEditNetworkForm` and `INetworkNodeItem` interfaces --- services/frontend/src/types/index.ts | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/services/frontend/src/types/index.ts b/services/frontend/src/types/index.ts index 059af69..76db33c 100644 --- a/services/frontend/src/types/index.ts +++ b/services/frontend/src/types/index.ts @@ -328,6 +328,12 @@ export interface IVolumeNodeItem extends INodeItem { volumeConfig: Partial; } +export interface INetworkNodeItem extends INodeItem { + outputs: string[]; + canvasConfig: ICanvasConfig; + networkConfig: Partial; +} + export interface IProjectPayload { name: string; data: { @@ -386,3 +392,26 @@ export interface IEditVolumeForm { value: string; }[]; } + +export interface IEditNetworkForm { + entryName: string; + networkName: string; + driver: string; + configurations: { + subnet: string; + ipRange: string; + gateway: string; + auxAddresses: { + hostName: string; + ipAddress: string; + }[]; + }[]; + options: { + key: string; + value: string; + }[]; + labels: { + key: string; + value: string; + }[]; +} From 7e2a2ff8457435917dcf23cfd704bff402627088 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 16:18:59 +0530 Subject: [PATCH 08/29] feat(frontend): created network form utils --- .../components/Modal/network/form-utils.ts | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 services/frontend/src/components/Modal/network/form-utils.ts diff --git a/services/frontend/src/components/Modal/network/form-utils.ts b/services/frontend/src/components/Modal/network/form-utils.ts new file mode 100644 index 0000000..1498b87 --- /dev/null +++ b/services/frontend/src/components/Modal/network/form-utils.ts @@ -0,0 +1,128 @@ +import lodash from "lodash"; +import * as yup from "yup"; +import { IEditNetworkForm, INetworkNodeItem } from "../../../types"; + +export const validationSchema = yup.object({ + entryName: yup + .string() + .max(256, "Entry name should be 256 characters or less") + .required("Entry name is required"), + + networkName: yup + .string() + .max(256, "Network name should be 256 characters or less") + .required("Network name is required"), + + driver: yup + .string() + .max(256, "Driver should be 256 characters or less") + .default("default"), + + configurations: yup.array( + yup.object({ + subnet: yup.string(), + ipRange: yup.string(), + gateway: yup.string(), + auxAddresses: yup.array( + yup.object({ + hostName: yup.string().required("Host name is required"), + ipAddress: yup.string().required("IP address is required") + }) + ) + }) + ), + + options: yup.array( + yup.object({ + key: yup.string().required("Key is required"), + value: yup.string().required("Value is required") + }) + ), + + labels: yup.array( + yup.object({ + key: yup.string().required("Key is required"), + value: yup.string().required("Value is required") + }) + ) +}); + +export const tabs = [ + { + name: "General", + href: "#", + current: true, + hidden: false + }, + { + name: "IPAM", + href: "#", + current: false, + hidden: false + }, + { + name: "Labels", + href: "#", + current: false, + hidden: false + } +]; + +export const initialValues: IEditNetworkForm = { + entryName: "unknown", + networkName: "unknown", + driver: "default", + configurations: [], + options: [], + labels: [] +}; + +export const getInitialValues = (node?: INetworkNodeItem): IEditNetworkForm => { + if (!node) { + return { + ...initialValues + }; + } + + const { canvasConfig, networkConfig } = node; + const { node_name = "" } = canvasConfig; + const { name = "", ipam } = networkConfig; + + return { + ...initialValues, + entryName: node_name, + networkName: name, + options: Object.keys(ipam?.options || {}).map((key) => { + if (!ipam) { + throw new Error("Control should not reach here."); + } + return { + key, + value: ipam.options[key].toString() + }; + }) + }; +}; + +export const getFinalValues = ( + values: IEditNetworkForm, + previous?: INetworkNodeItem +): INetworkNodeItem => { + return lodash.merge( + lodash.cloneDeep(previous) || { + key: "network", + type: "NETWORK", + inputs: [], + outputs: [], + config: {} + }, + { + canvasConfig: { + node_name: values.entryName + }, + networkConfig: { + name: values.networkName + } + } + ) as any; +}; From 76aa3cdd29fe8c7c224cbcb67e40fb2a6edc3e08 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 16:19:36 +0530 Subject: [PATCH 09/29] feat(frontend): updated network modal title --- services/frontend/src/components/Modal/network/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/frontend/src/components/Modal/network/index.tsx b/services/frontend/src/components/Modal/network/index.tsx index f531cfe..8c416d9 100644 --- a/services/frontend/src/components/Modal/network/index.tsx +++ b/services/frontend/src/components/Modal/network/index.tsx @@ -57,7 +57,7 @@ const ModalNetwork = (props: IModalNetworkProps) => {
-

Top level networks

+

Add top level network

From 2ad70f44850f821a53eae26ba872f47502ce8a83 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 16:20:38 +0530 Subject: [PATCH 11/29] feat(frontend): updated general form to use updated form shape --- services/frontend/src/components/Modal/network/General.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/Modal/network/General.tsx b/services/frontend/src/components/Modal/network/General.tsx index 12490db..68f7277 100644 --- a/services/frontend/src/components/Modal/network/General.tsx +++ b/services/frontend/src/components/Modal/network/General.tsx @@ -3,8 +3,8 @@ import TextField from "../../global/FormElements/TextField"; const General = () => { return ( <> - - + + ); }; From f42461cf268c2cdd6204ccd3c4027071978a2bca Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 16:21:22 +0530 Subject: [PATCH 12/29] feat(frontend): created `Records` component --- services/frontend/src/components/Records.tsx | 128 +++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 services/frontend/src/components/Records.tsx diff --git a/services/frontend/src/components/Records.tsx b/services/frontend/src/components/Records.tsx new file mode 100644 index 0000000..1f7b6e7 --- /dev/null +++ b/services/frontend/src/components/Records.tsx @@ -0,0 +1,128 @@ +import { Button, styled } from "@mui/joy"; +import { Fragment, FunctionComponent, ReactElement, useCallback } from "react"; +import { PlusIcon } from "@heroicons/react/outline"; +import Record, { IFieldType } from "./Record"; +import { useFormikContext } from "formik"; +import lodash from "lodash"; + +export interface IRecordsProps { + modal: string; + title: string; + referred: string; + name: string; + fields: (index: number) => IFieldType[]; + newValue: any; + renderLayout?: (elements: ReactElement[]) => ReactElement; + renderField?: (element: ReactElement, field: IFieldType) => ReactElement; + renderRemove?: (element: ReactElement) => ReactElement; + renderBorder?: () => ReactElement; +} + +const Group = styled("div")` + display: flex; + flex-direction: column; + align-items: center; +`; + +const GroupTitle = styled("h5")` + font-size: 0.75rem; + color: #374151; + font-weight: 500; + width: 100%; + text-align: left; +`; + +const RecordList = styled("div")` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: ${({ theme }) => theme.spacing(1)}; + margin-top: ${({ theme }) => theme.spacing(1)}; + width: 100%; +`; + +const AddButton = styled(Button)` + min-width: 140px; + margin-top: ${({ theme }) => theme.spacing(2)}; +`; + +const Description = styled("p")` + margin-top: ${({ theme }) => theme.spacing(2)}; + text-align: center; + color: #7a7a7a; + font-size: 14px; +`; + +const Records: FunctionComponent = ( + props: IRecordsProps +): ReactElement => { + const { + modal, + title, + referred, + name, + fields, + newValue, + renderLayout, + renderField, + renderRemove, + renderBorder + } = props; + + const formik = useFormikContext(); + const items = lodash.get(formik.values, name); + + const handleNew = useCallback(() => { + formik.setFieldValue(`${name}[${items.length}]`, newValue); + }, [formik]); + + const handleRemove = useCallback( + (index: number) => { + const newOptions = items.filter( + (_: unknown, currentIndex: number) => currentIndex != index + ); + formik.setFieldValue(name, newOptions); + }, + [formik] + ); + + const empty = items && items.length === 0; + + return ( + + {title} + {!empty && ( + + {items.map((_: unknown, index: number) => ( + + + {renderBorder && renderBorder()} + + ))} + + )} + {empty && ( + + This {modal} does not have any {referred}. +
+ Click "+ New {referred}" to add a new {referred}. +
+ )} + + + + New {referred} + +
+ ); +}; + +export default Records; From cbeea12114d807a7a25f233d1a809f91ae45954d Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 16:22:46 +0530 Subject: [PATCH 13/29] feat(frontend): added new capabilities to `Record` component * Added `records` type and extended `options` to accept `IRecordProps`. * Added `renderLayout`, `renderField`, and `renderRemove` props. --- services/frontend/src/components/Record.tsx | 114 ++++++++++++++------ 1 file changed, 83 insertions(+), 31 deletions(-) diff --git a/services/frontend/src/components/Record.tsx b/services/frontend/src/components/Record.tsx index b273fe7..058ef80 100644 --- a/services/frontend/src/components/Record.tsx +++ b/services/frontend/src/components/Record.tsx @@ -1,25 +1,38 @@ -import { Fragment, FunctionComponent, ReactElement, useCallback } from "react"; +import { + Fragment, + FunctionComponent, + ReactElement, + useCallback, + useMemo +} from "react"; import { styled } from "@mui/joy"; import IconButton from "@mui/joy/IconButton"; import { MinusSmIcon } from "@heroicons/react/solid"; import TextField from "./global/FormElements/TextField"; import Toggle from "./global/FormElements/Toggle"; +import Records, { IRecordsProps } from "./Records"; export interface IFieldType { name: string; - placeholder: string; + placeholder?: string; required?: boolean; - type: "text" | "toggle"; - options?: { - text: string; - value: string; - }[]; + type: "text" | "toggle" | "records"; + options?: + | { + text: string; + value: string; + }[] + | IRecordsProps; } export interface IRecordProps { fields: IFieldType[]; index: number; onRemove: (index: number) => void; + direction?: "column" | "row"; + renderLayout?: (elements: ReactElement[]) => ReactElement; + renderField?: (element: ReactElement, field: IFieldType) => ReactElement; + renderRemove?: (element: ReactElement) => ReactElement; } const Root = styled("div")` @@ -28,6 +41,8 @@ const Root = styled("div")` justify-content: flex-start; align-items: flex-start; column-gap: ${({ theme }) => theme.spacing(2)}; + width: 100%; + @media (max-width: 768px) { column-gap: ${({ theme }) => theme.spacing(1)}; } @@ -38,37 +53,74 @@ const RemoveButton = styled(IconButton)``; const Record: FunctionComponent = ( props: IRecordProps ): ReactElement => { - const { fields, index, onRemove } = props; + const { fields, index, onRemove, renderLayout, renderField, renderRemove } = + props; const handleRemove = useCallback(() => { onRemove(index); }, [index, onRemove]); + const renderLayoutWrapper = useMemo( + () => renderLayout || ((elements: ReactElement[]) => <>{elements}), + [renderLayout] + ); + + const renderFieldWrapper = useMemo( + () => renderField || ((element: ReactElement) => element), + [renderField] + ); + + const renderRemoveWrapper = useMemo( + () => renderRemove || ((element: ReactElement) => element), + [renderRemove] + ); + return ( - {fields.map(({ type, name, placeholder, required, options }) => ( - - {type === "text" && ( - - )} - {type === "toggle" && ( - - )} - - ))} - - - + {renderLayoutWrapper( + fields.map((field) => ( + + {renderFieldWrapper( + <> + {field.type === "text" && ( + + )} + {field.type === "toggle" && ( + + )} + {field.type === "records" && ( + + )} + , + field + )} + + )) + )} + {renderRemoveWrapper( + + + + )} ); }; From cd4ed9b98ee22d9da445cc49cff18095064480ae Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 16:24:40 +0530 Subject: [PATCH 14/29] feat(frontend): implemented IPAM form --- .../src/components/Modal/network/IPam.tsx | 159 +++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/services/frontend/src/components/Modal/network/IPam.tsx b/services/frontend/src/components/Modal/network/IPam.tsx index 2ea3f71..6fd4105 100644 --- a/services/frontend/src/components/Modal/network/IPam.tsx +++ b/services/frontend/src/components/Modal/network/IPam.tsx @@ -1,5 +1,162 @@ +import { styled } from "@mui/joy"; +import { ReactElement } from "react"; + +import TextField from "../../global/FormElements/TextField"; +import { IFieldType } from "../../Record"; +import Records from "../../Records"; + +const Fields = styled("div")` + display: flex; + flex-direction: column; + row-gap: ${({ theme }) => theme.spacing(1)}; + width: 100%; +`; + +const Field = styled("div")` + width: 100%; +`; + +const Remove = styled("div")` + margin-top: ${({ theme }) => theme.spacing(2)}; +`; + +const Configuration = styled("div")` + display: flex; + flex-direction: column; + row-gap: ${({ theme }) => theme.spacing(1)}; + padding-left: ${({ theme }) => theme.spacing(4)}; +`; + +const ConfigurationTop = styled("div")` + display: flex; + flex-direction: row; + column-gap: ${({ theme }) => theme.spacing(1)}; +`; + +const ConfigurationBorder = styled("div")` + border-bottom: dotted 1px black; + height: 1px; + width: 40px; + margin: 8px 0px 0px 0px; +`; + const IPam = () => { - return <>; + return ( + + + + [ + { + name: `configurations[${index}].subnet`, + label: "Subnet", + type: "text" + }, + { + name: `configurations[${index}].ipRange`, + label: "IP Range", + type: "text" + }, + { + name: `configurations[${index}].gateway`, + label: "Gateway", + type: "text" + }, + { + name: `configurations[${index}].auxAddresses`, + type: "records", + // TODO: Remove placeholder from the main object. + placeholder: "", + options: { + name: `configurations[${index}].auxAddresses`, + modal: "configuration", + title: "Aux addresses", + referred: "aux address", + fields: (index2: number) => [ + { + name: `configurations[${index}].auxAddresses[${index2}].hostName`, + label: "Host name", + type: "text" + }, + { + name: `configurations[${index}].auxAddresses[${index2}].ipAddress`, + label: "IP address", + type: "text" + } + ], + newValue: { + hostName: "", + ipAddress: "" + }, + renderField: (element: ReactElement): ReactElement => ( + {element} + ), + renderRemove: (element: ReactElement): ReactElement => ( + {element} + ) + } + } + ]} + newValue={{ + subnet: "", + ipRange: "", + gateway: "", + auxAddresses: [] + }} + renderLayout={(elements: ReactElement[]): ReactElement => ( + + + {elements[0]} + {elements[1]} + {elements[2]} + + {elements[3]} + + )} + renderField={( + element: ReactElement, + field: IFieldType + ): ReactElement => ( + + {element} + + )} + renderRemove={(element: ReactElement): ReactElement => ( + {element} + )} + renderBorder={() => } + /> + + [ + { + name: `options[${index}].key`, + placeholder: "Key", + required: true, + type: "text" + }, + { + name: `options[${index}].value`, + placeholder: "Value", + required: true, + type: "text" + } + ]} + newValue={{ key: "", value: "" }} + renderField={(element: ReactElement): ReactElement => ( + {element} + )} + /> + + ); }; export default IPam; From f2be93951f17f2b385d5e5daa224582a95da804c Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Wed, 27 Jul 2022 16:24:55 +0530 Subject: [PATCH 15/29] feat(frontend): implemented labels form for network modal --- .../src/components/Modal/network/Labels.tsx | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/Modal/network/Labels.tsx b/services/frontend/src/components/Modal/network/Labels.tsx index 12d9e27..55479ed 100644 --- a/services/frontend/src/components/Modal/network/Labels.tsx +++ b/services/frontend/src/components/Modal/network/Labels.tsx @@ -1,5 +1,39 @@ -const Labels = () => { - return <>; +import { styled } from "@mui/joy"; +import { FunctionComponent, ReactElement } from "react"; +import Records from "../../Records"; + +const Root = styled("div")` + display: flex; + flex-direction: column; + align-items: center; +`; + +const Labels: FunctionComponent = (): ReactElement => { + return ( + + [ + { + name: `labels[${index}].key`, + placeholder: "Key", + required: true, + type: "text" + }, + { + name: `labels[${index}].value`, + placeholder: "Value", + required: true, + type: "text" + } + ]} + newValue={{ key: "", value: "" }} + /> + + ); }; export default Labels; From 6c59f6e18e0d892e6a41f5eb76f528325e7c1f9e Mon Sep 17 00:00:00 2001 From: corpulent Date: Thu, 28 Jul 2022 14:47:31 +0300 Subject: [PATCH 16/29] fix: creating and updating a network --- .../Modal/network/CreateNetworkModal.tsx | 8 +-- .../Modal/network/EditNetworkModal.tsx | 64 ++----------------- .../src/components/Modal/network/IPam.tsx | 2 +- .../components/Modal/network/form-utils.ts | 16 ++++- .../src/components/Modal/network/index.tsx | 11 ++-- 5 files changed, 29 insertions(+), 72 deletions(-) diff --git a/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx b/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx index 9c04127..31b2e7b 100644 --- a/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx +++ b/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx @@ -16,19 +16,13 @@ const CreateNetworkModal: FunctionComponent = ( ): ReactElement => { const { onCreateNetwork } = props; const [openTab, setOpenTab] = useState("General"); - - const handleCreate = (values: any, formik: any) => { - onCreateNetwork(values); - formik.resetForm(); - }; - const initialValues = useMemo(() => getInitialValues(), []); return ( {(formik) => ( diff --git a/services/frontend/src/components/Modal/network/EditNetworkModal.tsx b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx index 1ee9632..5891435 100644 --- a/services/frontend/src/components/Modal/network/EditNetworkModal.tsx +++ b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx @@ -1,15 +1,11 @@ -import { useState } from "react"; +import { useMemo, useState } from "react"; import { Formik } from "formik"; -import * as yup from "yup"; import { TrashIcon } from "@heroicons/react/outline"; import General from "./General"; import IPam from "./IPam"; import Labels from "./Labels"; -import { - CallbackFunction, - ICanvasConfig, - INetworkTopLevel -} from "../../../types"; +import { CallbackFunction } from "../../../types"; +import { getInitialValues, tabs, validationSchema } from "./form-utils"; interface IEditNetworkModalProps { onUpdateNetwork: CallbackFunction; @@ -20,64 +16,16 @@ interface IEditNetworkModalProps { const EditNetworkModal = (props: IEditNetworkModalProps) => { const { onUpdateNetwork, onDeleteNetwork, network } = props; const [openTab, setOpenTab] = useState("General"); - const handleUpdate = (values: any) => { - const updated = { ...network }; - updated.canvasConfig = values.canvasConfig; - updated.networkConfig = values.networkConfig; - onUpdateNetwork(updated); - }; - const validationSchema = yup.object({ - canvasConfig: yup.object({ - node_name: yup - .string() - .max(256, "network name should be 256 characters or less") - .required("network name is required") - }), - networkConfig: yup.object({ - name: yup - .string() - .max(256, "name should be 256 characters or less") - .required("name is required") - }) - }); - const tabs = [ - { - name: "General", - href: "#", - current: true, - hidden: false - }, - { - name: "Ipam", - href: "#", - current: false, - hidden: false - }, - { - name: "Labels", - href: "#", - current: false, - hidden: false - } - ]; const classNames = (...classes: string[]) => { return classes.filter(Boolean).join(" "); }; + const initialValues = useMemo(() => getInitialValues(network), [network]); return ( { - handleUpdate(values); - }} + onSubmit={onUpdateNetwork} validationSchema={validationSchema} > {(formik) => ( diff --git a/services/frontend/src/components/Modal/network/IPam.tsx b/services/frontend/src/components/Modal/network/IPam.tsx index 6fd4105..b28f2dc 100644 --- a/services/frontend/src/components/Modal/network/IPam.tsx +++ b/services/frontend/src/components/Modal/network/IPam.tsx @@ -1,5 +1,5 @@ -import { styled } from "@mui/joy"; import { ReactElement } from "react"; +import { styled } from "@mui/joy"; import TextField from "../../global/FormElements/TextField"; import { IFieldType } from "../../Record"; diff --git a/services/frontend/src/components/Modal/network/form-utils.ts b/services/frontend/src/components/Modal/network/form-utils.ts index 1498b87..86e403e 100644 --- a/services/frontend/src/components/Modal/network/form-utils.ts +++ b/services/frontend/src/components/Modal/network/form-utils.ts @@ -1,6 +1,7 @@ import lodash from "lodash"; import * as yup from "yup"; import { IEditNetworkForm, INetworkNodeItem } from "../../../types"; +import { checkArray } from "../../../utils/forms"; export const validationSchema = yup.object({ entryName: yup @@ -86,7 +87,8 @@ export const getInitialValues = (node?: INetworkNodeItem): IEditNetworkForm => { const { canvasConfig, networkConfig } = node; const { node_name = "" } = canvasConfig; - const { name = "", ipam } = networkConfig; + const { name = "", ipam, labels } = networkConfig; + const labels0: string[] = checkArray(labels, "labels"); return { ...initialValues, @@ -100,6 +102,13 @@ export const getInitialValues = (node?: INetworkNodeItem): IEditNetworkForm => { key, value: ipam.options[key].toString() }; + }), + labels: labels0.map((label) => { + const [key, value] = label.split(":"); + return { + key, + value + }; }) }; }; @@ -108,6 +117,8 @@ export const getFinalValues = ( values: IEditNetworkForm, previous?: INetworkNodeItem ): INetworkNodeItem => { + const { labels } = values; + return lodash.merge( lodash.cloneDeep(previous) || { key: "network", @@ -121,7 +132,8 @@ export const getFinalValues = ( node_name: values.entryName }, networkConfig: { - name: values.networkName + name: values.networkName, + labels: labels.map((label) => `${label.key}:${label.value}`) } } ) as any; diff --git a/services/frontend/src/components/Modal/network/index.tsx b/services/frontend/src/components/Modal/network/index.tsx index 8c416d9..f6a2698 100644 --- a/services/frontend/src/components/Modal/network/index.tsx +++ b/services/frontend/src/components/Modal/network/index.tsx @@ -4,6 +4,7 @@ import CreateNetworkModal from "./CreateNetworkModal"; import { CallbackFunction } from "../../../types"; import EditNetworkModal from "./EditNetworkModal"; import { attachUUID } from "../../../utils"; +import { getFinalValues } from "./form-utils"; interface IModalNetworkProps { networks: Record; @@ -23,17 +24,19 @@ const ModalNetwork = (props: IModalNetworkProps) => { } = props; const [selectedNetwork, setSelectedNetwork] = useState(); const handleCreate = (values: any) => { - const uniqueKey = attachUUID(values.key); + const finalValues = getFinalValues(values); + const uniqueKey = attachUUID(finalValues.key); const network = { - ...values, + ...finalValues, key: uniqueKey }; onCreateNetwork(network); setSelectedNetwork(network); }; const handleUpdate = (values: any) => { - onUpdateNetwork(values); - setSelectedNetwork(values); + const finalValues = getFinalValues(values, selectedNetwork); + onUpdateNetwork(finalValues); + setSelectedNetwork(finalValues); }; const handleDelete = () => { onDeleteNetwork(selectedNetwork.key); From 5f3a319c3656916852e11198c21e0ebbf286f4bb Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Thu, 28 Jul 2022 21:44:16 +0530 Subject: [PATCH 17/29] feat(frontend): created `EmptyNetworks` component --- .../Modal/network/EmptyNetworks.tsx | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 services/frontend/src/components/Modal/network/EmptyNetworks.tsx diff --git a/services/frontend/src/components/Modal/network/EmptyNetworks.tsx b/services/frontend/src/components/Modal/network/EmptyNetworks.tsx new file mode 100644 index 0000000..2cfa597 --- /dev/null +++ b/services/frontend/src/components/Modal/network/EmptyNetworks.tsx @@ -0,0 +1,43 @@ +import { Button, styled } from "@mui/joy"; +import { FunctionComponent, ReactElement } from "react"; + +const Root = styled("div")` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: ${({ theme }) => theme.spacing(2, 5, 5, 5)}; + text-align: center; +`; + +const Image = styled("img")` + width: 300px; + height: auto; +`; + +const CreateNew = styled(Button)` + margin-top: ${({ theme }) => theme.spacing(1)}; +`; + +export interface IEmptyNetworksProps { + onCreate: () => void; +} + +const EmptyNetworks: FunctionComponent = ( + props: IEmptyNetworksProps +): ReactElement => { + const { onCreate } = props; + return ( + + +

+ We tried our best, but could not find any networks. +

+ + Create new network + +
+ ); +}; + +export default EmptyNetworks; From 8264d6cac869766c3f73c3714d6e5d2730f4d33c Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Thu, 28 Jul 2022 22:27:42 +0530 Subject: [PATCH 18/29] feat(frontend): updated management networks modal title --- services/frontend/src/components/Project/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/frontend/src/components/Project/index.tsx b/services/frontend/src/components/Project/index.tsx index c79e207..9825055 100644 --- a/services/frontend/src/components/Project/index.tsx +++ b/services/frontend/src/components/Project/index.tsx @@ -489,7 +489,7 @@ export default function Project() { onClick={() => setShowNetworksModal(true)} > - Add Network + Networks
From 6930cda7bd49aca43b6c8b1d14c0788809cb26f1 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Thu, 28 Jul 2022 22:29:19 +0530 Subject: [PATCH 19/29] fix(frontend): fixed incorrect tab identifier in edit network modal --- .../src/components/Modal/network/EditNetworkModal.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/services/frontend/src/components/Modal/network/EditNetworkModal.tsx b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx index 5891435..82f18d9 100644 --- a/services/frontend/src/components/Modal/network/EditNetworkModal.tsx +++ b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx @@ -6,6 +6,7 @@ import IPam from "./IPam"; import Labels from "./Labels"; import { CallbackFunction } from "../../../types"; import { getInitialValues, tabs, validationSchema } from "./form-utils"; +import { classNames } from "../../../utils/styles"; interface IEditNetworkModalProps { onUpdateNetwork: CallbackFunction; @@ -16,9 +17,6 @@ interface IEditNetworkModalProps { const EditNetworkModal = (props: IEditNetworkModalProps) => { const { onUpdateNetwork, onDeleteNetwork, network } = props; const [openTab, setOpenTab] = useState("General"); - const classNames = (...classes: string[]) => { - return classes.filter(Boolean).join(" "); - }; const initialValues = useMemo(() => getInitialValues(network), [network]); return ( @@ -60,7 +58,7 @@ const EditNetworkModal = (props: IEditNetworkModalProps) => {
{openTab === "General" && } - {openTab === "IPam" && } + {openTab === "IPAM" && } {openTab === "Labels" && }
From 3c23e902e9490c5eadfbe04a7e05dfe202d1cd7b Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Fri, 29 Jul 2022 11:10:37 +0530 Subject: [PATCH 20/29] fix(frontend): fixed `getInitialValues` and `getFinalValues` to work with IPAM and labels correctly --- .../components/Modal/network/form-utils.ts | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/services/frontend/src/components/Modal/network/form-utils.ts b/services/frontend/src/components/Modal/network/form-utils.ts index 86e403e..54762f0 100644 --- a/services/frontend/src/components/Modal/network/form-utils.ts +++ b/services/frontend/src/components/Modal/network/form-utils.ts @@ -1,7 +1,6 @@ import lodash from "lodash"; import * as yup from "yup"; import { IEditNetworkForm, INetworkNodeItem } from "../../../types"; -import { checkArray } from "../../../utils/forms"; export const validationSchema = yup.object({ entryName: yup @@ -88,12 +87,24 @@ export const getInitialValues = (node?: INetworkNodeItem): IEditNetworkForm => { const { canvasConfig, networkConfig } = node; const { node_name = "" } = canvasConfig; const { name = "", ipam, labels } = networkConfig; - const labels0: string[] = checkArray(labels, "labels"); return { ...initialValues, entryName: node_name, networkName: name, + driver: ipam?.driver ?? "", + configurations: + ipam?.config.map((item) => ({ + subnet: item.subnet, + ipRange: item.ip_range, + gateway: item.gateway, + auxAddresses: Object.entries(item.aux_addresses).map( + ([hostName, ipAddress]) => ({ + hostName, + ipAddress + }) + ) + })) ?? [], options: Object.keys(ipam?.options || {}).map((key) => { if (!ipam) { throw new Error("Control should not reach here."); @@ -103,13 +114,10 @@ export const getInitialValues = (node?: INetworkNodeItem): IEditNetworkForm => { value: ipam.options[key].toString() }; }), - labels: labels0.map((label) => { - const [key, value] = label.split(":"); - return { - key, - value - }; - }) + labels: Object.entries(labels as any).map(([key, value]: any) => ({ + key, + value + })) }; }; @@ -117,7 +125,7 @@ export const getFinalValues = ( values: IEditNetworkForm, previous?: INetworkNodeItem ): INetworkNodeItem => { - const { labels } = values; + const { labels, driver, configurations, options } = values; return lodash.merge( lodash.cloneDeep(previous) || { @@ -133,7 +141,26 @@ export const getFinalValues = ( }, networkConfig: { name: values.networkName, - labels: labels.map((label) => `${label.key}:${label.value}`) + ipam: { + driver, + config: configurations.map((configuration) => ({ + subnet: configuration.subnet, + ip_range: configuration.ipRange, + gateway: configuration.gateway, + aux_addresses: Object.fromEntries( + configuration.auxAddresses.map((auxAddress) => [ + auxAddress.hostName, + auxAddress.ipAddress + ]) + ) + })), + options: Object.fromEntries( + options.map((option) => [option.key, option.value]) + ) + }, + labels: Object.fromEntries( + labels.map((label) => [label.key, label.value]) + ) } } ) as any; From dcc8b5700485f9cffc01410eb815089423913a40 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Fri, 29 Jul 2022 11:11:03 +0530 Subject: [PATCH 21/29] feat(frontend): created `NetworkList` component --- .../components/Modal/network/NetworkList.tsx | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 services/frontend/src/components/Modal/network/NetworkList.tsx diff --git a/services/frontend/src/components/Modal/network/NetworkList.tsx b/services/frontend/src/components/Modal/network/NetworkList.tsx new file mode 100644 index 0000000..7c56ff9 --- /dev/null +++ b/services/frontend/src/components/Modal/network/NetworkList.tsx @@ -0,0 +1,104 @@ +import { MinusSmIcon, PlusSmIcon } from "@heroicons/react/outline"; +import { Button, styled } from "@mui/joy"; +import IconButton from "@mui/joy/IconButton"; +import { FunctionComponent, ReactElement } from "react"; + +export interface INetworkListProps { + networks: Record; + selectedUuid: string; + onEdit: (networkUuid: string) => void; + onNew: () => void; + onRemove: (networkUuid: string) => void; +} + +interface IListItemProps { + selected: boolean; +} + +const Root = styled("div")` + padding: ${({ theme }) => theme.spacing(0)}; + display: flex; + flex-direction: column; + justify-content: space-between; + border-right: solid #eaeaea 1px; + margin: ${({ theme }) => theme.spacing(1, 2, 1, 0)}; +`; + +const Top = styled("div")` + display: flex; + flex-direction: column; +`; + +const Bottom = styled("div")` + padding: ${({ theme }) => theme.spacing(1, 2)}; +`; + +const ListItem = styled("div")` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + column-gap: ${({ theme }) => theme.spacing(2)}; + padding: ${({ theme }) => theme.spacing(1, 2)}; + cursor: pointer; + background-color: ${({ selected }) => selected && "#f5f5f5"}; + + &:hover { + background-color: #f5f5f5; + } +`; + +const ListItemText = styled("h5")` + font-weight: 400; + font-size: 14px; +`; + +const RemoveButton = styled(IconButton)` + width: 24px; + max-height: 16px; +`; + +const NetworkList: FunctionComponent = ( + props: INetworkListProps +): ReactElement => { + const { onNew, onRemove, onEdit, networks, selectedUuid } = props; + + const handleEdit = (networkUuid: string) => () => onEdit(networkUuid); + + const handleRemove = (networkUuid: string) => () => onRemove(networkUuid); + + return ( + + + {Object.keys(networks).map((networkUuid: string) => ( + + + {networks[networkUuid].canvasConfig.node_name} + + + + + + ))} + + + + + + + ); +}; + +export default NetworkList; From 420ccdd2f3616b784436f9bc241f6b8a9a35550f Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Fri, 29 Jul 2022 11:17:22 +0530 Subject: [PATCH 22/29] feat(frontend): removed delete button from `EditNetworkModal` component --- .../components/Modal/network/EditNetworkModal.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/services/frontend/src/components/Modal/network/EditNetworkModal.tsx b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx index 82f18d9..56e2756 100644 --- a/services/frontend/src/components/Modal/network/EditNetworkModal.tsx +++ b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx @@ -1,6 +1,5 @@ import { useMemo, useState } from "react"; import { Formik } from "formik"; -import { TrashIcon } from "@heroicons/react/outline"; import General from "./General"; import IPam from "./IPam"; import Labels from "./Labels"; @@ -10,12 +9,11 @@ import { classNames } from "../../../utils/styles"; interface IEditNetworkModalProps { onUpdateNetwork: CallbackFunction; - onDeleteNetwork: CallbackFunction; network: any; } const EditNetworkModal = (props: IEditNetworkModalProps) => { - const { onUpdateNetwork, onDeleteNetwork, network } = props; + const { onUpdateNetwork, network } = props; const [openTab, setOpenTab] = useState("General"); const initialValues = useMemo(() => getInitialValues(network), [network]); @@ -63,14 +61,6 @@ const EditNetworkModal = (props: IEditNetworkModalProps) => {
- -
- {networks && Object.keys(networks).length > 0 && ( -
- + {networkKeys.length === 0 && !showCreate && ( + + )} - {selectedNetwork && ( - + {(networkKeys.length > 0 || showCreate) && ( + + {networkKeys.length > 0 && ( + )} -
- )} - {!selectedNetwork && ( - - )} + + {!selectedNetwork && ( + + )} - {selectedNetwork && ( - + {selectedNetwork && ( + + )} + + )} From 58aba1da61c939f8c452d41e4521cabdaad413eb Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Fri, 29 Jul 2022 11:20:21 +0530 Subject: [PATCH 24/29] feat(frontend): updated spacing in general tab of network modal --- .../frontend/src/components/Modal/network/General.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/Modal/network/General.tsx b/services/frontend/src/components/Modal/network/General.tsx index 68f7277..04e9bcd 100644 --- a/services/frontend/src/components/Modal/network/General.tsx +++ b/services/frontend/src/components/Modal/network/General.tsx @@ -1,11 +1,18 @@ +import { styled } from "@mui/joy"; import TextField from "../../global/FormElements/TextField"; +const Root = styled("div")` + display: flex; + flex-direction: column; + row-gap: ${({ theme }) => theme.spacing(1)}; +`; + const General = () => { return ( - <> + - + ); }; From 70ef1e13a73cc2bf298632f8299b2e7b6d04ca38 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Fri, 29 Jul 2022 11:27:07 +0530 Subject: [PATCH 25/29] feat(frontend): updated submit button UI in create network modal --- .../Modal/network/CreateNetworkModal.tsx | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx b/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx index 31b2e7b..586b3ca 100644 --- a/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx +++ b/services/frontend/src/components/Modal/network/CreateNetworkModal.tsx @@ -6,11 +6,20 @@ import Labels from "./Labels"; import { CallbackFunction } from "../../../types"; import { getInitialValues, tabs, validationSchema } from "./form-utils"; import { classNames } from "../../../utils/styles"; +import { Button, styled } from "@mui/joy"; interface ICreateNetworkModalProps { onCreateNetwork: CallbackFunction; } +const Actions = styled("div")` + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + padding: ${({ theme }) => theme.spacing(1)}; +`; + const CreateNetworkModal: FunctionComponent = ( props: ICreateNetworkModalProps ): ReactElement => { @@ -61,15 +70,11 @@ const CreateNetworkModal: FunctionComponent = ( {openTab === "Labels" && } -
- -
+ + + )} From 2e2349f6aba050f44e3ad0f781486f62a63e7204 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Fri, 29 Jul 2022 11:27:19 +0530 Subject: [PATCH 26/29] feat(frontend): updated submit button UI in edit network modal --- .../Modal/network/EditNetworkModal.tsx | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/services/frontend/src/components/Modal/network/EditNetworkModal.tsx b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx index 56e2756..734dc07 100644 --- a/services/frontend/src/components/Modal/network/EditNetworkModal.tsx +++ b/services/frontend/src/components/Modal/network/EditNetworkModal.tsx @@ -6,12 +6,21 @@ import Labels from "./Labels"; import { CallbackFunction } from "../../../types"; import { getInitialValues, tabs, validationSchema } from "./form-utils"; import { classNames } from "../../../utils/styles"; +import { Button, styled } from "@mui/joy"; interface IEditNetworkModalProps { onUpdateNetwork: CallbackFunction; network: any; } +const Actions = styled("div")` + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + padding: ${({ theme }) => theme.spacing(1)}; +`; + const EditNetworkModal = (props: IEditNetworkModalProps) => { const { onUpdateNetwork, network } = props; const [openTab, setOpenTab] = useState("General"); @@ -60,17 +69,11 @@ const EditNetworkModal = (props: IEditNetworkModalProps) => { {openTab === "Labels" && } -
- -
+ + + )} From 46d03d809ad38aba57884600c66186c8294115c3 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Fri, 29 Jul 2022 11:30:05 +0530 Subject: [PATCH 27/29] fix(frontend): fixed logic for generating final values for network forms * Previously, final values were generated by merging with previous state. This caused unexpected overwriting of values. Therefore, we do not merge states anymore. --- .../components/Modal/network/form-utils.ts | 62 +++++++++---------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/services/frontend/src/components/Modal/network/form-utils.ts b/services/frontend/src/components/Modal/network/form-utils.ts index 54762f0..66c9e4e 100644 --- a/services/frontend/src/components/Modal/network/form-utils.ts +++ b/services/frontend/src/components/Modal/network/form-utils.ts @@ -127,41 +127,37 @@ export const getFinalValues = ( ): INetworkNodeItem => { const { labels, driver, configurations, options } = values; - return lodash.merge( - lodash.cloneDeep(previous) || { - key: "network", - type: "NETWORK", - inputs: [], - outputs: [], - config: {} + return { + key: "network", + type: "NETWORK", + inputs: previous?.inputs ?? [], + outputs: previous?.outputs ?? [], + config: (previous as any)?.config ?? {}, + canvasConfig: { + node_name: values.entryName }, - { - canvasConfig: { - node_name: values.entryName - }, - networkConfig: { - name: values.networkName, - ipam: { - driver, - config: configurations.map((configuration) => ({ - subnet: configuration.subnet, - ip_range: configuration.ipRange, - gateway: configuration.gateway, - aux_addresses: Object.fromEntries( - configuration.auxAddresses.map((auxAddress) => [ - auxAddress.hostName, - auxAddress.ipAddress - ]) - ) - })), - options: Object.fromEntries( - options.map((option) => [option.key, option.value]) + networkConfig: { + name: values.networkName, + ipam: { + driver, + config: configurations.map((configuration) => ({ + subnet: configuration.subnet, + ip_range: configuration.ipRange, + gateway: configuration.gateway, + aux_addresses: Object.fromEntries( + configuration.auxAddresses.map((auxAddress) => [ + auxAddress.hostName, + auxAddress.ipAddress + ]) ) - }, - labels: Object.fromEntries( - labels.map((label) => [label.key, label.value]) + })), + options: Object.fromEntries( + options.map((option) => [option.key, option.value]) ) - } + }, + labels: Object.fromEntries( + labels.map((label) => [label.key, label.value]) + ) } - ) as any; + } as any; }; From 29ed43ce9f64c332bb87bab7662df425b62df3d7 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Fri, 29 Jul 2022 11:54:47 +0530 Subject: [PATCH 28/29] feat(frontend): removed default values such as 'unknown' and 'unnamed' --- .../src/components/Modal/network/form-utils.ts | 4 ++-- .../frontend/src/components/Modal/volume/form-utils.ts | 4 ++-- services/frontend/src/utils/index.ts | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/services/frontend/src/components/Modal/network/form-utils.ts b/services/frontend/src/components/Modal/network/form-utils.ts index 66c9e4e..4cb8f70 100644 --- a/services/frontend/src/components/Modal/network/form-utils.ts +++ b/services/frontend/src/components/Modal/network/form-utils.ts @@ -69,8 +69,8 @@ export const tabs = [ ]; export const initialValues: IEditNetworkForm = { - entryName: "unknown", - networkName: "unknown", + entryName: "", + networkName: "", driver: "default", configurations: [], options: [], diff --git a/services/frontend/src/components/Modal/volume/form-utils.ts b/services/frontend/src/components/Modal/volume/form-utils.ts index ba451f4..8b986bc 100644 --- a/services/frontend/src/components/Modal/volume/form-utils.ts +++ b/services/frontend/src/components/Modal/volume/form-utils.ts @@ -20,8 +20,8 @@ export const validationSchema = yup.object({ }); const initialValues: IEditVolumeForm = { - entryName: "unknown", - volumeName: "unknown", + entryName: "", + volumeName: "", labels: [] }; diff --git a/services/frontend/src/utils/index.ts b/services/frontend/src/utils/index.ts index 718bbe6..4971958 100644 --- a/services/frontend/src/utils/index.ts +++ b/services/frontend/src/utils/index.ts @@ -191,33 +191,33 @@ export const getNodeKeyFromConnectionId = (uuid: string) => { export const topLevelVolumeConfigInitialValues = (): Partial => { return { - name: "unnamed" + name: "" }; }; export const topLevelNetworkConfigInitialValues = (): Partial => { return { - name: "unnamed" + name: "" }; }; export const volumeConfigCanvasInitialValues = (): ICanvasConfig => { return { - node_name: "unnamed", + node_name: "", node_icon: "" }; }; export const networkConfigCanvasInitialValues = (): ICanvasConfig => { return { - node_name: "unnamed" + node_name: "" }; }; export const serviceConfigCanvasInitialValues = (): ICanvasConfig => { return { - node_name: "unnamed", + node_name: "", node_icon: "" }; }; From 5f94c1ec6269934e3bebd53be2d2f406ee5397c1 Mon Sep 17 00:00:00 2001 From: Samuel Rowe Date: Fri, 29 Jul 2022 11:56:04 +0530 Subject: [PATCH 29/29] refactor(frontend): removed unnecessary utility functions --- services/frontend/src/utils/index.ts | 43 +--------------------------- 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/services/frontend/src/utils/index.ts b/services/frontend/src/utils/index.ts index 4971958..830c3cd 100644 --- a/services/frontend/src/utils/index.ts +++ b/services/frontend/src/utils/index.ts @@ -11,14 +11,7 @@ import { values } from "lodash"; import { LOCAL_STORAGE } from "../constants"; -import { - IServiceNodeItem, - INodeLibraryItem, - INodeGroup, - ICanvasConfig, - INetworkTopLevel, - IVolumeTopLevel -} from "../types"; +import { IServiceNodeItem, INodeLibraryItem, INodeGroup } from "../types"; export function ensure( argument: T | undefined | null, @@ -188,40 +181,6 @@ export const getNodeKeyFromConnectionId = (uuid: string) => { return key; }; -export const topLevelVolumeConfigInitialValues = - (): Partial => { - return { - name: "" - }; - }; - -export const topLevelNetworkConfigInitialValues = - (): Partial => { - return { - name: "" - }; - }; - -export const volumeConfigCanvasInitialValues = (): ICanvasConfig => { - return { - node_name: "", - node_icon: "" - }; -}; - -export const networkConfigCanvasInitialValues = (): ICanvasConfig => { - return { - node_name: "" - }; -}; - -export const serviceConfigCanvasInitialValues = (): ICanvasConfig => { - return { - node_name: "", - node_icon: "" - }; -}; - export const toaster = (message: string, type: string) => { const toastConfig = { duration: 3000,