From b1e5e4fd194cf30df26bb8175f678a82db200d3c Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Wed, 10 May 2023 21:18:29 -0300 Subject: [PATCH] formated all code inside the src folder --- src/frontend/src/App.css | 50 +- .../components/parameterComponent/index.tsx | 4 +- .../src/CustomNodes/GenericNode/index.tsx | 378 ++++++++-------- .../components/singleAlertComponent/index.tsx | 286 ++++++------ .../src/alerts/alertDropDown/index.tsx | 106 ++--- .../alerts/hooks/useOnClickOutside/index.ts | 50 +- .../components/CrashErrorComponent/index.tsx | 12 +- .../ExtraSidebarComponent/index.tsx | 230 +++++----- .../LightTooltipComponent/index.tsx | 28 +- .../src/components/TooltipComponent/index.tsx | 12 +- .../chatComponent/chatMessage/index.tsx | 19 +- .../chatComponent/chatTrigger/index.tsx | 70 +-- .../src/components/chatComponent/index.tsx | 44 +- .../components/dropdownComponent/index.tsx | 166 +++---- .../src/components/floatComponent/index.tsx | 53 ++- .../src/components/inputComponent/index.tsx | 158 +++---- .../components/inputFileComponent/index.tsx | 16 +- .../components/inputListComponent/index.tsx | 116 +++-- .../src/components/intComponent/index.tsx | 19 +- .../src/components/loadingComponent/index.tsx | 43 +- .../components/textAreaComponent/index.tsx | 79 ++-- .../src/components/toggleComponent/index.tsx | 145 +++--- src/frontend/src/contexts/alertContext.tsx | 109 ++--- src/frontend/src/contexts/darkContext.tsx | 8 +- src/frontend/src/contexts/locationContext.tsx | 4 +- src/frontend/src/contexts/popUpContext.tsx | 32 +- src/frontend/src/contexts/tabsContext.tsx | 408 ++++++++--------- src/frontend/src/contexts/typesContext.tsx | 30 +- src/frontend/src/controllers/API/index.ts | 36 +- src/frontend/src/index.css | 20 +- src/frontend/src/index.tsx | 3 +- src/frontend/src/modals/NodeModal/index.tsx | 61 +-- .../src/modals/chatModal/chatInput/index.tsx | 4 +- .../chatModal/chatMessage/codeBlock/index.tsx | 139 +++--- .../modals/chatModal/chatMessage/index.tsx | 43 +- .../modals/chatModal/fileComponent/index.tsx | 5 +- .../src/modals/codeAreaModal/index.tsx | 4 +- src/frontend/src/modals/exportModal/index.tsx | 334 +++++++------- src/frontend/src/modals/importModal/index.tsx | 426 +++++++++--------- src/frontend/src/modals/promptModal/index.tsx | 3 +- .../src/modals/textAreaModal/index.tsx | 217 +++++---- .../ConnectionLineComponent/index.tsx | 8 +- .../components/DisclosureComponent/index.tsx | 7 +- .../extraSidebarComponent/index.tsx | 87 ++-- .../components/tabComponent/index.tsx | 16 +- .../components/tabsManagerComponent/index.tsx | 4 +- src/frontend/src/pages/FlowPage/index.tsx | 292 ++++++------ src/frontend/src/reportWebVitals.ts | 18 +- src/frontend/src/svg.d.ts | 4 +- src/frontend/src/types/alerts/index.ts | 36 +- src/frontend/src/types/api/index.ts | 46 +- src/frontend/src/types/chat/index.ts | 8 +- src/frontend/src/types/components/index.ts | 118 ++--- src/frontend/src/types/entities/index.ts | 8 +- src/frontend/src/types/flow/index.ts | 24 +- src/frontend/src/types/tabs/index.ts | 29 +- .../src/types/templatesContext/index.ts | 5 +- src/frontend/src/types/typesContext/index.ts | 9 +- src/frontend/src/utils.ts | 110 ++--- 59 files changed, 2468 insertions(+), 2331 deletions(-) diff --git a/src/frontend/src/App.css b/src/frontend/src/App.css index 319e2ba39..be7173d7f 100644 --- a/src/frontend/src/App.css +++ b/src/frontend/src/App.css @@ -3,45 +3,45 @@ @tailwind utilities; .App { - text-align: center; + text-align: center; } .App-logo { - height: 40vmin; - pointer-events: none; + height: 40vmin; + pointer-events: none; } @media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } + .App-logo { + animation: App-logo-spin infinite 20s linear; + } } .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; } .App-link { - color: #61dafb; + color: #61dafb; } @keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } -@font-face{ - font-family: text-security-disc; - src: url("assets/text-security-disc.woff") format("woff"); -} \ No newline at end of file +@font-face { + font-family: text-security-disc; + src: url("assets/text-security-disc.woff") format("woff"); +} diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx index 1a2eeb9e6..c79904661 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx @@ -198,7 +198,9 @@ export default function ParameterComponent({ save(); }} /> - ):(<>)} + ) : ( + <> + )} ); diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index cc6738dcb..8af96387c 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -1,10 +1,5 @@ import { Cog6ToothIcon, TrashIcon } from "@heroicons/react/24/outline"; -import { - classNames, - nodeColors, - nodeIcons, - toNormalCase, -} from "../../utils"; +import { classNames, nodeColors, nodeIcons, toNormalCase } from "../../utils"; import ParameterComponent from "./components/parameterComponent"; import { typesContext } from "../../contexts/typesContext"; import { useContext, useState, useEffect, useRef } from "react"; @@ -16,149 +11,148 @@ import { useCallback } from "react"; import { TabsContext } from "../../contexts/tabsContext"; import { debounce } from "../../utils"; export default function GenericNode({ - data, - selected, + data, + selected, }: { - data: NodeDataType; - selected: boolean; + data: NodeDataType; + selected: boolean; }) { - const { setErrorData } = useContext(alertContext); - const showError = useRef(true); - const { types, deleteNode } = useContext(typesContext); - const { openPopUp } = useContext(PopUpContext); - const Icon = nodeIcons[types[data.type]]; - const [validationStatus, setValidationStatus] = useState("idle"); - // State for outline color - const [isValid, setIsValid] = useState(false); - const { save } = useContext(TabsContext); - const { reactFlowInstance } = useContext(typesContext); - const [params, setParams] = useState([]); + const { setErrorData } = useContext(alertContext); + const showError = useRef(true); + const { types, deleteNode } = useContext(typesContext); + const { openPopUp } = useContext(PopUpContext); + const Icon = nodeIcons[types[data.type]]; + const [validationStatus, setValidationStatus] = useState("idle"); + // State for outline color + const [isValid, setIsValid] = useState(false); + const { save } = useContext(TabsContext); + const { reactFlowInstance } = useContext(typesContext); + const [params, setParams] = useState([]); + useEffect(() => { + if (reactFlowInstance) { + setParams(Object.values(reactFlowInstance.toObject())); + } + }, [save]); - useEffect(() => { - if (reactFlowInstance) { - setParams(Object.values(reactFlowInstance.toObject())); - } - }, [save]); + const validateNode = useCallback( + debounce(async () => { + try { + const response = await fetch(`/validate/node/${data.id}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(reactFlowInstance.toObject()), + }); - const validateNode = useCallback( - debounce(async () => { - try { - const response = await fetch(`/validate/node/${data.id}`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(reactFlowInstance.toObject()), - }); + if (response.status === 200) { + setValidationStatus("success"); + } else if (response.status === 500) { + setValidationStatus("error"); + } + } catch (error) { + // console.error("Error validating node:", error); + setValidationStatus("error"); + } + }, 1000), // Adjust the debounce delay (500ms) as needed + [reactFlowInstance, data.id] + ); + useEffect(() => { + if (params.length > 0) { + validateNode(); + } + }, [params, validateNode]); - if (response.status === 200) { - setValidationStatus("success"); - } else if (response.status === 500) { - setValidationStatus("error"); - } - } catch (error) { - // console.error("Error validating node:", error); - setValidationStatus("error"); - } - }, 1000), // Adjust the debounce delay (500ms) as needed - [reactFlowInstance, data.id] - ); - useEffect(() => { - if (params.length > 0) { - validateNode(); - } - }, [params, validateNode]); + useEffect(() => { + if (validationStatus === "success") { + setIsValid(true); + } else { + setIsValid(false); + } + }, [validationStatus]); - useEffect(() => { - if (validationStatus === "success") { - setIsValid(true); - } else { - setIsValid(false); - } - }, [validationStatus]); + if (!Icon) { + if (showError.current) { + setErrorData({ + title: data.type + ? `The ${data.type} node could not be rendered, please review your json file` + : "There was a node that can't be rendered, please review your json file", + }); + showError.current = false; + } + deleteNode(data.id); + return; + } - if (!Icon) { - if (showError.current) { - setErrorData({ - title: data.type - ? `The ${data.type} node could not be rendered, please review your json file` - : "There was a node that can't be rendered, please review your json file", - }); - showError.current = false; - } - deleteNode(data.id); - return; - } + return ( +
+
+
+ +
{data.type}
+
+
+ + +
+
- return ( -
-
-
- -
{data.type}
-
-
- - -
-
+
+
+ {data.node.description} +
-
-
- {data.node.description} -
- - <> - {Object.keys(data.node.template) - .filter((t) => t.charAt(0) !== "_") - .map((t: string, idx) => ( -
- {/* {idx === 0 ? ( + <> + {Object.keys(data.node.template) + .filter((t) => t.charAt(0) !== "_") + .map((t: string, idx) => ( +
+ {/* {idx === 0 ? (
)} */} - {data.node.template[t].show && - !data.node.template[t].advanced ? ( - - ) : ( - <> - )} -
- ))} -
- {" "} -
- {/*
+ {data.node.template[t].show && + !data.node.template[t].advanced ? ( + + ) : ( + <> + )} +
+ ))} +
+ {" "} +
+ {/*
Output
*/} - - -
-
- ); + + +
+
+ ); } diff --git a/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx b/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx index d9428a34b..6bf9bee57 100644 --- a/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx +++ b/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx @@ -1,8 +1,8 @@ import { - XCircleIcon, - XMarkIcon, - InformationCircleIcon, - CheckCircleIcon, + XCircleIcon, + XMarkIcon, + InformationCircleIcon, + CheckCircleIcon, } from "@heroicons/react/24/outline"; import { Link } from "react-router-dom"; import { Transition } from "@headlessui/react"; @@ -10,145 +10,145 @@ import { useState } from "react"; import { SingleAlertComponentType } from "../../../../types/alerts"; export default function SingleAlert({ - dropItem, - removeAlert, + dropItem, + removeAlert, }: SingleAlertComponentType) { - const [show, setShow] = useState(true); - const type = dropItem.type; + const [show, setShow] = useState(true); + const type = dropItem.type; - return ( - - {type === "error" ? ( -
-
-
-
-

- {dropItem.title} -

- {dropItem.list ? ( -
-
    - {dropItem.list.map((item, idx) => ( -
  • {item}
  • - ))} -
-
- ) : ( - <> - )} -
-
-
- -
-
-
- ) : type === "notice" ? ( -
-
-
-
-

{dropItem.title}

-

- {dropItem.link ? ( - - Details - - ) : ( - <> - )} -

-
-
-
- -
-
-
- ) : ( -
-
-
-
-

- {dropItem.title} -

-
-
-
- -
-
-
- )} -
- ); + return ( + + {type === "error" ? ( +
+
+
+
+

+ {dropItem.title} +

+ {dropItem.list ? ( +
+
    + {dropItem.list.map((item, idx) => ( +
  • {item}
  • + ))} +
+
+ ) : ( + <> + )} +
+
+
+ +
+
+
+ ) : type === "notice" ? ( +
+
+
+
+

{dropItem.title}

+

+ {dropItem.link ? ( + + Details + + ) : ( + <> + )} +

+
+
+
+ +
+
+
+ ) : ( +
+
+
+
+

+ {dropItem.title} +

+
+
+
+ +
+
+
+ )} +
+ ); } diff --git a/src/frontend/src/alerts/alertDropDown/index.tsx b/src/frontend/src/alerts/alertDropDown/index.tsx index 73ee9413c..84a376aaf 100644 --- a/src/frontend/src/alerts/alertDropDown/index.tsx +++ b/src/frontend/src/alerts/alertDropDown/index.tsx @@ -7,60 +7,60 @@ import { AlertDropdownType } from "../../types/alerts"; import { PopUpContext } from "../../contexts/popUpContext"; import { useOnClickOutside } from "../hooks/useOnClickOutside"; export default function AlertDropdown({}: AlertDropdownType) { - const { closePopUp } = useContext(PopUpContext); - const componentRef = useRef(null); + const { closePopUp } = useContext(PopUpContext); + const componentRef = useRef(null); - // Use the custom hook - useOnClickOutside(componentRef, () => { - closePopUp(); - }); + // Use the custom hook + useOnClickOutside(componentRef, () => { + closePopUp(); + }); - const { - notificationList, - clearNotificationList, - removeFromNotificationList, - } = useContext(alertContext); + const { + notificationList, + clearNotificationList, + removeFromNotificationList, + } = useContext(alertContext); - return ( -
-
- Notifications -
- - -
-
-
- {notificationList.length !== 0 ? ( - notificationList.map((alertItem, index) => ( - - )) - ) : ( -
- No new notifications -
- )} -
-
- ); + return ( +
+
+ Notifications +
+ + +
+
+
+ {notificationList.length !== 0 ? ( + notificationList.map((alertItem, index) => ( + + )) + ) : ( +
+ No new notifications +
+ )} +
+
+ ); } diff --git a/src/frontend/src/alerts/hooks/useOnClickOutside/index.ts b/src/frontend/src/alerts/hooks/useOnClickOutside/index.ts index 249133d96..3046d41a4 100644 --- a/src/frontend/src/alerts/hooks/useOnClickOutside/index.ts +++ b/src/frontend/src/alerts/hooks/useOnClickOutside/index.ts @@ -1,33 +1,33 @@ import { useEffect } from "react"; export function useOnClickOutside(ref, handler) { - useEffect(() => { - const listener = (event) => { - // Do nothing if clicking ref's element or its children - if (!ref.current || ref.current.contains(event.target)) { - return; - } + useEffect(() => { + const listener = (event) => { + // Do nothing if clicking ref's element or its children + if (!ref.current || ref.current.contains(event.target)) { + return; + } - handler(event); - }; + handler(event); + }; - // Attach the listener to the document - document.addEventListener("mousedown", listener, { passive: true }); + // Attach the listener to the document + document.addEventListener("mousedown", listener, { passive: true }); - // Attach the listener to the react-flow instance - const reactFlowContainer = document.querySelector(".react-flow"); - if (reactFlowContainer) { - reactFlowContainer.addEventListener("mousedown", listener, { - passive: true, - }); - } + // Attach the listener to the react-flow instance + const reactFlowContainer = document.querySelector(".react-flow"); + if (reactFlowContainer) { + reactFlowContainer.addEventListener("mousedown", listener, { + passive: true, + }); + } - // Clean up the listener when the component is unmounted - return () => { - document.removeEventListener("mousedown", listener); - if (reactFlowContainer) { - reactFlowContainer.removeEventListener("mousedown", listener); - } - }; - }, [ref, handler]); // Rerun only if ref or handler changes + // Clean up the listener when the component is unmounted + return () => { + document.removeEventListener("mousedown", listener); + if (reactFlowContainer) { + reactFlowContainer.removeEventListener("mousedown", listener); + } + }; + }, [ref, handler]); // Rerun only if ref or handler changes } diff --git a/src/frontend/src/components/CrashErrorComponent/index.tsx b/src/frontend/src/components/CrashErrorComponent/index.tsx index 7864e6d65..de3cea182 100644 --- a/src/frontend/src/components/CrashErrorComponent/index.tsx +++ b/src/frontend/src/components/CrashErrorComponent/index.tsx @@ -2,12 +2,14 @@ export default function CrashErrorComponent({ error, resetErrorBoundary }) { return (
-

Oops! An unknown error has occurred.

+

+ Oops! An unknown error has occurred. +

- Please click the 'Reset Application' button - to restore the application's state. If the error persists, please - create an issue on our GitHub page. We apologize for any inconvenience - this may have caused. + Please click the 'Reset Application' button to restore the + application's state. If the error persists, please create an issue on + our GitHub page. We apologize for any inconvenience this may have + caused.

)} {chat.thought && chat.thought !== "" && !hidden &&

} -
- {chat.message} +
+ {chat.message}
diff --git a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx index 61c1b4a3e..2759b13a5 100644 --- a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx +++ b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx @@ -1,37 +1,45 @@ import { Transition } from "@headlessui/react"; -import { Bars3CenterLeftIcon, ChatBubbleBottomCenterTextIcon } from "@heroicons/react/24/outline"; +import { + Bars3CenterLeftIcon, + ChatBubbleBottomCenterTextIcon, +} from "@heroicons/react/24/outline"; import { nodeColors } from "../../../utils"; import { PopUpContext } from "../../../contexts/popUpContext"; import { useContext } from "react"; import ChatModal from "../../../modals/chatModal"; -export default function ChatTrigger({open, setOpen}){ - const {openPopUp} = useContext(PopUpContext) - return( -
-
- -
-
-
) -} \ No newline at end of file +export default function ChatTrigger({ open, setOpen }) { + const { openPopUp } = useContext(PopUpContext); + return ( + +
+
+ +
+
+
+ ); +} diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index c2dfa2260..940a9341b 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -7,26 +7,26 @@ import ChatModal from "../../modals/chatModal"; const _ = require("lodash"); export default function Chat({ flow }: ChatType) { - const [open, setOpen] = useState(false); - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if ( - (event.key === "K" || event.key === "k") && - (event.metaKey || event.ctrlKey) - ) { - event.preventDefault(); - setOpen((oldState) => !oldState); - } - }; - document.addEventListener("keydown", handleKeyDown); - return () => { - document.removeEventListener("keydown", handleKeyDown); - }; - }, []); - return ( - <> - - - - ); + const [open, setOpen] = useState(false); + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if ( + (event.key === "K" || event.key === "k") && + (event.metaKey || event.ctrlKey) + ) { + event.preventDefault(); + setOpen((oldState) => !oldState); + } + }; + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, []); + return ( + <> + + + + ); } diff --git a/src/frontend/src/components/dropdownComponent/index.tsx b/src/frontend/src/components/dropdownComponent/index.tsx index bb4cd621c..92085d8b8 100644 --- a/src/frontend/src/components/dropdownComponent/index.tsx +++ b/src/frontend/src/components/dropdownComponent/index.tsx @@ -5,90 +5,90 @@ import { DropDownComponentType } from "../../types/components"; import { classNames } from "../../utils"; export default function Dropdown({ - value, - options, - onSelect, + value, + options, + onSelect, }: DropDownComponentType) { - let [internalValue, setInternalValue] = useState( - value === "" || !value ? "Choose an option" : value - ); - return ( - <> - { - setInternalValue(value); - onSelect(value); - }} - > - {({ open }) => ( - <> -
- - {internalValue} - - - + let [internalValue, setInternalValue] = useState( + value === "" || !value ? "Choose an option" : value + ); + return ( + <> + { + setInternalValue(value); + onSelect(value); + }} + > + {({ open }) => ( + <> +
+ + {internalValue} + + + - - - {options.map((option, id) => ( - - classNames( - active - ? "text-white bg-indigo-600 dark:bg-indigo-500" - : "text-gray-900", - "relative cursor-default select-none py-2 pl-3 pr-9 dark:text-gray-300 dark:bg-gray-800" - ) - } - value={option} - > - {({ selected, active }) => ( - <> - - {option} - + + + {options.map((option, id) => ( + + classNames( + active + ? "text-white bg-indigo-600 dark:bg-indigo-500" + : "text-gray-900", + "relative cursor-default select-none py-2 pl-3 pr-9 dark:text-gray-300 dark:bg-gray-800" + ) + } + value={option} + > + {({ selected, active }) => ( + <> + + {option} + - {selected ? ( - - - ) : null} - - )} - - ))} - - -
- - )} -
- - ); + {selected ? ( + + + ) : null} + + )} + + ))} + + +
+ + )} +
+ + ); } diff --git a/src/frontend/src/components/floatComponent/index.tsx b/src/frontend/src/components/floatComponent/index.tsx index adce64ba5..3a09527da 100644 --- a/src/frontend/src/components/floatComponent/index.tsx +++ b/src/frontend/src/components/floatComponent/index.tsx @@ -1,26 +1,33 @@ import { useEffect, useState } from "react"; import { FloatComponentType } from "../../types/components"; -export default function FloatComponent({value, onChange, disabled}: FloatComponentType){ - const [myValue, setMyValue] = useState(value ?? ""); - useEffect(()=> { - if(disabled){ - setMyValue(""); - onChange(""); - } - }, [disabled, onChange]) - return ( -
- { - setMyValue(e.target.value); - onChange(e.target.value); - }} - /> -
- ); -} \ No newline at end of file +export default function FloatComponent({ + value, + onChange, + disabled, +}: FloatComponentType) { + const [myValue, setMyValue] = useState(value ?? ""); + useEffect(() => { + if (disabled) { + setMyValue(""); + onChange(""); + } + }, [disabled, onChange]); + return ( +
+ { + setMyValue(e.target.value); + onChange(e.target.value); + }} + /> +
+ ); +} diff --git a/src/frontend/src/components/inputComponent/index.tsx b/src/frontend/src/components/inputComponent/index.tsx index f28d82307..05be68532 100644 --- a/src/frontend/src/components/inputComponent/index.tsx +++ b/src/frontend/src/components/inputComponent/index.tsx @@ -3,84 +3,84 @@ import { InputComponentType } from "../../types/components"; import { classNames } from "../../utils"; export default function InputComponent({ - value, - onChange, - disabled, - password, + value, + onChange, + disabled, + password, }: InputComponentType) { - const [myValue, setMyValue] = useState(value ?? ""); - const [pwdVisible, setPwdVisible] = useState(false); - useEffect(() => { - if (disabled) { - setMyValue(""); - onChange(""); - } - }, [disabled, onChange]); - return ( -
- { - setMyValue(e.target.value); - onChange(e.target.value); - }} - /> - -
- ); + const [myValue, setMyValue] = useState(value ?? ""); + const [pwdVisible, setPwdVisible] = useState(false); + useEffect(() => { + if (disabled) { + setMyValue(""); + onChange(""); + } + }, [disabled, onChange]); + return ( +
+ { + setMyValue(e.target.value); + onChange(e.target.value); + }} + /> + +
+ ); } diff --git a/src/frontend/src/components/inputFileComponent/index.tsx b/src/frontend/src/components/inputFileComponent/index.tsx index cb915bce5..d20044571 100644 --- a/src/frontend/src/components/inputFileComponent/index.tsx +++ b/src/frontend/src/components/inputFileComponent/index.tsx @@ -9,7 +9,7 @@ export default function InputFileComponent({ disabled, suffixes, fileTypes, - onFileChange + onFileChange, }: FileComponentType) { const [myValue, setMyValue] = useState(value); const { setErrorData } = useContext(alertContext); @@ -17,23 +17,23 @@ export default function InputFileComponent({ if (disabled) { setMyValue(""); onChange(""); - onFileChange("") + onFileChange(""); } }, [disabled, onChange]); function attachFile(fileReadEvent: ProgressEvent) { fileReadEvent.preventDefault(); const file = fileReadEvent.target.result; - onFileChange(file as string) + onFileChange(file as string); } - function checkFileType(fileName:string):boolean{ + function checkFileType(fileName: string): boolean { for (let index = 0; index < suffixes.length; index++) { - if(fileName.endsWith(suffixes[index])){ - return true + if (fileName.endsWith(suffixes[index])) { + return true; } } - return false + return false; } const handleButtonClick = () => { @@ -69,7 +69,7 @@ export default function InputFileComponent({ >
{ - if(disabled){ - setInputList([""]); - onChange([""]); - } -}, [disabled, onChange]) - return ( -
- {inputList.map((i, idx) => ( -
- { - setInputList((old) => { - let newInputList = _.cloneDeep(old); - newInputList[idx] = e.target.value; - return newInputList; - }); - onChange(inputList); - }} - /> - {idx === inputList.length - 1 ? - - : } -
- ))} -
- ); +export default function InputListComponent({ + value, + onChange, + disabled, +}: InputListComponentType) { + const [inputList, setInputList] = useState(value ?? [""]); + useEffect(() => { + if (disabled) { + setInputList([""]); + onChange([""]); + } + }, [disabled, onChange]); + return ( +
+ {inputList.map((i, idx) => ( +
+ { + setInputList((old) => { + let newInputList = _.cloneDeep(old); + newInputList[idx] = e.target.value; + return newInputList; + }); + onChange(inputList); + }} + /> + {idx === inputList.length - 1 ? ( + + ) : ( + + )} +
+ ))} +
+ ); } diff --git a/src/frontend/src/components/intComponent/index.tsx b/src/frontend/src/components/intComponent/index.tsx index 520a78c0d..cc435c897 100644 --- a/src/frontend/src/components/intComponent/index.tsx +++ b/src/frontend/src/components/intComponent/index.tsx @@ -14,12 +14,23 @@ export default function IntComponent({ } }, [disabled, onChange]); return ( -
+
{ - if (event.key !== 'Backspace' && event.key !== 'Enter' && event.key !== 'Delete' && event.key !== 'ArrowLeft' && event.key !== 'ArrowRight' && !/^[-]?\d*$/.test(event.key)) { - event.preventDefault(); - } + if ( + event.key !== "Backspace" && + event.key !== "Enter" && + event.key !== "Delete" && + event.key !== "ArrowLeft" && + event.key !== "ArrowRight" && + !/^[-]?\d*$/.test(event.key) + ) { + event.preventDefault(); + } }} type="number" value={myValue} diff --git a/src/frontend/src/components/loadingComponent/index.tsx b/src/frontend/src/components/loadingComponent/index.tsx index 6181fd7cc..43d6d9d75 100644 --- a/src/frontend/src/components/loadingComponent/index.tsx +++ b/src/frontend/src/components/loadingComponent/index.tsx @@ -1,17 +1,28 @@ -type LoadingComponentProps={ - remSize:number +type LoadingComponentProps = { + remSize: number; +}; + +export default function LoadingComponent({ remSize }: LoadingComponentProps) { + return ( +
+ +

+ Loading... +
+ ); } - - -export default function LoadingComponent({remSize}:LoadingComponentProps){ - return( -
- -

- Loading... -
- ) -} \ No newline at end of file diff --git a/src/frontend/src/components/textAreaComponent/index.tsx b/src/frontend/src/components/textAreaComponent/index.tsx index 153de4ffa..93b0ddb62 100644 --- a/src/frontend/src/components/textAreaComponent/index.tsx +++ b/src/frontend/src/components/textAreaComponent/index.tsx @@ -4,30 +4,57 @@ import { PopUpContext } from "../../contexts/popUpContext"; import TextAreaModal from "../../modals/textAreaModal"; import { TextAreaComponentType } from "../../types/components"; -export default function TextAreaComponent({ value, onChange, disabled }:TextAreaComponentType) { - const [myValue, setMyValue] = useState(value); - const { openPopUp } = useContext(PopUpContext); - useEffect(() => { - if (disabled) { - setMyValue(""); - onChange(""); - } - }, [disabled, onChange]); - return ( -
-
- {openPopUp( {setMyValue(t); onChange(t);}}/>)}} - className={ - "truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" + - (disabled ? " bg-gray-200" : "") - } - > - {myValue !== "" ? myValue : 'Text empty'} - - -
-
- ); +export default function TextAreaComponent({ + value, + onChange, + disabled, +}: TextAreaComponentType) { + const [myValue, setMyValue] = useState(value); + const { openPopUp } = useContext(PopUpContext); + useEffect(() => { + if (disabled) { + setMyValue(""); + onChange(""); + } + }, [disabled, onChange]); + return ( +
+
+ { + openPopUp( + { + setMyValue(t); + onChange(t); + }} + /> + ); + }} + className={ + "truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" + + (disabled ? " bg-gray-200" : "") + } + > + {myValue !== "" ? myValue : "Text empty"} + + +
+
+ ); } diff --git a/src/frontend/src/components/toggleComponent/index.tsx b/src/frontend/src/components/toggleComponent/index.tsx index 4cd6ee615..102512ab3 100644 --- a/src/frontend/src/components/toggleComponent/index.tsx +++ b/src/frontend/src/components/toggleComponent/index.tsx @@ -3,73 +3,80 @@ import { classNames } from "../../utils"; import { useEffect } from "react"; import { ToggleComponentType } from "../../types/components"; -export default function ToggleComponent({ enabled, setEnabled, disabled }:ToggleComponentType) { - useEffect(()=> { - if(disabled){ - setEnabled(false); - } -}, [disabled, setEnabled]) - return ( -
- { - setEnabled(x); - }} - className={classNames( - enabled ? "bg-indigo-600" : "bg-gray-200 dark:bg-gray-600", - "relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out " - )} - > - Use setting - - - - - -
- ); +export default function ToggleComponent({ + enabled, + setEnabled, + disabled, +}: ToggleComponentType) { + useEffect(() => { + if (disabled) { + setEnabled(false); + } + }, [disabled, setEnabled]); + return ( +
+ { + setEnabled(x); + }} + className={classNames( + enabled ? "bg-indigo-600" : "bg-gray-200 dark:bg-gray-600", + "relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out " + )} + > + Use setting + + + + + +
+ ); } diff --git a/src/frontend/src/contexts/alertContext.tsx b/src/frontend/src/contexts/alertContext.tsx index 0fba6f65e..ad2110217 100644 --- a/src/frontend/src/contexts/alertContext.tsx +++ b/src/frontend/src/contexts/alertContext.tsx @@ -20,13 +20,13 @@ type alertContextType = { notificationCenter: boolean; setNotificationCenter: (newState: boolean) => void; notificationList: Array; - pushNotificationList: (Object:AlertItemType) => void; + pushNotificationList: (Object: AlertItemType) => void; clearNotificationList: () => void; removeFromNotificationList: (index: string) => void; }; //initial values to alertContextType -const initialValue:alertContextType = { +const initialValue: alertContextType = { errorData: { title: "", list: [] }, setErrorData: () => {}, errorOpen: false, @@ -49,7 +49,7 @@ const initialValue:alertContextType = { export const alertContext = createContext(initialValue); -export function AlertProvider({ children }:{children:ReactNode}) { +export function AlertProvider({ children }: { children: ReactNode }) { const [errorData, setErrorDataState] = useState<{ title: string; list?: Array; @@ -73,68 +73,69 @@ export function AlertProvider({ children }:{children:ReactNode}) { return newNotificationList; }); }; -/** - * Sets the error data state, opens the error dialog and pushes the new error notification to the notification list - * @param newState An object containing the new error data, including title and optional list of error messages - */ -function setErrorData(newState: { title: string; list?: Array }) { - setErrorDataState(newState); - setErrorOpen(true); - if (newState.title) { - setNotificationCenter(true); - pushNotificationList({ - type: "error", - title: newState.title, - list: newState.list, - id: _.uniqueId(), - }); + /** + * Sets the error data state, opens the error dialog and pushes the new error notification to the notification list + * @param newState An object containing the new error data, including title and optional list of error messages + */ + function setErrorData(newState: { title: string; list?: Array }) { + setErrorDataState(newState); + setErrorOpen(true); + if (newState.title) { + setNotificationCenter(true); + pushNotificationList({ + type: "error", + title: newState.title, + list: newState.list, + id: _.uniqueId(), + }); + } } -} -/** - * Sets the state of the notice data and opens the notice modal, also adds a new notice to the notification center if the title is defined. - * @param newState An object containing the title of the notice and optionally a link. - */ -function setNoticeData(newState: { title: string; link?: string }) { - setNoticeDataState(newState); - setNoticeOpen(true); - if (newState.title) { - // Add new notice to notification center - setNotificationCenter(true); - pushNotificationList({ - type: "notice", - title: newState.title, - link: newState.link, - id: _.uniqueId(), - }); + /** + * Sets the state of the notice data and opens the notice modal, also adds a new notice to the notification center if the title is defined. + * @param newState An object containing the title of the notice and optionally a link. + */ + function setNoticeData(newState: { title: string; link?: string }) { + setNoticeDataState(newState); + setNoticeOpen(true); + if (newState.title) { + // Add new notice to notification center + setNotificationCenter(true); + pushNotificationList({ + type: "notice", + title: newState.title, + link: newState.link, + id: _.uniqueId(), + }); + } } -} -/** - * Update the success data state and show a success alert notification. - * @param newState - A state object with a "title" property to set in the success data state. - */ -function setSuccessData(newState: { title: string }) { - setSuccessDataState(newState); // update the success data state with the provided new state - setSuccessOpen(true); // open the success alert + /** + * Update the success data state and show a success alert notification. + * @param newState - A state object with a "title" property to set in the success data state. + */ + function setSuccessData(newState: { title: string }) { + setSuccessDataState(newState); // update the success data state with the provided new state + setSuccessOpen(true); // open the success alert - // If the new state has a "title" property, add a new success notification to the list - if (newState.title) { - setNotificationCenter(true); // show the notification center - pushNotificationList({ // add the new notification to the list - type: "success", - title: newState.title, - id: _.uniqueId(), - }); + // If the new state has a "title" property, add a new success notification to the list + if (newState.title) { + setNotificationCenter(true); // show the notification center + pushNotificationList({ + // add the new notification to the list + type: "success", + title: newState.title, + id: _.uniqueId(), + }); + } } -} function clearNotificationList() { setNotificationList([]); } function removeFromNotificationList(index: string) { // set the notification list to a new array that filters out the alert with the matching id setNotificationList((prevAlertsList) => - prevAlertsList.filter((alert) => alert.id !== index) + prevAlertsList.filter((alert) => alert.id !== index) ); - } + } return ( (initialValue); export function DarkProvider({ children }) { const [dark, setDark] = useState(false); - useEffect(()=>{ - if(dark){ + useEffect(() => { + if (dark) { document.getElementById("body").classList.add("dark"); } else { document.getElementById("body").classList.remove("dark"); } - }, [dark]) + }, [dark]); return ( ); -} \ No newline at end of file +} diff --git a/src/frontend/src/contexts/locationContext.tsx b/src/frontend/src/contexts/locationContext.tsx index dbefaa7c9..a73db24fe 100644 --- a/src/frontend/src/contexts/locationContext.tsx +++ b/src/frontend/src/contexts/locationContext.tsx @@ -32,7 +32,7 @@ type locationContextType = { //initial value for location context const initialValue = { - //actual + //actual current: window.location.pathname.replace(/\/$/g, "").split("/"), isStackedOpen: window.innerWidth > 1024 && window.location.pathname.split("/")[1] @@ -50,7 +50,7 @@ const initialValue = { export const locationContext = createContext(initialValue); -export function LocationProvider({ children }:{children:ReactNode}) { +export function LocationProvider({ children }: { children: ReactNode }) { const [current, setCurrent] = useState(initialValue.current); const [isStackedOpen, setIsStackedOpen] = useState( initialValue.isStackedOpen diff --git a/src/frontend/src/contexts/popUpContext.tsx b/src/frontend/src/contexts/popUpContext.tsx index efa263146..b8c47dea2 100644 --- a/src/frontend/src/contexts/popUpContext.tsx +++ b/src/frontend/src/contexts/popUpContext.tsx @@ -3,31 +3,31 @@ import React, { useState } from "react"; // context to set JSX element on the DOM export const PopUpContext = createContext({ - openPopUp: (popUpElement: JSX.Element) => {}, - closePopUp: () => {}, + openPopUp: (popUpElement: JSX.Element) => {}, + closePopUp: () => {}, }); interface PopUpProviderProps { - children: React.ReactNode; + children: React.ReactNode; } const PopUpProvider = ({ children }: PopUpProviderProps) => { - const [popUpElements, setPopUpElements] = useState([]); + const [popUpElements, setPopUpElements] = useState([]); - const openPopUp = (element: JSX.Element) => { - setPopUpElements(prevPopUps => [element, ...prevPopUps]); - }; + const openPopUp = (element: JSX.Element) => { + setPopUpElements((prevPopUps) => [element, ...prevPopUps]); + }; - const closePopUp = () => { - setPopUpElements(prevPopUps => prevPopUps.slice(1)); - }; + const closePopUp = () => { + setPopUpElements((prevPopUps) => prevPopUps.slice(1)); + }; - return ( - - {children} - {popUpElements[0]} - - ); + return ( + + {children} + {popUpElements[0]} + + ); }; export default PopUpProvider; diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index 3384ab479..9905051b2 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -1,10 +1,10 @@ import { - createContext, - useEffect, - useState, - useRef, - ReactNode, - useContext, + createContext, + useEffect, + useState, + useRef, + ReactNode, + useContext, } from "react"; import { FlowType } from "../types/flow"; import { LangFlowState, TabsContextType } from "../types/tabs"; @@ -15,221 +15,221 @@ import { APITemplateType, TemplateVariableType } from "../types/api"; const { v4: uuidv4 } = require("uuid"); const TabsContextInitialValue: TabsContextType = { - save: () => {}, - tabIndex: 0, - setTabIndex: (index: number) => {}, - flows: [], - removeFlow: (id: string) => {}, - addFlow: (flowData?: any) => {}, - updateFlow: (newFlow: FlowType) => {}, - incrementNodeId: () => 0, - downloadFlow: (flow: FlowType) => {}, - uploadFlow: () => {}, - hardReset: () => {}, + save: () => {}, + tabIndex: 0, + setTabIndex: (index: number) => {}, + flows: [], + removeFlow: (id: string) => {}, + addFlow: (flowData?: any) => {}, + updateFlow: (newFlow: FlowType) => {}, + incrementNodeId: () => 0, + downloadFlow: (flow: FlowType) => {}, + uploadFlow: () => {}, + hardReset: () => {}, }; export const TabsContext = createContext( - TabsContextInitialValue + TabsContextInitialValue ); export function TabsProvider({ children }: { children: ReactNode }) { - const { setNoticeData } = useContext(alertContext); - const [tabIndex, setTabIndex] = useState(0); - const [flows, setFlows] = useState>([]); - const [id, setId] = useState(""); - const { templates } = useContext(typesContext); + const { setNoticeData } = useContext(alertContext); + const [tabIndex, setTabIndex] = useState(0); + const [flows, setFlows] = useState>([]); + const [id, setId] = useState(""); + const { templates } = useContext(typesContext); - const newNodeId = useRef(0); - function incrementNodeId() { - newNodeId.current = newNodeId.current + 1; - return newNodeId.current; - } - function save() { - if (flows.length !== 0) - window.localStorage.setItem( - "tabsData", - JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current }) - ); - } - useEffect(() => { - //save tabs locally - save(); - }, [flows, id, tabIndex, newNodeId]); + const newNodeId = useRef(0); + function incrementNodeId() { + newNodeId.current = newNodeId.current + 1; + return newNodeId.current; + } + function save() { + if (flows.length !== 0) + window.localStorage.setItem( + "tabsData", + JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current }) + ); + } + useEffect(() => { + //save tabs locally + save(); + }, [flows, id, tabIndex, newNodeId]); - useEffect(() => { - //get tabs locally saved - let cookie = window.localStorage.getItem("tabsData"); - if (cookie && Object.keys(templates).length > 0) { - let cookieObject: LangFlowState = JSON.parse(cookie); - cookieObject.flows.forEach((flow) => { - flow.data.nodes.forEach((node) => { - if (Object.keys(templates[node.data.type]["template"]).length > 0) { - node.data.node.template = updateTemplate( - templates[node.data.type][ - "template" - ] as unknown as APITemplateType, + useEffect(() => { + //get tabs locally saved + let cookie = window.localStorage.getItem("tabsData"); + if (cookie && Object.keys(templates).length > 0) { + let cookieObject: LangFlowState = JSON.parse(cookie); + cookieObject.flows.forEach((flow) => { + flow.data.nodes.forEach((node) => { + if (Object.keys(templates[node.data.type]["template"]).length > 0) { + node.data.node.template = updateTemplate( + templates[node.data.type][ + "template" + ] as unknown as APITemplateType, - node.data.node.template as APITemplateType - ); - } - }); - }); - setTabIndex(cookieObject.tabIndex); - setFlows(cookieObject.flows); - setId(cookieObject.id); - newNodeId.current = cookieObject.nodeId; - } - }, [templates]); - function hardReset() { - newNodeId.current = 0; - setTabIndex(0); - setFlows([]); - setId(""); - } + node.data.node.template as APITemplateType + ); + } + }); + }); + setTabIndex(cookieObject.tabIndex); + setFlows(cookieObject.flows); + setId(cookieObject.id); + newNodeId.current = cookieObject.nodeId; + } + }, [templates]); + function hardReset() { + newNodeId.current = 0; + setTabIndex(0); + setFlows([]); + setId(""); + } - /** - * Downloads the current flow as a JSON file - */ - function downloadFlow(flow: FlowType) { - // create a data URI with the current flow data - const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( - JSON.stringify(flow) - )}`; + /** + * Downloads the current flow as a JSON file + */ + function downloadFlow(flow: FlowType) { + // create a data URI with the current flow data + const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( + JSON.stringify(flow) + )}`; - // create a link element and set its properties - const link = document.createElement("a"); - link.href = jsonString; - link.download = `${flows[tabIndex].name}.json`; + // create a link element and set its properties + const link = document.createElement("a"); + link.href = jsonString; + link.download = `${flows[tabIndex].name}.json`; - // simulate a click on the link element to trigger the download - link.click(); - setNoticeData({ - title: "Warning: Critical data,JSON file may including API keys.", - }); - } + // simulate a click on the link element to trigger the download + link.click(); + setNoticeData({ + title: "Warning: Critical data,JSON file may including API keys.", + }); + } - /** - * Creates a file input and listens to a change event to upload a JSON flow file. - * If the file type is application/json, the file is read and parsed into a JSON object. - * The resulting JSON object is passed to the addFlow function. - */ - function uploadFlow() { - // create a file input - const input = document.createElement("input"); - input.type = "file"; - // add a change event listener to the file input - input.onchange = (e: Event) => { - // check if the file type is application/json - if ((e.target as HTMLInputElement).files[0].type === "application/json") { - // get the file from the file input - const file = (e.target as HTMLInputElement).files[0]; - // read the file as text - file.text().then((text) => { - // parse the text into a JSON object - let flow: FlowType = JSON.parse(text); + /** + * Creates a file input and listens to a change event to upload a JSON flow file. + * If the file type is application/json, the file is read and parsed into a JSON object. + * The resulting JSON object is passed to the addFlow function. + */ + function uploadFlow() { + // create a file input + const input = document.createElement("input"); + input.type = "file"; + // add a change event listener to the file input + input.onchange = (e: Event) => { + // check if the file type is application/json + if ((e.target as HTMLInputElement).files[0].type === "application/json") { + // get the file from the file input + const file = (e.target as HTMLInputElement).files[0]; + // read the file as text + file.text().then((text) => { + // parse the text into a JSON object + let flow: FlowType = JSON.parse(text); - addFlow(flow); - }); - } - }; - // trigger the file input click event to open the file dialog - input.click(); - } - /** - * Removes a flow from an array of flows based on its id. - * Updates the state of flows and tabIndex using setFlows and setTabIndex hooks. - * @param {string} id - The id of the flow to remove. - */ - function removeFlow(id: string) { - setFlows((prevState) => { - const newFlows = [...prevState]; - const index = newFlows.findIndex((flow) => flow.id === id); - if (index >= 0) { - if (index === tabIndex) { - setTabIndex(flows.length - 2); - newFlows.splice(index, 1); - } else { - let flowId = flows[tabIndex].id; - newFlows.splice(index, 1); - setTabIndex(newFlows.findIndex((flow) => flow.id === flowId)); - } - } - return newFlows; - }); - } - /** - * Add a new flow to the list of flows. - * @param flow Optional flow to add. - */ - function addFlow(flow?: FlowType) { - // Get data from the flow or set it to null if there's no flow provided. - const data = flow?.data ? flow.data : null; - const description = flow?.description ? flow.description : ""; + addFlow(flow); + }); + } + }; + // trigger the file input click event to open the file dialog + input.click(); + } + /** + * Removes a flow from an array of flows based on its id. + * Updates the state of flows and tabIndex using setFlows and setTabIndex hooks. + * @param {string} id - The id of the flow to remove. + */ + function removeFlow(id: string) { + setFlows((prevState) => { + const newFlows = [...prevState]; + const index = newFlows.findIndex((flow) => flow.id === id); + if (index >= 0) { + if (index === tabIndex) { + setTabIndex(flows.length - 2); + newFlows.splice(index, 1); + } else { + let flowId = flows[tabIndex].id; + newFlows.splice(index, 1); + setTabIndex(newFlows.findIndex((flow) => flow.id === flowId)); + } + } + return newFlows; + }); + } + /** + * Add a new flow to the list of flows. + * @param flow Optional flow to add. + */ + function addFlow(flow?: FlowType) { + // Get data from the flow or set it to null if there's no flow provided. + const data = flow?.data ? flow.data : null; + const description = flow?.description ? flow.description : ""; - if (data) { - data.nodes.forEach((node) => { - if (Object.keys(templates[node.data.type]["template"]).length > 0) { - node.data.node.template = updateTemplate( - templates[node.data.type]["template"] as unknown as APITemplateType, - node.data.node.template as APITemplateType - ); - } - }); - } - // Create a new flow with a default name if no flow is provided. - let newFlow: FlowType = { - description, - name: flow?.name ?? "New Flow", - id: id.toString(), - data, - }; + if (data) { + data.nodes.forEach((node) => { + if (Object.keys(templates[node.data.type]["template"]).length > 0) { + node.data.node.template = updateTemplate( + templates[node.data.type]["template"] as unknown as APITemplateType, + node.data.node.template as APITemplateType + ); + } + }); + } + // Create a new flow with a default name if no flow is provided. + let newFlow: FlowType = { + description, + name: flow?.name ?? "New Flow", + id: id.toString(), + data, + }; - // Increment the ID counter. - setId(uuidv4()); + // Increment the ID counter. + setId(uuidv4()); - // Add the new flow to the list of flows. - setFlows((prevState) => { - const newFlows = [...prevState, newFlow]; - return newFlows; - }); + // Add the new flow to the list of flows. + setFlows((prevState) => { + const newFlows = [...prevState, newFlow]; + return newFlows; + }); - // Set the tab index to the new flow. - setTabIndex(flows.length); - } - /** - * Updates an existing flow with new data - * @param newFlow - The new flow object containing the updated data - */ - function updateFlow(newFlow: FlowType) { - setFlows((prevState) => { - const newFlows = [...prevState]; - const index = newFlows.findIndex((flow) => flow.id === newFlow.id); - if (index !== -1) { - newFlows[index].description = newFlow.description ?? ""; - newFlows[index].data = newFlow.data; - newFlows[index].name = newFlow.name; - } - return newFlows; - }); - } + // Set the tab index to the new flow. + setTabIndex(flows.length); + } + /** + * Updates an existing flow with new data + * @param newFlow - The new flow object containing the updated data + */ + function updateFlow(newFlow: FlowType) { + setFlows((prevState) => { + const newFlows = [...prevState]; + const index = newFlows.findIndex((flow) => flow.id === newFlow.id); + if (index !== -1) { + newFlows[index].description = newFlow.description ?? ""; + newFlows[index].data = newFlow.data; + newFlows[index].name = newFlow.name; + } + return newFlows; + }); + } - return ( - - {children} - - ); + return ( + + {children} + + ); } diff --git a/src/frontend/src/contexts/typesContext.tsx b/src/frontend/src/contexts/typesContext.tsx index ad86d4699..2ab1eb057 100644 --- a/src/frontend/src/contexts/typesContext.tsx +++ b/src/frontend/src/contexts/typesContext.tsx @@ -1,12 +1,12 @@ import { createContext, ReactNode, useEffect, useState } from "react"; -import { Node} from "reactflow"; +import { Node } from "reactflow"; import { typesContextType } from "../types/typesContext"; import { getAll } from "../controllers/API"; import { APIKindType } from "../types/api"; //context to share types adn functions from nodes to flow -const initialValue:typesContextType = { +const initialValue: typesContextType = { reactFlowInstance: null, setReactFlowInstance: () => {}, deleteNode: () => {}, @@ -14,13 +14,13 @@ const initialValue:typesContextType = { setTypes: () => {}, templates: {}, setTemplates: () => {}, - data:{}, - setData:()=>{} + data: {}, + setData: () => {}, }; export const typesContext = createContext(initialValue); -export function TypesProvider({ children }:{children:ReactNode}) { +export function TypesProvider({ children }: { children: ReactNode }) { const [types, setTypes] = useState({}); const [reactFlowInstance, setReactFlowInstance] = useState(null); const [templates, setTemplates] = useState({}); @@ -35,11 +35,11 @@ export function TypesProvider({ children }:{children:ReactNode}) { setData(result.data); setTemplates( Object.keys(result.data).reduce((acc, curr) => { - Object.keys(result.data[curr]).forEach((c: keyof APIKindType)=>{ - acc[c] = result.data[curr][c] - }) + Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { + acc[c] = result.data[curr][c]; + }); return acc; - },{}) + }, {}) ); // Set the types by reducing over the keys of the result data and updating the accumulator. setTypes( @@ -59,11 +59,15 @@ export function TypesProvider({ children }:{children:ReactNode}) { getTypes(); }, [setTypes]); - function deleteNode(idx:string) { + function deleteNode(idx: string) { reactFlowInstance.setNodes( - reactFlowInstance.getNodes().filter((n:Node) => n.id !== idx) + reactFlowInstance.getNodes().filter((n: Node) => n.id !== idx) + ); + reactFlowInstance.setEdges( + reactFlowInstance + .getEdges() + .filter((ns) => ns.source !== idx && ns.target !== idx) ); - reactFlowInstance.setEdges(reactFlowInstance.getEdges().filter((ns) => ns.source !== idx && ns.target !== idx)); } return ( {children} diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index f6f46404b..9a93a9b36 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -4,40 +4,40 @@ import axios, { AxiosResponse } from "axios"; import { FlowType } from "../../types/flow"; export async function getAll(): Promise> { - return await axios.get(`/all`); + return await axios.get(`/all`); } export async function sendAll(data: sendAllProps) { - return await axios.post(`/predict`, data); + return await axios.post(`/predict`, data); } export async function checkCode( - code: string + code: string ): Promise> { - return await axios.post("/validate/code", { code }); + return await axios.post("/validate/code", { code }); } export async function checkPrompt( - template: string + template: string ): Promise> { - return await axios.post("/validate/prompt", { template }); + return await axios.post("/validate/prompt", { template }); } export async function getExamples(): Promise { - const url = - "https://api.github.com/repos/logspace-ai/langflow_examples/contents/examples"; - const response = await axios.get(url); + const url = + "https://api.github.com/repos/logspace-ai/langflow_examples/contents/examples"; + const response = await axios.get(url); - const jsonFiles = response.data.filter((file: any) => { - return file.name.endsWith(".json"); - }); + const jsonFiles = response.data.filter((file: any) => { + return file.name.endsWith(".json"); + }); - const contentsPromises = jsonFiles.map(async (file: any) => { - const contentResponse = await axios.get(file.download_url); - return contentResponse.data; - }); + const contentsPromises = jsonFiles.map(async (file: any) => { + const contentResponse = await axios.get(file.download_url); + return contentResponse.data; + }); - const contents = await Promise.all(contentsPromises); + const contents = await Promise.all(contentsPromises); - return contents; + return contents; } diff --git a/src/frontend/src/index.css b/src/frontend/src/index.css index 67c0d3279..e0684378d 100644 --- a/src/frontend/src/index.css +++ b/src/frontend/src/index.css @@ -1,15 +1,13 @@ - - body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} \ No newline at end of file + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} diff --git a/src/frontend/src/index.tsx b/src/frontend/src/index.tsx index c71219a94..c98d24378 100644 --- a/src/frontend/src/index.tsx +++ b/src/frontend/src/index.tsx @@ -11,8 +11,7 @@ const root = ReactDOM.createRoot( root.render( - - + ); diff --git a/src/frontend/src/modals/NodeModal/index.tsx b/src/frontend/src/modals/NodeModal/index.tsx index aad549a83..68e1ed2d2 100644 --- a/src/frontend/src/modals/NodeModal/index.tsx +++ b/src/frontend/src/modals/NodeModal/index.tsx @@ -87,37 +87,38 @@ export default function NodeModal({ data }: { data: NodeDataType }) {
- { - Object.keys(data.node.template) - .filter((t) => t.charAt(0) !== "_"&& data.node.template[t].advanced && data.node.template[t].show) - .map((t: string, idx) => { - return ( - + t.charAt(0) !== "_" && + data.node.template[t].advanced && + data.node.template[t].show + ) + .map((t: string, idx) => { + return ( + - ); - }) - } + data={data} + title={ + data.node.template[t].display_name + ? data.node.template[t].display_name + : data.node.template[t].name + ? toNormalCase(data.node.template[t].name) + : toNormalCase(t) + } + required={data.node.template[t].required} + id={ + data.node.template[t].type + + "|" + + t + + "|" + + data.id + } + name={t} + type={data.node.template[t].type} + /> + ); + })}
diff --git a/src/frontend/src/modals/chatModal/chatInput/index.tsx b/src/frontend/src/modals/chatModal/chatInput/index.tsx index a05ef1ef3..9e59709fd 100644 --- a/src/frontend/src/modals/chatModal/chatInput/index.tsx +++ b/src/frontend/src/modals/chatModal/chatInput/index.tsx @@ -24,9 +24,9 @@ export default function ChatInput({ }} ref={inputRef} disabled={lockChat} - style={{resize: "none" }} + style={{ resize: "none" }} value={lockChat ? "Thinking..." : chatValue} - onChange={(e) => { + onChange={(e) => { setChatValue(e.target.value); }} className={classNames( diff --git a/src/frontend/src/modals/chatModal/chatMessage/codeBlock/index.tsx b/src/frontend/src/modals/chatModal/chatMessage/codeBlock/index.tsx index 0c2c1ea73..d9a20579a 100644 --- a/src/frontend/src/modals/chatModal/chatMessage/codeBlock/index.tsx +++ b/src/frontend/src/modals/chatModal/chatMessage/codeBlock/index.tsx @@ -1,84 +1,81 @@ -import { IconCheck, IconClipboard, IconDownload } from '@tabler/icons-react'; -import { FC, memo, useState } from 'react'; -import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; -import { oneDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'; -import { programmingLanguages } from '../../../../utils'; +import { IconCheck, IconClipboard, IconDownload } from "@tabler/icons-react"; +import { FC, memo, useState } from "react"; +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; +import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism"; +import { programmingLanguages } from "../../../../utils"; interface Props { - language: string; - value: string; + language: string; + value: string; } export const CodeBlock: FC = memo(({ language, value }) => { - const [isCopied, setIsCopied] = useState(false); + const [isCopied, setIsCopied] = useState(false); - const copyToClipboard = () => { - if (!navigator.clipboard || !navigator.clipboard.writeText) { - return; - } + const copyToClipboard = () => { + if (!navigator.clipboard || !navigator.clipboard.writeText) { + return; + } - navigator.clipboard.writeText(value).then(() => { - setIsCopied(true); + navigator.clipboard.writeText(value).then(() => { + setIsCopied(true); - setTimeout(() => { - setIsCopied(false); - }, 2000); - }); - }; - const downloadAsFile = () => { - const fileExtension = programmingLanguages[language] || '.file'; - const suggestedFileName = `${"generated-code"}${fileExtension}`; - const fileName = window.prompt( - "enter file name", - suggestedFileName, - ); + setTimeout(() => { + setIsCopied(false); + }, 2000); + }); + }; + const downloadAsFile = () => { + const fileExtension = programmingLanguages[language] || ".file"; + const suggestedFileName = `${"generated-code"}${fileExtension}`; + const fileName = window.prompt("enter file name", suggestedFileName); - if (!fileName) { - // user pressed cancel on prompt - return; - } + if (!fileName) { + // user pressed cancel on prompt + return; + } - const blob = new Blob([value], { type: 'text/plain' }); - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.download = fileName; - link.href = url; - link.style.display = 'none'; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - URL.revokeObjectURL(url); - }; - return ( -
-
- {language} + const blob = new Blob([value], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.download = fileName; + link.href = url; + link.style.display = "none"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + }; + return ( +
+
+ {language} -
- - -
-
+
+ + +
+
- - {value} - -
- ); + + {value} + +
+ ); }); -CodeBlock.displayName = 'CodeBlock'; +CodeBlock.displayName = "CodeBlock"; diff --git a/src/frontend/src/modals/chatModal/chatMessage/index.tsx b/src/frontend/src/modals/chatModal/chatMessage/index.tsx index 41a9d2fc9..e836fd887 100644 --- a/src/frontend/src/modals/chatModal/chatMessage/index.tsx +++ b/src/frontend/src/modals/chatModal/chatMessage/index.tsx @@ -69,28 +69,35 @@ export default function ChatMessage({ chat }: { chat: ChatMessageType }) { components={{ code({ node, inline, className, children, ...props }) { if (children.length) { - if (children[0] == '▍') { - return - } - - children[0] = (children[0] as string).replace("`▍`", "▍") + if (children[0] == "▍") { + return ( + + ▍ + + ); + } + + children[0] = (children[0] as string).replace( + "`▍`", + "▍" + ); } - - const match = /language-(\w+)/.exec(className || ''); - + + const match = /language-(\w+)/.exec(className || ""); + return !inline ? ( - + ) : ( - - {children} - + + {children} + ); - } + }, }} > {message} diff --git a/src/frontend/src/modals/chatModal/fileComponent/index.tsx b/src/frontend/src/modals/chatModal/fileComponent/index.tsx index 6c20d58b1..3e3349136 100644 --- a/src/frontend/src/modals/chatModal/fileComponent/index.tsx +++ b/src/frontend/src/modals/chatModal/fileComponent/index.tsx @@ -39,7 +39,10 @@ export default function FileCard({ fileName, content, fileType }) {
-
diff --git a/src/frontend/src/modals/codeAreaModal/index.tsx b/src/frontend/src/modals/codeAreaModal/index.tsx index db4de60f4..d2c539b28 100644 --- a/src/frontend/src/modals/codeAreaModal/index.tsx +++ b/src/frontend/src/modals/codeAreaModal/index.tsx @@ -134,7 +134,7 @@ export default function CodeAreaModal({ title: "Code is ready to run", }); setModalOpen(false); - setValue(code) + setValue(code); } else { if (funcErrors.length !== 0) { setErrorData({ @@ -142,7 +142,7 @@ export default function CodeAreaModal({ list: funcErrors, }); } - if(importsErrors.length!==0){ + if (importsErrors.length !== 0) { setErrorData({ title: "There is an error in your imports", list: importsErrors, diff --git a/src/frontend/src/modals/exportModal/index.tsx b/src/frontend/src/modals/exportModal/index.tsx index 10494bc58..e2761e0fd 100644 --- a/src/frontend/src/modals/exportModal/index.tsx +++ b/src/frontend/src/modals/exportModal/index.tsx @@ -1,9 +1,9 @@ import { Dialog, Transition } from "@headlessui/react"; import { - XMarkIcon, - ArrowDownTrayIcon, - DocumentDuplicateIcon, - ComputerDesktopIcon, + XMarkIcon, + ArrowDownTrayIcon, + DocumentDuplicateIcon, + ComputerDesktopIcon, } from "@heroicons/react/24/outline"; import { Fragment, useContext, useRef, useState } from "react"; import { alertContext } from "../../contexts/alertContext"; @@ -12,169 +12,169 @@ import { TabsContext } from "../../contexts/tabsContext"; import { removeApiKeys } from "../../utils"; export default function ExportModal() { - const [open, setOpen] = useState(true); - const { closePopUp } = useContext(PopUpContext); - const ref = useRef(); - const { setErrorData } = useContext(alertContext); - const { flows, tabIndex, updateFlow, downloadFlow } = useContext(TabsContext); - function setModalOpen(x: boolean) { - setOpen(x); - if (x === false) { - setTimeout(() => { - closePopUp(); - }, 300); - } - } - const [checked, setChecked] = useState(true); - const [name, setName] = useState(flows[tabIndex].name); - return ( - - - -
- + const [open, setOpen] = useState(true); + const { closePopUp } = useContext(PopUpContext); + const ref = useRef(); + const { setErrorData } = useContext(alertContext); + const { flows, tabIndex, updateFlow, downloadFlow } = useContext(TabsContext); + function setModalOpen(x: boolean) { + setOpen(x); + if (x === false) { + setTimeout(() => { + closePopUp(); + }, 300); + } + } + const [checked, setChecked] = useState(true); + const [name, setName] = useState(flows[tabIndex].name); + return ( + + + +
+ -
-
- - -
- -
-
-
-
-
-
- - Export as - -
-
-
-
- - { - if (event.target.value != "") { - let newFlow = flows[tabIndex]; - newFlow.name = event.target.value; - setName(event.target.value); - updateFlow(newFlow); - } else { - setName(event.target.value); - } - }} - type="text" - name="name" - value={name ?? null} - placeholder="File name" - id="name" - className="focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500 text-gray-900 dark:text-gray-100" - /> -
-
- - -
+
+
+ + +
+ +
+
+
+
+
+
+ + Export as + +
+
+
+
+ + { + if (event.target.value != "") { + let newFlow = flows[tabIndex]; + newFlow.name = event.target.value; + setName(event.target.value); + updateFlow(newFlow); + } else { + setName(event.target.value); + } + }} + type="text" + name="name" + value={name ?? null} + placeholder="File name" + id="name" + className="focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500 text-gray-900 dark:text-gray-100" + /> +
+
+ + +
-
- -
-
- -
-
-
-
-
-
-
-
-
- ); +
+ +
+
+ +
+
+
+ + +
+
+ + + ); } diff --git a/src/frontend/src/modals/importModal/index.tsx b/src/frontend/src/modals/importModal/index.tsx index 0ad655bf1..d351b847a 100644 --- a/src/frontend/src/modals/importModal/index.tsx +++ b/src/frontend/src/modals/importModal/index.tsx @@ -1,11 +1,11 @@ import { Dialog, Transition } from "@headlessui/react"; import { - XMarkIcon, - ArrowDownTrayIcon, - DocumentDuplicateIcon, - ComputerDesktopIcon, - ArrowUpTrayIcon, - ArrowLeftIcon, + XMarkIcon, + ArrowDownTrayIcon, + DocumentDuplicateIcon, + ComputerDesktopIcon, + ArrowUpTrayIcon, + ArrowLeftIcon, } from "@heroicons/react/24/outline"; import { Fragment, useContext, useRef, useState } from "react"; import { PopUpContext } from "../../contexts/popUpContext"; @@ -19,214 +19,214 @@ import { FlowType } from "../../types/flow"; import { classNames, toNormalCase } from "../../utils"; export default function ImportModal() { - const [open, setOpen] = useState(true); - const { setErrorData } = useContext(alertContext); - const { closePopUp } = useContext(PopUpContext); - const ref = useRef(); - const [showExamples, setShowExamples] = useState(false); - const [loadingExamples, setLoadingExamples] = useState(false); - const [examples, setExamples] = useState([]); - const { uploadFlow, addFlow } = useContext(TabsContext); - function setModalOpen(x: boolean) { - setOpen(x); - if (x === false) { - setTimeout(() => { - closePopUp(); - }, 300); - } - } + const [open, setOpen] = useState(true); + const { setErrorData } = useContext(alertContext); + const { closePopUp } = useContext(PopUpContext); + const ref = useRef(); + const [showExamples, setShowExamples] = useState(false); + const [loadingExamples, setLoadingExamples] = useState(false); + const [examples, setExamples] = useState([]); + const { uploadFlow, addFlow } = useContext(TabsContext); + function setModalOpen(x: boolean) { + setOpen(x); + if (x === false) { + setTimeout(() => { + closePopUp(); + }, 300); + } + } - function handleExamples() { - setLoadingExamples(true); - getExamples() - .then((result) => { - setLoadingExamples(false); - setExamples(result); - }) - .catch((error) => - setErrorData({ - title: "there was an error loading examples, please try again", - list: [error.message], - }) - ); - } + function handleExamples() { + setLoadingExamples(true); + getExamples() + .then((result) => { + setLoadingExamples(false); + setExamples(result); + }) + .catch((error) => + setErrorData({ + title: "there was an error loading examples, please try again", + list: [error.message], + }) + ); + } - return ( - - - -
- + return ( + + + +
+ -
-
- - -
- -
- {showExamples && ( - <> -
- -
- - - )} -
-
-
-
-
- - {showExamples ? "Select an example" : "Import from"} - -
-
-
- {!showExamples && ( -
- - } - onClick={() => { - setShowExamples(true); - handleExamples(); - }} - textColor="text-emerald-400" - title="Examples" - > - - } - onClick={() => { - uploadFlow(); - setModalOpen(false); - }} - textColor="text-blue-500" - title="Local file" - > -
- )} - {showExamples && loadingExamples && ( -
- -
- )} - {showExamples && - !loadingExamples && - examples.map((example, index) => { - return ( -
- {" "} - - } - onClick={() => { - addFlow(example); - setModalOpen(false); - }} - textColor="text-emerald-400" - title={toNormalCase(example.name)} - > -
- ); - })} -
-
-
-
-
-
-
-
- ); +
+
+ + +
+ +
+ {showExamples && ( + <> +
+ +
+ + + )} +
+
+
+
+
+ + {showExamples ? "Select an example" : "Import from"} + +
+
+
+ {!showExamples && ( +
+ + } + onClick={() => { + setShowExamples(true); + handleExamples(); + }} + textColor="text-emerald-400" + title="Examples" + > + + } + onClick={() => { + uploadFlow(); + setModalOpen(false); + }} + textColor="text-blue-500" + title="Local file" + > +
+ )} + {showExamples && loadingExamples && ( +
+ +
+ )} + {showExamples && + !loadingExamples && + examples.map((example, index) => { + return ( +
+ {" "} + + } + onClick={() => { + addFlow(example); + setModalOpen(false); + }} + textColor="text-emerald-400" + title={toNormalCase(example.name)} + > +
+ ); + })} +
+
+
+
+
+
+
+
+ ); } diff --git a/src/frontend/src/modals/promptModal/index.tsx b/src/frontend/src/modals/promptModal/index.tsx index 10dab2c2c..63edfeb94 100644 --- a/src/frontend/src/modals/promptModal/index.tsx +++ b/src/frontend/src/modals/promptModal/index.tsx @@ -135,7 +135,8 @@ export default function PromptAreaModal({ return setErrorData({ title: "There is something wrong with this prompt, please review it", - list:[error.response.data.detail]}); + list: [error.response.data.detail], + }); }); }} > diff --git a/src/frontend/src/modals/textAreaModal/index.tsx b/src/frontend/src/modals/textAreaModal/index.tsx index 8cfcebcd1..10e4555a4 100644 --- a/src/frontend/src/modals/textAreaModal/index.tsx +++ b/src/frontend/src/modals/textAreaModal/index.tsx @@ -1,104 +1,123 @@ import { Dialog, Transition } from "@headlessui/react"; -import { XMarkIcon, ClipboardDocumentListIcon } from "@heroicons/react/24/outline"; +import { + XMarkIcon, + ClipboardDocumentListIcon, +} from "@heroicons/react/24/outline"; import { Fragment, useContext, useRef, useState } from "react"; import { PopUpContext } from "../../contexts/popUpContext"; -export default function TextAreaModal({value, setValue}:{setValue:(value:string)=>void,value:string|string[]}){ - const [open, setOpen] = useState(true); - const [myValue, setMyValue] = useState(value); - const { closePopUp } = useContext(PopUpContext); - const ref = useRef(); - function setModalOpen(x:boolean){ - setOpen(x); - if(x === false){ - setTimeout(() => {closePopUp()}, 300); - } - } - return ( - - - -
- +export default function TextAreaModal({ + value, + setValue, +}: { + setValue: (value: string) => void; + value: string | string[]; +}) { + const [open, setOpen] = useState(true); + const [myValue, setMyValue] = useState(value); + const { closePopUp } = useContext(PopUpContext); + const ref = useRef(); + function setModalOpen(x: boolean) { + setOpen(x); + if (x === false) { + setTimeout(() => { + closePopUp(); + }, 300); + } + } + return ( + + + +
+ -
-
- - -
- -
-
-
-
-
-
- - Edit text - -
-
-
-
-
-