Fixed Flows state not being updated always
This commit is contained in:
parent
154d77b579
commit
d6ea72cbea
9 changed files with 77 additions and 81 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
import { cloneDeep } from "lodash";
|
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import { NodeToolbar, useUpdateNodeInternals } from "reactflow";
|
import { NodeToolbar, useUpdateNodeInternals } from "reactflow";
|
||||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||||
|
|
@ -14,11 +13,7 @@ import { undoRedoContext } from "../../contexts/undoRedoContext";
|
||||||
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
||||||
import { validationStatusType } from "../../types/components";
|
import { validationStatusType } from "../../types/components";
|
||||||
import { NodeDataType } from "../../types/flow";
|
import { NodeDataType } from "../../types/flow";
|
||||||
import {
|
import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
|
||||||
cleanEdges,
|
|
||||||
handleKeyDown,
|
|
||||||
scapedJSONStringfy,
|
|
||||||
} from "../../utils/reactflowUtils";
|
|
||||||
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
||||||
import { classNames, getFieldTitle } from "../../utils/utils";
|
import { classNames, getFieldTitle } from "../../utils/utils";
|
||||||
import ParameterComponent from "./components/parameterComponent";
|
import ParameterComponent from "./components/parameterComponent";
|
||||||
|
|
@ -34,7 +29,8 @@ export default function GenericNode({
|
||||||
xPos: number;
|
xPos: number;
|
||||||
yPos: number;
|
yPos: number;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const { updateFlow, flows, tabId } = useContext(FlowsContext);
|
const { updateFlow, flows, tabId, saveCurrentFlow } =
|
||||||
|
useContext(FlowsContext);
|
||||||
const updateNodeInternals = useUpdateNodeInternals();
|
const updateNodeInternals = useUpdateNodeInternals();
|
||||||
const { types, deleteNode, reactFlowInstance, setFilterEdge, getFilterEdge } =
|
const { types, deleteNode, reactFlowInstance, setFilterEdge, getFilterEdge } =
|
||||||
useContext(typesContext);
|
useContext(typesContext);
|
||||||
|
|
@ -87,18 +83,15 @@ export default function GenericNode({
|
||||||
|
|
||||||
// State for outline color
|
// State for outline color
|
||||||
const { sseData, isBuilding } = useSSE();
|
const { sseData, isBuilding } = useSSE();
|
||||||
useEffect(() => {
|
/* useEffect(() => {
|
||||||
let myFlow = flows.find((flow) => flow.id === tabId);
|
let flow = flows.find((flow) => flow.id === tabId);
|
||||||
if (reactFlowInstance && myFlow) {
|
if (reactFlowInstance && flow && flow.data) {
|
||||||
let flow = cloneDeep(myFlow);
|
|
||||||
flow.data = reactFlowInstance.toObject();
|
|
||||||
cleanEdges({
|
cleanEdges({
|
||||||
flow: {
|
flow: {
|
||||||
edges: flow.data.edges,
|
edges: flow.data!.edges,
|
||||||
nodes: flow.data.nodes,
|
nodes: flow.data!.nodes,
|
||||||
},
|
},
|
||||||
updateEdge: (edge) => {
|
updateEdge: (edge) => {
|
||||||
flow.data!.edges = edge;
|
|
||||||
reactFlowInstance.setEdges(edge);
|
reactFlowInstance.setEdges(edge);
|
||||||
updateNodeInternals(data.id);
|
updateNodeInternals(data.id);
|
||||||
},
|
},
|
||||||
|
|
@ -106,7 +99,7 @@ export default function GenericNode({
|
||||||
updateFlow(flow);
|
updateFlow(flow);
|
||||||
}
|
}
|
||||||
countHandles();
|
countHandles();
|
||||||
}, [data]);
|
}, [data]); */
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNodeDescription(data.node!.description);
|
setNodeDescription(data.node!.description);
|
||||||
|
|
@ -138,6 +131,7 @@ export default function GenericNode({
|
||||||
deleteNode={(id) => {
|
deleteNode={(id) => {
|
||||||
takeSnapshot();
|
takeSnapshot();
|
||||||
deleteNode(id);
|
deleteNode(id);
|
||||||
|
saveCurrentFlow();
|
||||||
}}
|
}}
|
||||||
setShowNode={(show: boolean) => {
|
setShowNode={(show: boolean) => {
|
||||||
data.showNode = show;
|
data.showNode = show;
|
||||||
|
|
|
||||||
|
|
@ -76,11 +76,8 @@ export default function BuildTrigger({
|
||||||
}
|
}
|
||||||
async function streamNodeData(flow: FlowType) {
|
async function streamNodeData(flow: FlowType) {
|
||||||
// Step 1: Make a POST request to send the flow data and receive a unique session ID
|
// 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 id = saveFlow(flow, true);
|
||||||
const response = await postBuildInit({
|
const response = await postBuildInit(flow);
|
||||||
...flow,
|
|
||||||
data: reactFlowInstance!.toObject(),
|
|
||||||
});
|
|
||||||
const { flowId } = response.data;
|
const { flowId } = response.data;
|
||||||
// Step 2: Use the session ID to establish an SSE connection using EventSource
|
// Step 2: Use the session ID to establish an SSE connection using EventSource
|
||||||
let validationResults: boolean[] = [];
|
let validationResults: boolean[] = [];
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ const FlowsContextInitialValue: FlowsContextType = {
|
||||||
setLastCopiedSelection: (selection: any) => {},
|
setLastCopiedSelection: (selection: any) => {},
|
||||||
tabsState: {},
|
tabsState: {},
|
||||||
setTabsState: (state: FlowsState) => {},
|
setTabsState: (state: FlowsState) => {},
|
||||||
|
saveCurrentFlow: () => {},
|
||||||
getNodeId: (nodeType: string) => "",
|
getNodeId: (nodeType: string) => "",
|
||||||
setTweak: (tweak: any) => {},
|
setTweak: (tweak: any) => {},
|
||||||
getTweak: [],
|
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) {
|
async function saveFlow(newFlow: FlowType, silent?: boolean) {
|
||||||
console.log(newFlow);
|
|
||||||
try {
|
try {
|
||||||
// updates flow in db
|
// updates flow in db
|
||||||
const updatedFlow = await updateFlowInDatabase(newFlow);
|
const updatedFlow = await updateFlowInDatabase(newFlow);
|
||||||
|
|
@ -668,8 +675,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(tabsState);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setErrorData({
|
setErrorData({
|
||||||
|
|
@ -713,6 +718,7 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
|
||||||
setIsBuilt,
|
setIsBuilt,
|
||||||
lastCopiedSelection,
|
lastCopiedSelection,
|
||||||
setLastCopiedSelection,
|
setLastCopiedSelection,
|
||||||
|
saveCurrentFlow,
|
||||||
hardReset,
|
hardReset,
|
||||||
tabId,
|
tabId,
|
||||||
setTabId,
|
setTabId,
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ const ExportModal = forwardRef(
|
||||||
downloadFlow(
|
downloadFlow(
|
||||||
{
|
{
|
||||||
id: tabId,
|
id: tabId,
|
||||||
data: reactFlowInstance?.toObject()!,
|
data: flow!.data!,
|
||||||
description,
|
description,
|
||||||
name,
|
name,
|
||||||
last_tested_version: version,
|
last_tested_version: version,
|
||||||
|
|
@ -85,7 +85,7 @@ const ExportModal = forwardRef(
|
||||||
downloadFlow(
|
downloadFlow(
|
||||||
removeApiKeys({
|
removeApiKeys({
|
||||||
id: tabId,
|
id: tabId,
|
||||||
data: reactFlowInstance?.toObject()!,
|
data: flow!.data!,
|
||||||
description,
|
description,
|
||||||
name,
|
name,
|
||||||
last_tested_version: version,
|
last_tested_version: version,
|
||||||
|
|
|
||||||
|
|
@ -393,7 +393,7 @@ export default function FormModal({
|
||||||
const message = inputs;
|
const message = inputs;
|
||||||
addChatHistory(message!, true, chatKey!, template.current);
|
addChatHistory(message!, true, chatKey!, template.current);
|
||||||
sendAll({
|
sendAll({
|
||||||
...reactFlowInstance?.toObject()!,
|
...flow.data!,
|
||||||
inputs: inputs!,
|
inputs: inputs!,
|
||||||
chatHistory,
|
chatHistory,
|
||||||
name: flow.name,
|
name: flow.name,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { Checkbox } from "../../components/ui/checkbox";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { FlowsContext } from "../../contexts/flowsContext";
|
import { FlowsContext } from "../../contexts/flowsContext";
|
||||||
import { StoreContext } from "../../contexts/storeContext";
|
import { StoreContext } from "../../contexts/storeContext";
|
||||||
|
import { typesContext } from "../../contexts/typesContext";
|
||||||
import {
|
import {
|
||||||
getStoreComponents,
|
getStoreComponents,
|
||||||
getStoreTags,
|
getStoreTags,
|
||||||
|
|
@ -41,6 +42,7 @@ export default function ShareModal({
|
||||||
const { version, addFlow } = useContext(FlowsContext);
|
const { version, addFlow } = useContext(FlowsContext);
|
||||||
const { hasApiKey, hasStore } = useContext(StoreContext);
|
const { hasApiKey, hasStore } = useContext(StoreContext);
|
||||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||||
|
const { reactFlowInstance } = useContext(typesContext);
|
||||||
const [checked, setChecked] = useState(false);
|
const [checked, setChecked] = useState(false);
|
||||||
const [name, setName] = useState(component?.name ?? "");
|
const [name, setName] = useState(component?.name ?? "");
|
||||||
const [description, setDescription] = useState(component?.description ?? "");
|
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)
|
if (!update)
|
||||||
saveFlowStore(flow!, getTagsIds(selectedTags, tags), sharePublic).then(
|
saveFlowStore(flow!, getTagsIds(selectedTags, tags), sharePublic).then(
|
||||||
successShare,
|
successShare,
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ export default function Page({
|
||||||
let {
|
let {
|
||||||
updateFlow,
|
updateFlow,
|
||||||
uploadFlow,
|
uploadFlow,
|
||||||
addFlow,
|
|
||||||
getNodeId,
|
getNodeId,
|
||||||
paste,
|
paste,
|
||||||
lastCopiedSelection,
|
lastCopiedSelection,
|
||||||
|
|
@ -69,7 +68,7 @@ export default function Page({
|
||||||
saveFlow,
|
saveFlow,
|
||||||
setTabsState,
|
setTabsState,
|
||||||
tabId,
|
tabId,
|
||||||
flows,
|
saveCurrentFlow,
|
||||||
} = useContext(FlowsContext);
|
} = useContext(FlowsContext);
|
||||||
const {
|
const {
|
||||||
types,
|
types,
|
||||||
|
|
@ -89,6 +88,12 @@ export default function Page({
|
||||||
const [lastSelection, setLastSelection] =
|
const [lastSelection, setLastSelection] =
|
||||||
useState<OnSelectionChangeParams | null>(null);
|
useState<OnSelectionChangeParams | null>(null);
|
||||||
|
|
||||||
|
const saveCurrentFlowTimeout = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
saveCurrentFlow();
|
||||||
|
}, 500); // need to do this because ReactFlow is not asynchronous.
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onKeyDown = (event: KeyboardEvent) => {
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
if (
|
if (
|
||||||
|
|
@ -132,6 +137,7 @@ export default function Page({
|
||||||
takeSnapshot();
|
takeSnapshot();
|
||||||
deleteNode(lastSelection.nodes.map((node) => node.id));
|
deleteNode(lastSelection.nodes.map((node) => node.id));
|
||||||
deleteEdge(lastSelection.edges.map((edge) => edge.id));
|
deleteEdge(lastSelection.edges.map((edge) => edge.id));
|
||||||
|
saveCurrentFlowTimeout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -147,7 +153,12 @@ export default function Page({
|
||||||
document.removeEventListener("keydown", onKeyDown);
|
document.removeEventListener("keydown", onKeyDown);
|
||||||
document.removeEventListener("mousemove", handleMouseMove);
|
document.removeEventListener("mousemove", handleMouseMove);
|
||||||
};
|
};
|
||||||
}, [lastCopiedSelection, lastSelection, takeSnapshot]);
|
}, [
|
||||||
|
lastCopiedSelection,
|
||||||
|
lastSelection,
|
||||||
|
takeSnapshot,
|
||||||
|
saveCurrentFlowTimeout,
|
||||||
|
]);
|
||||||
|
|
||||||
const [selectionMenuVisible, setSelectionMenuVisible] = useState(false);
|
const [selectionMenuVisible, setSelectionMenuVisible] = useState(false);
|
||||||
|
|
||||||
|
|
@ -190,16 +201,8 @@ export default function Page({
|
||||||
}, [flow, reactFlowInstance]);
|
}, [flow, reactFlowInstance]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const index = flows.findIndex((flowId) => flowId.id === flow.id);
|
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
saveFlow(
|
saveFlow(flow, true);
|
||||||
{
|
|
||||||
...flows[index]!,
|
|
||||||
data: reactFlowInstance ? reactFlowInstance!.toObject() : flow!.data,
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}, 30000);
|
}, 30000);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -209,10 +212,6 @@ export default function Page({
|
||||||
|
|
||||||
const onEdgesChangeMod = useCallback(
|
const onEdgesChangeMod = useCallback(
|
||||||
(change: EdgeChange[]) => {
|
(change: EdgeChange[]) => {
|
||||||
updateFlow({
|
|
||||||
...flow!,
|
|
||||||
data: reactFlowInstance ? reactFlowInstance!.toObject() : flow!.data,
|
|
||||||
});
|
|
||||||
onEdgesChange(change);
|
onEdgesChange(change);
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
setTabsState((prev: FlowsState) => {
|
setTabsState((prev: FlowsState) => {
|
||||||
|
|
@ -220,18 +219,18 @@ export default function Page({
|
||||||
...prev,
|
...prev,
|
||||||
[tabId]: {
|
[tabId]: {
|
||||||
...prev[tabId],
|
...prev[tabId],
|
||||||
isPending: false,
|
isPending: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
saveCurrentFlowTimeout();
|
||||||
},
|
},
|
||||||
[onEdgesChange, setNodes, setTabsState, tabId]
|
[onEdgesChange, setNodes, setTabsState, saveCurrentFlowTimeout, tabId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onNodesChangeMod = useCallback(
|
const onNodesChangeMod = useCallback(
|
||||||
(change: NodeChange[]) => {
|
(change: NodeChange[]) => {
|
||||||
const changeString = JSON.stringify(change);
|
const changeString = JSON.stringify(change);
|
||||||
|
|
||||||
if (changeString !== nodesOnFlow) {
|
if (changeString !== nodesOnFlow) {
|
||||||
onNodesChange(change);
|
onNodesChange(change);
|
||||||
updateNodeFlow(changeString);
|
updateNodeFlow(changeString);
|
||||||
|
|
@ -245,9 +244,10 @@ export default function Page({
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
saveCurrentFlowTimeout();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onNodesChange, setTabsState, tabId, updateNodeFlow]
|
[onNodesChange, setTabsState, tabId, updateNodeFlow, saveCurrentFlowTimeout]
|
||||||
);
|
);
|
||||||
|
|
||||||
function updateNodeFlow(changeString: string) {
|
function updateNodeFlow(changeString: string) {
|
||||||
|
|
@ -283,7 +283,7 @@ export default function Page({
|
||||||
return newX;
|
return newX;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[setEdges, setNodes, takeSnapshot]
|
[setEdges, setNodes, takeSnapshot, addEdge]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onNodeDragStart: NodeDragHandler = useCallback(() => {
|
const onNodeDragStart: NodeDragHandler = useCallback(() => {
|
||||||
|
|
@ -394,10 +394,7 @@ export default function Page({
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (tabsState && tabsState[flow.id]?.isPending) {
|
if (tabsState && tabsState[flow.id]?.isPending) {
|
||||||
saveFlow({
|
saveFlow(flow);
|
||||||
...flow!,
|
|
||||||
data: reactFlowInstance ? reactFlowInstance!.toObject() : flow!.data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -475,11 +472,7 @@ export default function Page({
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
onMove={() => {
|
onMove={() => {
|
||||||
if (reactFlowInstance)
|
saveCurrentFlowTimeout();
|
||||||
updateFlow({
|
|
||||||
...flow,
|
|
||||||
data: reactFlowInstance.toObject(),
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
onNodesChange={onNodesChangeMod}
|
onNodesChange={onNodesChangeMod}
|
||||||
|
|
|
||||||
|
|
@ -289,32 +289,34 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
<div className="side-bar-button">
|
<div className="side-bar-button">
|
||||||
<ShadTooltip content="Save" side="top">
|
{flow && flow.data && (
|
||||||
<div>
|
<ShadTooltip content="Save" side="top">
|
||||||
<button
|
<div>
|
||||||
disabled={flow?.data?.nodes.length === 0}
|
<button
|
||||||
className={
|
disabled={flow?.data?.nodes.length === 0}
|
||||||
"extra-side-bar-buttons " +
|
|
||||||
(isPending && flow!.data!.nodes?.length > 0
|
|
||||||
? ""
|
|
||||||
: "button-disable")
|
|
||||||
}
|
|
||||||
onClick={(event) => {
|
|
||||||
saveFlow({ ...flow!, data: reactFlowInstance!.toObject() });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IconComponent
|
|
||||||
name="Save"
|
|
||||||
className={
|
className={
|
||||||
"side-bar-button-size" +
|
"extra-side-bar-buttons " +
|
||||||
(isPending && flow!.data!.nodes?.length > 0
|
(isPending && flow!.data!.nodes?.length > 0
|
||||||
? " "
|
? ""
|
||||||
: " extra-side-bar-save-disable")
|
: "button-disable")
|
||||||
}
|
}
|
||||||
/>
|
onClick={(event) => {
|
||||||
</button>
|
saveFlow(flow!);
|
||||||
</div>
|
}}
|
||||||
</ShadTooltip>
|
>
|
||||||
|
<IconComponent
|
||||||
|
name="Save"
|
||||||
|
className={
|
||||||
|
"side-bar-button-size" +
|
||||||
|
(isPending && flow!.data!.nodes?.length > 0
|
||||||
|
? " "
|
||||||
|
: " extra-side-bar-save-disable")
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</ShadTooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<ShadTooltip content="Share" side="top" styleClasses="cursor-default">
|
<ShadTooltip content="Share" side="top" styleClasses="cursor-default">
|
||||||
<div className="side-bar-button">{ModalMemo}</div>
|
<div className="side-bar-button">{ModalMemo}</div>
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ export type FlowsContextType = {
|
||||||
uploadFlows: () => void;
|
uploadFlows: () => void;
|
||||||
isBuilt: boolean;
|
isBuilt: boolean;
|
||||||
setIsBuilt: (state: boolean) => void;
|
setIsBuilt: (state: boolean) => void;
|
||||||
|
saveCurrentFlow: () => void;
|
||||||
uploadFlow: ({
|
uploadFlow: ({
|
||||||
newProject,
|
newProject,
|
||||||
file,
|
file,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue