🐛 fix(EditNodeModal): fix state mutation issue by using useRef instead of useState for myData variable

 feat(EditNodeModal): add onChangeOpenModal prop to BaseModal component to reset myData to original data when modal is closed

🔧 chore: fix indentation in setTabsState function call for better code readability

🔧 fix(baseModal): import useEffect from react to fix missing dependency warning
🔧 fix(baseModal): add missing onChangeOpenModal prop to BaseModal component
🔧 fix(baseModal): call onChangeOpenModal prop in useEffect to notify parent component of modal open state change
🔧 fix(genericModal): add empty onChangeOpenModal prop to BaseModal component to fix prop type error
This commit is contained in:
Cristhian Zanforlin Lousa 2023-09-14 20:11:48 -03:00
commit bd9c53bf14
3 changed files with 127 additions and 65 deletions

View file

@ -1,5 +1,12 @@
import { cloneDeep } from "lodash";
import { ReactNode, forwardRef, useContext, useEffect, useState } from "react";
import {
ReactNode,
forwardRef,
useContext,
useEffect,
useRef,
useState,
} from "react";
import CodeAreaComponent from "../../components/codeAreaComponent";
import Dropdown from "../../components/dropdownComponent";
import FloatComponent from "../../components/floatComponent";
@ -44,40 +51,44 @@ const EditNodeModal = forwardRef(
ref
) => {
const [modalOpen, setModalOpen] = useState(false);
const [myData, setMyData] = useState(data);
const { setTabsState, tabId } = useContext(TabsContext);
const { reactFlowInstance } = useContext(typesContext);
const myData = useRef(data);
let disabled =
reactFlowInstance?.getEdges().some((e) => e.targetHandle === data.id) ??
false;
function changeAdvanced(n) {
setMyData((old) => {
let newData = cloneDeep(old);
newData.node.template[n].advanced = !newData.node.template[n].advanced;
return newData;
});
let newData = cloneDeep(data);
newData.node.template[n].advanced = !newData.node.template[n].advanced;
myData.current = newData;
}
const handleOnNewValue = (newValue: any, name) => {
setMyData((old) => {
let newData = cloneDeep(old);
newData.node.template[name].value = newValue;
return newData;
});
let newData = cloneDeep(data);
newData.node.template[name].value = newValue;
myData.current = newData;
};
useEffect(() => {
setMyData(data); // reset data to what it is on node when opening modal
myData.current = data;
}, [modalOpen]);
return (
<BaseModal size="large-h-full" open={modalOpen} setOpen={setModalOpen}>
<BaseModal
size="large-h-full"
open={modalOpen}
setOpen={setModalOpen}
onChangeOpenModal={(open) => {
let newData = cloneDeep(data);
myData.current = newData;
}}
>
<BaseModal.Trigger>{children}</BaseModal.Trigger>
<BaseModal.Header description={myData.node?.description}>
<span className="pr-2">{myData.type}</span>
<Badge variant="secondary">ID: {myData.id}</Badge>
<BaseModal.Header description={myData.current.node?.description}>
<span className="pr-2">{myData.current.type}</span>
<Badge variant="secondary">ID: {myData.current.id}</Badge>
</BaseModal.Header>
<BaseModal.Content>
<div className="flex pb-2">
@ -110,50 +121,57 @@ const EditNodeModal = forwardRef(
</TableRow>
</TableHeader>
<TableBody className="p-0">
{Object.keys(myData.node.template)
{Object.keys(myData.current.node.template)
.filter(
(t) =>
t.charAt(0) !== "_" &&
myData.node.template[t].show &&
(myData.node.template[t].type === "str" ||
myData.node.template[t].type === "bool" ||
myData.node.template[t].type === "float" ||
myData.node.template[t].type === "code" ||
myData.node.template[t].type === "prompt" ||
myData.node.template[t].type === "file" ||
myData.node.template[t].type === "int")
myData.current.node.template[t].show &&
(myData.current.node.template[t].type === "str" ||
myData.current.node.template[t].type === "bool" ||
myData.current.node.template[t].type ===
"float" ||
myData.current.node.template[t].type === "code" ||
myData.current.node.template[t].type ===
"prompt" ||
myData.current.node.template[t].type === "file" ||
myData.current.node.template[t].type === "int")
)
.map((n, i) => (
<TableRow key={i} className="h-10">
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
{myData.node.template[n].name
? myData.node.template[n].name
: myData.node.template[n].display_name}
{myData.current.node.template[n].name
? myData.current.node.template[n].name
: myData.current.node.template[n].display_name}
</TableCell>
<TableCell className="w-[300px] p-0 text-center text-xs text-foreground ">
{myData.node.template[n].type === "str" &&
!myData.node.template[n].options ? (
{myData.current.node.template[n].type === "str" &&
!myData.current.node.template[n].options ? (
<div className="mx-auto">
{myData.node.template[n].list ? (
{myData.current.node.template[n].list ? (
<InputListComponent
editNode={true}
disabled={disabled}
value={
!myData.node.template[n].value ||
myData.node.template[n].value === ""
!myData.current.node.template[n]
.value ||
myData.current.node.template[n]
.value === ""
? [""]
: myData.node.template[n].value
: myData.current.node.template[n]
.value
}
onChange={(t: string[]) => {
handleOnNewValue(t, n);
}}
/>
) : myData.node.template[n].multiline ? (
) : myData.current.node.template[n]
.multiline ? (
<TextAreaComponent
disabled={disabled}
editNode={true}
value={
myData.node.template[n].value ?? ""
myData.current.node.template[n].value ??
""
}
onChange={(t: string) => {
handleOnNewValue(t, n);
@ -164,11 +182,12 @@ const EditNodeModal = forwardRef(
editNode={true}
disabled={disabled}
password={
myData.node.template[n].password ??
false
myData.current.node.template[n]
.password ?? false
}
value={
myData.node.template[n].value ?? ""
myData.current.node.template[n].value ??
""
}
onChange={(t) => {
handleOnNewValue(t, n);
@ -176,89 +195,114 @@ const EditNodeModal = forwardRef(
/>
)}
</div>
) : myData.node.template[n].type === "bool" ? (
) : myData.current.node.template[n].type ===
"bool" ? (
<div className="ml-auto">
{" "}
<ToggleShadComponent
disabled={disabled}
enabled={myData.node.template[n].value}
enabled={
myData.current.node.template[n].value
}
setEnabled={(t) => {
handleOnNewValue(t, n);
}}
size="small"
/>
</div>
) : myData.node.template[n].type === "float" ? (
) : myData.current.node.template[n].type ===
"float" ? (
<div className="mx-auto">
<FloatComponent
disabled={disabled}
editNode={true}
value={myData.node.template[n].value ?? ""}
value={
myData.current.node.template[n].value ??
""
}
onChange={(t) => {
handleOnNewValue(t, n);
}}
/>
</div>
) : myData.node.template[n].type === "str" &&
myData.node.template[n].options ? (
) : myData.current.node.template[n].type ===
"str" &&
myData.current.node.template[n].options ? (
<div className="mx-auto">
<Dropdown
numberOfOptions={nodeLength}
editNode={true}
options={myData.node.template[n].options}
options={
myData.current.node.template[n].options
}
onSelect={(t) => handleOnNewValue(t, n)}
value={
myData.node.template[n].value ??
myData.current.node.template[n].value ??
"Choose an option"
}
></Dropdown>
</div>
) : myData.node.template[n].type === "int" ? (
) : myData.current.node.template[n].type ===
"int" ? (
<div className="mx-auto">
<IntComponent
disabled={disabled}
editNode={true}
value={myData.node.template[n].value ?? ""}
value={
myData.current.node.template[n].value ??
""
}
onChange={(t) => {
handleOnNewValue(t, n);
}}
/>
</div>
) : myData.node.template[n].type === "file" ? (
) : myData.current.node.template[n].type ===
"file" ? (
<div className="mx-auto">
<InputFileComponent
editNode={true}
disabled={disabled}
value={myData.node.template[n].value ?? ""}
value={
myData.current.node.template[n].value ??
""
}
onChange={(t: string) => {
handleOnNewValue(t, n);
}}
fileTypes={
myData.node.template[n].fileTypes
myData.current.node.template[n].fileTypes
}
suffixes={
myData.current.node.template[n].suffixes
}
suffixes={myData.node.template[n].suffixes}
onFileChange={(t: string) => {
data.node.template[n].file_path = t;
}}
></InputFileComponent>
</div>
) : myData.node.template[n].type === "prompt" ? (
) : myData.current.node.template[n].type ===
"prompt" ? (
<div className="mx-auto">
<PromptAreaComponent
field_name={n}
editNode={true}
disabled={disabled}
nodeClass={myData.node}
nodeClass={myData.current.node}
setNodeClass={(nodeClass) => {
myData.node = nodeClass;
myData.current.node = nodeClass;
}}
value={myData.node.template[n].value ?? ""}
value={
myData.current.node.template[n].value ??
""
}
onChange={(t: string) => {
handleOnNewValue(t, n);
}}
/>
</div>
) : myData.node.template[n].type === "code" ? (
) : myData.current.node.template[n].type ===
"code" ? (
<div className="mx-auto">
<CodeAreaComponent
dynamic={
@ -270,13 +314,17 @@ const EditNodeModal = forwardRef(
nodeClass={data.node}
disabled={disabled}
editNode={true}
value={myData.node.template[n].value ?? ""}
value={
myData.current.node.template[n].value ??
""
}
onChange={(t: string) => {
handleOnNewValue(t, n);
}}
/>
</div>
) : myData.node.template[n].type === "Any" ? (
) : myData.current.node.template[n].type ===
"Any" ? (
"-"
) : (
<div className="hidden"></div>
@ -285,7 +333,9 @@ const EditNodeModal = forwardRef(
<TableCell className="p-0 text-right">
<div className="items-center text-center">
<ToggleShadComponent
enabled={!myData.node.template[n].advanced}
enabled={
!myData.current.node.template[n].advanced
}
setEnabled={(e) => changeAdvanced(n)}
disabled={disabled}
size="small"
@ -306,7 +356,7 @@ const EditNodeModal = forwardRef(
<Button
className="mt-3"
onClick={() => {
setData(cloneDeep(myData)); //saves data with actual state of modal
setData(cloneDeep(myData.current)); //saves data with actual state of modal
setTabsState((prev) => {
return {
...prev,

View file

@ -1,4 +1,4 @@
import { ReactNode } from "react";
import { ReactNode, useEffect } from "react";
import React from "react";
import {
@ -48,6 +48,7 @@ interface BaseModalProps {
setOpen?: (open: boolean) => void;
disable?: boolean;
size?: "smaller" | "small" | "medium" | "large" | "large-h-full";
onChangeOpenModal?: (open: boolean) => void;
}
function BaseModal({
open,
@ -55,6 +56,7 @@ function BaseModal({
disable = false,
children,
size = "large",
onChangeOpenModal,
}: BaseModalProps) {
const headerChild = React.Children.toArray(children).find(
(child) => (child as React.ReactElement).type === Header
@ -98,6 +100,12 @@ function BaseModal({
break;
}
useEffect(() => {
if (onChangeOpenModal) {
onChangeOpenModal(open);
}
}, [open]);
//UPDATE COLORS AND STYLE CLASSSES
return (
<Dialog open={open} onOpenChange={setOpen}>

View file

@ -179,7 +179,11 @@ export default function GenericModal({
const [modalOpen, setModalOpen] = useState(false);
return (
<BaseModal open={modalOpen} setOpen={setModalOpen}>
<BaseModal
onChangeOpenModal={(open) => {}}
open={modalOpen}
setOpen={setModalOpen}
>
<BaseModal.Trigger>{children}</BaseModal.Trigger>
<BaseModal.Header
description={(() => {