fix: Formik wrap instead of useFormik

pull/70/head
Artem Golub 3 years ago
parent 653ab5d8bc
commit b4b9966ee8

@ -45,7 +45,8 @@
"typescript": "^4.5.5", "typescript": "^4.5.5",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"web-vitals": "^2.1.4", "web-vitals": "^2.1.4",
"yaml": "^1.10.2" "yaml": "^1.10.2",
"yup": "^0.32.11"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",

@ -1,4 +1,6 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { ServerIcon } from "@heroicons/react/outline";
import { truncateStr } from "../../utils";
import { IServiceNodeItem, CallbackFunction } from "../../types"; import { IServiceNodeItem, CallbackFunction } from "../../types";
import eventBus from "../../events/eventBus"; import eventBus from "../../events/eventBus";
import { Popover } from "./Popover"; import { Popover } from "./Popover";
@ -52,14 +54,21 @@ export default function ServiceNode(props: INodeProps) {
}} }}
></Popover> ></Popover>
)} )}
<div className="node-label w-full py-2 px-4"> <div className="relative node-label w-full py-2 px-4">
<> <>
<div className="text-sm font-semibold overflow-x-hidden"> {node.canvasConfig.service_name && (
{node.canvasConfig.service_name} <div className="text-sm font-semibold overflow-x-hidden">
</div> {truncateStr(node.canvasConfig.service_name, 12)}
<div className="text-xs text-gray-500 overflow-x-hidden"> </div>
{node.serviceConfig.container_name} )}
</div>
{node.serviceConfig.container_name && (
<div className="text-xs text-gray-500 overflow-x-hidden">
{truncateStr(node.serviceConfig.container_name, 20)}
</div>
)}
<ServerIcon className="w-3 h-3 text-gray-600 absolute top-2 right-2" />
</> </>
</div> </div>
</div> </div>

@ -1,4 +1,6 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { DatabaseIcon } from "@heroicons/react/outline";
import { truncateStr } from "../../utils";
import { IVolumeNodeItem, CallbackFunction } from "../../types"; import { IVolumeNodeItem, CallbackFunction } from "../../types";
import eventBus from "../../events/eventBus"; import eventBus from "../../events/eventBus";
import { Popover } from "./Popover"; import { Popover } from "./Popover";
@ -52,11 +54,15 @@ export default function VolumeNode(props: INodeProps) {
}} }}
></Popover> ></Popover>
)} )}
<div className="node-label w-full py-2 px-4"> <div className="relative node-label w-full py-2 px-4">
<> <>
<div className="text-xs text-gray-500 overflow-x-hidden"> {node.volumeConfig.name && (
{node.volumeConfig.name} <div className="text-sm font-semibold overflow-x-hidden">
</div> {truncateStr(node.volumeConfig.name, 20)}
</div>
)}
<DatabaseIcon className="w-3 h-3 text-gray-600 absolute top-2 right-2" />
</> </>
</div> </div>
</div> </div>

@ -1,32 +1,11 @@
const General = (props: any) => { import TextField from "../../global/FormElements/InputField";
const { formik } = props;
const General = () => {
return ( return (
<> <>
<div className="relative pb-3 flex-auto"> <TextField label="Name" name="name" />
<div className="grid grid-cols-6 gap-4">
<div className="col-span-3">
<label
htmlFor="name"
className="block text-xs font-medium text-gray-700"
>
Name
</label>
<div className="mt-1">
<input
id="name"
name="name"
type="text"
autoComplete="none"
className="input-util"
onChange={formik.handleChange}
value={formik.values.name}
/>
</div>
</div>
</div>
</div>
</> </>
); );
}; };
export default General; export default General;

@ -1,6 +1,5 @@
const IPam = (props: any) => { const IPam = () => {
const { formik } = props;
return <></>; return <></>;
}; };
export default IPam; export default IPam;

@ -1,6 +1,5 @@
const Labels = (props: any) => { const Labels = () => {
const { formik } = props;
return <></>; return <></>;
}; };
export default Labels; export default Labels;

@ -1,5 +1,6 @@
import { useState } from "react"; import { useState } from "react";
import { useFormik } from "formik"; import { Formik } from "formik";
import * as yup from "yup";
import { XIcon } from "@heroicons/react/outline"; import { XIcon } from "@heroicons/react/outline";
import General from "./General"; import General from "./General";
import IPam from "./IPam"; import IPam from "./IPam";
@ -14,12 +15,14 @@ interface IModalNetworkProps {
const ModalNetwork = (props: IModalNetworkProps) => { const ModalNetwork = (props: IModalNetworkProps) => {
const { onHide } = props; const { onHide } = props;
const [openTab, setOpenTab] = useState("General"); const [openTab, setOpenTab] = useState("General");
const handleCreate = (values: any, formik: any) => {
const formik = useFormik({ formik.resetForm();
initialValues: { };
...topLevelNetworkConfigInitialValues() const validationSchema = yup.object({
}, name: yup
onSubmit: () => undefined .string()
.max(256, "name should be 256 characters or less")
.required("name is required")
}); });
const tabs = [ const tabs = [
{ {
@ -66,54 +69,70 @@ const ModalNetwork = (props: IModalNetworkProps) => {
</button> </button>
</div> </div>
<div> <Formik
<div className="hidden sm:block"> initialValues={{
<div className="border-b border-gray-200 px-8"> ...topLevelNetworkConfigInitialValues(),
<nav className="-mb-px flex space-x-8" aria-label="Tabs"> key: "volume",
{tabs.map((tab) => ( type: "VOLUME",
<a inputs: [],
key={tab.name} outputs: [],
href={tab.href} config: {}
className={classNames( }}
tab.name === openTab enableReinitialize={true}
? "border-indigo-500 text-indigo-600" onSubmit={(values, formik) => {
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300", handleCreate(values, formik);
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm", }}
tab.hidden ? "hidden" : "" validationSchema={validationSchema}
)} >
aria-current={tab.current ? "page" : undefined} {(formik) => (
onClick={(e) => { <>
e.preventDefault(); <div className="hidden sm:block">
setOpenTab(tab.name); <div className="border-b border-gray-200 px-8">
}} <nav className="-mb-px flex space-x-8" aria-label="Tabs">
> {tabs.map((tab) => (
{tab.name} <a
</a> key={tab.name}
))} href={tab.href}
</nav> className={classNames(
</div> tab.name === openTab
</div> ? "border-indigo-500 text-indigo-600"
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300",
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
tab.hidden ? "hidden" : ""
)}
aria-current={tab.current ? "page" : undefined}
onClick={(e) => {
e.preventDefault();
setOpenTab(tab.name);
}}
>
{tab.name}
</a>
))}
</nav>
</div>
</div>
<div className="relative px-4 py-3 flex-auto"> <div className="relative px-4 py-3 flex-auto">
<form onSubmit={formik.handleSubmit}> {openTab === "General" && <General />}
{openTab === "General" && <General formik={formik} />} {openTab === "IPam" && <IPam />}
{openTab === "IPam" && <IPam formik={formik} />} {openTab === "Labels" && <Labels />}
{openTab === "Labels" && <Labels formik={formik} />} </div>
</form>
</div>
</div>
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b"> <div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b">
<button <button
className="btn-util" className="btn-util"
type="button" type="button"
onClick={() => { onClick={() => {
formik.resetForm(); formik.submitForm();
}} }}
> >
Add Add
</button> </button>
</div> </div>
</>
)}
</Formik>
</div> </div>
</div> </div>
</div> </div>

@ -1,5 +1,6 @@
import { useState } from "react"; import { useState } from "react";
import { useFormik } from "formik"; import { Formik } from "formik";
import * as yup from "yup";
import { XIcon } from "@heroicons/react/outline"; import { XIcon } from "@heroicons/react/outline";
import General from "./General"; import General from "./General";
import Environment from "./Environment"; import Environment from "./Environment";
@ -16,22 +17,23 @@ interface IModalServiceProps {
const ModalServiceCreate = (props: IModalServiceProps) => { const ModalServiceCreate = (props: IModalServiceProps) => {
const { onHide, onAddEndpoint } = props; const { onHide, onAddEndpoint } = props;
const [openTab, setOpenTab] = useState("General"); const [openTab, setOpenTab] = useState("General");
const handleCreate = (values: any, formik: any) => {
const formik = useFormik({ onAddEndpoint(values);
initialValues: { formik.resetForm();
canvasConfig: { };
...serviceConfigCanvasInitialValues() const validationSchema = yup.object({
}, canvasConfig: yup.object({
serviceConfig: { service_name: yup
container_name: "" .string()
}, .max(256, "service name should be 256 characters or less")
key: "service", .required("service name is required")
type: "SERVICE", }),
inputs: ["op_source"], serviceConfig: yup.object({
outputs: [], container_name: yup
config: {} .string()
}, .max(256, "container name should be 256 characters or less")
onSubmit: () => undefined .required("container name is required")
})
}); });
const tabs = [ const tabs = [
{ {
@ -84,56 +86,77 @@ const ModalServiceCreate = (props: IModalServiceProps) => {
</button> </button>
</div> </div>
<div> <Formik
<div className="hidden sm:block"> initialValues={{
<div className="border-b border-gray-200 px-8"> canvasConfig: {
<nav className="-mb-px flex space-x-8" aria-label="Tabs"> ...serviceConfigCanvasInitialValues()
{tabs.map((tab) => ( },
<a serviceConfig: {
key={tab.name} container_name: ""
href={tab.href} },
className={classNames( key: "service",
tab.name === openTab type: "SERVICE",
? "border-indigo-500 text-indigo-600" inputs: ["op_source"],
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300", outputs: [],
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm", config: {}
tab.hidden ? "hidden" : "" }}
)} enableReinitialize={true}
aria-current={tab.current ? "page" : undefined} onSubmit={(values, formik) => {
onClick={(e) => { handleCreate(values, formik);
e.preventDefault(); }}
setOpenTab(tab.name); validationSchema={validationSchema}
}} >
> {(formik) => (
{tab.name} <>
</a> <div className="hidden sm:block">
))} <div className="border-b border-gray-200 px-8">
</nav> <nav className="-mb-px flex space-x-8" aria-label="Tabs">
</div> {tabs.map((tab) => (
</div> <a
key={tab.name}
href={tab.href}
className={classNames(
tab.name === openTab
? "border-indigo-500 text-indigo-600"
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300",
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
tab.hidden ? "hidden" : ""
)}
aria-current={tab.current ? "page" : undefined}
onClick={(e) => {
e.preventDefault();
setOpenTab(tab.name);
}}
>
{tab.name}
</a>
))}
</nav>
</div>
</div>
<div className="relative px-4 py-3 flex-auto"> <div className="relative px-4 py-3 flex-auto">
<form onSubmit={formik.handleSubmit}> {openTab === "General" && <General />}
{openTab === "General" && <General formik={formik} />} {openTab === "Environment" && <Environment />}
{openTab === "Environment" && <Environment formik={formik} />} {openTab === "Volumes" && <Volumes />}
{openTab === "Volumes" && <Volumes formik={formik} />} {openTab === "Labels" && <Labels />}
{openTab === "Labels" && <Labels formik={formik} />} </div>
</form>
</div>
</div>
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b"> <div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b">
<button <button
className="btn-util" className="btn-util"
type="button" type="button"
onClick={() => { onClick={() => {
onAddEndpoint(formik.values); onAddEndpoint(formik.values);
formik.resetForm(); formik.resetForm();
}} }}
> >
Add Add
</button> </button>
</div> </div>
</>
)}
</Formik>
</div> </div>
</div> </div>
</div> </div>

@ -1,17 +1,12 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useFormik } from "formik"; import { Formik } from "formik";
import * as yup from "yup";
import { XIcon } from "@heroicons/react/outline"; import { XIcon } from "@heroicons/react/outline";
import General from "./General"; import General from "./General";
import Environment from "./Environment"; import Environment from "./Environment";
import Volumes from "./Volumes"; import Volumes from "./Volumes";
import Labels from "./Labels"; import Labels from "./Labels";
import { serviceConfigCanvasInitialValues } from "../../../utils"; import { CallbackFunction, IServiceNodeItem } from "../../../types";
import {
CallbackFunction,
ICanvasConfig,
IServiceNodeItem,
IService
} from "../../../types";
interface IModalServiceProps { interface IModalServiceProps {
node: IServiceNodeItem; node: IServiceNodeItem;
@ -23,16 +18,26 @@ const ModalServiceEdit = (props: IModalServiceProps) => {
const { node, onHide, onUpdateEndpoint } = props; const { node, onHide, onUpdateEndpoint } = props;
const [openTab, setOpenTab] = useState("General"); const [openTab, setOpenTab] = useState("General");
const [selectedNode, setSelectedNode] = useState<IServiceNodeItem>(); const [selectedNode, setSelectedNode] = useState<IServiceNodeItem>();
const formik = useFormik({
initialValues: { const handleUpdate = (values: any) => {
canvasConfig: { const updated = { ...selectedNode };
...serviceConfigCanvasInitialValues() updated.canvasConfig = values.canvasConfig;
}, updated.serviceConfig = values.serviceConfig;
serviceConfig: { onUpdateEndpoint(updated);
container_name: "" };
} const validationSchema = yup.object({
}, canvasConfig: yup.object({
onSubmit: () => undefined service_name: yup
.string()
.max(256, "service name should be 256 characters or less")
.required("service name is required")
}),
serviceConfig: yup.object({
container_name: yup
.string()
.max(256, "container name should be 256 characters or less")
.required("container name is required")
})
}); });
const tabs = [ const tabs = [
{ {
@ -70,25 +75,6 @@ const ModalServiceEdit = (props: IModalServiceProps) => {
} }
}, [node]); }, [node]);
useEffect(() => {
formik.resetForm();
if (selectedNode) {
formik.initialValues.canvasConfig = {
...selectedNode.canvasConfig
} as ICanvasConfig;
formik.initialValues.serviceConfig = {
...selectedNode.serviceConfig
} as IService;
}
}, [selectedNode]);
useEffect(() => {
return () => {
formik.resetForm();
};
}, []);
return ( return (
<div className="fixed z-50 inset-0 overflow-y-auto"> <div className="fixed z-50 inset-0 overflow-y-auto">
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 outline-none focus:outline-none"> <div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 outline-none focus:outline-none">
@ -110,58 +96,76 @@ const ModalServiceEdit = (props: IModalServiceProps) => {
</button> </button>
</div> </div>
<div> {selectedNode && (
<div className="hidden sm:block"> <Formik
<div className="border-b border-gray-200 px-8"> initialValues={{
<nav className="-mb-px flex space-x-8" aria-label="Tabs"> canvasConfig: {
{tabs.map((tab) => ( ...selectedNode.canvasConfig
<a },
key={tab.name} serviceConfig: {
href={tab.href} ...selectedNode.serviceConfig
className={classNames( }
tab.name === openTab }}
? "border-indigo-500 text-indigo-600" enableReinitialize={true}
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300", onSubmit={(values) => {
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm", handleUpdate(values);
tab.hidden ? "hidden" : ""
)}
aria-current={tab.current ? "page" : undefined}
onClick={(e) => {
e.preventDefault();
setOpenTab(tab.name);
}}
>
{tab.name}
</a>
))}
</nav>
</div>
</div>
<div className="relative px-4 py-3 flex-auto">
<form onSubmit={formik.handleSubmit}>
{openTab === "General" && <General formik={formik} />}
{openTab === "Environment" && <Environment formik={formik} />}
{openTab === "Volumes" && <Volumes formik={formik} />}
{openTab === "Labels" && <Labels formik={formik} />}
</form>
</div>
</div>
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b">
<button
className="btn-util"
type="button"
onClick={() => {
const updated = { ...selectedNode };
updated.canvasConfig = formik.values.canvasConfig;
updated.serviceConfig = formik.values.serviceConfig;
onUpdateEndpoint(updated);
}} }}
validationSchema={validationSchema}
> >
Update {(formik) => (
</button> <>
</div> <div className="hidden sm:block">
<div className="border-b border-gray-200 px-8">
<nav
className="-mb-px flex space-x-8"
aria-label="Tabs"
>
{tabs.map((tab) => (
<a
key={tab.name}
href={tab.href}
className={classNames(
tab.name === openTab
? "border-indigo-500 text-indigo-600"
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300",
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
tab.hidden ? "hidden" : ""
)}
aria-current={tab.current ? "page" : undefined}
onClick={(e) => {
e.preventDefault();
setOpenTab(tab.name);
}}
>
{tab.name}
</a>
))}
</nav>
</div>
</div>
<div className="relative px-4 py-3 flex-auto">
{openTab === "General" && <General />}
{openTab === "Environment" && <Environment />}
{openTab === "Volumes" && <Volumes />}
{openTab === "Labels" && <Labels />}
</div>
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b">
<button
className="btn-util"
type="button"
onClick={() => {
formik.submitForm();
}}
>
Update
</button>
</div>
</>
)}
</Formik>
)}
</div> </div>
</div> </div>
</div> </div>

@ -1,6 +1,5 @@
const Environment = (props: any) => { const Environment = () => {
const { formik } = props;
return <></>; return <></>;
}; };
export default Environment; export default Environment;

@ -1,56 +1,12 @@
const General = (props: any) => { import TextField from "../../global/FormElements/InputField";
const { formik } = props;
const General = () => {
return ( return (
<> <>
<div className="relative pb-3 flex-auto"> <TextField label="Service name" name="canvasConfig.service_name" />
<div className="grid grid-cols-6 gap-4"> <TextField label="Container name" name="serviceConfig.container_name" />
<div className="col-span-3">
<label
htmlFor="service_name"
className="block text-xs font-medium text-gray-700"
>
Service name
</label>
<div className="mt-1">
<input
id="service_name"
name="canvasConfig.service_name"
type="text"
autoComplete="none"
className="input-util"
onChange={formik.handleChange}
value={formik.values.canvasConfig.service_name}
/>
</div>
</div>
</div>
</div>
<div className="relative pb-3 flex-auto">
<div className="grid grid-cols-6 gap-4">
<div className="col-span-3">
<label
htmlFor="container_name"
className="block text-xs font-medium text-gray-700"
>
Container name
</label>
<div className="mt-1">
<input
id="container_name"
name="serviceConfig.container_name"
type="text"
autoComplete="none"
className="input-util"
onChange={formik.handleChange}
value={formik.values.serviceConfig.container_name}
/>
</div>
</div>
</div>
</div>
</> </>
); );
}; };
export default General; export default General;

@ -1,6 +1,5 @@
const Labels = (props: any) => { const Labels = () => {
const { formik } = props;
return <></>; return <></>;
}; };
export default Labels; export default Labels;

@ -1,6 +1,5 @@
const Volumes = (props: any) => { const Volumes = () => {
const { formik } = props;
return <></>; return <></>;
}; };
export default Volumes; export default Volumes;

@ -1,5 +1,6 @@
import { useState } from "react"; import { useState } from "react";
import { useFormik } from "formik"; import { Formik } from "formik";
import * as yup from "yup";
import { XIcon } from "@heroicons/react/outline"; import { XIcon } from "@heroicons/react/outline";
import General from "./General"; import General from "./General";
import Labels from "./Labels"; import Labels from "./Labels";
@ -14,19 +15,17 @@ interface IModalVolumeCreate {
const ModalVolumeCreate = (props: IModalVolumeCreate) => { const ModalVolumeCreate = (props: IModalVolumeCreate) => {
const { onHide, onAddEndpoint } = props; const { onHide, onAddEndpoint } = props;
const [openTab, setOpenTab] = useState("General"); const [openTab, setOpenTab] = useState("General");
const handleCreate = (values: any, formik: any) => {
const formik = useFormik({ onAddEndpoint(values);
initialValues: { formik.resetForm();
volumeConfig: { };
...topLevelVolumeConfigInitialValues() const validationSchema = yup.object({
}, volumeConfig: yup.object({
key: "volume", name: yup
type: "VOLUME", .string()
inputs: [], .max(256, "name should be 256 characters or less")
outputs: [], .required("name is required")
config: {} })
},
onSubmit: () => undefined
}); });
const tabs = [ const tabs = [
{ {
@ -67,54 +66,71 @@ const ModalVolumeCreate = (props: IModalVolumeCreate) => {
</button> </button>
</div> </div>
<div> <Formik
<div className="hidden sm:block"> initialValues={{
<div className="border-b border-gray-200 px-8"> volumeConfig: {
<nav className="-mb-px flex space-x-8" aria-label="Tabs"> ...topLevelVolumeConfigInitialValues()
{tabs.map((tab) => ( },
<a key: "volume",
key={tab.name} type: "VOLUME",
href={tab.href} inputs: [],
className={classNames( outputs: [],
tab.name === openTab config: {}
? "border-indigo-500 text-indigo-600" }}
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300", enableReinitialize={true}
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm", onSubmit={(values, formik) => {
tab.hidden ? "hidden" : "" handleCreate(values, formik);
)} }}
aria-current={tab.current ? "page" : undefined} validationSchema={validationSchema}
onClick={(e) => { >
e.preventDefault(); {(formik) => (
setOpenTab(tab.name); <>
}} <div className="hidden sm:block">
> <div className="border-b border-gray-200 px-8">
{tab.name} <nav className="-mb-px flex space-x-8" aria-label="Tabs">
</a> {tabs.map((tab) => (
))} <a
</nav> key={tab.name}
</div> href={tab.href}
</div> className={classNames(
tab.name === openTab
? "border-indigo-500 text-indigo-600"
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300",
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
tab.hidden ? "hidden" : ""
)}
aria-current={tab.current ? "page" : undefined}
onClick={(e) => {
e.preventDefault();
setOpenTab(tab.name);
}}
>
{tab.name}
</a>
))}
</nav>
</div>
</div>
<div className="relative px-4 py-3 flex-auto"> <div className="relative px-4 py-3 flex-auto">
<form onSubmit={formik.handleSubmit}> {openTab === "General" && <General />}
{openTab === "General" && <General formik={formik} />} {openTab === "Labels" && <Labels />}
{openTab === "Labels" && <Labels formik={formik} />} </div>
</form>
</div>
</div>
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b"> <div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b">
<button <button
className="btn-util" className="btn-util"
type="button" type="button"
onClick={() => { onClick={() => {
onAddEndpoint(formik.values); formik.submitForm();
formik.resetForm(); }}
}} >
> Add
Add </button>
</button> </div>
</div> </>
)}
</Formik>
</div> </div>
</div> </div>
</div> </div>

@ -1,14 +1,10 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useFormik } from "formik"; import { Formik } from "formik";
import * as yup from "yup";
import { XIcon } from "@heroicons/react/outline"; import { XIcon } from "@heroicons/react/outline";
import General from "./General"; import General from "./General";
import Labels from "./Labels"; import Labels from "./Labels";
import { topLevelVolumeConfigInitialValues } from "../../../utils"; import { CallbackFunction, IVolumeNodeItem } from "../../../types";
import {
CallbackFunction,
IVolumeNodeItem,
IVolumeTopLevel
} from "../../../types";
interface IModalVolumeEdit { interface IModalVolumeEdit {
node: IVolumeNodeItem; node: IVolumeNodeItem;
@ -20,14 +16,18 @@ const ModalVolumeEdit = (props: IModalVolumeEdit) => {
const { node, onHide, onUpdateEndpoint } = props; const { node, onHide, onUpdateEndpoint } = props;
const [openTab, setOpenTab] = useState("General"); const [openTab, setOpenTab] = useState("General");
const [selectedNode, setSelectedNode] = useState<IVolumeNodeItem>(); const [selectedNode, setSelectedNode] = useState<IVolumeNodeItem>();
const handleUpdate = (values: any) => {
const formik = useFormik({ const updated = { ...selectedNode };
initialValues: { updated.volumeConfig = values.volumeConfig;
volumeConfig: { onUpdateEndpoint(updated);
...topLevelVolumeConfigInitialValues() };
} const validationSchema = yup.object({
}, volumeConfig: yup.object({
onSubmit: () => undefined name: yup
.string()
.max(256, "name should be 256 characters or less")
.required("name is required")
})
}); });
const tabs = [ const tabs = [
{ {
@ -53,22 +53,6 @@ const ModalVolumeEdit = (props: IModalVolumeEdit) => {
} }
}, [node]); }, [node]);
useEffect(() => {
formik.resetForm();
if (selectedNode) {
formik.initialValues.volumeConfig = {
...selectedNode.volumeConfig
} as IVolumeTopLevel;
}
}, [selectedNode]);
useEffect(() => {
return () => {
formik.resetForm();
};
}, []);
return ( return (
<div className="fixed z-50 inset-0 overflow-y-auto"> <div className="fixed z-50 inset-0 overflow-y-auto">
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 outline-none focus:outline-none"> <div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 outline-none focus:outline-none">
@ -92,55 +76,71 @@ const ModalVolumeEdit = (props: IModalVolumeEdit) => {
</button> </button>
</div> </div>
<div> {selectedNode && (
<div className="hidden sm:block"> <Formik
<div className="border-b border-gray-200 px-8"> initialValues={{
<nav className="-mb-px flex space-x-8" aria-label="Tabs"> volumeConfig: {
{tabs.map((tab) => ( ...selectedNode.volumeConfig
<a }
key={tab.name} }}
href={tab.href} enableReinitialize={true}
className={classNames( onSubmit={(values) => {
tab.name === openTab handleUpdate(values);
? "border-indigo-500 text-indigo-600"
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300",
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
tab.hidden ? "hidden" : ""
)}
aria-current={tab.current ? "page" : undefined}
onClick={(e) => {
e.preventDefault();
setOpenTab(tab.name);
}}
>
{tab.name}
</a>
))}
</nav>
</div>
</div>
<div className="relative px-4 py-3 flex-auto">
<form onSubmit={formik.handleSubmit}>
{openTab === "General" && <General formik={formik} />}
{openTab === "Labels" && <Labels formik={formik} />}
</form>
</div>
</div>
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b">
<button
className="btn-util"
type="button"
onClick={() => {
const updated = { ...selectedNode };
updated.volumeConfig = formik.values.volumeConfig;
onUpdateEndpoint(updated);
}} }}
validationSchema={validationSchema}
> >
Update {(formik) => (
</button> <>
</div> <div className="hidden sm:block">
<div className="border-b border-gray-200 px-8">
<nav
className="-mb-px flex space-x-8"
aria-label="Tabs"
>
{tabs.map((tab) => (
<a
key={tab.name}
href={tab.href}
className={classNames(
tab.name === openTab
? "border-indigo-500 text-indigo-600"
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300",
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
tab.hidden ? "hidden" : ""
)}
aria-current={tab.current ? "page" : undefined}
onClick={(e) => {
e.preventDefault();
setOpenTab(tab.name);
}}
>
{tab.name}
</a>
))}
</nav>
</div>
</div>
<div className="relative px-4 py-3 flex-auto">
{openTab === "General" && <General />}
{openTab === "Labels" && <Labels />}
</div>
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b">
<button
className="btn-util"
type="button"
onClick={() => {
formik.submitForm();
}}
>
Update
</button>
</div>
</>
)}
</Formik>
)}
</div> </div>
</div> </div>
</div> </div>

@ -1,32 +1,11 @@
const General = (props: any) => { import TextField from "../../global/FormElements/InputField";
const { formik } = props;
const General = () => {
return ( return (
<> <>
<div className="relative pb-3 flex-auto"> <TextField label="Name" name="volumeConfig.name" />
<div className="grid grid-cols-6 gap-4">
<div className="col-span-3">
<label
htmlFor="name"
className="block text-xs font-medium text-gray-700"
>
Name
</label>
<div className="mt-1">
<input
id="name"
name="volumeConfig.name"
type="text"
autoComplete="none"
className="input-util"
onChange={formik.handleChange}
value={formik.values.volumeConfig.name}
/>
</div>
</div>
</div>
</div>
</> </>
); );
}; };
export default General; export default General;

@ -1,6 +1,4 @@
const Labels = (props: any) => { const Labels = () => {
const { formik } = props;
return <></>; return <></>;
}; };
export default Labels; export default Labels;

@ -245,9 +245,9 @@ export default function Project() {
if (existingIndex !== -1) { if (existingIndex !== -1) {
_connections.splice(existingIndex, 1); _connections.splice(existingIndex, 1);
setConnections(_connections);
stateConnectionsRef.current = _connections;
} }
setConnections(_connections);
}; };
const onConnectionAttached = (data: any) => { const onConnectionAttached = (data: any) => {

@ -0,0 +1,50 @@
import _ from "lodash";
import { useFormikContext } from "formik";
interface Props {
name: string;
help?: string;
[key: string]: any;
}
const TextField = (props: Props) => {
const { label, name, help, ...otherProps } = props;
const formik = useFormikContext();
const error = _.get(formik.touched, name) && _.get(formik.errors, name);
return (
<div className="relative pb-3 flex-auto">
<div className="grid grid-cols-6 gap-4">
<div className="col-span-3">
<label
htmlFor={name}
className="block text-xs font-medium text-gray-700"
>
{label}
</label>
<div className="mt-1">
<input
id={name}
name={name}
type="text"
autoComplete="none"
className="input-util"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
{...otherProps}
value={_.get(formik.values, name)}
/>
{
<div className="mt-1 text-xs text-red-600">
{error && <div className="caption">{error}</div>}
{!error && help}
</div>
}
</div>
</div>
</div>
</div>
);
};
export default TextField;
Loading…
Cancel
Save