Removed all reactFlowInstance nodes and edges settings. Centralized flow saving.

This commit is contained in:
Lucas Oliveira 2023-12-30 20:50:51 -03:00
commit f6bd5a4e4a
12 changed files with 96 additions and 167 deletions

View file

@ -73,10 +73,8 @@ export default function ParameterComponent({
const { const {
tabId, tabId,
flows, flows,
updateFlow,
nodes, nodes,
edges, edges,
setEdges,
setNode, setNode,
} = useContext(FlowsContext); } = useContext(FlowsContext);
@ -154,7 +152,7 @@ export default function ParameterComponent({
newData.node!.template[name].value = newValue; newData.node!.template[name].value = newValue;
return newData; return newData;
}); });
renderTooltips(); renderTooltips();
}; };

View file

@ -30,11 +30,9 @@ export default function GenericNode({
xPos: number; xPos: number;
yPos: number; yPos: number;
}): JSX.Element { }): JSX.Element {
const { updateFlow, flows, tabId, saveCurrentFlow } =
useContext(FlowsContext);
const updateNodeInternals = useUpdateNodeInternals(); const updateNodeInternals = useUpdateNodeInternals();
const { types, deleteNode } = const { types } = useContext(typesContext);
useContext(typesContext); const { deleteNode } = useContext(FlowsContext);
const name = nodeIconsLucide[data.type] ? data.type : types[data.type]; const name = nodeIconsLucide[data.type] ? data.type : types[data.type];
const [inputName, setInputName] = useState(false); const [inputName, setInputName] = useState(false);
const [nodeName, setNodeName] = useState(data.node!.display_name); const [nodeName, setNodeName] = useState(data.node!.display_name);
@ -46,7 +44,6 @@ export default function GenericNode({
useState<validationStatusType | null>(null); useState<validationStatusType | null>(null);
const [handles, setHandles] = useState<boolean[] | []>([]); const [handles, setHandles] = useState<boolean[] | []>([]);
let numberOfInputs: boolean[] = []; let numberOfInputs: boolean[] = [];
const { modalContextOpen } = useContext(alertContext);
const { takeSnapshot } = useContext(undoRedoContext); const { takeSnapshot } = useContext(undoRedoContext);
@ -118,7 +115,6 @@ 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;

View file

@ -13,7 +13,7 @@ import { NodeType } from "../../types/flow";
export default function Chat({ flow }: ChatType): JSX.Element { export default function Chat({ flow }: ChatType): JSX.Element {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [canOpen, setCanOpen] = useState(false); const [canOpen, setCanOpen] = useState(false);
const { tabsState, isBuilt, setIsBuilt } = useContext(FlowsContext); const { tabsState, isBuilt, setIsBuilt, isPending } = useContext(FlowsContext);
useEffect(() => { useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => { const handleKeyDown = (event: KeyboardEvent) => {
@ -51,9 +51,7 @@ export default function Chat({ flow }: ChatType): JSX.Element {
_.cloneDeep(node.data.node?.template) _.cloneDeep(node.data.node?.template)
); );
if ( if (
tabsState && isPending &&
tabsState[flow.id] &&
tabsState[flow.id].isPending &&
JSON.stringify(prevNodes) !== JSON.stringify(currentNodes) JSON.stringify(prevNodes) !== JSON.stringify(currentNodes)
) { ) {
setIsBuilt(false); setIsBuilt(false);

View file

@ -15,6 +15,7 @@ import {
Node, Node,
NodeChange, NodeChange,
ReactFlowJsonObject, ReactFlowJsonObject,
Viewport,
XYPosition, XYPosition,
addEdge, addEdge,
useEdgesState, useEdgesState,
@ -74,7 +75,8 @@ const FlowsContextInitialValue: FlowsContextType = {
flowData?: FlowType, flowData?: FlowType,
override?: boolean override?: boolean
) => "", ) => "",
updateFlow: (newFlow: FlowType) => {}, deleteNode: () => {},
deleteEdge: () => {},
incrementNodeId: () => uid(), incrementNodeId: () => uid(),
downloadFlow: (flow: FlowType) => {}, downloadFlow: (flow: FlowType) => {},
downloadFlows: () => {}, downloadFlows: () => {},
@ -83,14 +85,13 @@ const FlowsContextInitialValue: FlowsContextType = {
isBuilt: false, isBuilt: false,
setIsBuilt: (state: boolean) => {}, setIsBuilt: (state: boolean) => {},
hardReset: () => {}, hardReset: () => {},
saveFlow: async (flow: FlowType, silent?: boolean) => {}, saveFlow: async (flow?: FlowType, silent?: boolean) => {},
lastCopiedSelection: null, lastCopiedSelection: null,
setLastCopiedSelection: (selection: any) => {}, setLastCopiedSelection: (selection: any) => {},
isPending: false, isPending: false,
setPending: (pending: boolean) => {}, setPending: (pending: boolean) => {},
tabsState: {}, tabsState: {},
setTabsState: (state: FlowsState) => {}, setTabsState: (state: FlowsState) => {},
saveCurrentFlow: () => {},
getNodeId: (nodeType: string) => "", getNodeId: (nodeType: string) => "",
setTweak: (tweak: any) => {}, setTweak: (tweak: any) => {},
getTweak: [], getTweak: [],
@ -135,7 +136,7 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
const [edges, setEdgesInternal, onEdgesChangeInternal] = useEdgesState([]); const [edges, setEdgesInternal, onEdgesChangeInternal] = useEdgesState([]);
const setPending = useCallback( const setPending =
(pending: boolean) => { (pending: boolean) => {
//@ts-ignore //@ts-ignore
setTabsState((prev: FlowsState) => { setTabsState((prev: FlowsState) => {
@ -147,17 +148,13 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
}, },
}; };
}); });
}, }
[setTabsState]
);
const isPending = tabsState[tabId]?.isPending ?? false; const isPending = tabsState[tabId]?.isPending ?? false;
const onNodesChange = useCallback( const onNodesChange = useCallback(
(nodes: NodeChange[]) => { (change: NodeChange[]) => {
onNodesChangeInternal(nodes); onNodesChangeInternal(change);
console.log("nodesChangou")
setPending(true); setPending(true);
}, },
[onNodesChangeInternal, setTabsState, tabId] [onNodesChangeInternal, setTabsState, tabId]
@ -166,7 +163,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
const onEdgesChange = useCallback( const onEdgesChange = useCallback(
(edges: EdgeChange[]) => { (edges: EdgeChange[]) => {
onEdgesChangeInternal(edges); onEdgesChangeInternal(edges);
console.log("edgesChangou")
setPending(true); setPending(true);
}, },
[onEdgesChangeInternal, setTabsState, tabId] [onEdgesChangeInternal, setTabsState, tabId]
@ -174,14 +170,18 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
const setNodes = (change: Node[] | ((oldState: Node[]) => Node[])) => { const setNodes = (change: Node[] | ((oldState: Node[]) => Node[])) => {
let newChange = typeof change === "function" ? change(nodes) : change; let newChange = typeof change === "function" ? change(nodes) : change;
let newEdges = cleanEdges(newChange, edges);
saveCurrentFlow(newChange, newEdges, reactFlowInstance?.getViewport() ?? { zoom: 1, x: 0, y: 0 });
setEdgesInternal(cleanEdges(newChange, edges)); setEdgesInternal(newEdges);
setNodesInternal(newChange); setNodesInternal(newChange);
}; };
const setNode = (id: string, change: Node | ((oldState: Node) => Node)) => { const setNode = (id: string, change: Node | ((oldState: Node) => Node)) => {
let newChange = typeof change === "function" ? change(nodes.find((node) => node.id === id)!) : change; let newChange =
typeof change === "function"
? change(nodes.find((node) => node.id === id)!)
: change;
setNodes((oldNodes) => setNodes((oldNodes) =>
oldNodes.map((node) => { oldNodes.map((node) => {
@ -197,8 +197,11 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
return nodes.find((node) => node.id === id); return nodes.find((node) => node.id === id);
}; };
const setEdges = (edges: Edge[] | ((oldState: Edge[]) => Edge[])) => { const setEdges = (change: Edge[] | ((oldState: Edge[]) => Edge[])) => {
setEdgesInternal(edges); let newChange = typeof change === "function" ? change(edges) : change;
saveCurrentFlow(nodes, newChange, reactFlowInstance?.getViewport() ?? { zoom: 1, x: 0, y: 0 });
setEdgesInternal(newChange);
}; };
useEffect(() => { useEffect(() => {
@ -724,14 +727,22 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
}); });
} }
function saveCurrentFlow() { function saveCurrentFlow(nodes: Node[], edges: Edge[], viewport: Viewport) {
const currentFlow = flows.find((flow) => flow.id === tabId); const currentFlow = flows.find((flow) => flow.id === tabId);
if (currentFlow && reactFlowInstance && currentFlow.data) { if (currentFlow) {
updateFlow({ ...currentFlow, data: reactFlowInstance?.toObject()! }); saveFlow({ ...currentFlow, data: { nodes, edges, viewport } }, true);
} }
} }
async function saveFlow(newFlow: FlowType, silent?: boolean) { async function saveFlow(flow?: FlowType, silent?: boolean) {
let newFlow;
if (!flow) {
const currentFlow = flows.find((flow) => flow.id === tabId)!;
newFlow = { ...currentFlow, data: { nodes, edges, viewport: reactFlowInstance?.getViewport() ?? { zoom: 1, x: 0, y: 0 } } }
} else {
newFlow = flow;
}
try { try {
// updates flow in db // updates flow in db
const updatedFlow = await updateFlowInDatabase(newFlow); const updatedFlow = await updateFlowInDatabase(newFlow);
@ -740,26 +751,9 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
if (!silent) { if (!silent) {
setSuccessData({ title: "Changes saved successfully" }); setSuccessData({ title: "Changes saved successfully" });
} }
setFlows((prevState) => { updateFlow(newFlow);
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;
});
//update tabs state //update tabs state
setTabsState((prev) => { setPending(false);
return {
...prev,
[tabId]: {
...prev[tabId],
isPending: false,
},
};
});
} }
} catch (err) { } catch (err) {
setErrorData({ setErrorData({
@ -794,6 +788,31 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
}); });
}, []); }, []);
function deleteNode(idx: string | Array<string>) {
setEdges((oldEdges) =>
oldEdges.filter((edge) =>
typeof idx === "string"
? edge.source !== idx && edge.target !== idx
: !idx.includes(edge.source) && !idx.includes(edge.target)
)
);
setNodes((oldNodes) =>
oldNodes.filter((node) =>
typeof idx === "string" ? node.id !== idx : !idx.includes(node.id)
)
);
}
function deleteEdge(idx: string | Array<string>) {
setEdges((oldEdges) =>
oldEdges.filter((edge) =>
typeof idx === "string" ? edge.id !== idx : !idx.includes(edge.id)
)
);
}
return ( return (
<FlowsContext.Provider <FlowsContext.Provider
value={{ value={{
@ -803,7 +822,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
setIsBuilt, setIsBuilt,
lastCopiedSelection, lastCopiedSelection,
setLastCopiedSelection, setLastCopiedSelection,
saveCurrentFlow,
hardReset, hardReset,
tabId, tabId,
setTabId, setTabId,
@ -811,12 +829,13 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
incrementNodeId, incrementNodeId,
removeFlow, removeFlow,
addFlow, addFlow,
updateFlow,
downloadFlow, downloadFlow,
downloadFlows, downloadFlows,
uploadFlows, uploadFlows,
uploadFlow, uploadFlow,
getNodeId, getNodeId,
deleteNode,
deleteEdge,
isPending, isPending,
setPending, setPending,
tabsState, tabsState,

View file

@ -18,7 +18,6 @@ import { AuthContext } from "./authContext";
const initialValue: typesContextType = { const initialValue: typesContextType = {
reactFlowInstance: null, reactFlowInstance: null,
setReactFlowInstance: (newState: ReactFlowInstance) => {}, setReactFlowInstance: (newState: ReactFlowInstance) => {},
deleteNode: () => {},
types: {}, types: {},
setTypes: () => {}, setTypes: () => {},
templates: {}, templates: {},
@ -29,7 +28,6 @@ const initialValue: typesContextType = {
fetchError: false, fetchError: false,
setFilterEdge: (filter) => {}, setFilterEdge: (filter) => {},
getFilterEdge: [], getFilterEdge: [],
deleteEdge: () => {},
}; };
export const typesContext = createContext<typesContextType>(initialValue); export const typesContext = createContext<typesContextType>(initialValue);
@ -97,37 +95,14 @@ export function TypesProvider({ children }: { children: ReactNode }) {
} }
} }
function deleteNode(idx: string | Array<string>) {
if (reactFlowInstance === null) return;
const edges = reactFlowInstance!
.getEdges()
.filter((edge) =>
typeof idx === "string"
? edge.source == idx || edge.target == idx
: idx.includes(edge.source) || idx.includes(edge.target)
);
reactFlowInstance!.deleteElements({
nodes:
typeof idx === "string" ? [{ id: idx }] : idx.map((id) => ({ id })),
edges,
});
}
function deleteEdge(idx: string | Array<string>) {
reactFlowInstance!.deleteElements({
edges:
typeof idx === "string" ? [{ id: idx }] : idx.map((id) => ({ id })),
});
}
return ( return (
<typesContext.Provider <typesContext.Provider
value={{ value={{
deleteEdge,
types, types,
setTypes, setTypes,
reactFlowInstance, reactFlowInstance,
setReactFlowInstance, setReactFlowInstance,
deleteNode,
setTemplates, setTemplates,
templates, templates,
data, data,

View file

@ -536,15 +536,7 @@ const EditNodeModal = forwardRef(
onClick={() => { onClick={() => {
data.node = myData.node; data.node = myData.node;
//@ts-ignore //@ts-ignore
setTabsState((prev: FlowsState) => { setPending(true);
return {
...prev,
[tabId]: {
...prev[tabId],
isPending: true,
},
};
});
setOpen(false); setOpen(false);
}} }}
type="submit" type="submit"

View file

@ -12,15 +12,11 @@ import ReactFlow, {
Connection, Connection,
Controls, Controls,
Edge, Edge,
EdgeChange,
NodeChange,
NodeDragHandler, NodeDragHandler,
OnSelectionChangeParams, OnSelectionChangeParams,
SelectionDragHandler, SelectionDragHandler,
addEdge, addEdge,
updateEdge, updateEdge,
useEdgesState,
useNodesState,
useReactFlow, useReactFlow,
} from "reactflow"; } from "reactflow";
import GenericNode from "../../../../CustomNodes/GenericNode"; import GenericNode from "../../../../CustomNodes/GenericNode";
@ -58,17 +54,13 @@ export default function Page({
view?: boolean; view?: boolean;
}): JSX.Element { }): JSX.Element {
let { let {
updateFlow,
uploadFlow, uploadFlow,
getNodeId, getNodeId,
paste, paste,
lastCopiedSelection, lastCopiedSelection,
setLastCopiedSelection, setLastCopiedSelection,
tabsState, deleteNode,
saveFlow, deleteEdge,
setTabsState,
tabId,
saveCurrentFlow,
} = useContext(FlowsContext); } = useContext(FlowsContext);
const { const {
types, types,
@ -76,24 +68,16 @@ export default function Page({
setReactFlowInstance, setReactFlowInstance,
templates, templates,
setFilterEdge, setFilterEdge,
deleteNode,
deleteEdge,
} = useContext(typesContext); } = useContext(typesContext);
const reactFlowWrapper = useRef<HTMLDivElement>(null); const reactFlowWrapper = useRef<HTMLDivElement>(null);
const { takeSnapshot } = useContext(undoRedoContext); const { takeSnapshot } = useContext(undoRedoContext);
const { nodes, edges, setNodes, setEdges, onNodesChange, onEdgesChange } = useContext(FlowsContext); const { nodes, edges, setNodes, setEdges, onNodesChange, onEdgesChange, setPending, saveFlow } = useContext(FlowsContext);
const position = useRef({ x: 0, y: 0 }); const position = useRef({ x: 0, y: 0 });
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 (
@ -137,7 +121,6 @@ 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();
} }
} }
}; };
@ -157,7 +140,6 @@ export default function Page({
lastCopiedSelection, lastCopiedSelection,
lastSelection, lastSelection,
takeSnapshot, takeSnapshot,
saveCurrentFlowTimeout,
]); ]);
const [selectionMenuVisible, setSelectionMenuVisible] = useState(false); const [selectionMenuVisible, setSelectionMenuVisible] = useState(false);
@ -165,7 +147,6 @@ export default function Page({
const { setExtraComponent, setExtraNavigation } = useContext(locationContext); const { setExtraComponent, setExtraNavigation } = useContext(locationContext);
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
const { setViewport } = useReactFlow();
const edgeUpdateSuccessful = useRef(true); const edgeUpdateSuccessful = useRef(true);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@ -174,9 +155,11 @@ export default function Page({
useEffect(() => { useEffect(() => {
setLoading(true); setLoading(true);
setNodes(flow?.data?.nodes ?? []); if(reactFlowInstance){
setEdges(flow?.data?.edges ?? []); reactFlowInstance.setNodes(flow?.data?.nodes ?? []);
setViewport(flow?.data?.viewport ?? { zoom: 1, x: 0, y: 0 }); reactFlowInstance.setEdges(flow?.data?.edges ?? []);
reactFlowInstance.setViewport(flow?.data?.viewport ?? { zoom: 1, x: 0, y: 0 });
}
// Clear the previous timeout // Clear the previous timeout
if (timeoutRef.current) { if (timeoutRef.current) {
@ -194,16 +177,6 @@ export default function Page({
}; };
}, [flow, reactFlowInstance]); }, [flow, reactFlowInstance]);
useEffect(() => {
const interval = setInterval(() => {
saveFlow(flow, true);
}, 30000);
return () => {
clearInterval(interval);
};
}, [flow, flow.data]);
const onConnect = useCallback( const onConnect = useCallback(
(params: Connection) => { (params: Connection) => {
takeSnapshot(); takeSnapshot();
@ -228,17 +201,6 @@ export default function Page({
eds eds
) )
); );
//@ts-ignore
setTabsState((prev: FlowsState) => {
return {
...prev,
[tabId]: {
...prev[tabId],
isPending: true,
},
};
});
saveCurrentFlowTimeout();
}, },
[setEdges, takeSnapshot, addEdge] [setEdges, takeSnapshot, addEdge]
); );
@ -249,6 +211,12 @@ export default function Page({
// 👉 you can place your event handlers here // 👉 you can place your event handlers here
}, [takeSnapshot]); }, [takeSnapshot]);
const onNodeDragStop: NodeDragHandler = useCallback(() => {
// 👇 make dragging a node undoable
saveFlow();
// 👉 you can place your event handlers here
}, [takeSnapshot]);
const onSelectionDragStart: SelectionDragHandler = useCallback(() => { const onSelectionDragStart: SelectionDragHandler = useCallback(() => {
// 👇 make dragging a selection undoable // 👇 make dragging a selection undoable
takeSnapshot(); takeSnapshot();
@ -342,18 +310,12 @@ export default function Page({
} }
}, },
// Specify dependencies for useCallback // Specify dependencies for useCallback
[getNodeId, reactFlowInstance, setNodes, takeSnapshot] [getNodeId, setNodes, takeSnapshot]
); );
useEffect(() => { useEffect(() => {
setExtraComponent(<ExtraSidebar />); setExtraComponent(<ExtraSidebar />);
setExtraNavigation({ title: "Components" }); setExtraNavigation({ title: "Components" });
return () => {
if (tabsState && tabsState[flow.id]?.isPending) {
saveFlow(flow);
}
};
}, []); }, []);
const onEdgeUpdateStart = useCallback(() => { const onEdgeUpdateStart = useCallback(() => {
@ -367,7 +329,7 @@ export default function Page({
setEdges((els) => updateEdge(oldEdge, newConnection, els)); setEdges((els) => updateEdge(oldEdge, newConnection, els));
} }
}, },
[reactFlowInstance, setEdges] [setEdges]
); );
const onEdgeUpdateEnd = useCallback((_, edge: Edge): void => { const onEdgeUpdateEnd = useCallback((_, edge: Edge): void => {
@ -408,18 +370,9 @@ export default function Page({
}, []); }, []);
const onMove = useCallback(() => { const onMove = useCallback(() => {
saveCurrentFlowTimeout();
//@ts-ignore //@ts-ignore
setTabsState((prev: FlowsState) => { setPending(true);
return { }, [setPending]);
...prev,
[tabId]: {
...prev[tabId],
isPending: true,
},
};
});
}, [setTabsState, saveCurrentFlowTimeout]);
return ( return (
<div className="flex h-full overflow-hidden"> <div className="flex h-full overflow-hidden">
@ -454,6 +407,7 @@ export default function Page({
onEdgeUpdateStart={onEdgeUpdateStart} onEdgeUpdateStart={onEdgeUpdateStart}
onEdgeUpdateEnd={onEdgeUpdateEnd} onEdgeUpdateEnd={onEdgeUpdateEnd}
onNodeDragStart={onNodeDragStart} onNodeDragStart={onNodeDragStart}
onNodeDragStop={onNodeDragStop}
onSelectionDragStart={onSelectionDragStart} onSelectionDragStart={onSelectionDragStart}
onSelectionEnd={onSelectionEnd} onSelectionEnd={onSelectionEnd}
onSelectionStart={onSelectionStart} onSelectionStart={onSelectionStart}
@ -488,7 +442,8 @@ export default function Page({
) { ) {
const { newFlow } = generateFlow( const { newFlow } = generateFlow(
lastSelection!, lastSelection!,
reactFlowInstance!, nodes,
edges,
getRandomName() getRandomName()
); );
const newGroupNode = generateNodeFromFlow( const newGroupNode = generateNodeFromFlow(

View file

@ -28,13 +28,12 @@ import SidebarDraggableComponent from "./sideBarDraggableComponent";
export default function ExtraSidebar(): JSX.Element { export default function ExtraSidebar(): JSX.Element {
const { data, templates, getFilterEdge, setFilterEdge } = const { data, templates, getFilterEdge, setFilterEdge } =
useContext(typesContext); useContext(typesContext);
const { flows, tabId, uploadFlow, tabsState, saveFlow, isBuilt, version } = const { flows, tabId, uploadFlow, tabsState, saveFlow, isBuilt, isPending } =
useContext(FlowsContext); useContext(FlowsContext);
const { hasApiKey, validApiKey, hasStore } = useContext(StoreContext); const { hasApiKey, validApiKey, hasStore } = useContext(StoreContext);
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
const [dataFilter, setFilterData] = useState(data); const [dataFilter, setFilterData] = useState(data);
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const isPending = tabsState[tabId]?.isPending;
function onDragStart( function onDragStart(
event: React.DragEvent<any>, event: React.DragEvent<any>,
data: { type: string; node?: APIClassType } data: { type: string; node?: APIClassType }
@ -297,7 +296,7 @@ export default function ExtraSidebar(): JSX.Element {
: "button-disable") : "button-disable")
} }
onClick={(event) => { onClick={(event) => {
saveFlow(flow!); saveFlow();
}} }}
> >
<IconComponent <IconComponent

View file

@ -1,4 +1,3 @@
import { ReactFlowInstance } from "reactflow";
import { FlowType } from "../flow"; import { FlowType } from "../flow";
export type ChatType = { flow: FlowType; }; export type ChatType = { flow: FlowType; };

View file

@ -6,11 +6,13 @@ import { Dispatch, SetStateAction } from "react";
type OnChange<ChangesType> = (changes: ChangesType[]) => void; type OnChange<ChangesType> = (changes: ChangesType[]) => void;
export type FlowsContextType = { export type FlowsContextType = {
saveFlow: (flow: FlowType, silent?: boolean) => Promise<void>; saveFlow: (flow?: FlowType, silent?: boolean) => Promise<void>;
tabId: string; tabId: string;
isLoading: boolean; isLoading: boolean;
setTabId: (index: string) => void; setTabId: (index: string) => void;
flows: Array<FlowType>; flows: Array<FlowType>;
deleteNode: (idx: string | Array<string>) => void;
deleteEdge: (idx: string | Array<string>) => void;
removeFlow: (id: string) => void; removeFlow: (id: string) => void;
addFlow: ( addFlow: (
newProject: boolean, newProject: boolean,
@ -18,7 +20,6 @@ export type FlowsContextType = {
override?: boolean, override?: boolean,
position?: XYPosition position?: XYPosition
) => Promise<String | undefined>; ) => Promise<String | undefined>;
updateFlow: (newFlow: FlowType) => void;
incrementNodeId: () => string; incrementNodeId: () => string;
downloadFlow: ( downloadFlow: (
flow: FlowType, flow: FlowType,
@ -29,7 +30,6 @@ 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,

View file

@ -9,7 +9,6 @@ const data: { [char: string]: string } = {};
export type typesContextType = { export type typesContextType = {
reactFlowInstance: ReactFlowInstance | null; reactFlowInstance: ReactFlowInstance | null;
setReactFlowInstance: (newState: ReactFlowInstance) => void; setReactFlowInstance: (newState: ReactFlowInstance) => void;
deleteNode: (idx: string | Array<string>) => void;
types: typeof types; types: typeof types;
setTypes: (newState: {}) => void; setTypes: (newState: {}) => void;
templates: typeof template; templates: typeof template;
@ -20,7 +19,6 @@ export type typesContextType = {
setFetchError: (newState: boolean) => void; setFetchError: (newState: boolean) => void;
setFilterEdge: (newState) => void; setFilterEdge: (newState) => void;
getFilterEdge: any[]; getFilterEdge: any[];
deleteEdge: (idx: string | Array<string>) => void;
}; };
export type alertContextType = { export type alertContextType = {

View file

@ -4,7 +4,6 @@ import {
Edge, Edge,
Node, Node,
OnSelectionChangeParams, OnSelectionChangeParams,
ReactFlowInstance,
ReactFlowJsonObject, ReactFlowJsonObject,
XYPosition, XYPosition,
} from "reactflow"; } from "reactflow";
@ -502,10 +501,11 @@ export function getMiddlePoint(nodes: Node[]) {
export function generateFlow( export function generateFlow(
selection: OnSelectionChangeParams, selection: OnSelectionChangeParams,
reactFlowInstance: ReactFlowInstance, nodes: Node[],
edges: Edge[],
name: string name: string
): generateFlowType { ): generateFlowType {
const newFlowData = reactFlowInstance.toObject(); const newFlowData = {nodes, edges, viewport: { zoom: 1, x: 0, y: 0 }};
const uid = new ShortUniqueId({ length: 5 }); const uid = new ShortUniqueId({ length: 5 });
/* remove edges that are not connected to selected nodes on both ends /* remove edges that are not connected to selected nodes on both ends
in future we can save this edges to when ungrouping reconect to the old nodes in future we can save this edges to when ungrouping reconect to the old nodes