From 42ef82def05a5ea9cd1a6ea487e2296204cf4cf4 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 16:07:58 -0300 Subject: [PATCH 01/84] fixed patch update flow --- .../src/controllers/API/queries/flows/use-patch-update-flow.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts b/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts index d9551823e1d..c6435b9431d 100644 --- a/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts +++ b/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts @@ -24,7 +24,7 @@ export const usePatchUpdateFlow: useMutationFunctionType< const { mutate } = UseRequestProcessor(); const PatchUpdateFlowFn = async (payload: IPatchUpdateFlow): Promise => { - const response = await api.patch(`${getURL("FLOWS")}/${params}`, { + const response = await api.patch(`${getURL("FLOWS")}/${params.id}`, { name: payload.name, data: payload.data, description: payload.description, From 4a60211593187893429bd5c18c0ae07ba6faada2 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 16:37:57 -0300 Subject: [PATCH 02/84] fixed update flow patch to receive id by payload --- .../queries/flows/use-patch-update-flow.ts | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts b/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts index c6435b9431d..8b81ec3cd31 100644 --- a/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts +++ b/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts @@ -6,41 +6,34 @@ import { getURL } from "../../helpers/constants"; import { UseRequestProcessor } from "../../services/request-processor"; interface IPatchUpdateFlow { + id: string; name: string; data: ReactFlowJsonObject; description: string; - folder_id: string; - endpoint_name: string; -} - -interface IPatchUpdateFlowParams { - id: string; + folder_id: string | null | undefined; + endpoint_name: string | null | undefined; } export const usePatchUpdateFlow: useMutationFunctionType< - IPatchUpdateFlowParams, + undefined, IPatchUpdateFlow -> = (params, options?) => { +> = (options?) => { const { mutate } = UseRequestProcessor(); const PatchUpdateFlowFn = async (payload: IPatchUpdateFlow): Promise => { - const response = await api.patch(`${getURL("FLOWS")}/${params.id}`, { + const response = await api.patch(`${getURL("FLOWS")}/${payload.id}`, { name: payload.name, data: payload.data, description: payload.description, - folder_id: payload.folder_id === "" ? null : payload.folder_id, - endpoint_name: payload.endpoint_name, + folder_id: payload.folder_id || null, + endpoint_name: payload.endpoint_name || null, }); return response.data; }; const mutation: UseMutationResult = - mutate( - ["usePatchUpdateFlow", { id: params.id }], - PatchUpdateFlowFn, - options, - ); + mutate(["usePatchUpdateFlow"], PatchUpdateFlowFn, options); return mutation; }; From 842cabaa578e1e3e969c882673677d0210b284ea Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 16:38:09 -0300 Subject: [PATCH 03/84] created save flow hook with auto save and manual save functions --- src/frontend/src/hooks/flows/use-save-flow.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/frontend/src/hooks/flows/use-save-flow.ts diff --git a/src/frontend/src/hooks/flows/use-save-flow.ts b/src/frontend/src/hooks/flows/use-save-flow.ts new file mode 100644 index 00000000000..28671b1a734 --- /dev/null +++ b/src/frontend/src/hooks/flows/use-save-flow.ts @@ -0,0 +1,61 @@ +import { SAVE_DEBOUNCE_TIME } from "@/constants/constants"; +import { usePatchUpdateFlow } from "@/controllers/API/queries/flows/use-patch-update-flow"; +import useAlertStore from "@/stores/alertStore"; +import useFlowsManagerStore from "@/stores/flowsManagerStore"; +import { FlowType } from "@/types/flow"; +import { debounce } from "lodash"; + +const useSaveFlow = () => { + const flows = useFlowsManagerStore((state) => state.flows); + const setFlows = useFlowsManagerStore((state) => state.setFlows); + const setErrorData = useAlertStore((state) => state.setErrorData); + const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); + + const { mutate } = usePatchUpdateFlow(); + + const autoSaveFlow = debounce((flow?: FlowType) => { + saveFlow(flow).catch((e) => { + setErrorData({ + title: "Failed to save flow", + list: [e.message], + }); + }); + }, SAVE_DEBOUNCE_TIME); + + const saveFlow = async (flow?: FlowType): Promise => { + return new Promise((resolve, reject) => { + flow = flow || flows.find((flow) => flow.id === currentFlowId); + if (flow && flow.data) { + const { id, name, data, description, folder_id, endpoint_name } = flow; + mutate( + { id, name, data, description, folder_id, endpoint_name }, + { + onSuccess: (updatedFlow) => { + if (updatedFlow) { + // updates flow in state + setFlows( + flows.map((flow) => { + if (flow.id === updatedFlow.id) { + return updatedFlow; + } + return flow; + }), + ); + resolve(); + } + }, + onError: (e) => { + reject(e); + }, + }, + ); + } else { + reject(new Error("Flow not found")); + } + }); + }; + + return { saveFlow, autoSaveFlow }; +}; + +export default useSaveFlow; From b117f671de091baa9944ff1a3b61ce1b0be4d164 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 17:42:43 -0300 Subject: [PATCH 04/84] fix poetry lock --- src/backend/base/poetry.lock | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/backend/base/poetry.lock b/src/backend/base/poetry.lock index 7e9e76bf5a3..6142c834499 100644 --- a/src/backend/base/poetry.lock +++ b/src/backend/base/poetry.lock @@ -860,7 +860,6 @@ wrapt = ">=1.10,<2" dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] -<<<<<<< Updated upstream name = "devtools" version = "0.12.2" description = "Python's missing debug print command, and more." @@ -877,8 +876,6 @@ executing = ">=1.1.1" pygments = ">=2.15.0" [[package]] -======= ->>>>>>> Stashed changes name = "dictdiffer" version = "0.9.0" description = "Dictdiffer is a library that helps you to diff and patch dictionaries." @@ -5259,8 +5256,4 @@ local = [] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -<<<<<<< Updated upstream content-hash = "877648288f4f9d5d3304c36853d1b2c5f833d673665bf9b1c707c37bbf02e6ad" -======= -content-hash = "bbbc234350488c8293c4b74695db9757be15cabbf6df99ce24d569aecdcd503b" ->>>>>>> Stashed changes From b52fc2e13a1a3dab211d09b9ee1f8ed224310666 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 17:47:09 -0300 Subject: [PATCH 05/84] added auto save check with environment variable --- src/frontend/src/hooks/flows/use-save-flow.ts | 21 ++++++++++++------- src/frontend/vite.config.mts | 3 +++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/frontend/src/hooks/flows/use-save-flow.ts b/src/frontend/src/hooks/flows/use-save-flow.ts index 28671b1a734..afc74b405cf 100644 --- a/src/frontend/src/hooks/flows/use-save-flow.ts +++ b/src/frontend/src/hooks/flows/use-save-flow.ts @@ -1,6 +1,7 @@ import { SAVE_DEBOUNCE_TIME } from "@/constants/constants"; import { usePatchUpdateFlow } from "@/controllers/API/queries/flows/use-patch-update-flow"; import useAlertStore from "@/stores/alertStore"; +import useAuthStore from "@/stores/authStore"; import useFlowsManagerStore from "@/stores/flowsManagerStore"; import { FlowType } from "@/types/flow"; import { debounce } from "lodash"; @@ -10,17 +11,17 @@ const useSaveFlow = () => { const setFlows = useFlowsManagerStore((state) => state.setFlows); const setErrorData = useAlertStore((state) => state.setErrorData); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); + const user = useAuthStore((state) => state.userData); + + const shouldAutosave = Boolean(process.env.LANGFLOW_AUTO_SAVE) ?? true; const { mutate } = usePatchUpdateFlow(); - const autoSaveFlow = debounce((flow?: FlowType) => { - saveFlow(flow).catch((e) => { - setErrorData({ - title: "Failed to save flow", - list: [e.message], - }); - }); - }, SAVE_DEBOUNCE_TIME); + const autoSaveFlow = shouldAutosave + ? debounce((flow?: FlowType) => { + saveFlow(flow); + }, SAVE_DEBOUNCE_TIME) + : () => {}; const saveFlow = async (flow?: FlowType): Promise => { return new Promise((resolve, reject) => { @@ -45,6 +46,10 @@ const useSaveFlow = () => { } }, onError: (e) => { + setErrorData({ + title: "Failed to save flow", + list: [e.message], + }); reject(e); }, }, diff --git a/src/frontend/vite.config.mts b/src/frontend/vite.config.mts index 24e4c179540..43b0d85adaa 100644 --- a/src/frontend/vite.config.mts +++ b/src/frontend/vite.config.mts @@ -31,6 +31,9 @@ export default defineConfig(({ mode }) => { outDir: "build", }, define: { + "process.env.LANGFLOW_AUTO_SAVE": JSON.stringify( + process.env.LANGFLOW_AUTO_SAVE, + ), "process.env.BACKEND_URL": JSON.stringify(process.env.BACKEND_URL), "process.env.ACCESS_TOKEN_EXPIRE_SECONDS": JSON.stringify( process.env.ACCESS_TOKEN_EXPIRE_SECONDS, From 4d7a7a35cebb001615591453002a2f5b125aebc5 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 17:47:18 -0300 Subject: [PATCH 06/84] removed unused user --- src/frontend/src/hooks/flows/use-save-flow.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/frontend/src/hooks/flows/use-save-flow.ts b/src/frontend/src/hooks/flows/use-save-flow.ts index afc74b405cf..8699ae7312e 100644 --- a/src/frontend/src/hooks/flows/use-save-flow.ts +++ b/src/frontend/src/hooks/flows/use-save-flow.ts @@ -1,7 +1,6 @@ import { SAVE_DEBOUNCE_TIME } from "@/constants/constants"; import { usePatchUpdateFlow } from "@/controllers/API/queries/flows/use-patch-update-flow"; import useAlertStore from "@/stores/alertStore"; -import useAuthStore from "@/stores/authStore"; import useFlowsManagerStore from "@/stores/flowsManagerStore"; import { FlowType } from "@/types/flow"; import { debounce } from "lodash"; @@ -11,7 +10,6 @@ const useSaveFlow = () => { const setFlows = useFlowsManagerStore((state) => state.setFlows); const setErrorData = useAlertStore((state) => state.setErrorData); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); - const user = useAuthStore((state) => state.userData); const shouldAutosave = Boolean(process.env.LANGFLOW_AUTO_SAVE) ?? true; From 05840eb37a13f62b6f8b713269d55a9f20884905 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 18:21:18 -0300 Subject: [PATCH 07/84] separated autosave and put the flow as a creation with nodes and edges --- src/frontend/src/hooks/flows/use-save-flow.ts | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/frontend/src/hooks/flows/use-save-flow.ts b/src/frontend/src/hooks/flows/use-save-flow.ts index 8699ae7312e..39818dd25ef 100644 --- a/src/frontend/src/hooks/flows/use-save-flow.ts +++ b/src/frontend/src/hooks/flows/use-save-flow.ts @@ -1,29 +1,40 @@ -import { SAVE_DEBOUNCE_TIME } from "@/constants/constants"; import { usePatchUpdateFlow } from "@/controllers/API/queries/flows/use-patch-update-flow"; import useAlertStore from "@/stores/alertStore"; import useFlowsManagerStore from "@/stores/flowsManagerStore"; +import useFlowStore from "@/stores/flowStore"; import { FlowType } from "@/types/flow"; -import { debounce } from "lodash"; const useSaveFlow = () => { const flows = useFlowsManagerStore((state) => state.flows); const setFlows = useFlowsManagerStore((state) => state.setFlows); const setErrorData = useAlertStore((state) => state.setErrorData); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); + const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance); + const nodes = useFlowStore((state) => state.nodes); + const edges = useFlowStore((state) => state.edges); - const shouldAutosave = Boolean(process.env.LANGFLOW_AUTO_SAVE) ?? true; + const currentFlow = flows.find((flow) => flow.id === currentFlowId); + const flowData = currentFlow?.data; const { mutate } = usePatchUpdateFlow(); - const autoSaveFlow = shouldAutosave - ? debounce((flow?: FlowType) => { - saveFlow(flow); - }, SAVE_DEBOUNCE_TIME) - : () => {}; - const saveFlow = async (flow?: FlowType): Promise => { return new Promise((resolve, reject) => { - flow = flow || flows.find((flow) => flow.id === currentFlowId); + if (currentFlow) { + flow = flow || { + ...currentFlow, + data: { + ...flowData, + nodes, + edges, + viewport: reactFlowInstance?.getViewport() ?? { + zoom: 1, + x: 0, + y: 0, + }, + }, + }; + } if (flow && flow.data) { const { id, name, data, description, folder_id, endpoint_name } = flow; mutate( @@ -32,6 +43,7 @@ const useSaveFlow = () => { onSuccess: (updatedFlow) => { if (updatedFlow) { // updates flow in state + console.log("uai"); setFlows( flows.map((flow) => { if (flow.id === updatedFlow.id) { @@ -58,7 +70,7 @@ const useSaveFlow = () => { }); }; - return { saveFlow, autoSaveFlow }; + return saveFlow; }; export default useSaveFlow; From f1dae3d1b065b23c1de1c5e1424bb1aafaccb22a Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 18:21:36 -0300 Subject: [PATCH 08/84] removed set nodes that skipped saving --- .../cardComponent/hooks/use-playground-effect.tsx | 12 ++++++------ src/frontend/src/pages/Playground/index.tsx | 10 ++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx b/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx index e9236e98be1..ab05c0c036a 100644 --- a/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx +++ b/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx @@ -6,18 +6,18 @@ const usePlaygroundEffect = ( playground: boolean, openPlayground: boolean, currentFlow: FlowType | undefined, - setNodes: (value: any, value2: boolean) => void, - setEdges: (value: any, value2: boolean) => void, + setNodes: (value: any) => void, + setEdges: (value: any) => void, cleanFlowPool: () => void, ) => { useEffect(() => { if (currentFlowId && playground) { if (openPlayground) { - setNodes(currentFlow?.data?.nodes ?? [], true); - setEdges(currentFlow?.data?.edges ?? [], true); + setNodes(currentFlow?.data?.nodes ?? []); + setEdges(currentFlow?.data?.edges ?? []); } else { - setNodes([], true); - setEdges([], true); + setNodes([]); + setEdges([]); } cleanFlowPool(); } diff --git a/src/frontend/src/pages/Playground/index.tsx b/src/frontend/src/pages/Playground/index.tsx index 4ea3cc506db..694468a652c 100644 --- a/src/frontend/src/pages/Playground/index.tsx +++ b/src/frontend/src/pages/Playground/index.tsx @@ -13,7 +13,6 @@ export default function PlaygroundPage() { const setCurrentFlowId = useFlowsManagerStore( (state) => state.setCurrentFlowId, ); - const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow); const setNodes = useFlowStore((state) => state.setNodes); const setEdges = useFlowStore((state) => state.setEdges); @@ -37,17 +36,16 @@ export default function PlaygroundPage() { }); } }, [id]); - useEffect(() => { if (currentFlow) { - setNodes(currentFlow?.data?.nodes ?? [], true); - setEdges(currentFlow?.data?.edges ?? [], true); + setNodes(currentFlow?.data?.nodes ?? []); + setEdges(currentFlow?.data?.edges ?? []); cleanFlowPool(); setLoading(false); } return () => { - setNodes([], true); - setEdges([], true); + setNodes([]); + setEdges([]); cleanFlowPool(); }; }, [currentFlow]); From 67454082da656d54a03ac5f0b0f7732bbfdd50eb Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 18:21:51 -0300 Subject: [PATCH 09/84] implemented auto save hook --- .../src/hooks/flows/use-autosave-flow.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/frontend/src/hooks/flows/use-autosave-flow.ts diff --git a/src/frontend/src/hooks/flows/use-autosave-flow.ts b/src/frontend/src/hooks/flows/use-autosave-flow.ts new file mode 100644 index 00000000000..15983e2527c --- /dev/null +++ b/src/frontend/src/hooks/flows/use-autosave-flow.ts @@ -0,0 +1,25 @@ +import { SAVE_DEBOUNCE_TIME } from "@/constants/constants"; +import { FlowType } from "@/types/flow"; +import { debounce } from "lodash"; +import { useMemo } from "react"; +import useSaveFlow from "./use-save-flow"; + +const useAutoSaveFlow = () => { + const saveFlow = useSaveFlow(); + + const shouldAutosave = Boolean(process.env.LANGFLOW_AUTO_SAVE) ?? true; + + const autoSaveFlow = shouldAutosave + ? useMemo( + () => + debounce((flow?: FlowType) => { + saveFlow(flow); + }, SAVE_DEBOUNCE_TIME), + [], + ) + : () => {}; + + return autoSaveFlow; +}; + +export default useAutoSaveFlow; From 647ef80a46ea595048d6c04381c6229b5bc6b8b2 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 18:23:24 -0300 Subject: [PATCH 10/84] removed autosave from setNodes and setEdges --- src/frontend/src/stores/flowStore.ts | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index 489cfb1ead0..50ba74d28d9 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -206,7 +206,7 @@ const useFlowStore = create((set, get) => ({ edges: applyEdgeChanges(changes, get().edges), }); }, - setNodes: (change, skipSave = false) => { + setNodes: (change) => { let newChange = typeof change === "function" ? change(get().nodes) : change; let newEdges = cleanEdges(newChange, get().edges); const { inputs, outputs } = getInputsAndOutputs(newChange); @@ -219,31 +219,13 @@ const useFlowStore = create((set, get) => ({ outputs, hasIO: inputs.length > 0 || outputs.length > 0, }); - - const flowsManager = useFlowsManagerStore.getState(); - if (!get().isBuilding && !skipSave && get().onFlowPage) { - flowsManager.autoSaveCurrentFlow( - newChange, - newEdges, - get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }, - ); - } }, - setEdges: (change, skipSave = false) => { + setEdges: (change) => { let newChange = typeof change === "function" ? change(get().edges) : change; set({ edges: newChange, flowState: undefined, }); - - const flowsManager = useFlowsManagerStore.getState(); - if (!get().isBuilding && !skipSave && get().onFlowPage) { - flowsManager.autoSaveCurrentFlow( - get().nodes, - newChange, - get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }, - ); - } }, setNode: ( id: string, From 55c590c93d822c2f33fe61d629e265774564f3f5 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 18:25:45 -0300 Subject: [PATCH 11/84] added auto save hook and saved on viewport move and added useEffect to save on nodes and edges changed --- .../components/PageComponent/index.tsx | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index cddddeb0585..cbf5e64351a 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -1,5 +1,6 @@ import LoadingComponent from "@/components/loadingComponent"; import { useGetBuildsQuery } from "@/controllers/API/queries/_builds"; +import useAutoSaveFlow from "@/hooks/flows/use-autosave-flow"; import useUploadFlow from "@/hooks/flows/use-upload-flow"; import { getInputsAndOutputs } from "@/utils/storeUtils"; import _, { cloneDeep } from "lodash"; @@ -65,9 +66,7 @@ export default function Page({ view?: boolean; }): JSX.Element { const uploadFlow = useUploadFlow(); - const autoSaveCurrentFlow = useFlowsManagerStore( - (state) => state.autoSaveCurrentFlow, - ); + const autoSaveFlow = useAutoSaveFlow(); const types = useTypesStore((state) => state.types); const templates = useTypesStore((state) => state.templates); const setFilterEdge = useFlowStore((state) => state.setFilterEdge); @@ -200,6 +199,12 @@ export default function Page({ }; }, [currentFlowId]); + useEffect(() => { + if (nodes.length !== 0) { + autoSaveFlow(); + } + }, [nodes, edges]); + function handleUndo(e: KeyboardEvent) { if (!isWrappedWithClass(e, "noflow")) { e.preventDefault(); @@ -334,15 +339,10 @@ export default function Page({ // 👉 you can place your event handlers here }, [takeSnapshot]); - const onNodeDragStop: NodeDragHandler = useCallback(() => { - autoSaveCurrentFlow(nodes, edges, reactFlowInstance?.getViewport()!); - // 👉 you can place your event handlers here - }, [takeSnapshot, autoSaveCurrentFlow, nodes, edges, reactFlowInstance]); - const onMoveEnd: OnMove = useCallback(() => { // 👇 make moving the canvas undoable - autoSaveCurrentFlow(nodes, edges, reactFlowInstance?.getViewport()!); - }, [takeSnapshot, autoSaveCurrentFlow, nodes, edges, reactFlowInstance]); + autoSaveFlow(); + }, [takeSnapshot, autoSaveFlow, nodes, edges, reactFlowInstance]); const onSelectionDragStart: SelectionDragHandler = useCallback(() => { // 👇 make dragging a selection undoable @@ -493,7 +493,6 @@ export default function Page({ onEdgeUpdateStart={onEdgeUpdateStart} onEdgeUpdateEnd={onEdgeUpdateEnd} onNodeDragStart={onNodeDragStart} - onNodeDragStop={onNodeDragStop} onSelectionDragStart={onSelectionDragStart} onSelectionEnd={onSelectionEnd} onSelectionStart={onSelectionStart} From b70cfb1b020ab439e4353f3cad503be7a5e7c648 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 7 Aug 2024 18:26:02 -0300 Subject: [PATCH 12/84] changed type of setNodes --- src/frontend/src/types/zustand/flow/index.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/frontend/src/types/zustand/flow/index.ts b/src/frontend/src/types/zustand/flow/index.ts index 59ea979fad9..da52455e297 100644 --- a/src/frontend/src/types/zustand/flow/index.ts +++ b/src/frontend/src/types/zustand/flow/index.ts @@ -101,14 +101,8 @@ export type FlowStoreType = { edges: Edge[]; onNodesChange: OnNodesChange; onEdgesChange: OnEdgesChange; - setNodes: ( - update: Node[] | ((oldState: Node[]) => Node[]), - skipSave?: boolean, - ) => void; - setEdges: ( - update: Edge[] | ((oldState: Edge[]) => Edge[]), - skipSave?: boolean, - ) => void; + setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void; + setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void; setNode: ( id: string, update: Node | ((oldState: Node) => Node), From e9f30bfc55a6d1fdb46d8615be12edb5774f2d7e Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Thu, 8 Aug 2024 11:40:20 -0300 Subject: [PATCH 13/84] removed unused var --- src/frontend/src/components/chatComponent/index.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index cf4ea95e241..7823adcbbef 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -1,6 +1,6 @@ import FeatureFlags from "@/../feature-config.json"; import { Transition } from "@headlessui/react"; -import { useMemo, useRef, useState } from "react"; +import { useMemo, useState } from "react"; import { useHotkeys } from "react-hotkeys-hook"; import IOModal from "../../modals/IOModal"; import ApiModal from "../../modals/apiModal"; @@ -49,8 +49,6 @@ export default function FlowToolbar(): JSX.Element { const hasApiKey = useStoreStore((state) => state.hasApiKey); const currentFlow = useFlowsManagerStore((state) => state.currentFlow); - const prevNodesRef = useRef(); - const ModalMemo = useMemo( () => ( Date: Thu, 8 Aug 2024 11:41:15 -0300 Subject: [PATCH 14/84] removed deletion of empty flow --- .../src/components/headerComponent/index.tsx | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index c806b4d5cae..ab63a9ecb9b 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -1,7 +1,7 @@ import { useContext } from "react"; import { FaDiscord, FaGithub } from "react-icons/fa"; import { RiTwitterXFill } from "react-icons/ri"; -import { Link, useLocation, useNavigate, useParams } from "react-router-dom"; +import { Link, useLocation, useNavigate } from "react-router-dom"; import AlertDropdown from "../../alerts/alertDropDown"; import { BASE_URL_API, @@ -12,11 +12,9 @@ import { AuthContext } from "../../contexts/authContext"; import FeatureFlags from "@/../feature-config.json"; import { useLogout } from "@/controllers/API/queries/auth"; -import useDeleteFlow from "@/hooks/flows/use-delete-flow"; import useAuthStore from "@/stores/authStore"; import useAlertStore from "../../stores/alertStore"; import { useDarkStore } from "../../stores/darkStore"; -import useFlowStore from "../../stores/flowStore"; import { useLocationStore } from "../../stores/locationStore"; import { useStoreStore } from "../../stores/storeStore"; import IconComponent, { ForwardedIconComponent } from "../genericIconComponent"; @@ -44,10 +42,7 @@ export default function Header(): JSX.Element { const logout = useAuthStore((state) => state.logout); const navigate = useNavigate(); - const deleteFlow = useDeleteFlow(); const hasStore = useStoreStore((state) => state.hasStore); - const { id } = useParams(); - const nodes = useFlowStore((state) => state.nodes); const dark = useDarkStore((state) => state.dark); const setDark = useDarkStore((state) => state.setDark); @@ -58,11 +53,6 @@ export default function Header(): JSX.Element { const profileImageUrl = `${BASE_URL_API}files/profile_pictures/${ userData?.profile_image ?? "Space/046-rocket.svg" }`; - async function checkForChanges(): Promise { - if (nodes.length === 0 && id) { - await deleteFlow({ id }); - } - } const redirectToLastLocation = () => { const lastFlowVisitedIndex = routeHistory @@ -100,14 +90,13 @@ export default function Header(): JSX.Element { return (
- + ⛓️ {showArrowReturnIcon && (
+ } + > + + , ); reportWebVitals(); From 578e0ae33ea18b230d1731be495e96d52efd02e5 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 14:46:47 -0300 Subject: [PATCH 35/84] Changed flowStore to have a local flow state --- src/frontend/src/stores/flowStore.ts | 28 ++++++++++++++++++-- src/frontend/src/types/zustand/flow/index.ts | 18 +++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index 1aea57414ad..0c62f04c72d 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -152,7 +152,10 @@ const useFlowStore = create((set, get) => ({ setPending: (isPending) => { set({ isPending }); }, - resetFlow: ({ nodes, edges, viewport }) => { + resetFlow: (flow) => { + const nodes = flow?.data?.nodes ?? []; + const edges = flow?.data?.edges ?? []; + const viewport = flow?.data?.viewport ?? { zoom: 1, x: 0, y: 0 }; let brokenEdges = detectBrokenEdgesEdges(nodes, edges); if (brokenEdges.length > 0) { useAlertStore.getState().setErrorData({ @@ -171,6 +174,7 @@ const useFlowStore = create((set, get) => ({ outputs, hasIO: inputs.length > 0 || outputs.length > 0, flowPool: {}, + currentFlow: flow, }); get().reactFlowInstance?.setViewport(viewport); }, @@ -596,7 +600,6 @@ const useFlowStore = create((set, get) => ({ useFlowStore.getState().updateBuildStatus([vertexBuildData.id], status); } - console.log("on flow page", get().onFlowPage, "nodes", get().nodes); await buildFlowVerticesWithFallback({ input_value, files, @@ -721,6 +724,27 @@ const useFlowStore = create((set, get) => ({ }); set({ flowBuildStatus: newFlowBuildStatus }); }, + currentFlow: undefined, + setCurrentFlow: (flow) => { + set({ currentFlow: flow }); + }, + updateCurrentFlow: ({ nodes, edges, viewport }) => { + set({ + currentFlow: { + ...get().currentFlow!, + data: { + nodes: nodes ?? get().currentFlow?.data?.nodes ?? [], + edges: edges ?? get().currentFlow?.data?.edges ?? [], + viewport: viewport ?? + get().currentFlow?.data?.viewport ?? { + x: 0, + y: 0, + zoom: 1, + }, + }, + }, + }); + }, })); export default useFlowStore; diff --git a/src/frontend/src/types/zustand/flow/index.ts b/src/frontend/src/types/zustand/flow/index.ts index da52455e297..574e8e54753 100644 --- a/src/frontend/src/types/zustand/flow/index.ts +++ b/src/frontend/src/types/zustand/flow/index.ts @@ -1,3 +1,4 @@ +import { FlowType } from "@/types/flow"; import { Connection, Edge, @@ -83,11 +84,7 @@ export type FlowStoreType = { isPending: boolean; setIsBuilding: (isBuilding: boolean) => void; setPending: (isPending: boolean) => void; - resetFlow: (flow: { - nodes: Node[]; - edges: Edge[]; - viewport: Viewport; - }) => void; + resetFlow: (flow: FlowType | undefined) => void; reactFlowInstance: ReactFlowInstance | null; setReactFlowInstance: (newState: ReactFlowInstance) => void; flowState: FlowState | undefined; @@ -171,4 +168,15 @@ export type FlowStoreType = { setLockChat: (lock: boolean) => void; lockChat: boolean; updateFreezeStatus: (nodeIds: string[], freeze: boolean) => void; + currentFlow: FlowType | undefined; + setCurrentFlow: (flow: FlowType | undefined) => void; + updateCurrentFlow: ({ + nodes, + edges, + viewport, + }: { + nodes?: Node[]; + edges?: Edge[]; + viewport?: Viewport; + }) => void; }; From a984b6dea9d7c3823ec17497b673e307e5bba76c Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 14:47:12 -0300 Subject: [PATCH 36/84] Implemented setting the current flow state when saving the flow --- src/frontend/src/hooks/flows/use-save-flow.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontend/src/hooks/flows/use-save-flow.ts b/src/frontend/src/hooks/flows/use-save-flow.ts index e4f50d66b11..dee4143c0c5 100644 --- a/src/frontend/src/hooks/flows/use-save-flow.ts +++ b/src/frontend/src/hooks/flows/use-save-flow.ts @@ -12,6 +12,7 @@ const useSaveFlow = () => { const nodes = useFlowStore((state) => state.nodes); const edges = useFlowStore((state) => state.edges); const setSaveLoading = useFlowsManagerStore((state) => state.setSaveLoading); + const setCurrentFlow = useFlowStore((state) => state.setCurrentFlow); const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const flowData = currentFlow?.data; @@ -53,6 +54,7 @@ const useSaveFlow = () => { return flow; }), ); + setCurrentFlow(updatedFlow); resolve(); } }, From 352d8aa7c9488513f189471493291cfbfa2971c0 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 14:47:38 -0300 Subject: [PATCH 37/84] Added the update of current flow when auto saving --- .../components/PageComponent/index.tsx | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 10a0f9c7c6b..4dd4e5425c4 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -80,7 +80,6 @@ export default function Page({ const onEdgesChange = useFlowStore((state) => state.onEdgesChange); const setNodes = useFlowStore((state) => state.setNodes); const setEdges = useFlowStore((state) => state.setEdges); - const cleanFlow = useFlowStore((state) => state.cleanFlow); const deleteNode = useFlowStore((state) => state.deleteNode); const deleteEdge = useFlowStore((state) => state.deleteEdge); const undo = useFlowsManagerStore((state) => state.undo); @@ -97,15 +96,13 @@ export default function Page({ const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const setErrorData = useAlertStore((state) => state.setErrorData); const setNoticeData = useAlertStore((state) => state.setNoticeData); + const updateCurrentFlow = useFlowStore((state) => state.updateCurrentFlow); const [selectionMenuVisible, setSelectionMenuVisible] = useState(false); const edgeUpdateSuccessful = useRef(true); const position = useRef({ x: 0, y: 0 }); const [lastSelection, setLastSelection] = useState(null); - - const setFlowState = useFlowStore((state) => state.setFlowState); - const setHasIO = useFlowStore((state) => state.setHasIO); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); function handleGroupNode() { @@ -178,8 +175,12 @@ export default function Page({ }, [currentFlowId]); useEffect(() => { - if (currentFlow) { + if (currentFlow && reactFlowInstance) { autoSaveFlow(); + updateCurrentFlow({ + nodes, + edges, + }); } }, [nodes, edges]); @@ -320,7 +321,17 @@ export default function Page({ const onMoveEnd: OnMove = useCallback(() => { // 👇 make moving the canvas undoable autoSaveFlow(); - }, [takeSnapshot, autoSaveFlow, nodes, edges, reactFlowInstance]); + updateCurrentFlow({ + viewport: reactFlowInstance?.getViewport(), + }); + }, [ + takeSnapshot, + autoSaveFlow, + updateCurrentFlow, + nodes, + edges, + reactFlowInstance, + ]); const onSelectionDragStart: SelectionDragHandler = useCallback(() => { // 👇 make dragging a selection undoable From 244370c076239368768900d126b26c0ff6862c65 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 14:48:03 -0300 Subject: [PATCH 38/84] changed current flow to use the current flow from Flow Store instead of Flows Manager Store --- src/frontend/src/components/chatComponent/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 7823adcbbef..1b40466e13c 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -6,7 +6,6 @@ import IOModal from "../../modals/IOModal"; import ApiModal from "../../modals/apiModal"; import ShareModal from "../../modals/shareModal"; import useFlowStore from "../../stores/flowStore"; -import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { useShortcutsStore } from "../../stores/shortcuts"; import { useStoreStore } from "../../stores/storeStore"; import { classNames, isThereModal } from "../../utils/utils"; @@ -47,7 +46,7 @@ export default function FlowToolbar(): JSX.Element { const hasStore = useStoreStore((state) => state.hasStore); const validApiKey = useStoreStore((state) => state.validApiKey); const hasApiKey = useStoreStore((state) => state.hasApiKey); - const currentFlow = useFlowsManagerStore((state) => state.currentFlow); + const currentFlow = useFlowStore((state) => state.currentFlow); const ModalMemo = useMemo( () => ( From 633da70a1d224f71bf12be17989095c12c4cd325 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 14:48:23 -0300 Subject: [PATCH 39/84] Changed codeTabsComponent Tweaks check to show if its checked --- src/frontend/src/components/codeTabsComponent/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/src/components/codeTabsComponent/index.tsx b/src/frontend/src/components/codeTabsComponent/index.tsx index 239a3117e0c..f17afa61571 100644 --- a/src/frontend/src/components/codeTabsComponent/index.tsx +++ b/src/frontend/src/components/codeTabsComponent/index.tsx @@ -86,6 +86,7 @@ export default function CodeTabsComponent({ }} id="tweaks-switch" onCheckedChange={setActiveTweaks} + checked={activeTweaks} autoFocus={false} />
+ {blocker.state === "blocked" && ( + (blocker.reset ? blocker.reset() : null)} + onProceed={() => (blocker.proceed ? blocker.proceed() : null)} + /> + )} ); } From 6e887ade46b9734dabaf5bcc4ce35ca3e8564351 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 14:51:10 -0300 Subject: [PATCH 49/84] Added new types on ConfirmationModalType --- src/frontend/src/types/components/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 058c6a83355..e65101ffeeb 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -435,6 +435,7 @@ export type ConfirmationModalType = { title: string; titleHeader?: string; destructive?: boolean; + destructiveCancel?: boolean; modalContentTitle?: string; cancelText: string; confirmationText: string; @@ -446,7 +447,7 @@ export type ConfirmationModalType = { index?: number; onConfirm: (index, data) => void; open?: boolean; - onClose?: (close: boolean) => void; + onClose?: () => void; size?: | "x-small" | "smaller" From 734820a082e5efc7752c9ce524cd1c30264400c9 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 15:50:26 -0300 Subject: [PATCH 50/84] Implement save on clicking the save button on the header --- .../components/menuBar/index.tsx | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index a5a2747af92..dd562487fd1 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -255,19 +255,36 @@ export const MenuBar = ({}: {}): JSX.Element => { >
- 1 - ? "Save" - : "CheckCircle2" - } +
{printByBuildStatus()}
diff --git a/src/frontend/src/modals/exportModal/index.tsx b/src/frontend/src/modals/exportModal/index.tsx index 8904f79befe..9689170faa6 100644 --- a/src/frontend/src/modals/exportModal/index.tsx +++ b/src/frontend/src/modals/exportModal/index.tsx @@ -1,3 +1,4 @@ +import useFlowStore from "@/stores/flowStore"; import { ReactNode, forwardRef, useEffect, useState } from "react"; import EditFlowSettings from "../../components/editFlowSettingsComponent"; import IconComponent from "../../components/genericIconComponent"; @@ -10,7 +11,6 @@ import { } from "../../constants/constants"; import useAlertStore from "../../stores/alertStore"; import { useDarkStore } from "../../stores/darkStore"; -import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { downloadFlow, removeApiKeys } from "../../utils/reactflowUtils"; import BaseModal from "../baseModal"; @@ -19,7 +19,7 @@ const ExportModal = forwardRef( const version = useDarkStore((state) => state.version); const setNoticeData = useAlertStore((state) => state.setNoticeData); const [checked, setChecked] = useState(false); - const currentFlow = useFlowsManagerStore((state) => state.currentFlow); + const currentFlow = useFlowStore((state) => state.currentFlow); useEffect(() => { setName(currentFlow!.name); setDescription(currentFlow!.description); diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 4dd4e5425c4..5af80da3106 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -36,7 +36,7 @@ import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; import { useShortcutsStore } from "../../../../stores/shortcuts"; import { useTypesStore } from "../../../../stores/typesStore"; import { APIClassType } from "../../../../types/api"; -import { FlowType, NodeType } from "../../../../types/flow"; +import { NodeType } from "../../../../types/flow"; import { checkOldComponents, generateFlow, @@ -56,13 +56,7 @@ const nodeTypes = { genericNode: GenericNode, }; -export default function Page({ - flow, - view, -}: { - flow: FlowType; - view?: boolean; -}): JSX.Element { +export default function Page({ view }: { view?: boolean }): JSX.Element { const uploadFlow = useUploadFlow(); const autoSaveFlow = useAutoSaveFlow(); const types = useTypesStore((state) => state.types); @@ -93,7 +87,7 @@ export default function Page({ (state) => state.setLastCopiedSelection, ); const onConnect = useFlowStore((state) => state.onConnect); - const currentFlow = useFlowsManagerStore((state) => state.currentFlow); + const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow); const setErrorData = useAlertStore((state) => state.setErrorData); const setNoticeData = useAlertStore((state) => state.setNoticeData); const updateCurrentFlow = useFlowStore((state) => state.updateCurrentFlow); @@ -151,8 +145,12 @@ export default function Page({ }, [lastCopiedSelection, lastSelection, takeSnapshot, selectionMenuVisible]); useEffect(() => { - if (reactFlowInstance && currentFlow) { - const viewport = currentFlow.data?.viewport ?? { zoom: 1, x: 0, y: 0 }; + if (reactFlowInstance && currentSavedFlow) { + const viewport = currentSavedFlow.data?.viewport ?? { + zoom: 1, + x: 0, + y: 0, + }; reactFlowInstance!.setViewport(viewport); } }, [currentFlowId, reactFlowInstance]); @@ -175,7 +173,7 @@ export default function Page({ }, [currentFlowId]); useEffect(() => { - if (currentFlow && reactFlowInstance) { + if (currentSavedFlow && reactFlowInstance) { autoSaveFlow(); updateCurrentFlow({ nodes, diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx index 3ac87f76c0d..b16d7cc733c 100644 --- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx @@ -1,17 +1,13 @@ import { cloneDeep } from "lodash"; import { LinkIcon, SparklesIcon } from "lucide-react"; -import { Fragment, useEffect, useMemo, useState } from "react"; +import { Fragment, useEffect, useState } from "react"; import IconComponent from "../../../../components/genericIconComponent"; import ShadTooltip from "../../../../components/shadTooltipComponent"; import { Input } from "../../../../components/ui/input"; import { Separator } from "../../../../components/ui/separator"; import { PRIORITY_SIDEBAR_ORDER } from "../../../../constants/constants"; -import ExportModal from "../../../../modals/exportModal"; -import ShareModal from "../../../../modals/shareModal"; import useAlertStore from "../../../../stores/alertStore"; import useFlowStore from "../../../../stores/flowStore"; -import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; -import { useStoreStore } from "../../../../stores/storeStore"; import { useTypesStore } from "../../../../stores/typesStore"; import { APIClassType, APIObjectType } from "../../../../types/api"; import { @@ -19,7 +15,7 @@ import { nodeIconsLucide, nodeNames, } from "../../../../utils/styleUtils"; -import { classNames, removeCountFromString } from "../../../../utils/utils"; +import { removeCountFromString } from "../../../../utils/utils"; import DisclosureComponent from "../DisclosureComponent"; import ParentDisclosureComponent from "../ParentDisclosureComponent"; import SidebarDraggableComponent from "./sideBarDraggableComponent"; @@ -31,10 +27,6 @@ export default function ExtraSidebar(): JSX.Element { const templates = useTypesStore((state) => state.templates); const getFilterEdge = useFlowStore((state) => state.getFilterEdge); const setFilterEdge = useFlowStore((state) => state.setFilterEdge); - const currentFlow = useFlowsManagerStore((state) => state.currentFlow); - const hasStore = useStoreStore((state) => state.hasStore); - const hasApiKey = useStoreStore((state) => state.hasApiKey); - const validApiKey = useStoreStore((state) => state.validApiKey); const setErrorData = useAlertStore((state) => state.setErrorData); const [dataFilter, setFilterData] = useState(data); @@ -187,63 +179,6 @@ export default function ExtraSidebar(): JSX.Element { } }, [getFilterEdge, data]); - const ModalMemo = useMemo( - () => ( - - - - ), - [hasApiKey, validApiKey, currentFlow, hasStore], - ); - - const ExportMemo = useMemo( - () => ( - - - - ), - [], - ); - - const getIcon = useMemo(() => { - return (SBSectionName: string) => { - if (nodeIconsLucide[SBSectionName]) { - return ( - - ); - } - }; - }, []); - return (
diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 58107d8b94c..9e492d8100a 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -82,7 +82,7 @@ export default function NodeToolbarComponent({ const validApiKey = useStoreStore((state) => state.validApiKey); const shortcuts = useShortcutsStore((state) => state.shortcuts); const unselectAll = useFlowStore((state) => state.unselectAll); - const currentFlow = useFlowsManagerStore((state) => state.currentFlow); + const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); const addFlow = useAddFlow(); function handleMinimizeWShortcut(e: KeyboardEvent) { @@ -179,7 +179,7 @@ export default function NodeToolbarComponent({ function handleFreezeAll(e: KeyboardEvent) { if (isWrappedWithClass(e, "noflow")) return; e.preventDefault(); - FreezeAllVertices({ flowId: currentFlow!.id, stopNodeId: data.id }); + FreezeAllVertices({ flowId: currentFlowId, stopNodeId: data.id }); } const advanced = useShortcutsStore((state) => state.advanced); @@ -280,7 +280,7 @@ export default function NodeToolbarComponent({ })); break; case "freezeAll": - FreezeAllVertices({ flowId: currentFlow!.id, stopNodeId: data.id }); + FreezeAllVertices({ flowId: currentFlowId, stopNodeId: data.id }); break; case "code": setOpenModal(!openModal); @@ -480,7 +480,7 @@ export default function NodeToolbarComponent({ event.preventDefault(); takeSnapshot(); FreezeAllVertices({ - flowId: currentFlow!.id, + flowId: currentFlowId, stopNodeId: data.id, }); }} diff --git a/src/frontend/src/pages/FlowPage/index.tsx b/src/frontend/src/pages/FlowPage/index.tsx index 68874b63b6b..02a2d52782a 100644 --- a/src/frontend/src/pages/FlowPage/index.tsx +++ b/src/frontend/src/pages/FlowPage/index.tsx @@ -79,7 +79,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
{/* Primary column */}
- +
{!view && }
diff --git a/src/frontend/src/pages/Playground/index.tsx b/src/frontend/src/pages/Playground/index.tsx index 694468a652c..e83faa24b26 100644 --- a/src/frontend/src/pages/Playground/index.tsx +++ b/src/frontend/src/pages/Playground/index.tsx @@ -1,25 +1,20 @@ -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { useParams } from "react-router-dom"; import LoadingComponent from "../../components/loadingComponent"; import { getComponent } from "../../controllers/API"; import IOModal from "../../modals/IOModal"; -import useFlowStore from "../../stores/flowStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore"; import cloneFLowWithParent from "../../utils/storeUtils"; export default function PlaygroundPage() { - const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const getFlowById = useFlowsManagerStore((state) => state.getFlowById); const setCurrentFlowId = useFlowsManagerStore( (state) => state.setCurrentFlowId, ); const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow); - const setNodes = useFlowStore((state) => state.setNodes); - const setEdges = useFlowStore((state) => state.setEdges); - const cleanFlowPool = useFlowStore((state) => state.CleanFlowPool); + const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow); const { id } = useParams(); - const [loading, setLoading] = useState(true); async function getFlowData() { const res = await getComponent(id!); const newFlow = cloneFLowWithParent(res, res.id, false, true); @@ -36,23 +31,10 @@ export default function PlaygroundPage() { }); } }, [id]); - useEffect(() => { - if (currentFlow) { - setNodes(currentFlow?.data?.nodes ?? []); - setEdges(currentFlow?.data?.edges ?? []); - cleanFlowPool(); - setLoading(false); - } - return () => { - setNodes([]); - setEdges([]); - cleanFlowPool(); - }; - }, [currentFlow]); return (
- {loading ? ( + {currentSavedFlow ? (
diff --git a/src/frontend/src/pages/ViewPage/index.tsx b/src/frontend/src/pages/ViewPage/index.tsx index 5498b77bd1e..a5487937f55 100644 --- a/src/frontend/src/pages/ViewPage/index.tsx +++ b/src/frontend/src/pages/ViewPage/index.tsx @@ -4,7 +4,6 @@ import useFlowsManagerStore from "../../stores/flowsManagerStore"; import Page from "../FlowPage/components/PageComponent"; export default function ViewPage() { - const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const setCurrentFlowId = useFlowsManagerStore( (state) => state.setCurrentFlowId, ); @@ -17,7 +16,7 @@ export default function ViewPage() { return (
- {currentFlow && } +
); } From 3a7e8c5017ad06013dc050fa64abc2afe211b36a Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 18:09:41 -0300 Subject: [PATCH 69/84] added check of isFlowPage to display the menubar --- .../components/headerComponent/components/menuBar/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index 53b5e2e931e..c9fff9dc815 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -53,6 +53,7 @@ export const MenuBar = ({}: {}): JSX.Element => { const currentFlow = useFlowStore((state) => state.currentFlow); const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow); const updatedAt = currentSavedFlow?.updated_at; + const onFlowPage = useFlowStore((state) => state.onFlowPage); const changesNotSaved = customStringify(currentFlow) !== customStringify(currentSavedFlow); @@ -99,7 +100,7 @@ export const MenuBar = ({}: {}): JSX.Element => { const changes = useShortcutsStore((state) => state.changes); useHotkeys(changes, handleSave, { preventDefault: true }); - return currentFlow ? ( + return currentFlow && onFlowPage ? (
From 11a506ed225ed527cc00b89c03e6a7862868d6b6 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 18:14:47 -0300 Subject: [PATCH 70/84] Added checks to render playground if API key is valid and if Flows exists --- src/frontend/src/pages/Playground/index.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/frontend/src/pages/Playground/index.tsx b/src/frontend/src/pages/Playground/index.tsx index e83faa24b26..cf751052502 100644 --- a/src/frontend/src/pages/Playground/index.tsx +++ b/src/frontend/src/pages/Playground/index.tsx @@ -1,3 +1,4 @@ +import { useStoreStore } from "@/stores/storeStore"; import { useEffect } from "react"; import { useParams } from "react-router-dom"; import LoadingComponent from "../../components/loadingComponent"; @@ -8,11 +9,13 @@ import cloneFLowWithParent from "../../utils/storeUtils"; export default function PlaygroundPage() { const getFlowById = useFlowsManagerStore((state) => state.getFlowById); + const flows = useFlowsManagerStore((state) => state.flows); const setCurrentFlowId = useFlowsManagerStore( (state) => state.setCurrentFlowId, ); const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow); const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow); + const validApiKey = useStoreStore((state) => state.validApiKey); const { id } = useParams(); async function getFlowData() { @@ -26,15 +29,16 @@ export default function PlaygroundPage() { if (getFlowById(id!)) { setCurrentFlowId(id!); } else { - getFlowData().then((flow) => { - setCurrentFlow(flow); - }); + if (validApiKey) + getFlowData().then((flow) => { + setCurrentFlow(flow); + }); } - }, [id]); + }, [id, flows, validApiKey]); return (
- {currentSavedFlow ? ( + {!currentSavedFlow ? (
From 7343b3358ce090c69d1e3a47dac7a3c78bfe7a62 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 18:16:56 -0300 Subject: [PATCH 71/84] Added check to not display X on chat on playground page --- src/frontend/src/modals/IOModal/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontend/src/modals/IOModal/index.tsx b/src/frontend/src/modals/IOModal/index.tsx index 7e13a6f1275..caa10f9bb8e 100644 --- a/src/frontend/src/modals/IOModal/index.tsx +++ b/src/frontend/src/modals/IOModal/index.tsx @@ -33,6 +33,7 @@ export default function IOModal({ open, setOpen, disable, + isPlayground, }: IOModalPropsType): JSX.Element { const allNodes = useFlowStore((state) => state.nodes); const inputs = useFlowStore((state) => state.inputs).filter( @@ -178,6 +179,7 @@ export default function IOModal({ open={open} setOpen={setOpen} disable={disable} + type={isPlayground ? "modal" : undefined} onSubmit={() => sendMessage({ repeat: 1 })} > {children} From a335e77a8c5dbff5394c577839b03e0e0c582569 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 9 Aug 2024 18:28:12 -0300 Subject: [PATCH 72/84] Updated flows variable to be undefined by start to prevent things from loading before flows initialize --- .../sidebarComponent/hooks/use-on-file-drop.tsx | 4 ++-- src/frontend/src/hooks/flows/use-add-flow.ts | 9 ++++++--- src/frontend/src/hooks/flows/use-delete-flow.ts | 2 +- src/frontend/src/hooks/flows/use-save-flow.ts | 2 +- .../src/modals/flowSettingsModal/index.tsx | 13 ++++++++----- .../sideBarDraggableComponent/index.tsx | 2 +- .../components/nodeToolbarComponent/index.tsx | 2 +- src/frontend/src/pages/FlowPage/index.tsx | 15 ++++++++++----- src/frontend/src/pages/Playground/index.tsx | 16 +++++++++------- src/frontend/src/stores/flowsManagerStore.ts | 4 ++-- .../src/types/zustand/flowsManager/index.ts | 2 +- 11 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx index 216fde9f93e..659eadddf42 100644 --- a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx +++ b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx @@ -106,14 +106,14 @@ const useFileDrop = ( }; const uploadFromDragCard = (flowId, folderId) => { - const selectedFlow = flows.find((flow) => flow.id === flowId); + const selectedFlow = flows?.find((flow) => flow.id === flowId); if (!selectedFlow) { throw new Error("Flow not found"); } const updatedFlow = { ...selectedFlow, folder_id: folderId }; - const newName = addVersionToDuplicates(updatedFlow, flows); + const newName = addVersionToDuplicates(updatedFlow, flows ?? []); updatedFlow.name = newName; diff --git a/src/frontend/src/hooks/flows/use-add-flow.ts b/src/frontend/src/hooks/flows/use-add-flow.ts index 5d9587db3ee..9a5fe31b5e6 100644 --- a/src/frontend/src/hooks/flows/use-add-flow.ts +++ b/src/frontend/src/hooks/flows/use-add-flow.ts @@ -49,7 +49,7 @@ const useAddFlow = () => { const my_collection_id = useFolderStore.getState().myCollectionId; if (params?.override && flow) { - const flowId = flows.find((f) => f.name === flow.name); + const flowId = flows?.find((f) => f.name === flow.name); if (flowId) { await deleteFlow({ id: flowId.id }); } @@ -60,7 +60,7 @@ const useAddFlow = () => { flow, ); - const newName = addVersionToDuplicates(newFlow, flows); + const newName = addVersionToDuplicates(newFlow, flows ?? []); newFlow.name = newName; newFlow.folder_id = useFolderStore.getState().folderUrl; @@ -68,7 +68,10 @@ const useAddFlow = () => { onSuccess: ({ id }) => { newFlow.id = id; // Add the new flow to the list of flows. - const { data, flows: myFlows } = processFlows([newFlow, ...flows]); + const { data, flows: myFlows } = processFlows([ + newFlow, + ...(flows ?? []), + ]); setFlows(myFlows); useTypesStore.setState((state) => ({ data: { ...state.data, ["saved_components"]: data }, diff --git a/src/frontend/src/hooks/flows/use-delete-flow.ts b/src/frontend/src/hooks/flows/use-delete-flow.ts index bc8c5d5387d..043df2d2978 100644 --- a/src/frontend/src/hooks/flows/use-delete-flow.ts +++ b/src/frontend/src/hooks/flows/use-delete-flow.ts @@ -27,7 +27,7 @@ const useDeleteFlow = () => { { onSuccess: () => { const { data, flows: myFlows } = processFlows( - flows.filter((flow) => !id.includes(flow.id)), + (flows ?? []).filter((flow) => !id.includes(flow.id)), ); setFlows(myFlows); setIsLoading(false); diff --git a/src/frontend/src/hooks/flows/use-save-flow.ts b/src/frontend/src/hooks/flows/use-save-flow.ts index d204f2d031f..55383b73400 100644 --- a/src/frontend/src/hooks/flows/use-save-flow.ts +++ b/src/frontend/src/hooks/flows/use-save-flow.ts @@ -44,7 +44,7 @@ const useSaveFlow = () => { { onSuccess: (updatedFlow) => { setSaveLoading(false); - if (updatedFlow !== null) { + if (updatedFlow !== null && flows) { // updates flow in state setFlows( flows.map((flow) => { diff --git a/src/frontend/src/modals/flowSettingsModal/index.tsx b/src/frontend/src/modals/flowSettingsModal/index.tsx index 7c8a1c374fe..a55441598cc 100644 --- a/src/frontend/src/modals/flowSettingsModal/index.tsx +++ b/src/frontend/src/modals/flowSettingsModal/index.tsx @@ -65,11 +65,14 @@ export default function FlowSettingsModal({ const [nameLists, setNameList] = useState([]); useEffect(() => { - const tempNameList: string[] = []; - flows.forEach((flow: FlowType) => { - if ((flow.is_component ?? false) === false) tempNameList.push(flow.name); - }); - setNameList(tempNameList.filter((name) => name !== currentFlow!.name)); + if (flows) { + const tempNameList: string[] = []; + flows.forEach((flow: FlowType) => { + if ((flow.is_component ?? false) === false) + tempNameList.push(flow.name); + }); + setNameList(tempNameList.filter((name) => name !== currentFlow!.name)); + } }, [flows]); useEffect(() => { diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/sideBarDraggableComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/sideBarDraggableComponent/index.tsx index 835f98c69d6..1dc7e2afa2a 100644 --- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/sideBarDraggableComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/sideBarDraggableComponent/index.tsx @@ -72,7 +72,7 @@ export const SidebarDraggableComponent = forwardRef( ); break; case "delete": - const flowId = flows.find((f) => f.name === display_name); + const flowId = flows?.find((f) => f.name === display_name); if (flowId) deleteFlow({ id: flowId.id }); break; } diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 9e492d8100a..743c5acd444 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -355,7 +355,7 @@ export default function NodeToolbarComponent({ } }; - const isSaved = flows.some((flow) => + const isSaved = flows?.some((flow) => Object.values(flow).includes(data.node?.display_name!), ); diff --git a/src/frontend/src/pages/FlowPage/index.tsx b/src/frontend/src/pages/FlowPage/index.tsx index 02a2d52782a..32c93305573 100644 --- a/src/frontend/src/pages/FlowPage/index.tsx +++ b/src/frontend/src/pages/FlowPage/index.tsx @@ -54,14 +54,19 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element { // Set flow tab id useEffect(() => { - const isAnExistingFlow = flows.some((flow) => flow.id === id); + if (flows) { + const isAnExistingFlow = flows.some((flow) => flow.id === id); - if (!isAnExistingFlow) { - navigate("/all"); - return; + if (!isAnExistingFlow) { + navigate("/all"); + return; + } + + setCurrentFlowId(id!); } + }, [id, flows]); - setCurrentFlowId(id!); + useEffect(() => { setOnFlowPage(true); return () => { diff --git a/src/frontend/src/pages/Playground/index.tsx b/src/frontend/src/pages/Playground/index.tsx index cf751052502..21276a96691 100644 --- a/src/frontend/src/pages/Playground/index.tsx +++ b/src/frontend/src/pages/Playground/index.tsx @@ -26,13 +26,15 @@ export default function PlaygroundPage() { // Set flow tab id useEffect(() => { - if (getFlowById(id!)) { - setCurrentFlowId(id!); - } else { - if (validApiKey) - getFlowData().then((flow) => { - setCurrentFlow(flow); - }); + if (flows) { + if (getFlowById(id!)) { + setCurrentFlowId(id!); + } else { + if (validApiKey) + getFlowData().then((flow) => { + setCurrentFlow(flow); + }); + } } }, [id, flows, validApiKey]); diff --git a/src/frontend/src/stores/flowsManagerStore.ts b/src/frontend/src/stores/flowsManagerStore.ts index d06c6864380..ed16031d249 100644 --- a/src/frontend/src/stores/flowsManagerStore.ts +++ b/src/frontend/src/stores/flowsManagerStore.ts @@ -37,7 +37,7 @@ const useFlowsManagerStore = create((set, get) => ({ useFlowStore.getState().resetFlow(flow); }, getFlowById: (id: string) => { - return get().flows.find((flow) => flow.id === id); + return get().flows?.find((flow) => flow.id === id); }, setCurrentFlowId: (currentFlowId: string) => { const flow = get().flows?.find((flow) => flow.id === currentFlowId); @@ -48,7 +48,7 @@ const useFlowsManagerStore = create((set, get) => ({ }); useFlowStore.getState().resetFlow(flow); }, - flows: [], + flows: undefined, allFlows: [], setAllFlows: (allFlows: FlowType[]) => { set({ allFlows }); diff --git a/src/frontend/src/types/zustand/flowsManager/index.ts b/src/frontend/src/types/zustand/flowsManager/index.ts index 6fd343e0768..419d5b514b0 100644 --- a/src/frontend/src/types/zustand/flowsManager/index.ts +++ b/src/frontend/src/types/zustand/flowsManager/index.ts @@ -2,7 +2,7 @@ import { FlowType } from "../../flow"; export type FlowsManagerStoreType = { getFlowById: (id: string) => FlowType | undefined; - flows: Array; + flows: Array | undefined; allFlows: Array; setAllFlows: (flows: FlowType[]) => void; setFlows: (flows: FlowType[]) => void; From f101bd1a6f04936c79feefba5ee21103de883ba6 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Sun, 11 Aug 2024 23:12:59 -0300 Subject: [PATCH 73/84] Implemented log builds parameter to not allow the builds to be logged if user not on flowPage --- src/frontend/src/stores/flowStore.ts | 1 + src/frontend/src/utils/buildUtils.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index 53bad8291b2..3283fee306e 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -647,6 +647,7 @@ const useFlowStore = create((set, get) => ({ onValidateNodes: validateSubgraph, nodes: get().nodes || undefined, edges: get().edges || undefined, + logBuilds: get().onFlowPage, }); get().setIsBuilding(false); get().setLockChat(false); diff --git a/src/frontend/src/utils/buildUtils.ts b/src/frontend/src/utils/buildUtils.ts index 77dbb8054e7..1a6a9f31c98 100644 --- a/src/frontend/src/utils/buildUtils.ts +++ b/src/frontend/src/utils/buildUtils.ts @@ -30,6 +30,7 @@ type BuildVerticesParams = { onValidateNodes?: (nodes: string[]) => void; nodes?: Node[]; edges?: Edge[]; + logBuilds?: boolean; }; function getInactiveVertexData(vertexId: string): VertexBuildTypeAPI { @@ -146,6 +147,7 @@ export async function buildFlowVertices({ onValidateNodes, nodes, edges, + logBuilds, setLockChat, }: BuildVerticesParams) { let url = `${BASE_URL_API}build/${flowId}/flow?`; @@ -155,6 +157,9 @@ export async function buildFlowVertices({ if (stopNodeId) { url = `${url}&stop_component_id=${stopNodeId}`; } + if (logBuilds !== undefined) { + url = `${url}&log_builds=${logBuilds}`; + } const postData = {}; if (typeof input_value !== "undefined") { postData["inputs"] = { input_value: input_value }; From 2fa6f7112f901084fcc07d9a55ad8dd7c0d2383d Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 14:06:52 -0300 Subject: [PATCH 74/84] fix flows manager store removing the setCurrentFlowId --- src/frontend/src/stores/flowsManagerStore.ts | 9 --------- src/frontend/src/types/zustand/flowsManager/index.ts | 3 +-- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/frontend/src/stores/flowsManagerStore.ts b/src/frontend/src/stores/flowsManagerStore.ts index ed16031d249..5b5bb451b03 100644 --- a/src/frontend/src/stores/flowsManagerStore.ts +++ b/src/frontend/src/stores/flowsManagerStore.ts @@ -39,15 +39,6 @@ const useFlowsManagerStore = create((set, get) => ({ getFlowById: (id: string) => { return get().flows?.find((flow) => flow.id === id); }, - setCurrentFlowId: (currentFlowId: string) => { - const flow = get().flows?.find((flow) => flow.id === currentFlowId); - set({ - currentFlowId, - currentFlow: - get().flows?.find((flow) => flow.id === currentFlowId) ?? undefined, - }); - useFlowStore.getState().resetFlow(flow); - }, flows: undefined, allFlows: [], setAllFlows: (allFlows: FlowType[]) => { diff --git a/src/frontend/src/types/zustand/flowsManager/index.ts b/src/frontend/src/types/zustand/flowsManager/index.ts index 419d5b514b0..ae1252f26eb 100644 --- a/src/frontend/src/types/zustand/flowsManager/index.ts +++ b/src/frontend/src/types/zustand/flowsManager/index.ts @@ -8,7 +8,6 @@ export type FlowsManagerStoreType = { setFlows: (flows: FlowType[]) => void; currentFlow: FlowType | undefined; currentFlowId: string; - setCurrentFlowId: (currentFlowId: string) => void; saveLoading: boolean; setSaveLoading: (saveLoading: boolean) => void; isLoading: boolean; @@ -19,7 +18,7 @@ export type FlowsManagerStoreType = { takeSnapshot: () => void; examples: Array; setExamples: (examples: FlowType[]) => void; - setCurrentFlow: (flow: FlowType) => void; + setCurrentFlow: (flow?: FlowType) => void; setSearchFlowsComponents: (search: string) => void; searchFlowsComponents: string; selectedFlowsComponentsCards: string[]; From eb97599a0ce9fb9d535b2224b046f33aa93ffbad Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 14:07:06 -0300 Subject: [PATCH 75/84] Add viewport setting on setReactFlowInstance --- src/frontend/src/stores/flowStore.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index 3283fee306e..ca42275a3ae 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -193,6 +193,16 @@ const useFlowStore = create((set, get) => ({ }, setReactFlowInstance: (newState) => { set({ reactFlowInstance: newState }); + const viewport = get().currentFlow?.data?.viewport ?? { + zoom: 1, + x: 0, + y: 0, + }; + if (viewport.x == 0 && viewport.y == 0) { + newState.fitView(); + } else { + newState.setViewport(viewport); + } }, onNodesChange: (changes: NodeChange[]) => { set({ From a852b6c6eb3034ebadafbc1b1678dc7060d263e9 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 14:07:35 -0300 Subject: [PATCH 76/84] Remove unused imports --- .../components/OutputComponent/index.tsx | 15 --------------- src/frontend/src/stores/darkStore.ts | 2 +- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx index 6c18e6b0bfa..d3992035f75 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx @@ -1,17 +1,5 @@ -import { cloneDeep } from "lodash"; -import { useUpdateNodeInternals } from "reactflow"; -import ForwardedIconComponent from "../../../../components/genericIconComponent"; import ShadTooltip from "../../../../components/shadTooltipComponent"; -import { Button } from "../../../../components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "../../../../components/ui/dropdown-menu"; -import useFlowStore from "../../../../stores/flowStore"; import { outputComponentType } from "../../../../types/components"; -import { NodeDataType } from "../../../../types/flow"; import { cn } from "../../../../utils/utils"; export default function OutputComponent({ @@ -23,9 +11,6 @@ export default function OutputComponent({ name, proxy, }: outputComponentType) { - const setNode = useFlowStore((state) => state.setNode); - const updateNodeInternals = useUpdateNodeInternals(); - const displayProxy = (children) => { if (proxy) { return ( diff --git a/src/frontend/src/stores/darkStore.ts b/src/frontend/src/stores/darkStore.ts index a652525925a..6e3c28afa56 100644 --- a/src/frontend/src/stores/darkStore.ts +++ b/src/frontend/src/stores/darkStore.ts @@ -1,5 +1,5 @@ import { create } from "zustand"; -import { getRepoStars, getVersion } from "../controllers/API"; +import { getRepoStars } from "../controllers/API"; import { DarkStoreType } from "../types/zustand/dark"; const startedStars = Number(window.localStorage.getItem("githubStars")) ?? 0; From bac3e1bbdb6f6b24df833dd3809489a11a46fec4 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 14:08:39 -0300 Subject: [PATCH 77/84] Removed setting of currentFlowId on every page and made the setting of currentFlow become default --- .../src/components/cardComponent/index.tsx | 7 ++-- src/frontend/src/pages/AdminPage/index.tsx | 9 ----- src/frontend/src/pages/FlowPage/index.tsx | 12 +++---- .../pages/MainPage/pages/mainPage/index.tsx | 11 +----- src/frontend/src/pages/Playground/index.tsx | 8 ++--- .../src/pages/ProfileSettingsPage/index.tsx | 12 +------ src/frontend/src/pages/SettingsPage/index.tsx | 11 ------ .../SettingsPage/pages/GeneralPage/index.tsx | 7 +--- .../pages/hooks/use-scroll-to-element.tsx | 9 +---- src/frontend/src/pages/StorePage/index.tsx | 10 +----- src/frontend/src/pages/ViewPage/index.tsx | 35 ++++++++++++++++--- 11 files changed, 46 insertions(+), 85 deletions(-) diff --git a/src/frontend/src/components/cardComponent/index.tsx b/src/frontend/src/components/cardComponent/index.tsx index f90f2c35024..c36aef2913d 100644 --- a/src/frontend/src/components/cardComponent/index.tsx +++ b/src/frontend/src/components/cardComponent/index.tsx @@ -63,9 +63,6 @@ export default function CollectionCardComponent({ const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow); const getFlowById = useFlowsManagerStore((state) => state.getFlowById); const [openPlayground, setOpenPlayground] = useState(false); - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); const [loadingPlayground, setLoadingPlayground] = useState(false); const selectedFlowsComponentsCards = useFlowsManagerStore( @@ -299,7 +296,7 @@ export default function CollectionCardComponent({ setLoadingPlayground(false); return; } - setCurrentFlowId(data.id); + setCurrentFlow(flow); setOpenPlayground(true); setLoadingPlayground(false); } else { @@ -455,7 +452,7 @@ export default function CollectionCardComponent({ setLoadingPlayground(false); return; } - setCurrentFlowId(data.id); + setCurrentFlow(flow); setOpenPlayground(true); setLoadingPlayground(false); } else { diff --git a/src/frontend/src/pages/AdminPage/index.tsx b/src/frontend/src/pages/AdminPage/index.tsx index e715340d4ad..5605742a0c4 100644 --- a/src/frontend/src/pages/AdminPage/index.tsx +++ b/src/frontend/src/pages/AdminPage/index.tsx @@ -38,7 +38,6 @@ import { AuthContext } from "../../contexts/authContext"; import ConfirmationModal from "../../modals/confirmationModal"; import UserManagementModal from "../../modals/userManagementModal"; import useAlertStore from "../../stores/alertStore"; -import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { Users } from "../../types/api"; import { UserInputType } from "../../types/components"; @@ -51,19 +50,11 @@ export default function AdminPage() { const setErrorData = useAlertStore((state) => state.setErrorData); const { userData } = useContext(AuthContext); const [totalRowsCount, setTotalRowsCount] = useState(0); - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); const { mutate: mutateDeleteUser } = useDeleteUsers(); const { mutate: mutateUpdateUser } = useUpdateUser(); const { mutate: mutateAddUser } = useAddUser(); - // set null id - useEffect(() => { - setCurrentFlowId(""); - }, []); - const userList = useRef([]); useEffect(() => { diff --git a/src/frontend/src/pages/FlowPage/index.tsx b/src/frontend/src/pages/FlowPage/index.tsx index 32c93305573..e4a6553d996 100644 --- a/src/frontend/src/pages/FlowPage/index.tsx +++ b/src/frontend/src/pages/FlowPage/index.tsx @@ -14,9 +14,7 @@ import Page from "./components/PageComponent"; import ExtraSidebar from "./components/extraSidebarComponent"; export default function FlowPage({ view }: { view?: boolean }): JSX.Element { - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); + const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow); const currentFlow = useFlowStore((state) => state.currentFlow); const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow); @@ -32,6 +30,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element { const saveFlow = useSaveFlow(); const flows = useFlowsManagerStore((state) => state.flows); + const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); const handleSave = () => { saveFlow().then(() => (blocker.proceed ? blocker.proceed() : null)); @@ -54,15 +53,15 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element { // Set flow tab id useEffect(() => { - if (flows) { - const isAnExistingFlow = flows.some((flow) => flow.id === id); + if (flows && currentFlowId === "") { + const isAnExistingFlow = flows.find((flow) => flow.id === id); if (!isAnExistingFlow) { navigate("/all"); return; } - setCurrentFlowId(id!); + setCurrentFlow(isAnExistingFlow); } }, [id, flows]); @@ -71,6 +70,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element { return () => { setOnFlowPage(false); + setCurrentFlow(); }; }, [id]); diff --git a/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx b/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx index 98d26452c0e..6847ad5794c 100644 --- a/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx @@ -1,6 +1,6 @@ import { useDeleteFolders } from "@/controllers/API/queries/folders"; import useAlertStore from "@/stores/alertStore"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { Outlet, useLocation, useNavigate } from "react-router-dom"; import DropdownButton from "../../../../components/dropdownButtonComponent"; import PageLayout from "../../../../components/pageLayout"; @@ -9,17 +9,12 @@ import { MY_COLLECTION_DESC, USER_PROJECTS_HEADER, } from "../../../../constants/constants"; -import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; import { useFolderStore } from "../../../../stores/foldersStore"; import ModalsComponent from "../../components/modalsComponent"; import useDropdownOptions from "../../hooks/use-dropdown-options"; import { getFolderById } from "../../services"; export default function HomePage(): JSX.Element { - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); - const location = useLocation(); const pathname = location.pathname; const [openModal, setOpenModal] = useState(false); @@ -35,10 +30,6 @@ export default function HomePage(): JSX.Element { const myCollectionId = useFolderStore((state) => state.myCollectionId); const getFoldersApi = useFolderStore((state) => state.getFoldersApi); - useEffect(() => { - setCurrentFlowId(""); - }, [pathname]); - const dropdownOptions = useDropdownOptions({ navigate, is_component, diff --git a/src/frontend/src/pages/Playground/index.tsx b/src/frontend/src/pages/Playground/index.tsx index 21276a96691..47c2aa17744 100644 --- a/src/frontend/src/pages/Playground/index.tsx +++ b/src/frontend/src/pages/Playground/index.tsx @@ -10,9 +10,6 @@ import cloneFLowWithParent from "../../utils/storeUtils"; export default function PlaygroundPage() { const getFlowById = useFlowsManagerStore((state) => state.getFlowById); const flows = useFlowsManagerStore((state) => state.flows); - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow); const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow); const validApiKey = useStoreStore((state) => state.validApiKey); @@ -27,8 +24,9 @@ export default function PlaygroundPage() { // Set flow tab id useEffect(() => { if (flows) { - if (getFlowById(id!)) { - setCurrentFlowId(id!); + const flow = getFlowById(id!); + if (flow) { + setCurrentFlow(flow); } else { if (validApiKey) getFlowData().then((flow) => { diff --git a/src/frontend/src/pages/ProfileSettingsPage/index.tsx b/src/frontend/src/pages/ProfileSettingsPage/index.tsx index 5d0135d9f62..ef8beadaa5a 100644 --- a/src/frontend/src/pages/ProfileSettingsPage/index.tsx +++ b/src/frontend/src/pages/ProfileSettingsPage/index.tsx @@ -4,7 +4,7 @@ import { } from "@/controllers/API/queries/auth"; import * as Form from "@radix-ui/react-form"; import { cloneDeep } from "lodash"; -import { useContext, useEffect, useState } from "react"; +import { useContext, useState } from "react"; import IconComponent from "../../components/genericIconComponent"; import Header from "../../components/headerComponent"; import InputComponent from "../../components/inputComponent"; @@ -18,7 +18,6 @@ import { import { CONTROL_PATCH_USER_STATE } from "../../constants/constants"; import { AuthContext } from "../../contexts/authContext"; import useAlertStore from "../../stores/alertStore"; -import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { inputHandlerEventType, patchUserInputStateType, @@ -26,18 +25,9 @@ import { import { gradients } from "../../utils/styleUtils"; import GradientChooserComponent from "../SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent"; export default function ProfileSettingsPage(): JSX.Element { - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); - const [inputState, setInputState] = useState( CONTROL_PATCH_USER_STATE, ); - - // set null id - useEffect(() => { - setCurrentFlowId(""); - }, []); const setSuccessData = useAlertStore((state) => state.setSuccessData); const setErrorData = useAlertStore((state) => state.setErrorData); const { userData, setUserData } = useContext(AuthContext); diff --git a/src/frontend/src/pages/SettingsPage/index.tsx b/src/frontend/src/pages/SettingsPage/index.tsx index bb08417d4d6..297aba41874 100644 --- a/src/frontend/src/pages/SettingsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/index.tsx @@ -1,19 +1,12 @@ import FeatureFlags from "@/../feature-config.json"; import useAuthStore from "@/stores/authStore"; import { useStoreStore } from "@/stores/storeStore"; -import { useEffect } from "react"; import { Outlet } from "react-router-dom"; import ForwardedIconComponent from "../../components/genericIconComponent"; import PageLayout from "../../components/pageLayout"; import SidebarNav from "../../components/sidebarComponent"; -import useFlowsManagerStore from "../../stores/flowsManagerStore"; export default function SettingsPage(): JSX.Element { - const pathname = location.pathname; - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); - const autoLogin = useAuthStore((state) => state.autoLogin); const hasStore = useStoreStore((state) => state.hasStore); @@ -21,10 +14,6 @@ export default function SettingsPage(): JSX.Element { const showGeneralSettings = FeatureFlags.ENABLE_PROFILE_ICONS || hasStore || !autoLogin; - useEffect(() => { - setCurrentFlowId(""); - }, [pathname]); - const sidebarNavItems: { href?: string; title: string; diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx index 5218edb5d22..a4570f7c5d1 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx @@ -18,7 +18,6 @@ import { useParams } from "react-router-dom"; import { CONTROL_PATCH_USER_STATE } from "../../../../constants/constants"; import { AuthContext } from "../../../../contexts/authContext"; import useAlertStore from "../../../../stores/alertStore"; -import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; import { useStoreStore } from "../../../../stores/storeStore"; import { inputHandlerEventType, @@ -31,10 +30,6 @@ import ProfilePictureFormComponent from "./components/ProfilePictureForm"; import StoreApiKeyFormComponent from "./components/StoreApiKeyForm"; export const GeneralPage = () => { - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); - const { scrollId } = useParams(); const [inputState, setInputState] = useState( @@ -112,7 +107,7 @@ export const GeneralPage = () => { } }; - useScrollToElement(scrollId, setCurrentFlowId); + useScrollToElement(scrollId); const { mutate } = usePostAddApiKey({ onSuccess: () => { diff --git a/src/frontend/src/pages/SettingsPage/pages/hooks/use-scroll-to-element.tsx b/src/frontend/src/pages/SettingsPage/pages/hooks/use-scroll-to-element.tsx index faa7408a333..966d4bb3481 100644 --- a/src/frontend/src/pages/SettingsPage/pages/hooks/use-scroll-to-element.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/hooks/use-scroll-to-element.tsx @@ -1,9 +1,6 @@ import { useEffect } from "react"; -const useScrollToElement = ( - scrollId: string | null | undefined, - setCurrentFlowId: (currentFlowId: string) => void, -) => { +const useScrollToElement = (scrollId: string | null | undefined) => { useEffect(() => { const element = document.getElementById(scrollId ?? "null"); if (element) { @@ -11,10 +8,6 @@ const useScrollToElement = ( element.scrollIntoView({ behavior: "smooth" }); } }, [scrollId]); - - useEffect(() => { - setCurrentFlowId(""); - }, [setCurrentFlowId]); }; export default useScrollToElement; diff --git a/src/frontend/src/pages/StorePage/index.tsx b/src/frontend/src/pages/StorePage/index.tsx index 36e6ce08de1..5342eb248ee 100644 --- a/src/frontend/src/pages/StorePage/index.tsx +++ b/src/frontend/src/pages/StorePage/index.tsx @@ -28,7 +28,7 @@ import { } from "../../constants/alerts_constants"; import { STORE_DESC, STORE_TITLE } from "../../constants/constants"; import { AuthContext } from "../../contexts/authContext"; -import { getStoreComponents, getStoreTags } from "../../controllers/API"; +import { getStoreComponents } from "../../controllers/API"; import useAlertStore from "../../stores/alertStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { useStoreStore } from "../../stores/storeStore"; @@ -46,9 +46,6 @@ export default function StorePage(): JSX.Element { const { apiKey } = useContext(AuthContext); const setErrorData = useAlertStore((state) => state.setErrorData); - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); const [loading, setLoading] = useState(true); const { id } = useParams(); @@ -148,11 +145,6 @@ export default function StorePage(): JSX.Element { }); } - // Set a null id - useEffect(() => { - setCurrentFlowId(""); - }, []); - function resetPagination() { setPageIndex(1); setPageSize(12); diff --git a/src/frontend/src/pages/ViewPage/index.tsx b/src/frontend/src/pages/ViewPage/index.tsx index a5487937f55..456e8c35d77 100644 --- a/src/frontend/src/pages/ViewPage/index.tsx +++ b/src/frontend/src/pages/ViewPage/index.tsx @@ -1,17 +1,42 @@ +import { useGetGlobalVariables } from "@/controllers/API/queries/variables"; +import useFlowStore from "@/stores/flowStore"; import { useEffect } from "react"; -import { useParams } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; import useFlowsManagerStore from "../../stores/flowsManagerStore"; import Page from "../FlowPage/components/PageComponent"; export default function ViewPage() { - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); + const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow); + + const setOnFlowPage = useFlowStore((state) => state.setOnFlowPage); const { id } = useParams(); + const navigate = useNavigate(); + useGetGlobalVariables(); + + const flows = useFlowsManagerStore((state) => state.flows); + const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); // Set flow tab id useEffect(() => { - setCurrentFlowId(id!); + if (flows && currentFlowId === "") { + const isAnExistingFlow = flows.find((flow) => flow.id === id); + + if (!isAnExistingFlow) { + navigate("/all"); + return; + } + + setCurrentFlow(isAnExistingFlow); + } + }, [id, flows]); + + useEffect(() => { + setOnFlowPage(true); + + return () => { + setOnFlowPage(false); + setCurrentFlow(); + }; }, [id]); return ( From f91807935a243079dadb9028d9f043b912bdb4cc Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 14:08:50 -0300 Subject: [PATCH 78/84] removed fit view on page --- .../components/PageComponent/index.tsx | 45 ++++--------------- 1 file changed, 9 insertions(+), 36 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 2a0a20a0420..f84dd90af12 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -144,21 +144,6 @@ export default function Page({ view }: { view?: boolean }): JSX.Element { }; }, [lastCopiedSelection, lastSelection, takeSnapshot, selectionMenuVisible]); - useEffect(() => { - if (reactFlowInstance && currentSavedFlow) { - const viewport = currentSavedFlow.data?.viewport ?? { - zoom: 1, - x: 0, - y: 0, - }; - if (viewport.x == 0 && viewport.y == 0) { - reactFlowInstance.fitView(); - } else { - reactFlowInstance.setViewport(viewport); - } - } - }, [currentSavedFlow, reactFlowInstance]); - const { isFetching, refetch } = useGetBuildsQuery({}); const showCanvas = @@ -176,16 +161,6 @@ export default function Page({ view }: { view?: boolean }): JSX.Element { } }, [currentFlowId]); - useEffect(() => { - if (currentSavedFlow && reactFlowInstance) { - autoSaveFlow(); - updateCurrentFlow({ - nodes, - edges, - }); - } - }, [nodes, edges]); - function handleUndo(e: KeyboardEvent) { if (!isWrappedWithClass(e, "noflow")) { e.preventDefault(); @@ -323,17 +298,14 @@ export default function Page({ view }: { view?: boolean }): JSX.Element { const onMoveEnd: OnMove = useCallback(() => { // 👇 make moving the canvas undoable autoSaveFlow(); - updateCurrentFlow({ - viewport: reactFlowInstance?.getViewport(), - }); - }, [ - takeSnapshot, - autoSaveFlow, - updateCurrentFlow, - nodes, - edges, - reactFlowInstance, - ]); + updateCurrentFlow({ viewport: reactFlowInstance?.getViewport() }); + }, [takeSnapshot, autoSaveFlow, nodes, edges, reactFlowInstance]); + + const onNodeDragStop: NodeDragHandler = useCallback(() => { + // 👇 make moving the canvas undoable + autoSaveFlow(); + updateCurrentFlow({ nodes }); + }, [takeSnapshot, autoSaveFlow, nodes, edges, reactFlowInstance]); const onSelectionDragStart: SelectionDragHandler = useCallback(() => { // 👇 make dragging a selection undoable @@ -490,6 +462,7 @@ export default function Page({ view }: { view?: boolean }): JSX.Element { connectionLineComponent={ConnectionLineComponent} onDragOver={onDragOver} onMoveEnd={onMoveEnd} + onNodeDragStop={onNodeDragStop} onDrop={onDrop} onSelectionChange={onSelectionChange} deleteKeyCode={[]} From cf763658f782d5289878499340ab8d54e0ef52b6 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 14:16:56 -0300 Subject: [PATCH 79/84] added auto save flow function setting on the store to allow the flow to be auto saved on set node --- .../src/pages/FlowPage/components/PageComponent/index.tsx | 1 + src/frontend/src/stores/flowStore.ts | 7 +++++++ src/frontend/src/types/zustand/flow/index.ts | 1 + 3 files changed, 9 insertions(+) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index f84dd90af12..22a8f65bf62 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -153,6 +153,7 @@ export default function Page({ view }: { view?: boolean }): JSX.Element { useEffect(() => { refetch(); + useFlowStore.setState({ autoSaveFlow }); if (checkOldComponents({ nodes })) { setNoticeData({ title: diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index ca42275a3ae..3a8289e2e50 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -50,6 +50,7 @@ import { useTypesStore } from "./typesStore"; // this is our useStore hook that we can use in our components to get parts of the store and call actions const useFlowStore = create((set, get) => ({ + autoSaveFlow: undefined, componentsToUpdate: false, updateComponentsToUpdate: (nodes) => { let outdatedNodes = false; @@ -227,6 +228,9 @@ const useFlowStore = create((set, get) => ({ outputs, hasIO: inputs.length > 0 || outputs.length > 0, }); + if (get().autoSaveFlow) { + get().autoSaveFlow!(); + } }, setEdges: (change) => { let newChange = typeof change === "function" ? change(get().edges) : change; @@ -234,6 +238,9 @@ const useFlowStore = create((set, get) => ({ edges: newChange, flowState: undefined, }); + if (get().autoSaveFlow) { + get().autoSaveFlow!(); + } }, setNode: ( id: string, diff --git a/src/frontend/src/types/zustand/flow/index.ts b/src/frontend/src/types/zustand/flow/index.ts index 574e8e54753..c27e056e24b 100644 --- a/src/frontend/src/types/zustand/flow/index.ts +++ b/src/frontend/src/types/zustand/flow/index.ts @@ -54,6 +54,7 @@ export type FlowPoolType = { }; export type FlowStoreType = { + autoSaveFlow: (() => void) | undefined; componentsToUpdate: boolean; updateComponentsToUpdate: (nodes: Node[]) => void; onFlowPage: boolean; From 4d9fa7ebdff6f028e64c485908906da48f7fbbbd Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 14:20:18 -0300 Subject: [PATCH 80/84] Changed header to just show the save button if autosave is disabled --- .../components/headerComponent/components/menuBar/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index c9fff9dc815..776059dcd6b 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -56,7 +56,8 @@ export const MenuBar = ({}: {}): JSX.Element => { const onFlowPage = useFlowStore((state) => state.onFlowPage); const changesNotSaved = - customStringify(currentFlow) !== customStringify(currentSavedFlow); + customStringify(currentFlow) !== customStringify(currentSavedFlow) && + !shouldAutosave; const savedText = updatedAt && changesNotSaved From fd701786a08ac0604a56890c57de0c2c06970ce6 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 16:39:59 -0300 Subject: [PATCH 81/84] Added check to only save empty flow when it was already empty before --- .../queries/flows/use-patch-update-flow.ts | 1 - src/frontend/src/hooks/flows/use-save-flow.ts | 76 ++++++++++++------- .../src/modals/flowSettingsModal/index.tsx | 8 +- 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts b/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts index 1bbe871e2d8..8b81ec3cd31 100644 --- a/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts +++ b/src/frontend/src/controllers/API/queries/flows/use-patch-update-flow.ts @@ -21,7 +21,6 @@ export const usePatchUpdateFlow: useMutationFunctionType< const { mutate } = UseRequestProcessor(); const PatchUpdateFlowFn = async (payload: IPatchUpdateFlow): Promise => { - if (payload.data.nodes.length === 0) return null; const response = await api.patch(`${getURL("FLOWS")}/${payload.id}`, { name: payload.name, data: payload.data, diff --git a/src/frontend/src/hooks/flows/use-save-flow.ts b/src/frontend/src/hooks/flows/use-save-flow.ts index 55383b73400..117273ca44c 100644 --- a/src/frontend/src/hooks/flows/use-save-flow.ts +++ b/src/frontend/src/hooks/flows/use-save-flow.ts @@ -13,6 +13,7 @@ const useSaveFlow = () => { const edges = useFlowStore((state) => state.edges); const setSaveLoading = useFlowsManagerStore((state) => state.setSaveLoading); const setCurrentFlow = useFlowStore((state) => state.setCurrentFlow); + const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow); const currentFlow = useFlowStore((state) => state.currentFlow); const flowData = currentFlow?.data; @@ -39,36 +40,55 @@ const useSaveFlow = () => { } if (flow && flow.data) { const { id, name, data, description, folder_id, endpoint_name } = flow; - mutate( - { id, name, data, description, folder_id, endpoint_name }, - { - onSuccess: (updatedFlow) => { - setSaveLoading(false); - if (updatedFlow !== null && flows) { - // updates flow in state - setFlows( - flows.map((flow) => { - if (flow.id === updatedFlow.id) { - return updatedFlow; - } - return flow; - }), - ); - setCurrentFlow(updatedFlow); - resolve(); - } + if (!currentSavedFlow?.data?.nodes.length || data.nodes.length > 0) { + mutate( + { id, name, data, description, folder_id, endpoint_name }, + { + onSuccess: (updatedFlow) => { + setSaveLoading(false); + if (flows) { + // updates flow in state + setFlows( + flows.map((flow) => { + if (flow.id === updatedFlow.id) { + return updatedFlow; + } + return flow; + }), + ); + setCurrentFlow(updatedFlow); + resolve(); + } else { + setErrorData({ + title: "Failed to save flow", + list: ["Flows variable undefined"], + }); + reject(new Error("Flows variable undefined")); + } + }, + onError: (e) => { + setErrorData({ + title: "Failed to save flow", + list: [e.message], + }); + setSaveLoading(false); + reject(e); + }, }, - onError: (e) => { - setErrorData({ - title: "Failed to save flow", - list: [e.message], - }); - setSaveLoading(false); - reject(e); - }, - }, - ); + ); + } else { + setErrorData({ + title: "Failed to save flow", + list: ["Can't save empty flow"], + }); + setSaveLoading(false); + reject(new Error("Can't save empty flow")); + } } else { + setErrorData({ + title: "Failed to save flow", + list: ["Flow not found"], + }); reject(new Error("Flow not found")); } }); diff --git a/src/frontend/src/modals/flowSettingsModal/index.tsx b/src/frontend/src/modals/flowSettingsModal/index.tsx index a55441598cc..c8e31a8d51f 100644 --- a/src/frontend/src/modals/flowSettingsModal/index.tsx +++ b/src/frontend/src/modals/flowSettingsModal/index.tsx @@ -5,7 +5,6 @@ import { useEffect, useState } from "react"; import EditFlowSettings from "../../components/editFlowSettingsComponent"; import IconComponent from "../../components/genericIconComponent"; import { SETTINGS_DIALOG_SUBTITLE } from "../../constants/constants"; -import useAlertStore from "../../stores/alertStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { FlowSettingsPropsType } from "../../types/components"; import { FlowType } from "../../types/flow"; @@ -47,12 +46,7 @@ export default function FlowSettingsModal({ setOpen(false); setIsSaving(false); }) - .catch((err) => { - useAlertStore.getState().setErrorData({ - title: "Error while saving changes", - list: [err?.response?.data.detail ?? ""], - }); - console.error(err); + .catch(() => { setIsSaving(false); }); } else { From a667f8b73794bdcbc64e34d3056ce333ad258bf0 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 18:14:13 -0300 Subject: [PATCH 82/84] Changed tests and added message to not fail tests about flow settings --- src/frontend/src/modals/flowSettingsModal/index.tsx | 3 +++ src/frontend/tests/end-to-end/flowSettings.spec.ts | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/frontend/src/modals/flowSettingsModal/index.tsx b/src/frontend/src/modals/flowSettingsModal/index.tsx index c8e31a8d51f..e7a9b90782a 100644 --- a/src/frontend/src/modals/flowSettingsModal/index.tsx +++ b/src/frontend/src/modals/flowSettingsModal/index.tsx @@ -1,4 +1,5 @@ import useSaveFlow from "@/hooks/flows/use-save-flow"; +import useAlertStore from "@/stores/alertStore"; import useFlowStore from "@/stores/flowStore"; import { cloneDeep } from "lodash"; import { useEffect, useState } from "react"; @@ -18,6 +19,7 @@ export default function FlowSettingsModal({ const saveFlow = useSaveFlow(); const currentFlow = useFlowStore((state) => state.currentFlow); const setCurrentFlow = useFlowStore((state) => state.setCurrentFlow); + const setSuccessData = useAlertStore((state) => state.setSuccessData); const flows = useFlowsManagerStore((state) => state.flows); useEffect(() => { setName(currentFlow!.name); @@ -45,6 +47,7 @@ export default function FlowSettingsModal({ ?.then(() => { setOpen(false); setIsSaving(false); + setSuccessData({ title: "Changes saved successfully" }); }) .catch(() => { setIsSaving(false); diff --git a/src/frontend/tests/end-to-end/flowSettings.spec.ts b/src/frontend/tests/end-to-end/flowSettings.spec.ts index 062bb5bea62..04dd0694ab4 100644 --- a/src/frontend/tests/end-to-end/flowSettings.spec.ts +++ b/src/frontend/tests/end-to-end/flowSettings.spec.ts @@ -47,10 +47,6 @@ test("flowSettings", async ({ page }) => { await page.getByTestId("save-flow-settings").click(); - await page.getByText("Close").last().click(); - - await page.waitForTimeout(1000); - await page.getByText("Changes saved successfully").isVisible(); await page.getByTestId("flow_name").click(); From b0c226d6db35158d182acc759d6025c11b1628ee Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 18:35:59 -0300 Subject: [PATCH 83/84] Changed on file drop to use saveFlow --- .../hooks/use-on-file-drop.tsx | 5 ++-- src/frontend/src/controllers/API/index.ts | 28 ------------------- 2 files changed, 3 insertions(+), 30 deletions(-) diff --git a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx index 659eadddf42..9e353624c06 100644 --- a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx +++ b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx @@ -1,8 +1,8 @@ +import useSaveFlow from "@/hooks/flows/use-save-flow"; import { UPLOAD_ALERT_LIST, WRONG_FILE_ERROR_ALERT, } from "../../../constants/alerts_constants"; -import { updateFlowInDatabase } from "../../../controllers/API"; import { uploadFlowToFolder } from "../../../pages/MainPage/services"; import useAlertStore from "../../../stores/alertStore"; import useFlowsManagerStore from "../../../stores/flowsManagerStore"; @@ -21,6 +21,7 @@ const useFileDrop = ( const setErrorData = useAlertStore((state) => state.setErrorData); const refreshFolders = useFolderStore((state) => state.refreshFolders); const flows = useFlowsManagerStore((state) => state.flows); + const saveFlow = useSaveFlow(); const triggerFolderChange = (folderId) => { if (folderChangeCallback) { @@ -120,7 +121,7 @@ const useFileDrop = ( setFolderDragging(false); setFolderIdDragging(""); - updateFlowInDatabase(updatedFlow).then(() => { + saveFlow(updatedFlow).then(() => { refreshFolders(); triggerFolderChange(folderId); }); diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index e1918ccec8d..0c46f27396c 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -141,34 +141,6 @@ export async function saveFlowToDatabase(newFlow: { throw error; } } -/** - * Updates an existing flow in the database. - * - * @param {FlowType} updatedFlow - The updated flow data. - * @returns {Promise} The updated flow data. - * @throws Will throw an error if the update fails. - */ -export async function updateFlowInDatabase( - updatedFlow: FlowType, -): Promise { - try { - const response = await api.patch(`${BASE_URL_API}flows/${updatedFlow.id}`, { - name: updatedFlow.name, - data: updatedFlow.data, - description: updatedFlow.description, - folder_id: updatedFlow.folder_id === "" ? null : updatedFlow.folder_id, - endpoint_name: updatedFlow.endpoint_name, - }); - - if (response && response?.status !== 200) { - throw new Error(`HTTP error! status: ${response?.status}`); - } - return response?.data; - } catch (error) { - console.error(error); - throw error; - } -} /** * Reads all flows from the database. From 6dd99e6f1215c5a849a66b34cd999bd76cd2c677 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 12 Aug 2024 18:36:14 -0300 Subject: [PATCH 84/84] Updated tests --- src/frontend/tests/end-to-end/store-shard-2.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/frontend/tests/end-to-end/store-shard-2.spec.ts b/src/frontend/tests/end-to-end/store-shard-2.spec.ts index 9c017b8219a..c5f4881e80b 100644 --- a/src/frontend/tests/end-to-end/store-shard-2.spec.ts +++ b/src/frontend/tests/end-to-end/store-shard-2.spec.ts @@ -1,4 +1,4 @@ -import { expect, test } from "@playwright/test"; +import { test } from "@playwright/test"; import * as dotenv from "dotenv"; import path from "path"; @@ -111,7 +111,6 @@ test("should share component with share button", async ({ page }) => { .inputValue(); await page.getByPlaceholder("Flow name").fill(randomName); await page.getByText("Save").last().click(); - await page.getByText("Close").last().click(); await page.waitForSelector('[data-testid="shared-button-flow"]', { timeout: 100000,