feat(GenericNode): add debounced validation of node on change to improve performance and user experience
feat(utils.ts): add debounce function to debounce function calls
This commit is contained in:
parent
7a50129149
commit
ed5fd7f862
2 changed files with 208 additions and 185 deletions
|
|
@ -14,6 +14,7 @@ import { PopUpContext } from "../../contexts/popUpContext";
|
||||||
import NodeModal from "../../modals/NodeModal";
|
import NodeModal from "../../modals/NodeModal";
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
|
import { debounce } from "../../utils";
|
||||||
export default function GenericNode({
|
export default function GenericNode({
|
||||||
data,
|
data,
|
||||||
selected,
|
selected,
|
||||||
|
|
@ -29,7 +30,7 @@ export default function GenericNode({
|
||||||
const [validationStatus, setValidationStatus] = useState("idle");
|
const [validationStatus, setValidationStatus] = useState("idle");
|
||||||
// State for outline color
|
// State for outline color
|
||||||
const [isValid, setIsValid] = useState(false);
|
const [isValid, setIsValid] = useState(false);
|
||||||
const {save} = useContext(TabsContext)
|
const { save } = useContext(TabsContext);
|
||||||
const { reactFlowInstance } = useContext(typesContext);
|
const { reactFlowInstance } = useContext(typesContext);
|
||||||
const [params, setParams] = useState([]);
|
const [params, setParams] = useState([]);
|
||||||
|
|
||||||
|
|
@ -41,15 +42,17 @@ export default function GenericNode({
|
||||||
}
|
}
|
||||||
}, [save]);
|
}, [save]);
|
||||||
|
|
||||||
useEffect(() => {
|
const validateNode = useCallback(
|
||||||
|
debounce(async () => {
|
||||||
try {
|
try {
|
||||||
fetch(`/validate/node/${data.id}`, {
|
const response = await fetch(`/validate/node/${data.id}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(reactFlowInstance.toObject()),
|
body: JSON.stringify(reactFlowInstance.toObject()),
|
||||||
}).then((response) => {
|
});
|
||||||
|
|
||||||
console.log(response.status, response.body);
|
console.log(response.status, response.body);
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
|
|
@ -57,12 +60,18 @@ export default function GenericNode({
|
||||||
} else if (response.status === 500) {
|
} else if (response.status === 500) {
|
||||||
setValidationStatus("error");
|
setValidationStatus("error");
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error validating node:", error);
|
console.error("Error validating node:", error);
|
||||||
setValidationStatus("error");
|
setValidationStatus("error");
|
||||||
}
|
}
|
||||||
}, [params]);
|
}, 1000), // Adjust the debounce delay (500ms) as needed
|
||||||
|
[reactFlowInstance, data.id]
|
||||||
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
if (params.length > 0) {
|
||||||
|
validateNode();
|
||||||
|
}
|
||||||
|
}, [params, validateNode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (validationStatus === "success") {
|
if (validationStatus === "success") {
|
||||||
|
|
@ -123,7 +132,8 @@ export default function GenericNode({
|
||||||
<Cog6ToothIcon
|
<Cog6ToothIcon
|
||||||
className={classNames(
|
className={classNames(
|
||||||
Object.keys(data.node.template).some(
|
Object.keys(data.node.template).some(
|
||||||
(t) => data.node.template[t].advanced && data.node.template[t].show
|
(t) =>
|
||||||
|
data.node.template[t].advanced && data.node.template[t].show
|
||||||
)
|
)
|
||||||
? ""
|
? ""
|
||||||
: "hidden",
|
: "hidden",
|
||||||
|
|
@ -170,7 +180,8 @@ export default function GenericNode({
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
)} */}
|
)} */}
|
||||||
{data.node.template[t].show && !data.node.template[t].advanced ? (
|
{data.node.template[t].show &&
|
||||||
|
!data.node.template[t].advanced ? (
|
||||||
<ParameterComponent
|
<ParameterComponent
|
||||||
data={data}
|
data={data}
|
||||||
color={
|
color={
|
||||||
|
|
|
||||||
|
|
@ -399,8 +399,11 @@ export function removeApiKeys(flow: FlowType): FlowType {
|
||||||
return cleanFLow;
|
return cleanFLow;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateObject<T extends Record<string, any>>(reference: T, objectToUpdate: T): T {
|
export function updateObject<T extends Record<string, any>>(
|
||||||
let clonedObject = _.cloneDeep(objectToUpdate)
|
reference: T,
|
||||||
|
objectToUpdate: T
|
||||||
|
): T {
|
||||||
|
let clonedObject = _.cloneDeep(objectToUpdate);
|
||||||
// Loop through each key in the object to update
|
// Loop through each key in the object to update
|
||||||
for (const key in clonedObject) {
|
for (const key in clonedObject) {
|
||||||
// If the key is not in the reference object, delete it
|
// If the key is not in the reference object, delete it
|
||||||
|
|
@ -417,3 +420,12 @@ export function updateObject<T extends Record<string, any>>(reference: T, object
|
||||||
}
|
}
|
||||||
return clonedObject;
|
return clonedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function debounce(func, wait) {
|
||||||
|
let timeout;
|
||||||
|
return function (...args) {
|
||||||
|
const context = this;
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(() => func.apply(context, args), wait);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue