-
- Update top level volumes
-
+ Edit top level volumes
>
@@ -163,4 +126,4 @@ const ModalVolumeEdit = (props: IModalVolumeEdit) => {
);
};
-export default ModalVolumeEdit;
+export default EditVolumeModal;
diff --git a/services/frontend/src/components/Modal/volume/General.tsx b/services/frontend/src/components/Modal/volume/General.tsx
new file mode 100644
index 0000000..d2985ae
--- /dev/null
+++ b/services/frontend/src/components/Modal/volume/General.tsx
@@ -0,0 +1,20 @@
+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 (
+
+
+
+
+ );
+};
+
+export default General;
diff --git a/services/frontend/src/components/Modal/volume/Labels.tsx b/services/frontend/src/components/Modal/volume/Labels.tsx
new file mode 100644
index 0000000..b3fbab7
--- /dev/null
+++ b/services/frontend/src/components/Modal/volume/Labels.tsx
@@ -0,0 +1,98 @@
+import { useCallback } from "react";
+import { PlusIcon } from "@heroicons/react/outline";
+import { Button, styled } from "@mui/joy";
+import { useFormikContext } from "formik";
+import Record from "../../Record";
+import { IEditServiceForm } from "../../../types";
+
+const Root = styled("div")`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+`;
+
+const Records = styled("div")`
+ display: flex;
+ flex-direction: column;
+ row-gap: ${({ theme }) => theme.spacing(1)};
+`;
+
+const AddButton = styled(Button)`
+ 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 Labels = () => {
+ const formik = useFormikContext
();
+ const { labels } = formik.values;
+
+ const handleNewLabel = useCallback(() => {
+ formik.setFieldValue(`labels[${labels.length}]`, {
+ key: "",
+ value: ""
+ });
+ }, [formik]);
+
+ const handleRemoveLabel = useCallback(
+ (index: number) => {
+ const newLabels = labels.filter(
+ (_: unknown, currentIndex: number) => currentIndex != index
+ );
+ formik.setFieldValue(`labels`, newLabels);
+ },
+ [formik]
+ );
+
+ const emptyLabels = labels && labels.length === 0 ? true : false;
+
+ return (
+
+ {!emptyLabels && (
+
+ {labels.map((_: unknown, index: number) => (
+
+ ))}
+
+ )}
+ {emptyLabels && (
+
+ This volume does not have any labels.
+
+ Click "+ New label" to add a new label.
+
+ )}
+
+
+
+ New label
+
+
+ );
+};
+
+export default Labels;
diff --git a/services/frontend/src/components/Modal/volume/form-utils.ts b/services/frontend/src/components/Modal/volume/form-utils.ts
new file mode 100644
index 0000000..da2aaf3
--- /dev/null
+++ b/services/frontend/src/components/Modal/volume/form-utils.ts
@@ -0,0 +1,95 @@
+import lodash from "lodash";
+import * as yup from "yup";
+import { IEditVolumeForm, IVolumeNodeItem } from "../../../types";
+import { checkArray } from "../../../utils/forms";
+
+export const validationSchema = yup.object({
+ entryName: yup
+ .string()
+ .max(256, "Entry name should be 256 characters or less")
+ .required("Entry name is required"),
+ volumeName: yup
+ .string()
+ .max(256, "Volume name should be 256 characters or less")
+ .required("Volume name is required"),
+ labels: yup.array(
+ yup.object({
+ key: yup.string().required("Key is required"),
+ value: yup.string().required("Value is required")
+ })
+ )
+});
+
+const initialValues: IEditVolumeForm = {
+ entryName: "unknown",
+ volumeName: "unknown",
+ labels: []
+};
+
+export const getInitialValues = (node?: IVolumeNodeItem): IEditVolumeForm => {
+ if (!node) {
+ return {
+ ...initialValues
+ };
+ }
+
+ const { canvasConfig, volumeConfig } = node;
+ const { node_name = "" } = canvasConfig;
+ const { name = "", labels } = volumeConfig;
+
+ const labels0: string[] = checkArray(labels, "labels");
+
+ return {
+ ...initialValues,
+ entryName: node_name,
+ volumeName: name,
+ labels: labels0.map((label) => {
+ const [key, value] = label.split(":");
+ return {
+ key,
+ value
+ };
+ })
+ };
+};
+
+export const getFinalValues = (
+ values: IEditVolumeForm,
+ previous?: IVolumeNodeItem
+): IVolumeNodeItem => {
+ const { labels } = values;
+
+ return lodash.merge(
+ lodash.cloneDeep(previous) || {
+ key: "volume",
+ type: "VOLUME",
+ inputs: [],
+ outputs: [],
+ config: {}
+ },
+ {
+ canvasConfig: {
+ node_name: values.entryName
+ },
+ volumeConfig: {
+ name: values.volumeName,
+ labels: labels.map((label) => `${label.key}:${label.value}`)
+ }
+ }
+ ) as any;
+};
+
+export const tabs = [
+ {
+ name: "General",
+ href: "#",
+ current: true,
+ hidden: false
+ },
+ {
+ name: "Labels",
+ href: "#",
+ current: false,
+ hidden: false
+ }
+];
diff --git a/services/frontend/src/components/Project/index.tsx b/services/frontend/src/components/Project/index.tsx
index 497a1df..f29ea34 100644
--- a/services/frontend/src/components/Project/index.tsx
+++ b/services/frontend/src/components/Project/index.tsx
@@ -9,8 +9,7 @@ import {
IServiceNodeItem,
IVolumeNodeItem,
IServiceNodePosition,
- IProject,
- INetworkTopLevel
+ IProject
} from "../../types";
import eventBus from "../../events/eventBus";
import { useMutation } from "react-query";
@@ -37,8 +36,8 @@ import ModalConfirmDelete from "../Modal/ConfirmDelete";
import ModalServiceCreate from "../Modal/Service/Create";
import ModalServiceEdit from "../Modal/Service/Edit";
import ModalNetwork from "../Modal/Network";
-import ModalVolumeCreate from "../Modal/Volume/Create";
-import ModalVolumeEdit from "../Modal/Volume/Edit";
+import CreateVolumeModal from "../Modal/volume/CreateVolumeModal";
+import EditVolumeModal from "../Modal/volume/EditVolumeModal";
import CodeEditor from "../CodeEditor";
export default function Project() {
@@ -329,7 +328,7 @@ export default function Project() {
) : null}
{showVolumesModal ? (
- setShowVolumesModal(false)}
onAddEndpoint={(values: any) => onAddEndpoint(values)}
/>
@@ -361,7 +360,7 @@ export default function Project() {
) : null}
{volumeToEdit ? (
- setVolumeToEdit(null)}
onUpdateEndpoint={(values: any) => onUpdateEndpoint(values)}
diff --git a/services/frontend/src/types/index.ts b/services/frontend/src/types/index.ts
index 2f3f875..059af69 100644
--- a/services/frontend/src/types/index.ts
+++ b/services/frontend/src/types/index.ts
@@ -377,3 +377,12 @@ export interface IEditServiceForm {
value: string;
}[];
}
+
+export interface IEditVolumeForm {
+ entryName: string;
+ volumeName: string;
+ labels: {
+ key: string;
+ value: string;
+ }[];
+}
diff --git a/services/frontend/src/utils/forms.ts b/services/frontend/src/utils/forms.ts
new file mode 100644
index 0000000..931a359
--- /dev/null
+++ b/services/frontend/src/utils/forms.ts
@@ -0,0 +1,8 @@
+export const checkArray = (array: any, name: string): T => {
+ if (!Array.isArray(array)) {
+ throw new Error(
+ `Looks like we encountered a bug. The current implementation expects "${name}" to be an array.`
+ );
+ }
+ return array as unknown as T;
+};