Removed all reactFlowInstance nodes and edges settings. Centralized flow saving.
This commit is contained in:
parent
6e2673e1d5
commit
f6bd5a4e4a
12 changed files with 96 additions and 167 deletions
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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; };
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 = {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue