Fixed flowsContext to work using useFlow zustand, removed unused functions

This commit is contained in:
Lucas Oliveira 2024-01-05 11:31:40 -03:00
commit 3d720f7f79
5 changed files with 37 additions and 262 deletions

View file

@ -46,9 +46,11 @@ import {
checkOldEdgesHandles, checkOldEdgesHandles,
cleanEdges, cleanEdges,
createFlowComponent, createFlowComponent,
processFlowEdges,
removeFileNameFromComponents, removeFileNameFromComponents,
scapeJSONParse, scapeJSONParse,
scapedJSONStringfy, scapedJSONStringfy,
updateEdges,
updateEdgesHandleIds, updateEdgesHandleIds,
updateIds, updateIds,
} from "../utils/reactflowUtils"; } from "../utils/reactflowUtils";
@ -60,6 +62,7 @@ import {
import { alertContext } from "./alertContext"; import { alertContext } from "./alertContext";
import { AuthContext } from "./authContext"; import { AuthContext } from "./authContext";
import { typesContext } from "./typesContext"; import { typesContext } from "./typesContext";
import useFlow from "../stores/flowManagerStore";
const uid = new ShortUniqueId({ length: 5 }); const uid = new ShortUniqueId({ length: 5 });
@ -98,98 +101,10 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
const [tabId, setTabId] = useState(""); const [tabId, setTabId] = useState("");
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [flows, setFlows] = useState<Array<FlowType>>([]); const [flows, setFlows] = useState<Array<FlowType>>([]);
const { reactFlowInstance, setData } = useContext(typesContext); const { setData } = useContext(typesContext);
const [lastCopiedSelection, setLastCopiedSelection] = useState<{
nodes: any;
edges: any;
} | null>(null);
const [tabsState, setTabsState] = useState<FlowsState>({}); const [tabsState, setTabsState] = useState<FlowsState>({});
const [getTweak, setTweak] = useState<tweakType>([]);
const [nodes, setNodesInternal, onNodesChangeInternal] = useNodesState([]); const {nodes, edges, paste, setPending, reactFlowInstance} = useFlow();
const [edges, setEdgesInternal, onEdgesChangeInternal] = useEdgesState([]);
const setPending = (pending: boolean) => {
setTabsState((prev: FlowsState) => {
return {
...prev,
[tabId]: {
...prev[tabId],
isPending: pending,
},
};
});
};
const isPending = tabsState[tabId]?.isPending ?? false;
const onNodesChange = useCallback(
(change: NodeChange[]) => {
onNodesChangeInternal(change);
if (!isPending) setPending(true);
},
[onNodesChangeInternal, setPending, isPending]
);
const onEdgesChange = useCallback(
(edges: EdgeChange[]) => {
onEdgesChangeInternal(edges);
if (!isPending) setPending(true);
},
[onEdgesChangeInternal, setPending, isPending]
);
const setNodes = (change: Node[] | ((oldState: Node[]) => Node[])) => {
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(newEdges);
setNodesInternal(newChange);
};
const setNode = (id: string, change: Node | ((oldState: Node) => Node)) => {
let newChange =
typeof change === "function"
? change(nodes.find((node) => node.id === id)!)
: change;
setNodes((oldNodes) =>
oldNodes.map((node) => {
if (node.id === id) {
return newChange;
}
return node;
})
);
};
const getNode = (id: string) => {
return nodes.find((node) => node.id === id);
};
const setEdges = (change: Edge[] | ((oldState: Edge[]) => Edge[])) => {
let newChange = typeof change === "function" ? change(edges) : change;
saveCurrentFlow(
nodes,
newChange,
reactFlowInstance?.getViewport() ?? { zoom: 1, x: 0, y: 0 }
);
setEdgesInternal(newChange);
};
const newNodeId = useRef(uid());
function incrementNodeId() {
newNodeId.current = uid();
return newNodeId.current;
}
function refreshFlows() { function refreshFlows() {
setIsLoading(true); setIsLoading(true);
@ -197,7 +112,7 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
if (DbData) { if (DbData) {
try { try {
processFlows(DbData, false); processFlows(DbData, false);
updateStateWithDbData(DbData); setFlows(DbData);
setIsLoading(false); setIsLoading(false);
} catch (e) {} } catch (e) {}
} }
@ -247,23 +162,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
}); });
} }
function processFlowEdges(flow: FlowType) {
if (!flow.data || !flow.data.edges) return;
if (checkOldEdgesHandles(flow.data.edges)) {
const newEdges = updateEdgesHandleIds(flow.data);
flow.data.edges = newEdges;
}
//update edges colors
flow.data.edges.forEach((edge) => {
edge.className = "";
edge.style = { stroke: "#555" };
});
}
function updateStateWithDbData(tabsData: FlowType[]) {
setFlows(tabsData);
}
/** /**
* Downloads the current flow as a JSON file * Downloads the current flow as a JSON file
*/ */
@ -311,11 +209,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
link.click(); link.click();
}); });
} }
function getNodeId(nodeType: string) {
return nodeType + "-" + incrementNodeId();
}
/** /**
* Creates a file input and listens to a change event to upload a JSON flow file. * Creates a file input and listens to a change event to upload a JSON flow file.
* If the file type is application/json, the file is read and parsed into a JSON object. * If the file type is application/json, the file is read and parsed into a JSON object.
@ -424,111 +317,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
processFlows(flows.filter((flow) => flow.id !== id)); processFlows(flows.filter((flow) => flow.id !== id));
} }
} }
/**
* Add a new flow to the list of flows.
* @param flow Optional flow to add.
*/
function paste(
selectionInstance: { nodes: Node[]; edges: Edge[] },
position: { x: number; y: number; paneX?: number; paneY?: number }
) {
let minimumX = Infinity;
let minimumY = Infinity;
let idsMap = {};
let newNodes: Node<NodeDataType>[] = nodes;
let newEdges = edges;
selectionInstance.nodes.forEach((node: Node) => {
if (node.position.y < minimumY) {
minimumY = node.position.y;
}
if (node.position.x < minimumX) {
minimumX = node.position.x;
}
});
const insidePosition = position.paneX
? { x: position.paneX + position.x, y: position.paneY! + position.y }
: reactFlowInstance!.screenToFlowPosition({
x: position.x,
y: position.y,
});
selectionInstance.nodes.forEach((node: NodeType) => {
// Generate a unique node ID
let newId = getNodeId(node.data.type);
idsMap[node.id] = newId;
// Create a new node object
const newNode: NodeType = {
id: newId,
type: "genericNode",
position: {
x: insidePosition.x + node.position!.x - minimumX,
y: insidePosition.y + node.position!.y - minimumY,
},
data: {
..._.cloneDeep(node.data),
id: newId,
},
};
// Add the new node to the list of nodes in state
newNodes = newNodes
.map((node) => ({ ...node, selected: false }))
.concat({ ...newNode, selected: false });
});
setNodes(newNodes);
selectionInstance.edges.forEach((edge: Edge) => {
let source = idsMap[edge.source];
let target = idsMap[edge.target];
const sourceHandleObject: sourceHandleType = scapeJSONParse(
edge.sourceHandle!
);
let sourceHandle = scapedJSONStringfy({
...sourceHandleObject,
id: source,
});
sourceHandleObject.id = source;
edge.data.sourceHandle = sourceHandleObject;
const targetHandleObject: targetHandleType = scapeJSONParse(
edge.targetHandle!
);
let targetHandle = scapedJSONStringfy({
...targetHandleObject,
id: target,
});
targetHandleObject.id = target;
edge.data.targetHandle = targetHandleObject;
let id =
"reactflow__edge-" +
source +
sourceHandle +
"-" +
target +
targetHandle;
newEdges = addEdge(
{
source,
target,
sourceHandle,
targetHandle,
id,
data: cloneDeep(edge.data),
style: { stroke: "#555" },
className:
targetHandleObject.type === "Text"
? "stroke-gray-800 "
: "stroke-gray-900 ",
animated: targetHandleObject.type === "Text",
selected: false,
},
newEdges.map((edge) => ({ ...edge, selected: false }))
);
});
setEdges(newEdges);
}
const addFlow = async ( const addFlow = async (
newProject: Boolean, newProject: Boolean,
@ -592,26 +380,12 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
//add animation to text type edges //add animation to text type edges
updateEdges(data.edges); updateEdges(data.edges);
// updateNodes(data.nodes, data.edges); // updateNodes(data.nodes, data.edges);
if (refreshIds) updateIds(data, getNodeId); // Assuming updateIds is defined elsewhere if (refreshIds) updateIds(data); // Assuming updateIds is defined elsewhere
} }
return data; return data;
}; };
const updateEdges = (edges: Edge[]) => {
if (edges)
edges.forEach((edge) => {
const targetHandleObject: targetHandleType = scapeJSONParse(
edge.targetHandle!
);
edge.className =
(targetHandleObject.type === "Text"
? "stroke-gray-800 "
: "stroke-gray-900 ") + " stroke-connection";
edge.animated = targetHandleObject.type === "Text";
});
};
const createNewFlow = ( const createNewFlow = (
flowData: ReactFlowJsonObject | null, flowData: ReactFlowJsonObject | null,
flow: FlowType flow: FlowType
@ -726,7 +500,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
} }
} }
const [isBuilt, setIsBuilt] = useState(false);
// Initialize state variable for the version // Initialize state variable for the version
const [version, setVersion] = useState(""); const [version, setVersion] = useState("");
useEffect(() => { useEffect(() => {
@ -735,21 +508,6 @@ export function FlowsProvider({ children }: { children: ReactNode }) {
}); });
}, []); }, []);
function deleteNode(idx: string | Array<string>) {
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

View file

@ -16,8 +16,6 @@ import { AuthContext } from "./authContext";
//context to share types adn functions from nodes to flow //context to share types adn functions from nodes to flow
const initialValue: typesContextType = { const initialValue: typesContextType = {
reactFlowInstance: null,
setReactFlowInstance: (newState: ReactFlowInstance) => {},
types: {}, types: {},
setTypes: () => {}, setTypes: () => {},
templates: {}, templates: {},
@ -34,8 +32,6 @@ export const typesContext = createContext<typesContextType>(initialValue);
export function TypesProvider({ children }: { children: ReactNode }) { export function TypesProvider({ children }: { children: ReactNode }) {
const [types, setTypes] = useState({}); const [types, setTypes] = useState({});
const [reactFlowInstance, setReactFlowInstance] =
useState<ReactFlowInstance | null>(null);
const [templates, setTemplates] = useState({}); const [templates, setTemplates] = useState({});
const [data, setData] = useState({}); const [data, setData] = useState({});
const [fetchError, setFetchError] = useState(false); const [fetchError, setFetchError] = useState(false);
@ -100,8 +96,6 @@ export function TypesProvider({ children }: { children: ReactNode }) {
value={{ value={{
types, types,
setTypes, setTypes,
reactFlowInstance,
setReactFlowInstance,
setTemplates, setTemplates,
templates, templates,
data, data,

View file

@ -290,10 +290,9 @@ export default function ExtraSidebar(): JSX.Element {
{flow && flow.data && ( {flow && flow.data && (
<ShadTooltip content="Save" side="top"> <ShadTooltip content="Save" side="top">
<button <button
disabled={flow?.data?.nodes.length === 0}
className={ className={
"extra-side-bar-buttons " + "extra-side-bar-buttons " +
(isPending && flow!.data!.nodes?.length > 0 (isPending
? "" ? ""
: "button-disable") : "button-disable")
} }
@ -305,7 +304,7 @@ export default function ExtraSidebar(): JSX.Element {
name="Save" name="Save"
className={ className={
"side-bar-button-size" + "side-bar-button-size" +
(isPending && flow!.data!.nodes?.length > 0 (isPending
? " " ? " "
: " extra-side-bar-save-disable") : " extra-side-bar-save-disable")
} }

View file

@ -7,8 +7,6 @@ const template: { [char: string]: APIClassType } = {};
const data: { [char: string]: string } = {}; const data: { [char: string]: string } = {};
export type typesContextType = { export type typesContextType = {
reactFlowInstance: ReactFlowInstance | null;
setReactFlowInstance: (newState: ReactFlowInstance) => void;
types: typeof types; types: typeof types;
setTypes: (newState: {}) => void; setTypes: (newState: {}) => void;
templates: typeof template; templates: typeof template;

View file

@ -150,7 +150,6 @@ export function updateTemplate(
export function updateIds( export function updateIds(
newFlow: ReactFlowJsonObject, newFlow: ReactFlowJsonObject,
getNodeId: (type: string) => string
) { ) {
let idsMap = {}; let idsMap = {};
@ -269,6 +268,20 @@ export function validateNodes(nodes: Node[], edges: Edge[]) {
return nodes.flatMap((n: NodeType) => validateNode(n, edges)); return nodes.flatMap((n: NodeType) => validateNode(n, edges));
} }
export function updateEdges(edges: Edge[]) {
if (edges)
edges.forEach((edge) => {
const targetHandleObject: targetHandleType = scapeJSONParse(
edge.targetHandle!
);
edge.className =
(targetHandleObject.type === "Text"
? "stroke-gray-800 "
: "stroke-gray-900 ") + " stroke-connection";
edge.animated = targetHandleObject.type === "Text";
});
};
export function addVersionToDuplicates(flow: FlowType, flows: FlowType[]) { export function addVersionToDuplicates(flow: FlowType, flows: FlowType[]) {
const existingNames = flows.map((item) => item.name); const existingNames = flows.map((item) => item.name);
let newName = flow.name; let newName = flow.name;
@ -922,6 +935,19 @@ function updateEdgesIds(edges: Edge[], idsMap: { [key: string]: string }) {
}); });
} }
export function processFlowEdges(flow: FlowType) {
if (!flow.data || !flow.data.edges) return;
if (checkOldEdgesHandles(flow.data.edges)) {
const newEdges = updateEdgesHandleIds(flow.data);
flow.data.edges = newEdges;
}
//update edges colors
flow.data.edges.forEach((edge) => {
edge.className = "";
edge.style = { stroke: "#555" };
});
}
export function expandGroupNode( export function expandGroupNode(
groupNode: NodeDataType, groupNode: NodeDataType,
nodes: Node[], nodes: Node[],
@ -930,7 +956,7 @@ export function expandGroupNode(
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
) { ) {
const { template, flow } = _.cloneDeep(groupNode.node!); const { template, flow } = _.cloneDeep(groupNode.node!);
const idsMap = updateIds(flow!.data!, getNodeId); const idsMap = updateIds(flow!.data!);
updateProxyIdsOnTemplate(template, idsMap); updateProxyIdsOnTemplate(template, idsMap);
let flowEdges = edges; let flowEdges = edges;
updateEdgesIds(flowEdges, idsMap); updateEdgesIds(flowEdges, idsMap);