Fixed Flows state not being updated always

This commit is contained in:
Lucas Oliveira 2023-12-08 19:10:32 -03:00
commit d6ea72cbea
9 changed files with 77 additions and 81 deletions

View file

@ -1,4 +1,3 @@
import { cloneDeep } from "lodash";
import { useContext, useEffect, useState } from "react";
import { NodeToolbar, useUpdateNodeInternals } from "reactflow";
import ShadTooltip from "../../components/ShadTooltipComponent";
@ -14,11 +13,7 @@ import { undoRedoContext } from "../../contexts/undoRedoContext";
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
import { validationStatusType } from "../../types/components";
import { NodeDataType } from "../../types/flow";
import {
cleanEdges,
handleKeyDown,
scapedJSONStringfy,
} from "../../utils/reactflowUtils";
import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
import { classNames, getFieldTitle } from "../../utils/utils";
import ParameterComponent from "./components/parameterComponent";
@ -34,7 +29,8 @@ export default function GenericNode({
xPos: number;
yPos: number;
}): JSX.Element {
const { updateFlow, flows, tabId } = useContext(FlowsContext);
const { updateFlow, flows, tabId, saveCurrentFlow } =
useContext(FlowsContext);
const updateNodeInternals = useUpdateNodeInternals();
const { types, deleteNode, reactFlowInstance, setFilterEdge, getFilterEdge } =
useContext(typesContext);
@ -87,18 +83,15 @@ export default function GenericNode({
// State for outline color
const { sseData, isBuilding } = useSSE();
useEffect(() => {
let myFlow = flows.find((flow) => flow.id === tabId);
if (reactFlowInstance && myFlow) {
let flow = cloneDeep(myFlow);
flow.data = reactFlowInstance.toObject();
/* useEffect(() => {
let flow = flows.find((flow) => flow.id === tabId);
if (reactFlowInstance && flow && flow.data) {
cleanEdges({
flow: {
edges: flow.data.edges,
nodes: flow.data.nodes,
edges: flow.data!.edges,
nodes: flow.data!.nodes,
},
updateEdge: (edge) => {
flow.data!.edges = edge;
reactFlowInstance.setEdges(edge);
updateNodeInternals(data.id);
},
@ -106,7 +99,7 @@ export default function GenericNode({
updateFlow(flow);
}
countHandles();
}, [data]);
}, [data]); */
useEffect(() => {
setNodeDescription(data.node!.description);
@ -138,6 +131,7 @@ export default function GenericNode({
deleteNode={(id) => {
takeSnapshot();
deleteNode(id);
saveCurrentFlow();
}}
setShowNode={(show: boolean) => {
data.showNode = show;

View file

@ -76,11 +76,8 @@ export default function BuildTrigger({
}
async function streamNodeData(flow: FlowType) {
// Step 1: Make a POST request to send the flow data and receive a unique session ID
const id = saveFlow({ ...flow, data: reactFlowInstance!.toObject() }, true);
const response = await postBuildInit({
...flow,
data: reactFlowInstance!.toObject(),
});
const id = saveFlow(flow, true);
const response = await postBuildInit(flow);
const { flowId } = response.data;
// Step 2: Use the session ID to establish an SSE connection using EventSource
let validationResults: boolean[] = [];

View file

@ -82,6 +82,7 @@ const FlowsContextInitialValue: FlowsContextType = {
setLastCopiedSelection: (selection: any) => {},
tabsState: {},
setTabsState: (state: FlowsState) => {},
saveCurrentFlow: () => {},
getNodeId: (nodeType: string) => "",
setTweak: (tweak: any) => {},
getTweak: [],
@ -638,8 +639,14 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
});
}
function saveCurrentFlow() {
const currentFlow = flows.find((flow) => flow.id === tabId);
if (currentFlow && reactFlowInstance && currentFlow.data) {
updateFlow({ ...currentFlow, data: reactFlowInstance?.toObject()! });
}
}
async function saveFlow(newFlow: FlowType, silent?: boolean) {
console.log(newFlow);
try {
// updates flow in db
const updatedFlow = await updateFlowInDatabase(newFlow);
@ -668,8 +675,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
},
};
});
console.log(tabsState);
}
} catch (err) {
setErrorData({
@ -713,6 +718,7 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
setIsBuilt,
lastCopiedSelection,
setLastCopiedSelection,
saveCurrentFlow,
hardReset,
tabId,
setTabId,

View file

@ -68,7 +68,7 @@ const ExportModal = forwardRef(
downloadFlow(
{
id: tabId,
data: reactFlowInstance?.toObject()!,
data: flow!.data!,
description,
name,
last_tested_version: version,
@ -85,7 +85,7 @@ const ExportModal = forwardRef(
downloadFlow(
removeApiKeys({
id: tabId,
data: reactFlowInstance?.toObject()!,
data: flow!.data!,
description,
name,
last_tested_version: version,

View file

@ -393,7 +393,7 @@ export default function FormModal({
const message = inputs;
addChatHistory(message!, true, chatKey!, template.current);
sendAll({
...reactFlowInstance?.toObject()!,
...flow.data!,
inputs: inputs!,
chatHistory,
name: flow.name,

View file

@ -8,6 +8,7 @@ import { Checkbox } from "../../components/ui/checkbox";
import { alertContext } from "../../contexts/alertContext";
import { FlowsContext } from "../../contexts/flowsContext";
import { StoreContext } from "../../contexts/storeContext";
import { typesContext } from "../../contexts/typesContext";
import {
getStoreComponents,
getStoreTags,
@ -41,6 +42,7 @@ export default function ShareModal({
const { version, addFlow } = useContext(FlowsContext);
const { hasApiKey, hasStore } = useContext(StoreContext);
const { setSuccessData, setErrorData } = useContext(alertContext);
const { reactFlowInstance } = useContext(typesContext);
const [checked, setChecked] = useState(false);
const [name, setName] = useState(component?.name ?? "");
const [description, setDescription] = useState(component?.description ?? "");
@ -127,7 +129,8 @@ export default function ShareModal({
});
}
await saveFlow(flows.find((flow) => flow.id === tabId)!, true);
await saveFlow({ ...flows.find((flow) => flow.id === tabId)! }, true);
if (!update)
saveFlowStore(flow!, getTagsIds(selectedTags, tags), sharePublic).then(
successShare,

View file

@ -60,7 +60,6 @@ export default function Page({
let {
updateFlow,
uploadFlow,
addFlow,
getNodeId,
paste,
lastCopiedSelection,
@ -69,7 +68,7 @@ export default function Page({
saveFlow,
setTabsState,
tabId,
flows,
saveCurrentFlow,
} = useContext(FlowsContext);
const {
types,
@ -89,6 +88,12 @@ export default function Page({
const [lastSelection, setLastSelection] =
useState<OnSelectionChangeParams | null>(null);
const saveCurrentFlowTimeout = () => {
setTimeout(() => {
saveCurrentFlow();
}, 500); // need to do this because ReactFlow is not asynchronous.
};
useEffect(() => {
const onKeyDown = (event: KeyboardEvent) => {
if (
@ -132,6 +137,7 @@ export default function Page({
takeSnapshot();
deleteNode(lastSelection.nodes.map((node) => node.id));
deleteEdge(lastSelection.edges.map((edge) => edge.id));
saveCurrentFlowTimeout();
}
}
};
@ -147,7 +153,12 @@ export default function Page({
document.removeEventListener("keydown", onKeyDown);
document.removeEventListener("mousemove", handleMouseMove);
};
}, [lastCopiedSelection, lastSelection, takeSnapshot]);
}, [
lastCopiedSelection,
lastSelection,
takeSnapshot,
saveCurrentFlowTimeout,
]);
const [selectionMenuVisible, setSelectionMenuVisible] = useState(false);
@ -190,16 +201,8 @@ export default function Page({
}, [flow, reactFlowInstance]);
useEffect(() => {
const index = flows.findIndex((flowId) => flowId.id === flow.id);
const interval = setInterval(() => {
saveFlow(
{
...flows[index]!,
data: reactFlowInstance ? reactFlowInstance!.toObject() : flow!.data,
},
true
);
saveFlow(flow, true);
}, 30000);
return () => {
@ -209,10 +212,6 @@ export default function Page({
const onEdgesChangeMod = useCallback(
(change: EdgeChange[]) => {
updateFlow({
...flow!,
data: reactFlowInstance ? reactFlowInstance!.toObject() : flow!.data,
});
onEdgesChange(change);
//@ts-ignore
setTabsState((prev: FlowsState) => {
@ -220,18 +219,18 @@ export default function Page({
...prev,
[tabId]: {
...prev[tabId],
isPending: false,
isPending: true,
},
};
});
saveCurrentFlowTimeout();
},
[onEdgesChange, setNodes, setTabsState, tabId]
[onEdgesChange, setNodes, setTabsState, saveCurrentFlowTimeout, tabId]
);
const onNodesChangeMod = useCallback(
(change: NodeChange[]) => {
const changeString = JSON.stringify(change);
if (changeString !== nodesOnFlow) {
onNodesChange(change);
updateNodeFlow(changeString);
@ -245,9 +244,10 @@ export default function Page({
},
};
});
saveCurrentFlowTimeout();
}
},
[onNodesChange, setTabsState, tabId, updateNodeFlow]
[onNodesChange, setTabsState, tabId, updateNodeFlow, saveCurrentFlowTimeout]
);
function updateNodeFlow(changeString: string) {
@ -283,7 +283,7 @@ export default function Page({
return newX;
});
},
[setEdges, setNodes, takeSnapshot]
[setEdges, setNodes, takeSnapshot, addEdge]
);
const onNodeDragStart: NodeDragHandler = useCallback(() => {
@ -394,10 +394,7 @@ export default function Page({
return () => {
if (tabsState && tabsState[flow.id]?.isPending) {
saveFlow({
...flow!,
data: reactFlowInstance ? reactFlowInstance!.toObject() : flow!.data,
});
saveFlow(flow);
}
};
}, []);
@ -475,11 +472,7 @@ export default function Page({
<ReactFlow
nodes={nodes}
onMove={() => {
if (reactFlowInstance)
updateFlow({
...flow,
data: reactFlowInstance.toObject(),
});
saveCurrentFlowTimeout();
}}
edges={edges}
onNodesChange={onNodesChangeMod}

View file

@ -289,32 +289,34 @@ export default function ExtraSidebar(): JSX.Element {
</div>
</ShadTooltip>
<div className="side-bar-button">
<ShadTooltip content="Save" side="top">
<div>
<button
disabled={flow?.data?.nodes.length === 0}
className={
"extra-side-bar-buttons " +
(isPending && flow!.data!.nodes?.length > 0
? ""
: "button-disable")
}
onClick={(event) => {
saveFlow({ ...flow!, data: reactFlowInstance!.toObject() });
}}
>
<IconComponent
name="Save"
{flow && flow.data && (
<ShadTooltip content="Save" side="top">
<div>
<button
disabled={flow?.data?.nodes.length === 0}
className={
"side-bar-button-size" +
"extra-side-bar-buttons " +
(isPending && flow!.data!.nodes?.length > 0
? " "
: " extra-side-bar-save-disable")
? ""
: "button-disable")
}
/>
</button>
</div>
</ShadTooltip>
onClick={(event) => {
saveFlow(flow!);
}}
>
<IconComponent
name="Save"
className={
"side-bar-button-size" +
(isPending && flow!.data!.nodes?.length > 0
? " "
: " extra-side-bar-save-disable")
}
/>
</button>
</div>
</ShadTooltip>
)}
</div>
<ShadTooltip content="Share" side="top" styleClasses="cursor-default">
<div className="side-bar-button">{ModalMemo}</div>

View file

@ -26,6 +26,7 @@ export type FlowsContextType = {
uploadFlows: () => void;
isBuilt: boolean;
setIsBuilt: (state: boolean) => void;
saveCurrentFlow: () => void;
uploadFlow: ({
newProject,
file,