From 7264028e414da4f0284e79e322cca38e384cd3a5 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com> Date: Mon, 12 Aug 2024 19:21:52 -0300 Subject: [PATCH] refactor: optimize flow saving functionality and implement manual saving (#3283) * fixed patch update flow * fixed update flow patch to receive id by payload * created save flow hook with auto save and manual save functions * fix poetry lock * added auto save check with environment variable * removed unused user * separated autosave and put the flow as a creation with nodes and edges * removed set nodes that skipped saving * implemented auto save hook * removed autosave from setNodes and setEdges * added auto save hook and saved on viewport move and added useEffect to save on nodes and edges changed * changed type of setNodes * removed unused var * removed deletion of empty flow * Added saving of flow on button when autoSave is disabled * disable saving when the nodes are empty * removed save loading as false when the access token is renewed * implemented useDebounce * added save loading to save flow hook * removed setting nodes and edges on fetching, since they are set when the current flow is updated * removed unused var * use debounce hook to save flow * set nodes and edges on current flow id change * removed useplaygroundeffect * removed unused import * put set save loading before the If * removed flow cleaning and inputs setting, since the inputs and outputs are set on the ResetFlow function * updated to use ResetFlow function to update everything regarding flow * removed flow pool get on resetFlow, for it to be fetched only if the user is inside the flow * updated packagelock * Changed router to outlet on app.tsx to use createRouter * Created authSettingsGuard to guard the general settings * Fixed routes to use createBrowserRouter to allow the use of useBlocker * Changed index.tsx to use RouterProvider and the router just created * Changed flowStore to have a local flow state * Implemented setting the current flow state when saving the flow * Added the update of current flow when auto saving * changed current flow to use the current flow from Flow Store instead of Flows Manager Store * Changed codeTabsComponent Tweaks check to show if its checked * Removed unused variables * Removed browser router from context wrapper * Removed unused console.log * Changed initialSetup to just run when opening the modal * changed confirmationModal to have destructiveCancel and to only call onCancel if the other buttons were not pressed * Created a SaveChangesModal that confirms if the user wants to save their changes * Get folder by id when folder id changes too * Changed reset flow calls to store whole flow * Added check if user is exiting page to prevent him when there are unsaved changes * Added new types on ConfirmationModalType * Implement save on clicking the save button on the header * added save component shortcut to use save shortcut as save flow * added save component shortcut on shortcutsStore type * changed save shortcut to save component on node toolbar * added save shortcut to header menubar * changed shortcuts name to be compatible with existing ones * changed shortcuts to be backwards compatible * changed save to changes to maintain retrocompatibility * changed save_component to save to maintain retrocompatibility * Changed time difference to unsaved changes * changed the toolbar select item to get the right save shortcut * Changed save flow to use current flow from useFlowStore instead of the previous saved flow * changed changesNotSaved to include flow name and metadata * Added way of saving the flow settings just locally instead of directly to database * Changed shareModal to save flow with hook * removed old auto saving on connect * Removed save functions from flowsManagerStore * refactor: Remove unused imports and state variables in EditFlowSettings component * use current flow not saved one and refactored page to not receive flow * added check of isFlowPage to display the menubar * Added checks to render playground if API key is valid and if Flows exists * Added check to not display X on chat on playground page * Updated flows variable to be undefined by start to prevent things from loading before flows initialize * Implemented log builds parameter to not allow the builds to be logged if user not on flowPage --- src/frontend/package-lock.json | 1 - src/frontend/src/App.tsx | 5 +- .../components/OutputComponent/index.tsx | 15 - .../src/CustomNodes/GenericNode/index.tsx | 1 - .../components/authSettingsGuard/index.tsx | 19 ++ .../hooks/use-playground-effect.tsx | 27 -- .../src/components/cardComponent/index.tsx | 30 +- .../src/components/chatComponent/index.tsx | 7 +- .../components/codeTabsComponent/index.tsx | 1 + .../editFlowSettingsComponent/index.tsx | 2 - .../components/menuBar/index.tsx | 82 ++++- .../src/components/headerComponent/index.tsx | 17 +- .../hooks/use-on-file-drop.tsx | 9 +- src/frontend/src/constants/constants.ts | 6 +- src/frontend/src/contexts/authContext.tsx | 9 - src/frontend/src/contexts/index.tsx | 23 +- src/frontend/src/controllers/API/api.tsx | 4 - src/frontend/src/controllers/API/index.ts | 28 -- .../API/queries/_builds/use-get-builds.ts | 3 +- .../queries/flows/use-patch-update-flow.ts | 25 +- src/frontend/src/hooks/flows/use-add-flow.ts | 9 +- .../src/hooks/flows/use-autosave-flow.ts | 19 ++ .../src/hooks/flows/use-delete-flow.ts | 2 +- src/frontend/src/hooks/flows/use-save-flow.ts | 100 ++++++ src/frontend/src/hooks/use-debounce.ts | 13 + src/frontend/src/index.tsx | 15 +- .../IOModal/components/chatView/index.tsx | 1 - src/frontend/src/modals/IOModal/index.tsx | 12 +- src/frontend/src/modals/apiModal/index.tsx | 3 - .../src/modals/confirmationModal/index.tsx | 14 +- src/frontend/src/modals/exportModal/index.tsx | 4 +- .../src/modals/flowSettingsModal/index.tsx | 59 ++-- .../src/modals/saveChangesModal/index.tsx | 22 ++ src/frontend/src/modals/shareModal/index.tsx | 7 +- src/frontend/src/pages/AdminPage/index.tsx | 9 - .../components/PageComponent/index.tsx | 80 ++--- .../extraSidebarComponent/index.tsx | 69 +--- .../sideBarDraggableComponent/index.tsx | 2 +- .../components/nodeToolbarComponent/index.tsx | 15 +- src/frontend/src/pages/FlowPage/index.tsx | 64 +++- .../components/componentsComponent/index.tsx | 2 +- .../pages/MainPage/pages/mainPage/index.tsx | 11 +- src/frontend/src/pages/Playground/index.tsx | 48 +-- .../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 | 38 ++- src/frontend/src/routes.tsx | 297 ++++++++---------- src/frontend/src/stores/darkStore.ts | 2 +- src/frontend/src/stores/flowStore.ts | 84 ++--- src/frontend/src/stores/flowsManagerStore.ts | 82 +---- src/frontend/src/stores/shortcuts.ts | 3 +- src/frontend/src/types/components/index.ts | 3 +- src/frontend/src/types/store/index.ts | 1 + src/frontend/src/types/zustand/flow/index.ts | 29 +- .../src/types/zustand/flowsManager/index.ts | 21 +- src/frontend/src/utils/buildUtils.ts | 5 + .../tests/end-to-end/flowSettings.spec.ts | 4 - .../tests/end-to-end/store-shard-2.spec.ts | 3 +- src/frontend/vite.config.mts | 3 + 62 files changed, 731 insertions(+), 787 deletions(-) create mode 100644 src/frontend/src/components/authSettingsGuard/index.tsx delete mode 100644 src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx create mode 100644 src/frontend/src/hooks/flows/use-autosave-flow.ts create mode 100644 src/frontend/src/hooks/flows/use-save-flow.ts create mode 100644 src/frontend/src/hooks/use-debounce.ts create mode 100644 src/frontend/src/modals/saveChangesModal/index.tsx diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index f150e6b429da..db0e15228cd9 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -1079,7 +1079,6 @@ }, "node_modules/@clack/prompts/node_modules/is-unicode-supported": { "version": "1.3.0", - "extraneous": true, "inBundle": true, "license": "MIT", "engines": { diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index ddccd55cceed..9423ce55f237 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -1,6 +1,7 @@ import { useContext, useEffect } from "react"; import { Cookies } from "react-cookie"; import { ErrorBoundary } from "react-error-boundary"; +import { Outlet } from "react-router-dom"; import "reactflow/dist/style.css"; import "./App.css"; import AlertDisplayArea from "./alerts/displayArea"; @@ -22,7 +23,6 @@ import { useGetHealthQuery } from "./controllers/API/queries/health"; import { useGetVersionQuery } from "./controllers/API/queries/version"; import { setupAxiosDefaults } from "./controllers/API/utils"; import useTrackLastVisitedPath from "./hooks/use-track-last-visited-path"; -import Router from "./routes"; import useAlertStore from "./stores/alertStore"; import useAuthStore from "./stores/authStore"; import { useDarkStore } from "./stores/darkStore"; @@ -172,8 +172,7 @@ export default function App() { > - - +
diff --git a/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx index 6c18e6b0bfad..d3992035f75c 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/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index e0a582d445c4..09dd6f6a4e23 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -289,7 +289,6 @@ export default function GenericNode({ function handlePlayWShortcut() { if (buildStatus === BuildStatus.BUILDING || isBuilding || !selected) return; setValidationStatus(null); - console.log(data.node?.display_name); buildFlow({ stopNodeId: data.id }); } diff --git a/src/frontend/src/components/authSettingsGuard/index.tsx b/src/frontend/src/components/authSettingsGuard/index.tsx new file mode 100644 index 000000000000..90bf63dd93c0 --- /dev/null +++ b/src/frontend/src/components/authSettingsGuard/index.tsx @@ -0,0 +1,19 @@ +import FeatureFlags from "@/../feature-config.json"; +import useAuthStore from "@/stores/authStore"; +import { useStoreStore } from "@/stores/storeStore"; +import { Navigate } from "react-router-dom"; + +export const AuthSettingsGuard = ({ children }) => { + const autoLogin = useAuthStore((state) => state.autoLogin); + const hasStore = useStoreStore((state) => state.hasStore); + + // Hides the General settings if there is nothing to show + const showGeneralSettings = + FeatureFlags.ENABLE_PROFILE_ICONS || hasStore || !autoLogin; + + if (showGeneralSettings) { + return children; + } else { + return ; + } +}; diff --git a/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx b/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx deleted file mode 100644 index e9236e98be14..000000000000 --- a/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useEffect } from "react"; -import { FlowType } from "../../../types/flow"; - -const usePlaygroundEffect = ( - currentFlowId: string, - playground: boolean, - openPlayground: boolean, - currentFlow: FlowType | undefined, - setNodes: (value: any, value2: boolean) => void, - setEdges: (value: any, value2: boolean) => void, - cleanFlowPool: () => void, -) => { - useEffect(() => { - if (currentFlowId && playground) { - if (openPlayground) { - setNodes(currentFlow?.data?.nodes ?? [], true); - setEdges(currentFlow?.data?.edges ?? [], true); - } else { - setNodes([], true); - setEdges([], true); - } - cleanFlowPool(); - } - }, [openPlayground]); -}; - -export default usePlaygroundEffect; diff --git a/src/frontend/src/components/cardComponent/index.tsx b/src/frontend/src/components/cardComponent/index.tsx index 0e6af1f35f27..c36aef2913d8 100644 --- a/src/frontend/src/components/cardComponent/index.tsx +++ b/src/frontend/src/components/cardComponent/index.tsx @@ -1,12 +1,10 @@ import { usePostLikeComponent } from "@/controllers/API/queries/store"; -import { useEffect, useState } from "react"; -import { createRoot } from "react-dom/client"; +import { useState } from "react"; import { Control } from "react-hook-form"; -import { getComponent, postLikeComponent } from "../../controllers/API"; +import { getComponent } from "../../controllers/API"; import IOModal from "../../modals/IOModal"; import DeleteConfirmationModal from "../../modals/deleteConfirmationModal"; import useAlertStore from "../../stores/alertStore"; -import useFlowStore from "../../stores/flowStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { useStoreStore } from "../../stores/storeStore"; import { FlowType } from "../../types/flow"; @@ -31,7 +29,6 @@ import Loading from "../ui/loading"; import useDataEffect from "./hooks/use-data-effect"; import useInstallComponent from "./hooks/use-handle-install"; import useDragStart from "./hooks/use-on-drag-start"; -import usePlaygroundEffect from "./hooks/use-playground-effect"; import { convertTestName } from "./utils/convert-test-name"; export default function CollectionCardComponent({ @@ -56,7 +53,6 @@ export default function CollectionCardComponent({ const setSuccessData = useAlertStore((state) => state.setSuccessData); const setErrorData = useAlertStore((state) => state.setErrorData); const setValidApiKey = useStoreStore((state) => state.updateValidApiKey); - const cleanFlowPool = useFlowStore((state) => state.CleanFlowPool); const isStore = false; const [loading, setLoading] = useState(false); const [likedByUser, setLikedByUser] = useState(data?.liked_by_user ?? false); @@ -64,16 +60,9 @@ export default function CollectionCardComponent({ const [downloadsCount, setDownloadsCount] = useState( data?.downloads_count ?? 0, ); - const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow); const getFlowById = useFlowsManagerStore((state) => state.getFlowById); - const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); - const setNodes = useFlowStore((state) => state.setNodes); - const setEdges = useFlowStore((state) => state.setEdges); const [openPlayground, setOpenPlayground] = useState(false); - const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, - ); const [loadingPlayground, setLoadingPlayground] = useState(false); const selectedFlowsComponentsCards = useFlowsManagerStore( @@ -96,16 +85,6 @@ export default function CollectionCardComponent({ return inputs.length > 0 || outputs.length > 0; } - usePlaygroundEffect( - currentFlowId, - playground!, - openPlayground, - currentFlow, - setNodes, - setEdges, - cleanFlowPool, - ); - useDataEffect(data, setLikedByUser, setLikesCount, setDownloadsCount); const { handleInstall } = useInstallComponent( @@ -317,7 +296,7 @@ export default function CollectionCardComponent({ setLoadingPlayground(false); return; } - setCurrentFlowId(data.id); + setCurrentFlow(flow); setOpenPlayground(true); setLoadingPlayground(false); } else { @@ -473,7 +452,7 @@ export default function CollectionCardComponent({ setLoadingPlayground(false); return; } - setCurrentFlowId(data.id); + setCurrentFlow(flow); setOpenPlayground(true); setLoadingPlayground(false); } else { @@ -510,6 +489,7 @@ export default function CollectionCardComponent({ {openPlayground && ( state.hasStore); const validApiKey = useStoreStore((state) => state.validApiKey); const hasApiKey = useStoreStore((state) => state.hasApiKey); - const currentFlow = useFlowsManagerStore((state) => state.currentFlow); - - const prevNodesRef = useRef(); + const currentFlow = useFlowStore((state) => state.currentFlow); const ModalMemo = useMemo( () => ( diff --git a/src/frontend/src/components/codeTabsComponent/index.tsx b/src/frontend/src/components/codeTabsComponent/index.tsx index 239a3117e0c4..f17afa61571b 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} />