Fix error on React Flow with Auto Login = False (#2164)

This pull request addresses several improvements and fixes to enhance
the overall functionality and user experience. The key changes include:

- Improved Folders Behavior Context

- Enhanced Duplicate Request Blocker

- Bug Fix: Folders Compatibility with AutoLogin = False
This commit is contained in:
Cristhian Zanforlin Lousa 2024-06-14 13:23:39 -03:00 • committed by GitHub
commit f520e0bf77
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 112 additions and 84 deletions

View file

@ -18,13 +18,13 @@ import { autoLogin, getGlobalVariables, getHealth } from "./controllers/API";
import { setupAxiosDefaults } from "./controllers/API/utils"; import { setupAxiosDefaults } from "./controllers/API/utils";
import useTrackLastVisitedPath from "./hooks/use-track-last-visited-path"; import useTrackLastVisitedPath from "./hooks/use-track-last-visited-path";
import Router from "./routes"; import Router from "./routes";
import { Case } from "./shared/components/caseComponent";
import useAlertStore from "./stores/alertStore"; import useAlertStore from "./stores/alertStore";
import { useDarkStore } from "./stores/darkStore"; import { useDarkStore } from "./stores/darkStore";
import useFlowsManagerStore from "./stores/flowsManagerStore"; import useFlowsManagerStore from "./stores/flowsManagerStore";
import { useFolderStore } from "./stores/foldersStore"; import { useFolderStore } from "./stores/foldersStore";
import { useGlobalVariablesStore } from "./stores/globalVariablesStore/globalVariables"; import { useGlobalVariablesStore } from "./stores/globalVariablesStore/globalVariables";
import { useStoreStore } from "./stores/storeStore"; import { useStoreStore } from "./stores/storeStore";
import { useTypesStore } from "./stores/typesStore";
export default function App() { export default function App() {
useTrackLastVisitedPath(); useTrackLastVisitedPath();
@ -43,10 +43,8 @@ export default function App() {
const { isAuthenticated, login, setUserData, setAutoLogin, getUser } = const { isAuthenticated, login, setUserData, setAutoLogin, getUser } =
useContext(AuthContext); useContext(AuthContext);
const refreshFlows = useFlowsManagerStore((state) => state.refreshFlows);
const setLoading = useAlertStore((state) => state.setLoading); const setLoading = useAlertStore((state) => state.setLoading);
const fetchApiData = useStoreStore((state) => state.fetchApiData); const fetchApiData = useStoreStore((state) => state.fetchApiData);
const getTypes = useTypesStore((state) => state.getTypes);
const refreshVersion = useDarkStore((state) => state.refreshVersion); const refreshVersion = useDarkStore((state) => state.refreshVersion);
const refreshStars = useDarkStore((state) => state.refreshStars); const refreshStars = useDarkStore((state) => state.refreshStars);
const setGlobalVariables = useGlobalVariablesStore( const setGlobalVariables = useGlobalVariablesStore(
@ -56,8 +54,7 @@ export default function App() {
const navigate = useNavigate(); const navigate = useNavigate();
const dark = useDarkStore((state) => state.dark); const dark = useDarkStore((state) => state.dark);
const getFoldersApi = useFolderStore((state) => state.getFoldersApi); const isLoadingFolders = useFolderStore((state) => state.isLoadingFolders);
const loadingFolders = useFolderStore((state) => state.loading);
const [isLoadingHealth, setIsLoadingHealth] = useState(false); const [isLoadingHealth, setIsLoadingHealth] = useState(false);
@ -115,13 +112,13 @@ export default function App() {
if (isAuthenticated) { if (isAuthenticated) {
try { try {
await setupAxiosDefaults(); await setupAxiosDefaults();
await getFoldersApi();
await getTypes();
await refreshFlows();
const res = await getGlobalVariables(); const res = await getGlobalVariables();
setGlobalVariables(res); setGlobalVariables(res);
checkHasStore(); checkHasStore();
fetchApiData(); fetchApiData();
resolve(); resolve();
} catch (error) { } catch (error) {
console.error("Failed to fetch data:", error); console.error("Failed to fetch data:", error);
@ -174,6 +171,8 @@ export default function App() {
} }
}; };
const isLoadingApplication = isLoading || isLoadingFolders;
return ( return (
//need parent component with width and height //need parent component with width and height
<div className="flex h-full flex-col"> <div className="flex h-full flex-col">
@ -196,15 +195,15 @@ export default function App() {
></FetchErrorComponent> ></FetchErrorComponent>
} }
{isLoading || loadingFolders ? ( <Case condition={isLoadingApplication}>
<div className="loading-page-panel"> <div className="loading-page-panel">
<LoadingComponent remSize={50} /> <LoadingComponent remSize={50} />
</div> </div>
) : ( </Case>
<>
<Case condition={!isLoadingApplication}>
<Router /> <Router />
</> </Case>
)}
</> </>
</ErrorBoundary> </ErrorBoundary>
<div></div> <div></div>

View file

@ -37,8 +37,8 @@ const SideBarFoldersButtonsComponent = ({
const currentFolder = pathname.split("/"); const currentFolder = pathname.split("/");
const urlWithoutPath = pathname.split("/").length < 4; const urlWithoutPath = pathname.split("/").length < 4;
const myCollectionId = useFolderStore((state) => state.myCollectionId); const myCollectionId = useFolderStore((state) => state.myCollectionId);
const getFoldersApi = useFolderStore((state) => state.getFoldersApi);
const folderIdDragging = useFolderStore((state) => state.folderIdDragging); const folderIdDragging = useFolderStore((state) => state.folderIdDragging);
const refreshFolders = useFolderStore((state) => state.refreshFolders);
const checkPathName = (itemId: string) => { const checkPathName = (itemId: string) => {
if (urlWithoutPath && itemId === myCollectionId) { if (urlWithoutPath && itemId === myCollectionId) {
@ -85,7 +85,7 @@ const SideBarFoldersButtonsComponent = ({
function addNewFolder() { function addNewFolder() {
addFolder({ name: "New Folder", parent_id: null, description: "" }).then( addFolder({ name: "New Folder", parent_id: null, description: "" }).then(
(res) => { (res) => {
getFoldersApi(true); refreshFolders();
} }
); );
} }

View file

@ -16,7 +16,7 @@ const useFileDrop = (folderId, folderChangeCallback) => {
); );
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const getFoldersApi = useFolderStore((state) => state.getFoldersApi); const refreshFolders = useFolderStore((state) => state.refreshFolders);
const flows = useFlowsManagerStore((state) => state.flows); const flows = useFlowsManagerStore((state) => state.flows);
const triggerFolderChange = (folderId) => { const triggerFolderChange = (folderId) => {
@ -118,7 +118,7 @@ const useFileDrop = (folderId, folderChangeCallback) => {
setFolderIdDragging(""); setFolderIdDragging("");
updateFlowInDatabase(updatedFlow).then(() => { updateFlowInDatabase(updatedFlow).then(() => {
getFoldersApi(true); refreshFolders();
triggerFolderChange(folderId); triggerFolderChange(folderId);
}); });
}; };
@ -129,7 +129,7 @@ const useFileDrop = (folderId, folderChangeCallback) => {
setFolderDragging(false); setFolderDragging(false);
setFolderIdDragging(""); setFolderIdDragging("");
uploadFlowsFromFolders(formData).then(() => { uploadFlowsFromFolders(formData).then(() => {
getFoldersApi(true); refreshFolders();
triggerFolderChange(folderId); triggerFolderChange(folderId);
}); });
}; };

View file

@ -28,7 +28,7 @@ export default function SidebarNav({
}: SidebarNavProps) { }: SidebarNavProps) {
const location = useLocation(); const location = useLocation();
const pathname = location.pathname; const pathname = location.pathname;
const loadingFolders = useFolderStore((state) => state.loading); const loadingFolders = useFolderStore((state) => state.isLoadingFolders);
const folders = useFolderStore((state) => state.folders); const folders = useFolderStore((state) => state.folders);
const pathValues = ["folder", "components", "flows", "all"]; const pathValues = ["folder", "components", "flows", "all"];

View file

@ -105,7 +105,7 @@ const TableComponent = forwardRef<
} }
}, 50); }, 50);
setTimeout(() => { setTimeout(() => {
realRef.current.api.hideOverlay(); realRef?.current?.api?.hideOverlay();
}, 1000); }, 1000);
if (props.onGridReady) props.onGridReady(params); if (props.onGridReady) props.onGridReady(params);
}; };

View file

@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom";
import Cookies from "universal-cookie"; import Cookies from "universal-cookie";
import { getLoggedUser, requestLogout } from "../controllers/API"; import { getLoggedUser, requestLogout } from "../controllers/API";
import useAlertStore from "../stores/alertStore"; import useAlertStore from "../stores/alertStore";
import { useFolderStore } from "../stores/foldersStore";
import { Users } from "../types/api"; import { Users } from "../types/api";
import { AuthContextType } from "../types/contexts/auth"; import { AuthContextType } from "../types/contexts/auth";
@ -42,7 +43,8 @@ export function AuthProvider({ children }): React.ReactElement {
const [apiKey, setApiKey] = useState<string | null>( const [apiKey, setApiKey] = useState<string | null>(
cookies.get("apikey_tkn_lflw") cookies.get("apikey_tkn_lflw")
); );
// const getFoldersApi = useFolderStore((state) => state.getFoldersApi);
const getFoldersApi = useFolderStore((state) => state.getFoldersApi);
useEffect(() => { useEffect(() => {
const storedAccessToken = cookies.get("access_token_lf"); const storedAccessToken = cookies.get("access_token_lf");
@ -64,7 +66,8 @@ export function AuthProvider({ children }): React.ReactElement {
setUserData(user); setUserData(user);
const isSuperUser = user!.is_superuser; const isSuperUser = user!.is_superuser;
setIsAdmin(isSuperUser); setIsAdmin(isSuperUser);
// await getFoldersApi(true);
getFoldersApi(true, true);
}) })
.catch((error) => { .catch((error) => {
setLoading(false); setLoading(false);

View file

@ -87,6 +87,7 @@ function ApiInterceptor() {
if (!checkRequest) { if (!checkRequest) {
controller.abort("Duplicate Request"); controller.abort("Duplicate Request");
console.error("Duplicate Request");
} }
const accessToken = cookies.get("access_token_lf"); const accessToken = cookies.get("access_token_lf");

View file

@ -4,9 +4,10 @@ export function checkDuplicateRequestAndStoreRequest(config) {
const lastUrl = localStorage.getItem("lastUrlCalled"); const lastUrl = localStorage.getItem("lastUrlCalled");
const lastMethodCalled = localStorage.getItem("lastMethodCalled"); const lastMethodCalled = localStorage.getItem("lastMethodCalled");
const lastRequestTime = localStorage.getItem("lastRequestTime"); const lastRequestTime = localStorage.getItem("lastRequestTime");
const lastCurrentUrl = localStorage.getItem("lastCurrentUrl");
const currentUrl = window.location.pathname;
const currentTime = Date.now(); const currentTime = Date.now();
const isContained = AUTHORIZED_DUPLICATE_REQUESTS.some((request) => const isContained = AUTHORIZED_DUPLICATE_REQUESTS.some((request) =>
config?.url!.includes(request) config?.url!.includes(request)
); );
@ -17,7 +18,8 @@ export function checkDuplicateRequestAndStoreRequest(config) {
lastMethodCalled === config.method && lastMethodCalled === config.method &&
lastMethodCalled === "get" && // Assuming you want to check only for GET requests lastMethodCalled === "get" && // Assuming you want to check only for GET requests
lastRequestTime && lastRequestTime &&
currentTime - parseInt(lastRequestTime, 10) < 800 currentTime - parseInt(lastRequestTime, 10) < 300 &&
lastCurrentUrl === currentUrl
) { ) {
return false; return false;
} }
@ -25,6 +27,7 @@ export function checkDuplicateRequestAndStoreRequest(config) {
localStorage.setItem("lastUrlCalled", config.url ?? ""); localStorage.setItem("lastUrlCalled", config.url ?? "");
localStorage.setItem("lastMethodCalled", config.method ?? ""); localStorage.setItem("lastMethodCalled", config.method ?? "");
localStorage.setItem("lastRequestTime", currentTime.toString()); localStorage.setItem("lastRequestTime", currentTime.toString());
localStorage.setItem("lastCurrentUrl", currentUrl);
return true; return true;
} }

View file

@ -1091,8 +1091,6 @@ export async function getMessagesTable(
const rowsOrganized = rows.data; const rowsOrganized = rows.data;
console.log(rowsOrganized);
const columns = extractColumnsFromRows(rowsOrganized, mode, excludedFields); const columns = extractColumnsFromRows(rowsOrganized, mode, excludedFields);
const sessions = new Set<string>(); const sessions = new Set<string>();
rowsOrganized.forEach((row) => { rowsOrganized.forEach((row) => {

View file

@ -19,6 +19,7 @@ export default function LoginAdminPage() {
const [inputState, setInputState] = const [inputState, setInputState] =
useState<loginInputStateType>(CONTROL_LOGIN_STATE); useState<loginInputStateType>(CONTROL_LOGIN_STATE);
const { login, isAuthenticated, setUserData } = useContext(AuthContext); const { login, isAuthenticated, setUserData } = useContext(AuthContext);
const setLoading = useAlertStore((state) => state.setLoading);
const { password, username } = inputState; const { password, username } = inputState;
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
@ -35,6 +36,10 @@ export default function LoginAdminPage() {
}; };
onLogin(user) onLogin(user)
.then((user) => { .then((user) => {
console.log("admin page");
setLoading(true);
login(user.access_token); login(user.access_token);
navigate("/admin/"); navigate("/admin/");
}) })

View file

@ -9,6 +9,7 @@ import { CONTROL_LOGIN_STATE } from "../../constants/constants";
import { AuthContext } from "../../contexts/authContext"; import { AuthContext } from "../../contexts/authContext";
import { onLogin } from "../../controllers/API"; import { onLogin } from "../../controllers/API";
import useAlertStore from "../../stores/alertStore"; import useAlertStore from "../../stores/alertStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { LoginType } from "../../types/api"; import { LoginType } from "../../types/api";
import { import {
inputHandlerEventType, inputHandlerEventType,
@ -23,6 +24,7 @@ export default function LoginPage(): JSX.Element {
const { login } = useContext(AuthContext); const { login } = useContext(AuthContext);
const navigate = useNavigate(); const navigate = useNavigate();
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const setLoading = useFlowsManagerStore((state) => state.setIsLoading);
function handleInput({ function handleInput({
target: { name, value }, target: { name, value },
@ -37,6 +39,9 @@ export default function LoginPage(): JSX.Element {
}; };
onLogin(user) onLogin(user)
.then((user) => { .then((user) => {
console.log("login page");
setLoading(true);
login(user.access_token); login(user.access_token);
navigate("/"); navigate("/");
}) })

View file

@ -1,39 +1,19 @@
import { useState } from "react"; import { useState } from "react";
import { useLocation } from "react-router-dom";
import useAlertStore from "../../../../../../stores/alertStore";
import useFlowsManagerStore from "../../../../../../stores/flowsManagerStore"; import useFlowsManagerStore from "../../../../../../stores/flowsManagerStore";
import { useFolderStore } from "../../../../../../stores/foldersStore";
import { handleDownloadFolderFn } from "../../../../utils/handle-download-folder";
import InputSearchComponent from "../inputSearchComponent"; import InputSearchComponent from "../inputSearchComponent";
import TabsSearchComponent from "../tabsComponent"; import TabsSearchComponent from "../tabsComponent";
type HeaderTabsSearchComponentProps = {}; type HeaderTabsSearchComponentProps = {};
const HeaderTabsSearchComponent = ({}: HeaderTabsSearchComponentProps) => { const HeaderTabsSearchComponent = ({}: HeaderTabsSearchComponentProps) => {
const location = useLocation();
const myCollectionId = useFolderStore((state) => state.myCollectionId);
const folderId = location?.state?.folderId || myCollectionId;
const isLoading = useFlowsManagerStore((state) => state.isLoading); const isLoading = useFlowsManagerStore((state) => state.isLoading);
const [tabActive, setTabActive] = useState("Flows"); const [tabActive, setTabActive] = useState("Flows");
const setErrorData = useAlertStore((state) => state.setErrorData);
const allFlows = useFlowsManagerStore((state) => state.allFlows);
const [inputValue, setInputValue] = useState(""); const [inputValue, setInputValue] = useState("");
const setSearchFlowsComponents = useFlowsManagerStore( const setSearchFlowsComponents = useFlowsManagerStore(
(state) => state.setSearchFlowsComponents (state) => state.setSearchFlowsComponents
); );
const handleDownloadFolder = () => {
if (allFlows.length === 0) {
setErrorData({
title: "Folder is empty",
list: [],
});
return;
}
handleDownloadFolderFn(folderId);
};
return ( return (
<> <>
<div className="relative flex items-end gap-4"> <div className="relative flex items-end gap-4">

View file

@ -2,11 +2,12 @@ import useAlertStore from "../../../stores/alertStore";
import { useFolderStore } from "../../../stores/foldersStore"; import { useFolderStore } from "../../../stores/foldersStore";
import { deleteFolder, getFolderById } from "../services"; import { deleteFolder, getFolderById } from "../services";
const useDeleteFolder = ({ navigate, getFoldersApi }) => { const useDeleteFolder = ({ navigate }) => {
const setSuccessData = useAlertStore((state) => state.setSuccessData); const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const folderToEdit = useFolderStore((state) => state.folderToEdit); const folderToEdit = useFolderStore((state) => state.folderToEdit);
const myCollectionId = useFolderStore((state) => state.myCollectionId); const myCollectionId = useFolderStore((state) => state.myCollectionId);
const getFoldersApi = useFolderStore((state) => state.getFoldersApi);
const handleDeleteFolder = () => { const handleDeleteFolder = () => {
deleteFolder(folderToEdit?.id!) deleteFolder(folderToEdit?.id!)

View file

@ -25,16 +25,9 @@ export default function HomePage(): JSX.Element {
const [openFolderModal, setOpenFolderModal] = useState(false); const [openFolderModal, setOpenFolderModal] = useState(false);
const [openDeleteFolderModal, setOpenDeleteFolderModal] = useState(false); const [openDeleteFolderModal, setOpenDeleteFolderModal] = useState(false);
const is_component = pathname === "/components"; const is_component = pathname === "/components";
const getFoldersApi = useFolderStore((state) => state.getFoldersApi);
const setFolderToEdit = useFolderStore((state) => state.setFolderToEdit); const setFolderToEdit = useFolderStore((state) => state.setFolderToEdit);
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => {
setTimeout(() => {
getFoldersApi();
}, 300);
}, []);
useEffect(() => { useEffect(() => {
setCurrentFlowId(""); setCurrentFlowId("");
}, [pathname]); }, [pathname]);
@ -45,7 +38,7 @@ export default function HomePage(): JSX.Element {
is_component, is_component,
}); });
const { handleDeleteFolder } = useDeleteFolder({ navigate, getFoldersApi }); const { handleDeleteFolder } = useDeleteFolder({ navigate });
return ( return (
<> <>

View file

@ -7,64 +7,100 @@ import {
} from "../pages/MainPage/services"; } from "../pages/MainPage/services";
import { FoldersStoreType } from "../types/zustand/folders"; import { FoldersStoreType } from "../types/zustand/folders";
import useFlowsManagerStore from "./flowsManagerStore"; import useFlowsManagerStore from "./flowsManagerStore";
import { useTypesStore } from "./typesStore";
export const useFolderStore = create<FoldersStoreType>((set, get) => ({ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
folders: [], folders: [],
getFoldersApi: (refetch = false) => { getFoldersApi: (refetch = false, startupApplication: boolean = false) => {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
if (get()?.folders.length === 0 || refetch === true) { if (get()?.folders.length === 0 || refetch === true) {
get().setLoading(true); get().setIsLoadingFolders(true);
getFolders().then( getFolders().then(
(res) => { async (res) => {
const foldersWithoutStarterProjects = res?.filter( const foldersWithoutStarterProjects = res?.filter(
(folder) => folder.name !== STARTER_FOLDER_NAME, (folder) => folder.name !== STARTER_FOLDER_NAME
); );
const starterProjects = res?.find( const starterProjects = res?.find(
(folder) => folder.name === STARTER_FOLDER_NAME, (folder) => folder.name === STARTER_FOLDER_NAME
); );
set({ starterProjectId: starterProjects!.id ?? "" }); set({ starterProjectId: starterProjects!.id ?? "" });
set({ folders: foldersWithoutStarterProjects }); set({ folders: foldersWithoutStarterProjects });
const myCollectionId = res?.find( const myCollectionId = res?.find(
(f) => f.name === DEFAULT_FOLDER, (f) => f.name === DEFAULT_FOLDER
)?.id; )?.id;
set({ myCollectionId }); set({ myCollectionId });
if (refetch === true) { const { refreshFlows } = useFlowsManagerStore.getState();
useFlowsManagerStore.getState().refreshFlows(); const { getTypes } = useTypesStore.getState();
useFlowsManagerStore.getState().setAllFlows; const { setIsLoadingFolders } = get();
}
if (refetch) {
if (startupApplication) {
await refreshFlows();
await getTypes();
} else {
refreshFlows();
getTypes();
}
}
setIsLoadingFolders(false);
get().setLoading(false);
resolve(); resolve();
}, },
(error) => { (error) => {
set({ folders: [] }); set({ folders: [] });
get().setLoading(false); get().setIsLoadingFolders(false);
reject(error); reject(error);
}, }
); );
} }
}); });
}, },
refreshFolders: () => {
return new Promise<void>((resolve, reject) => {
getFolders().then(
async (res) => {
const foldersWithoutStarterProjects = res?.filter(
(folder) => folder.name !== STARTER_FOLDER_NAME
);
const starterProjects = res?.find(
(folder) => folder.name === STARTER_FOLDER_NAME
);
set({ starterProjectId: starterProjects!.id ?? "" });
set({ folders: foldersWithoutStarterProjects });
const myCollectionId = res?.find(
(f) => f.name === DEFAULT_FOLDER
)?.id;
set({ myCollectionId });
resolve();
},
(error) => {
set({ folders: [] });
get().setIsLoadingFolders(false);
reject(error);
}
);
});
},
setFolders: (folders) => set(() => ({ folders: folders })), setFolders: (folders) => set(() => ({ folders: folders })),
loading: false, isLoadingFolders: false,
setLoading: (loading) => set(() => ({ loading: loading })), setIsLoadingFolders: (isLoadingFolders) => set(() => ({ isLoadingFolders })),
getFolderById: (id) => { getFolderById: (id) => {
if (id) { if (id) {
getFolderById(id).then( getFolderById(id).then((res) => {
(res) => {
const setAllFlows = useFlowsManagerStore.getState().setAllFlows; const setAllFlows = useFlowsManagerStore.getState().setAllFlows;
setAllFlows(res.flows); setAllFlows(res.flows);
set({ selectedFolder: res }); set({ selectedFolder: res });
}, });
() => {
get().getFoldersApi(true);
},
);
} }
}, },
selectedFolder: null, selectedFolder: null,

View file

@ -2,10 +2,13 @@ import { FolderType } from "../../../pages/MainPage/entities";
export type FoldersStoreType = { export type FoldersStoreType = {
folders: FolderType[]; folders: FolderType[];
getFoldersApi: (refetch?: boolean) => Promise<void>; getFoldersApi: (
refetch?: boolean,
startupApplication?: boolean
) => Promise<void>;
setFolders: (folders: FolderType[]) => void; setFolders: (folders: FolderType[]) => void;
loading: boolean; isLoadingFolders: boolean;
setLoading: (loading: boolean) => void; setIsLoadingFolders: (isLoadingFolders: boolean) => void;
selectedFolder: FolderType | null; selectedFolder: FolderType | null;
getFolderById: (id: string) => void; getFolderById: (id: string) => void;
getMyCollectionFolder: () => void; getMyCollectionFolder: () => void;
@ -23,4 +26,5 @@ export type FoldersStoreType = {
setFolderIdDragging: (id: string) => void; setFolderIdDragging: (id: string) => void;
starterProjectId: string; starterProjectId: string;
setStarterProjectId: (id: string) => void; setStarterProjectId: (id: string) => void;
refreshFolders: () => void;
}; };