Passed the rest of the flowsContext functions to zustand, removed flowsContext
This commit is contained in:
parent
616a4f0031
commit
882f365ff6
13 changed files with 225 additions and 534 deletions
|
|
@ -1,5 +1,4 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import { FlowsContext } from "../../contexts/flowsContext";
|
|
||||||
import { getComponent, postLikeComponent } from "../../controllers/API";
|
import { getComponent, postLikeComponent } from "../../controllers/API";
|
||||||
import DeleteConfirmationModal from "../../modals/DeleteConfirmationModal";
|
import DeleteConfirmationModal from "../../modals/DeleteConfirmationModal";
|
||||||
import useAlertStore from "../../stores/alertStore";
|
import useAlertStore from "../../stores/alertStore";
|
||||||
|
|
@ -18,6 +17,7 @@ import {
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "../ui/card";
|
} from "../ui/card";
|
||||||
|
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||||
|
|
||||||
export default function CollectionCardComponent({
|
export default function CollectionCardComponent({
|
||||||
data,
|
data,
|
||||||
|
|
@ -32,7 +32,7 @@ export default function CollectionCardComponent({
|
||||||
button?: JSX.Element;
|
button?: JSX.Element;
|
||||||
onDelete?: () => void;
|
onDelete?: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { addFlow } = useContext(FlowsContext);
|
const addFlow = useFlowsManagerStore((state) => state.addFlow);
|
||||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
const setValidApiKey = useStoreStore((state) => state.updateValidApiKey);
|
const setValidApiKey = useStoreStore((state) => state.updateValidApiKey);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { useContext, useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
import { FlowsContext } from "../../../../contexts/flowsContext";
|
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
|
|
@ -17,7 +16,7 @@ import IconComponent from "../../../genericIconComponent";
|
||||||
import { Button } from "../../../ui/button";
|
import { Button } from "../../../ui/button";
|
||||||
|
|
||||||
export const MenuBar = (): JSX.Element => {
|
export const MenuBar = (): JSX.Element => {
|
||||||
const { addFlow } = useContext(FlowsContext);
|
const addFlow = useFlowsManagerStore((state) => state.addFlow);
|
||||||
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
|
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
const { undo, redo } = useContext(undoRedoContext);
|
const { undo, redo } = useContext(undoRedoContext);
|
||||||
|
|
|
||||||
|
|
@ -1,500 +0,0 @@
|
||||||
import { AxiosError } from "axios";
|
|
||||||
import _, { cloneDeep } from "lodash";
|
|
||||||
import { ReactNode, createContext, useContext, useRef, useState } from "react";
|
|
||||||
import {
|
|
||||||
Edge,
|
|
||||||
Node,
|
|
||||||
ReactFlowJsonObject,
|
|
||||||
Viewport,
|
|
||||||
XYPosition,
|
|
||||||
} from "reactflow";
|
|
||||||
import ShortUniqueId from "short-unique-id";
|
|
||||||
import {
|
|
||||||
deleteFlowFromDatabase,
|
|
||||||
downloadFlowsFromDatabase,
|
|
||||||
readFlowsFromDatabase,
|
|
||||||
saveFlowToDatabase,
|
|
||||||
updateFlowInDatabase,
|
|
||||||
uploadFlowsToDatabase,
|
|
||||||
} from "../controllers/API";
|
|
||||||
import useAlertStore from "../stores/alertStore";
|
|
||||||
import useFlowStore from "../stores/flowStore";
|
|
||||||
import { APIClassType } from "../types/api";
|
|
||||||
import { FlowType, NodeDataType } from "../types/flow";
|
|
||||||
import { FlowsContextType, FlowsState } from "../types/tabs";
|
|
||||||
import {
|
|
||||||
addVersionToDuplicates,
|
|
||||||
createFlowComponent,
|
|
||||||
processFlowEdges,
|
|
||||||
removeFileNameFromComponents,
|
|
||||||
updateEdges,
|
|
||||||
updateIds,
|
|
||||||
} from "../utils/reactflowUtils";
|
|
||||||
import {
|
|
||||||
createRandomKey,
|
|
||||||
getRandomDescription,
|
|
||||||
getRandomName,
|
|
||||||
} from "../utils/utils";
|
|
||||||
import { useTypesStore } from "../stores/typesStore";
|
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 5 });
|
|
||||||
|
|
||||||
const FlowsContextInitialValue: FlowsContextType = {
|
|
||||||
//Remove tab id and get current id from url
|
|
||||||
tabId: "",
|
|
||||||
setTabId: (index: string) => {},
|
|
||||||
isLoading: true,
|
|
||||||
flows: [],
|
|
||||||
setVersion: () => {},
|
|
||||||
removeFlow: (id: string) => {},
|
|
||||||
addFlow: async (
|
|
||||||
newProject: boolean,
|
|
||||||
flowData?: FlowType,
|
|
||||||
override?: boolean
|
|
||||||
) => "",
|
|
||||||
downloadFlow: (flow: FlowType) => {},
|
|
||||||
downloadFlows: () => {},
|
|
||||||
uploadFlows: () => {},
|
|
||||||
uploadFlow: async () => "",
|
|
||||||
saveFlow: async (flow?: FlowType, silent?: boolean) => {},
|
|
||||||
tabsState: {},
|
|
||||||
setTabsState: () => {},
|
|
||||||
saveComponent: async (component: NodeDataType, override: boolean) => "",
|
|
||||||
deleteComponent: (key: string) => {},
|
|
||||||
version: "",
|
|
||||||
refreshFlows: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FlowsContext = createContext<FlowsContextType>(
|
|
||||||
FlowsContextInitialValue
|
|
||||||
);
|
|
||||||
|
|
||||||
export function FlowsProvider({ children }: { children: ReactNode }) {
|
|
||||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
|
||||||
const [tabId, setTabId] = useState("");
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [flows, setFlows] = useState<Array<FlowType>>([]);
|
|
||||||
const [tabsState, setTabsState] = useState<FlowsState>({});
|
|
||||||
const setData = useTypesStore((state) => state.setData);
|
|
||||||
const nodes = useFlowStore((state) => state.nodes);
|
|
||||||
const edges = useFlowStore((state) => state.edges);
|
|
||||||
const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance);
|
|
||||||
const setPending = useFlowStore((state) => state.setPending);
|
|
||||||
const paste = useFlowStore((state) => state.paste);
|
|
||||||
|
|
||||||
function refreshFlows() {
|
|
||||||
setIsLoading(true);
|
|
||||||
getTabsDataFromDB().then((DbData) => {
|
|
||||||
if (DbData) {
|
|
||||||
try {
|
|
||||||
processFlows(DbData, false);
|
|
||||||
setFlows(DbData);
|
|
||||||
setIsLoading(false);
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTabsDataFromDB() {
|
|
||||||
//get tabs from db
|
|
||||||
return readFlowsFromDatabase();
|
|
||||||
}
|
|
||||||
|
|
||||||
function processFlows(DbData: FlowType[], skipUpdate = true) {
|
|
||||||
let savedComponents: { [key: string]: APIClassType } = {};
|
|
||||||
DbData.forEach((flow: FlowType) => {
|
|
||||||
try {
|
|
||||||
if (!flow.data) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (flow.data && flow.is_component) {
|
|
||||||
(flow.data.nodes[0].data as NodeDataType).node!.display_name =
|
|
||||||
flow.name;
|
|
||||||
savedComponents[
|
|
||||||
createRandomKey(
|
|
||||||
(flow.data.nodes[0].data as NodeDataType).type,
|
|
||||||
uid()
|
|
||||||
)
|
|
||||||
] = _.cloneDeep((flow.data.nodes[0].data as NodeDataType).node!);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!skipUpdate) processDataFromFlow(flow, false);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setData((prev) => {
|
|
||||||
let newData = cloneDeep(prev);
|
|
||||||
newData["saved_components"] = cloneDeep(savedComponents);
|
|
||||||
return newData;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads the current flow as a JSON file
|
|
||||||
*/
|
|
||||||
function downloadFlow(
|
|
||||||
flow: FlowType,
|
|
||||||
flowName: string,
|
|
||||||
flowDescription?: string
|
|
||||||
) {
|
|
||||||
let clonedFlow = cloneDeep(flow);
|
|
||||||
removeFileNameFromComponents(clonedFlow);
|
|
||||||
// create a data URI with the current flow data
|
|
||||||
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
|
|
||||||
JSON.stringify({
|
|
||||||
...clonedFlow,
|
|
||||||
name: flowName,
|
|
||||||
description: flowDescription,
|
|
||||||
})
|
|
||||||
)}`;
|
|
||||||
|
|
||||||
// create a link element and set its properties
|
|
||||||
const link = document.createElement("a");
|
|
||||||
link.href = jsonString;
|
|
||||||
link.download = `${
|
|
||||||
flowName && flowName != ""
|
|
||||||
? flowName
|
|
||||||
: flows.find((f) => f.id === tabId)!.name
|
|
||||||
}.json`;
|
|
||||||
|
|
||||||
// simulate a click on the link element to trigger the download
|
|
||||||
link.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
function downloadFlows() {
|
|
||||||
downloadFlowsFromDatabase().then((flows) => {
|
|
||||||
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
|
|
||||||
JSON.stringify(flows)
|
|
||||||
)}`;
|
|
||||||
|
|
||||||
// create a link element and set its properties
|
|
||||||
const link = document.createElement("a");
|
|
||||||
link.href = jsonString;
|
|
||||||
link.download = `flows.json`;
|
|
||||||
|
|
||||||
// simulate a click on the link element to trigger the download
|
|
||||||
link.click();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
* The resulting JSON object is passed to the addFlow function.
|
|
||||||
*/
|
|
||||||
async function uploadFlow({
|
|
||||||
newProject,
|
|
||||||
file,
|
|
||||||
isComponent = false,
|
|
||||||
position = { x: 10, y: 10 },
|
|
||||||
}: {
|
|
||||||
newProject: boolean;
|
|
||||||
file?: File;
|
|
||||||
isComponent?: boolean;
|
|
||||||
position?: XYPosition;
|
|
||||||
}): Promise<String | never> {
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
let id;
|
|
||||||
if (file) {
|
|
||||||
let text = await file.text();
|
|
||||||
let fileData = JSON.parse(text);
|
|
||||||
if (
|
|
||||||
newProject &&
|
|
||||||
((!fileData.is_component && isComponent === true) ||
|
|
||||||
(fileData.is_component !== undefined &&
|
|
||||||
fileData.is_component !== isComponent))
|
|
||||||
) {
|
|
||||||
reject("You cannot upload a component as a flow or vice versa");
|
|
||||||
} else {
|
|
||||||
if (fileData.flows) {
|
|
||||||
fileData.flows.forEach((flow: FlowType) => {
|
|
||||||
id = addFlow(newProject, flow, undefined, position);
|
|
||||||
});
|
|
||||||
resolve("");
|
|
||||||
} else {
|
|
||||||
id = await addFlow(newProject, fileData, undefined, position);
|
|
||||||
resolve(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// create a file input
|
|
||||||
const input = document.createElement("input");
|
|
||||||
input.type = "file";
|
|
||||||
input.accept = ".json";
|
|
||||||
// add a change event listener to the file input
|
|
||||||
input.onchange = async (e: Event) => {
|
|
||||||
if (
|
|
||||||
(e.target as HTMLInputElement).files![0].type === "application/json"
|
|
||||||
) {
|
|
||||||
const currentfile = (e.target as HTMLInputElement).files![0];
|
|
||||||
let text = await currentfile.text();
|
|
||||||
let fileData: FlowType = await JSON.parse(text);
|
|
||||||
|
|
||||||
if (
|
|
||||||
(!fileData.is_component && isComponent === true) ||
|
|
||||||
(fileData.is_component !== undefined &&
|
|
||||||
fileData.is_component !== isComponent)
|
|
||||||
) {
|
|
||||||
reject("You cannot upload a component as a flow or vice versa");
|
|
||||||
} else {
|
|
||||||
id = await addFlow(newProject, fileData);
|
|
||||||
resolve(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// trigger the file input click event to open the file dialog
|
|
||||||
input.click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function uploadFlows() {
|
|
||||||
// create a file input
|
|
||||||
const input = document.createElement("input");
|
|
||||||
input.type = "file";
|
|
||||||
// add a change event listener to the file input
|
|
||||||
input.onchange = (event: Event) => {
|
|
||||||
// check if the file type is application/json
|
|
||||||
if (
|
|
||||||
(event.target as HTMLInputElement).files![0].type === "application/json"
|
|
||||||
) {
|
|
||||||
// get the file from the file input
|
|
||||||
const file = (event.target as HTMLInputElement).files![0];
|
|
||||||
// read the file as text
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("file", file);
|
|
||||||
uploadFlowsToDatabase(formData).then(() => {
|
|
||||||
refreshFlows();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// trigger the file input click event to open the file dialog
|
|
||||||
input.click();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Removes a flow from an array of flows based on its id.
|
|
||||||
* Updates the state of flows and tabIndex using setFlows and setTabIndex hooks.
|
|
||||||
* @param {string} id - The id of the flow to remove.
|
|
||||||
*/
|
|
||||||
async function removeFlow(id: string) {
|
|
||||||
const index = flows.findIndex((flow) => flow.id === id);
|
|
||||||
if (index >= 0) {
|
|
||||||
await deleteFlowFromDatabase(id);
|
|
||||||
//removes component from data if there is any
|
|
||||||
setFlows(flows.filter((flow) => flow.id !== id));
|
|
||||||
processFlows(flows.filter((flow) => flow.id !== id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const addFlow = async (
|
|
||||||
newProject: Boolean,
|
|
||||||
flow?: FlowType,
|
|
||||||
override?: boolean,
|
|
||||||
position?: XYPosition
|
|
||||||
): Promise<String | undefined> => {
|
|
||||||
if (newProject) {
|
|
||||||
let flowData = flow
|
|
||||||
? processDataFromFlow(flow)
|
|
||||||
: { nodes: [], edges: [], viewport: { zoom: 1, x: 0, y: 0 } };
|
|
||||||
|
|
||||||
// Create a new flow with a default name if no flow is provided.
|
|
||||||
|
|
||||||
if (override) {
|
|
||||||
deleteComponent(flow!.name);
|
|
||||||
const newFlow = createNewFlow(flowData, flow!);
|
|
||||||
const { id } = await saveFlowToDatabase(newFlow);
|
|
||||||
newFlow.id = id;
|
|
||||||
//setTimeout to prevent update state with wrong state
|
|
||||||
setTimeout(() => {
|
|
||||||
addFlowToLocalState(newFlow);
|
|
||||||
}, 200);
|
|
||||||
// addFlowToLocalState(newFlow);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newFlow = createNewFlow(flowData, flow!);
|
|
||||||
|
|
||||||
const newName = addVersionToDuplicates(newFlow, flows);
|
|
||||||
|
|
||||||
newFlow.name = newName;
|
|
||||||
try {
|
|
||||||
const { id } = await saveFlowToDatabase(newFlow);
|
|
||||||
// Change the id to the new id.
|
|
||||||
newFlow.id = id;
|
|
||||||
|
|
||||||
// Add the new flow to the list of flows.
|
|
||||||
addFlowToLocalState(newFlow);
|
|
||||||
|
|
||||||
// Return the id
|
|
||||||
return id;
|
|
||||||
} catch (error) {
|
|
||||||
// Handle the error if needed
|
|
||||||
throw error; // Re-throw the error so the caller can handle it if needed
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
paste(
|
|
||||||
{ nodes: flow!.data!.nodes, edges: flow!.data!.edges },
|
|
||||||
position ?? { x: 10, y: 10 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const processDataFromFlow = (flow: FlowType, refreshIds = true) => {
|
|
||||||
let data = flow?.data ? flow.data : null;
|
|
||||||
if (data) {
|
|
||||||
processFlowEdges(flow);
|
|
||||||
//prevent node update for now
|
|
||||||
// processFlowNodes(flow);
|
|
||||||
//add animation to text type edges
|
|
||||||
updateEdges(data.edges);
|
|
||||||
// updateNodes(data.nodes, data.edges);
|
|
||||||
if (refreshIds) updateIds(data); // Assuming updateIds is defined elsewhere
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createNewFlow = (
|
|
||||||
flowData: ReactFlowJsonObject | null,
|
|
||||||
flow: FlowType
|
|
||||||
) => ({
|
|
||||||
description: flow?.description ?? getRandomDescription(),
|
|
||||||
name: flow?.name ?? getRandomName(),
|
|
||||||
data: flowData,
|
|
||||||
id: "",
|
|
||||||
is_component: flow?.is_component ?? false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const addFlowToLocalState = (newFlow: FlowType) => {
|
|
||||||
let newFlows: FlowType[] = [];
|
|
||||||
setFlows((prevState) => {
|
|
||||||
newFlows = newFlows.concat(prevState);
|
|
||||||
newFlows.push(newFlow);
|
|
||||||
return [...prevState, newFlow];
|
|
||||||
});
|
|
||||||
processFlows(newFlows);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates an existing flow with new data
|
|
||||||
* @param newFlow - The new flow object containing the updated data
|
|
||||||
*/
|
|
||||||
function updateFlow(newFlow: FlowType) {
|
|
||||||
setFlows((prevState) => {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
newFlow = {
|
|
||||||
...newFlow,
|
|
||||||
};
|
|
||||||
return newFlows;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const saveTimeoutId = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
|
|
||||||
const saveCurrentFlow = (
|
|
||||||
nodes: Node[],
|
|
||||||
edges: Edge[],
|
|
||||||
viewport: Viewport
|
|
||||||
) => {
|
|
||||||
// Clear the previous timeout if it exists.
|
|
||||||
if (saveTimeoutId.current) {
|
|
||||||
clearTimeout(saveTimeoutId.current);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up a new timeout.
|
|
||||||
saveTimeoutId.current = setTimeout(() => {
|
|
||||||
const currentFlow = flows.find((flow: FlowType) => flow.id === tabId);
|
|
||||||
if (currentFlow) {
|
|
||||||
saveFlow({ ...currentFlow, data: { nodes, edges, viewport } }, true);
|
|
||||||
}
|
|
||||||
}, 300); // Delay of 300ms.
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
|
||||||
// updates flow in db
|
|
||||||
const updatedFlow = await updateFlowInDatabase(newFlow);
|
|
||||||
if (updatedFlow) {
|
|
||||||
// updates flow in state
|
|
||||||
if (!silent) {
|
|
||||||
setSuccessData({ title: "Changes saved successfully" });
|
|
||||||
}
|
|
||||||
updateFlow(newFlow);
|
|
||||||
//update tabs state
|
|
||||||
setPending(false);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
setErrorData({
|
|
||||||
title: "Error while saving changes",
|
|
||||||
list: [(err as AxiosError).message],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveComponent(component: NodeDataType, override: boolean) {
|
|
||||||
component.node!.official = false;
|
|
||||||
return addFlow(true, createFlowComponent(component, version), override);
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteComponent(key: string) {
|
|
||||||
let componentFlow = flows.find(
|
|
||||||
(componentFlow) =>
|
|
||||||
componentFlow.is_component && componentFlow.name === key
|
|
||||||
);
|
|
||||||
|
|
||||||
if (componentFlow) {
|
|
||||||
removeFlow(componentFlow.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize state variable for the version
|
|
||||||
const [version, setVersion] = useState("");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FlowsContext.Provider
|
|
||||||
value={{
|
|
||||||
version,
|
|
||||||
setVersion,
|
|
||||||
flows,
|
|
||||||
saveFlow,
|
|
||||||
tabId,
|
|
||||||
setTabId,
|
|
||||||
removeFlow,
|
|
||||||
addFlow,
|
|
||||||
downloadFlow,
|
|
||||||
downloadFlows,
|
|
||||||
uploadFlows,
|
|
||||||
uploadFlow,
|
|
||||||
tabsState,
|
|
||||||
setTabsState,
|
|
||||||
refreshFlows,
|
|
||||||
isLoading,
|
|
||||||
saveComponent,
|
|
||||||
deleteComponent,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</FlowsContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -5,7 +5,6 @@ import { TooltipProvider } from "../components/ui/tooltip";
|
||||||
import { ApiInterceptor } from "../controllers/API/api";
|
import { ApiInterceptor } from "../controllers/API/api";
|
||||||
import { SSEProvider } from "./SSEContext";
|
import { SSEProvider } from "./SSEContext";
|
||||||
import { AuthProvider } from "./authContext";
|
import { AuthProvider } from "./authContext";
|
||||||
import { FlowsProvider } from "./flowsContext";
|
|
||||||
import { LocationProvider } from "./locationContext";
|
import { LocationProvider } from "./locationContext";
|
||||||
|
|
||||||
import { UndoRedoProvider } from "./undoRedoContext";
|
import { UndoRedoProvider } from "./undoRedoContext";
|
||||||
|
|
@ -21,9 +20,7 @@ export default function ContextWrapper({ children }: { children: ReactNode }) {
|
||||||
<LocationProvider>
|
<LocationProvider>
|
||||||
<ApiInterceptor />
|
<ApiInterceptor />
|
||||||
<SSEProvider>
|
<SSEProvider>
|
||||||
<FlowsProvider>
|
<UndoRedoProvider>{children}</UndoRedoProvider>
|
||||||
<UndoRedoProvider>{children}</UndoRedoProvider>
|
|
||||||
</FlowsProvider>
|
|
||||||
</SSEProvider>
|
</SSEProvider>
|
||||||
</LocationProvider>
|
</LocationProvider>
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import ReactFlow, {
|
||||||
import GenericNode from "../../../../CustomNodes/GenericNode";
|
import GenericNode from "../../../../CustomNodes/GenericNode";
|
||||||
import Chat from "../../../../components/chatComponent";
|
import Chat from "../../../../components/chatComponent";
|
||||||
import Loading from "../../../../components/ui/loading";
|
import Loading from "../../../../components/ui/loading";
|
||||||
import { FlowsContext } from "../../../../contexts/flowsContext";
|
|
||||||
import { locationContext } from "../../../../contexts/locationContext";
|
import { locationContext } from "../../../../contexts/locationContext";
|
||||||
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
||||||
import useAlertStore from "../../../../stores/alertStore";
|
import useAlertStore from "../../../../stores/alertStore";
|
||||||
|
|
@ -53,7 +52,7 @@ export default function Page({
|
||||||
flow: FlowType;
|
flow: FlowType;
|
||||||
view?: boolean;
|
view?: boolean;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
let { uploadFlow } = useContext(FlowsContext);
|
const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow);
|
||||||
const autoSaveCurrentFlow = useFlowsManagerStore(
|
const autoSaveCurrentFlow = useFlowsManagerStore(
|
||||||
(state) => state.autoSaveCurrentFlow
|
(state) => state.autoSaveCurrentFlow
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||||
import IconComponent from "../../../../components/genericIconComponent";
|
import IconComponent from "../../../../components/genericIconComponent";
|
||||||
import { Input } from "../../../../components/ui/input";
|
import { Input } from "../../../../components/ui/input";
|
||||||
import { Separator } from "../../../../components/ui/separator";
|
import { Separator } from "../../../../components/ui/separator";
|
||||||
import { FlowsContext } from "../../../../contexts/flowsContext";
|
|
||||||
import ApiModal from "../../../../modals/ApiModal";
|
import ApiModal from "../../../../modals/ApiModal";
|
||||||
import ExportModal from "../../../../modals/exportModal";
|
import ExportModal from "../../../../modals/exportModal";
|
||||||
import ShareModal from "../../../../modals/shareModal";
|
import ShareModal from "../../../../modals/shareModal";
|
||||||
|
|
@ -32,7 +31,7 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
const templates = useTypesStore((state) => state.templates);
|
const templates = useTypesStore((state) => state.templates);
|
||||||
const getFilterEdge = useTypesStore((state) => state.getFilterEdge);
|
const getFilterEdge = useTypesStore((state) => state.getFilterEdge);
|
||||||
const setFilterEdge = useTypesStore((state) => state.setFilterEdge);
|
const setFilterEdge = useTypesStore((state) => state.setFilterEdge);
|
||||||
const { uploadFlow } = useContext(FlowsContext);
|
const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow);
|
||||||
const saveFlow = useFlowsManagerStore((state) => state.saveFlow);
|
const saveFlow = useFlowsManagerStore((state) => state.saveFlow);
|
||||||
const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance);
|
const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance);
|
||||||
const nodes = useFlowStore((state) => state.nodes);
|
const nodes = useFlowStore((state) => state.nodes);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import {
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
} from "../../../../../components/ui/select-custom";
|
} from "../../../../../components/ui/select-custom";
|
||||||
import { AuthContext } from "../../../../../contexts/authContext";
|
import { AuthContext } from "../../../../../contexts/authContext";
|
||||||
import { FlowsContext } from "../../../../../contexts/flowsContext";
|
|
||||||
import { APIClassType } from "../../../../../types/api";
|
import { APIClassType } from "../../../../../types/api";
|
||||||
import {
|
import {
|
||||||
createFlowComponent,
|
createFlowComponent,
|
||||||
|
|
@ -16,6 +15,7 @@ import {
|
||||||
} from "../../../../../utils/reactflowUtils";
|
} from "../../../../../utils/reactflowUtils";
|
||||||
import { removeCountFromString } from "../../../../../utils/utils";
|
import { removeCountFromString } from "../../../../../utils/utils";
|
||||||
import { useDarkStore } from "../../../../../stores/darkStore";
|
import { useDarkStore } from "../../../../../stores/darkStore";
|
||||||
|
import useFlowsManagerStore from "../../../../../stores/flowsManagerStore";
|
||||||
|
|
||||||
export default function SidebarDraggableComponent({
|
export default function SidebarDraggableComponent({
|
||||||
sectionName,
|
sectionName,
|
||||||
|
|
@ -37,7 +37,9 @@ export default function SidebarDraggableComponent({
|
||||||
official: boolean;
|
official: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const { deleteComponent } = useContext(FlowsContext);
|
const deleteComponent = useFlowsManagerStore(
|
||||||
|
(state) => state.deleteComponent
|
||||||
|
);
|
||||||
const version = useDarkStore((state) => state.version);
|
const version = useDarkStore((state) => state.version);
|
||||||
const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 });
|
const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 });
|
||||||
const popoverRef = useRef<HTMLDivElement>(null);
|
const popoverRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import {
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
} from "../../../../components/ui/select-custom";
|
} from "../../../../components/ui/select-custom";
|
||||||
import { FlowsContext } from "../../../../contexts/flowsContext";
|
|
||||||
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
||||||
import ConfirmationModal from "../../../../modals/ConfirmationModal";
|
import ConfirmationModal from "../../../../modals/ConfirmationModal";
|
||||||
import EditNodeModal from "../../../../modals/EditNodeModal";
|
import EditNodeModal from "../../../../modals/EditNodeModal";
|
||||||
|
|
@ -74,7 +73,7 @@ export default function NodeToolbarComponent({
|
||||||
const setNodes = useFlowStore((state) => state.setNodes);
|
const setNodes = useFlowStore((state) => state.setNodes);
|
||||||
const setEdges = useFlowStore((state) => state.setEdges);
|
const setEdges = useFlowStore((state) => state.setEdges);
|
||||||
|
|
||||||
const { saveComponent } = useContext(FlowsContext);
|
const saveComponent = useFlowsManagerStore((state) => state.saveComponent);
|
||||||
const flows = useFlowsManagerStore((state) => state.flows);
|
const flows = useFlowsManagerStore((state) => state.flows);
|
||||||
const version = useDarkStore((state) => state.version);
|
const version = useDarkStore((state) => state.version);
|
||||||
const { takeSnapshot } = useContext(undoRedoContext);
|
const { takeSnapshot } = useContext(undoRedoContext);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import CardsWrapComponent from "../../../../components/cardsWrapComponent";
|
||||||
import IconComponent from "../../../../components/genericIconComponent";
|
import IconComponent from "../../../../components/genericIconComponent";
|
||||||
import { SkeletonCardComponent } from "../../../../components/skeletonCardComponent";
|
import { SkeletonCardComponent } from "../../../../components/skeletonCardComponent";
|
||||||
import { Button } from "../../../../components/ui/button";
|
import { Button } from "../../../../components/ui/button";
|
||||||
import { FlowsContext } from "../../../../contexts/flowsContext";
|
|
||||||
import useAlertStore from "../../../../stores/alertStore";
|
import useAlertStore from "../../../../stores/alertStore";
|
||||||
import { FlowType } from "../../../../types/flow";
|
import { FlowType } from "../../../../types/flow";
|
||||||
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
||||||
|
|
@ -16,8 +15,9 @@ export default function ComponentsComponent({
|
||||||
}: {
|
}: {
|
||||||
is_component?: boolean;
|
is_component?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { removeFlow, uploadFlow, addFlow } =
|
const addFlow = useFlowsManagerStore((state) => state.addFlow);
|
||||||
useContext(FlowsContext);
|
const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow);
|
||||||
|
const removeFlow = useFlowsManagerStore((state) => state.removeFlow);
|
||||||
const isLoading = useFlowsManagerStore((state) => state.isLoading);
|
const isLoading = useFlowsManagerStore((state) => state.isLoading);
|
||||||
const flows = useFlowsManagerStore((state) => state.flows);
|
const flows = useFlowsManagerStore((state) => state.flows);
|
||||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,12 @@ import PageLayout from "../../components/pageLayout";
|
||||||
import SidebarNav from "../../components/sidebarComponent";
|
import SidebarNav from "../../components/sidebarComponent";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
||||||
import { FlowsContext } from "../../contexts/flowsContext";
|
|
||||||
import useAlertStore from "../../stores/alertStore";
|
import useAlertStore from "../../stores/alertStore";
|
||||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||||
import { downloadFlows } from "../../utils/reactflowUtils";
|
import { downloadFlows } from "../../utils/reactflowUtils";
|
||||||
export default function HomePage(): JSX.Element {
|
export default function HomePage(): JSX.Element {
|
||||||
const { addFlow, uploadFlow } =
|
const addFlow = useFlowsManagerStore((state) => state.addFlow);
|
||||||
useContext(FlowsContext);
|
const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow);
|
||||||
const setCurrentFlowId = useFlowsManagerStore(
|
const setCurrentFlowId = useFlowsManagerStore(
|
||||||
(state) => state.setCurrentFlowId
|
(state) => state.setCurrentFlowId
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,27 @@
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
import { Edge, Node, Viewport } from "reactflow";
|
import { Edge, Node, Viewport, XYPosition } from "reactflow";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import {
|
import {
|
||||||
|
deleteFlowFromDatabase,
|
||||||
readFlowsFromDatabase,
|
readFlowsFromDatabase,
|
||||||
|
saveFlowToDatabase,
|
||||||
updateFlowInDatabase,
|
updateFlowInDatabase,
|
||||||
uploadFlowsToDatabase,
|
uploadFlowsToDatabase,
|
||||||
} from "../controllers/API";
|
} from "../controllers/API";
|
||||||
import { FlowType } from "../types/flow";
|
import { FlowType, NodeDataType } from "../types/flow";
|
||||||
import { FlowState } from "../types/tabs";
|
import { FlowState } from "../types/tabs";
|
||||||
import { FlowsManagerStoreType } from "../types/zustand/flowsManager";
|
import { FlowsManagerStoreType } from "../types/zustand/flowsManager";
|
||||||
import { processFlows } from "../utils/reactflowUtils";
|
import {
|
||||||
|
addVersionToDuplicates,
|
||||||
|
createFlowComponent,
|
||||||
|
createNewFlow,
|
||||||
|
processDataFromFlow,
|
||||||
|
processFlows,
|
||||||
|
} from "../utils/reactflowUtils";
|
||||||
import useAlertStore from "./alertStore";
|
import useAlertStore from "./alertStore";
|
||||||
import useFlowStore from "./flowStore";
|
import useFlowStore from "./flowStore";
|
||||||
import { useTypesStore } from "./typesStore";
|
import { useTypesStore } from "./typesStore";
|
||||||
|
import { useDarkStore } from "./darkStore";
|
||||||
|
|
||||||
let saveTimeoutId: NodeJS.Timeout | null = null;
|
let saveTimeoutId: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
|
|
@ -154,6 +163,173 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
|
||||||
input.click();
|
input.click();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
addFlow: async (
|
||||||
|
newProject: Boolean,
|
||||||
|
flow?: FlowType,
|
||||||
|
override?: boolean,
|
||||||
|
position?: XYPosition
|
||||||
|
): Promise<string | undefined> => {
|
||||||
|
if (newProject) {
|
||||||
|
let flowData = flow
|
||||||
|
? processDataFromFlow(flow)
|
||||||
|
: { nodes: [], edges: [], viewport: { zoom: 1, x: 0, y: 0 } };
|
||||||
|
|
||||||
|
// Create a new flow with a default name if no flow is provided.
|
||||||
|
|
||||||
|
if (override) {
|
||||||
|
get().deleteComponent(flow!.name);
|
||||||
|
const newFlow = createNewFlow(flowData!, flow!);
|
||||||
|
const { id } = await saveFlowToDatabase(newFlow);
|
||||||
|
newFlow.id = id;
|
||||||
|
//setTimeout to prevent update state with wrong state
|
||||||
|
setTimeout(() => {
|
||||||
|
const { data, flows } = processFlows([newFlow, ...get().flows]);
|
||||||
|
get().setFlows(flows);
|
||||||
|
set({ isLoading: false });
|
||||||
|
useTypesStore.setState((state) => ({
|
||||||
|
data: { ...state.data, ["saved_components"]: data },
|
||||||
|
}));
|
||||||
|
}, 200);
|
||||||
|
// addFlowToLocalState(newFlow);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newFlow = createNewFlow(flowData!, flow!);
|
||||||
|
|
||||||
|
const newName = addVersionToDuplicates(newFlow, get().flows);
|
||||||
|
|
||||||
|
newFlow.name = newName;
|
||||||
|
try {
|
||||||
|
const { id } = await saveFlowToDatabase(newFlow);
|
||||||
|
// Change the id to the new id.
|
||||||
|
newFlow.id = id;
|
||||||
|
|
||||||
|
// Add the new flow to the list of flows.
|
||||||
|
const { data, flows } = processFlows([newFlow, ...get().flows]);
|
||||||
|
get().setFlows(flows);
|
||||||
|
set({ isLoading: false });
|
||||||
|
useTypesStore.setState((state) => ({
|
||||||
|
data: { ...state.data, ["saved_components"]: data },
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Return the id
|
||||||
|
return id;
|
||||||
|
} catch (error) {
|
||||||
|
// Handle the error if needed
|
||||||
|
throw error; // Re-throw the error so the caller can handle it if needed
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
useFlowStore
|
||||||
|
.getState()
|
||||||
|
.paste(
|
||||||
|
{ nodes: flow!.data!.nodes, edges: flow!.data!.edges },
|
||||||
|
position ?? { x: 10, y: 10 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeFlow: async (id: string) => {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
const index = get().flows.findIndex((flow) => flow.id === id);
|
||||||
|
if (index >= 0) {
|
||||||
|
deleteFlowFromDatabase(id).then(() => {
|
||||||
|
const { data, flows } = processFlows(
|
||||||
|
get().flows.filter((flow) => flow.id !== id)
|
||||||
|
);
|
||||||
|
get().setFlows(flows);
|
||||||
|
set({ isLoading: false });
|
||||||
|
useTypesStore.setState((state) => ({
|
||||||
|
data: { ...state.data, ["saved_components"]: data },
|
||||||
|
}));
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteComponent: async (key: string) => {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
let componentFlow = get().flows.find(
|
||||||
|
(componentFlow) =>
|
||||||
|
componentFlow.is_component && componentFlow.name === key
|
||||||
|
);
|
||||||
|
|
||||||
|
if (componentFlow) {
|
||||||
|
get()
|
||||||
|
.removeFlow(componentFlow.id)
|
||||||
|
.then(() => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
uploadFlow: async ({
|
||||||
|
newProject,
|
||||||
|
file,
|
||||||
|
isComponent = false,
|
||||||
|
position = { x: 10, y: 10 },
|
||||||
|
}: {
|
||||||
|
newProject: boolean;
|
||||||
|
file?: File;
|
||||||
|
isComponent?: boolean;
|
||||||
|
position?: XYPosition;
|
||||||
|
}): Promise<string | never> => {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
let id;
|
||||||
|
if (file) {
|
||||||
|
let text = await file.text();
|
||||||
|
let fileData = JSON.parse(text);
|
||||||
|
if (
|
||||||
|
newProject &&
|
||||||
|
((!fileData.is_component && isComponent === true) ||
|
||||||
|
(fileData.is_component !== undefined &&
|
||||||
|
fileData.is_component !== isComponent))
|
||||||
|
) {
|
||||||
|
reject("You cannot upload a component as a flow or vice versa");
|
||||||
|
} else {
|
||||||
|
if (fileData.flows) {
|
||||||
|
fileData.flows.forEach((flow: FlowType) => {
|
||||||
|
id = get().addFlow(newProject, flow, undefined, position);
|
||||||
|
});
|
||||||
|
resolve("");
|
||||||
|
} else {
|
||||||
|
id = await get().addFlow(newProject, fileData, undefined, position);
|
||||||
|
resolve(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// create a file input
|
||||||
|
const input = document.createElement("input");
|
||||||
|
input.type = "file";
|
||||||
|
input.accept = ".json";
|
||||||
|
// add a change event listener to the file input
|
||||||
|
input.onchange = async (e: Event) => {
|
||||||
|
if (
|
||||||
|
(e.target as HTMLInputElement).files![0].type === "application/json"
|
||||||
|
) {
|
||||||
|
const currentfile = (e.target as HTMLInputElement).files![0];
|
||||||
|
let text = await currentfile.text();
|
||||||
|
let fileData: FlowType = await JSON.parse(text);
|
||||||
|
|
||||||
|
if (
|
||||||
|
(!fileData.is_component && isComponent === true) ||
|
||||||
|
(fileData.is_component !== undefined &&
|
||||||
|
fileData.is_component !== isComponent)
|
||||||
|
) {
|
||||||
|
reject("You cannot upload a component as a flow or vice versa");
|
||||||
|
} else {
|
||||||
|
id = await get().addFlow(newProject, fileData);
|
||||||
|
resolve(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// trigger the file input click event to open the file dialog
|
||||||
|
input.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
saveComponent: (component: NodeDataType, override: boolean) => {
|
||||||
|
component.node!.official = false;
|
||||||
|
return get().addFlow(true, createFlowComponent(component, useDarkStore.getState().version), override);
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default useFlowsManagerStore;
|
export default useFlowsManagerStore;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Node, Edge, Viewport } from "reactflow";
|
import { Node, Edge, Viewport, XYPosition } from "reactflow";
|
||||||
import { FlowType } from "../../flow";
|
import { FlowType } from "../../flow";
|
||||||
import { FlowState, FlowsState } from "../../tabs";
|
import { FlowState, FlowsState } from "../../tabs";
|
||||||
|
|
||||||
|
|
@ -17,4 +17,9 @@ export type FlowsManagerStoreType = {
|
||||||
saveFlow: (flow: FlowType, silent?: boolean) => Promise<void>;
|
saveFlow: (flow: FlowType, silent?: boolean) => Promise<void>;
|
||||||
autoSaveCurrentFlow: (nodes: Node[], edges: Edge[], viewport: Viewport) => void;
|
autoSaveCurrentFlow: (nodes: Node[], edges: Edge[], viewport: Viewport) => void;
|
||||||
uploadFlows: () => Promise<void>;
|
uploadFlows: () => Promise<void>;
|
||||||
|
uploadFlow: ({newProject, file, isComponent, position}: {newProject: boolean, file?: File, isComponent?: boolean, position?: XYPosition}) => Promise<string | never>;
|
||||||
|
addFlow: (newProject: boolean, flow?: FlowType, override?: boolean, position?: XYPosition) => Promise<string | undefined>;
|
||||||
|
deleteComponent: (key: string) => Promise<void>;
|
||||||
|
removeFlow: (id: string) => Promise<void>;
|
||||||
|
saveComponent: (component: any, override: boolean) => Promise<string | undefined>;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import {
|
||||||
LANGFLOW_SUPPORTED_TYPES,
|
LANGFLOW_SUPPORTED_TYPES,
|
||||||
specialCharsRegex,
|
specialCharsRegex,
|
||||||
} from "../constants/constants";
|
} from "../constants/constants";
|
||||||
|
import { downloadFlowsFromDatabase } from "../controllers/API";
|
||||||
import {
|
import {
|
||||||
APIClassType,
|
APIClassType,
|
||||||
APIKindType,
|
APIKindType,
|
||||||
|
|
@ -32,8 +33,13 @@ import {
|
||||||
unselectAllNodesType,
|
unselectAllNodesType,
|
||||||
updateEdgesHandleIdsType,
|
updateEdgesHandleIdsType,
|
||||||
} from "../types/utils/reactflowUtils";
|
} from "../types/utils/reactflowUtils";
|
||||||
import { createRandomKey, getFieldTitle, toTitleCase } from "./utils";
|
import {
|
||||||
import { downloadFlowsFromDatabase } from "../controllers/API";
|
createRandomKey,
|
||||||
|
getFieldTitle,
|
||||||
|
getRandomDescription,
|
||||||
|
getRandomName,
|
||||||
|
toTitleCase,
|
||||||
|
} from "./utils";
|
||||||
const uid = new ShortUniqueId({ length: 5 });
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
|
|
||||||
export function cleanEdges(nodes: Node[], edges: Edge[]) {
|
export function cleanEdges(nodes: Node[], edges: Edge[]) {
|
||||||
|
|
@ -189,6 +195,7 @@ export const processDataFromFlow = (flow: FlowType, refreshIds = true) => {
|
||||||
// updateNodes(data.nodes, data.edges);
|
// updateNodes(data.nodes, data.edges);
|
||||||
if (refreshIds) updateIds(data); // Assuming updateIds is defined elsewhere
|
if (refreshIds) updateIds(data); // Assuming updateIds is defined elsewhere
|
||||||
}
|
}
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function updateIds(newFlow: ReactFlowJsonObject) {
|
export function updateIds(newFlow: ReactFlowJsonObject) {
|
||||||
|
|
@ -1226,11 +1233,7 @@ export function downloadFlow(
|
||||||
// create a link element and set its properties
|
// create a link element and set its properties
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.href = jsonString;
|
link.href = jsonString;
|
||||||
link.download = `${
|
link.download = `${flowName && flowName != "" ? flowName : flow.name}.json`;
|
||||||
flowName && flowName != ""
|
|
||||||
? flowName
|
|
||||||
: flow.name
|
|
||||||
}.json`;
|
|
||||||
|
|
||||||
// simulate a click on the link element to trigger the download
|
// simulate a click on the link element to trigger the download
|
||||||
link.click();
|
link.click();
|
||||||
|
|
@ -1250,4 +1253,17 @@ export function downloadFlows() {
|
||||||
// simulate a click on the link element to trigger the download
|
// simulate a click on the link element to trigger the download
|
||||||
link.click();
|
link.click();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const createNewFlow = (
|
||||||
|
flowData: ReactFlowJsonObject,
|
||||||
|
flow: FlowType
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
description: flow?.description ?? getRandomDescription(),
|
||||||
|
name: flow?.name ?? getRandomName(),
|
||||||
|
data: flowData,
|
||||||
|
id: "",
|
||||||
|
is_component: flow?.is_component ?? false,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue