refactor: routes and back button (#3600)
* Changed ProtectedRoute to handle refresh token * Created DashboardWrapperPage to insert header into elements * Changed routes to be contained by only one ProtectedRoute * Removed refresh and get version query of App.tsx * Added loading if user not authenticated in ProtectedAdminRoute * Changed page layout to not contain header * Changed AdminPage and FlowPage to not have headers * Removed unused variables * Refactored redirectToLastLocation of headerComponent * Removed unused track last visited path * changed viewPage to not set onFlowPage since it's used only on header * Added flow fetching into Playground page * Fixed back button not working between flows * Changed duplicate requests to show which request failed * Refactored useGetBuilds to remove duplicated request * Re-added get version query and config query * [autofix.ci] apply automated fixes * Fix tests that rely on autosave delay --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
ffff5720d8
commit
d6537b724e
19 changed files with 221 additions and 282 deletions
|
|
@ -3,10 +3,6 @@ import { Cookies } from "react-cookie";
|
|||
import { RouterProvider } from "react-router-dom";
|
||||
import "reactflow/dist/style.css";
|
||||
import LoadingComponent from "./components/loadingComponent";
|
||||
import {
|
||||
LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS_ENV,
|
||||
} from "./constants/constants";
|
||||
import { AuthContext } from "./contexts/authContext";
|
||||
import {
|
||||
useAutoLogin,
|
||||
|
|
@ -34,8 +30,6 @@ export default function App() {
|
|||
|
||||
const { mutate: mutateAutoLogin } = useAutoLogin();
|
||||
|
||||
useGetVersionQuery();
|
||||
|
||||
const { mutate: mutateRefresh } = useRefreshAccessToken();
|
||||
|
||||
const isLoginPage = location.pathname.includes("login");
|
||||
|
|
@ -79,23 +73,7 @@ export default function App() {
|
|||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const envRefreshTime = LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS_ENV;
|
||||
const automaticRefreshTime = LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS;
|
||||
|
||||
const accessTokenTimer = isNaN(envRefreshTime)
|
||||
? automaticRefreshTime
|
||||
: envRefreshTime;
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
if (isAuthenticated && !isLoginPage) {
|
||||
mutateRefresh({ refresh_token: refreshToken });
|
||||
}
|
||||
}, accessTokenTimer * 1000);
|
||||
|
||||
return () => clearInterval(intervalId);
|
||||
}, [isLoginPage]);
|
||||
|
||||
useGetVersionQuery();
|
||||
useSaveConfig();
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -2,17 +2,20 @@ import useAuthStore from "@/stores/authStore";
|
|||
import { useContext } from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { AuthContext } from "../../contexts/authContext";
|
||||
import LoadingComponent from "../loadingComponent";
|
||||
|
||||
export const ProtectedAdminRoute = ({ children }) => {
|
||||
const { userData } = useContext(AuthContext);
|
||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
||||
const autoLogin = useAuthStore((state) => state.autoLogin);
|
||||
const isAdmin = useAuthStore((state) => state.isAdmin);
|
||||
const isLoginPage = location.pathname.includes("login");
|
||||
const logout = useAuthStore((state) => state.logout);
|
||||
|
||||
if (!isAuthenticated && !isLoginPage) {
|
||||
logout();
|
||||
if (!isAuthenticated) {
|
||||
return (
|
||||
<div className="flex h-screen w-screen items-center justify-center">
|
||||
<LoadingComponent remSize={30} />
|
||||
</div>
|
||||
);
|
||||
} else if ((userData && !isAdmin) || autoLogin) {
|
||||
return <Navigate to="/" replace />;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,40 @@
|
|||
import { LANGFLOW_AUTO_LOGIN_OPTION } from "@/constants/constants";
|
||||
import {
|
||||
LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS_ENV,
|
||||
LANGFLOW_AUTO_LOGIN_OPTION,
|
||||
} from "@/constants/constants";
|
||||
import { useRefreshAccessToken } from "@/controllers/API/queries/auth";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import { useEffect } from "react";
|
||||
import { Cookies } from "react-cookie";
|
||||
|
||||
export const ProtectedRoute = ({ children }) => {
|
||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
||||
const hasToken = !!localStorage.getItem(LANGFLOW_AUTO_LOGIN_OPTION);
|
||||
const isLoginPage = location.pathname.includes("login");
|
||||
const logout = useAuthStore((state) => state.logout);
|
||||
|
||||
if (!isAuthenticated && hasToken && !isLoginPage) {
|
||||
const cookies = new Cookies();
|
||||
const refreshToken = cookies.get("refresh_token");
|
||||
const { mutate: mutateRefresh } = useRefreshAccessToken();
|
||||
|
||||
useEffect(() => {
|
||||
const envRefreshTime = LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS_ENV;
|
||||
const automaticRefreshTime = LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS;
|
||||
|
||||
const accessTokenTimer = isNaN(envRefreshTime)
|
||||
? automaticRefreshTime
|
||||
: envRefreshTime;
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
if (isAuthenticated) {
|
||||
mutateRefresh({ refresh_token: refreshToken });
|
||||
}
|
||||
}, accessTokenTimer * 1000);
|
||||
|
||||
return () => clearInterval(intervalId);
|
||||
}, []);
|
||||
|
||||
if (!isAuthenticated && hasToken) {
|
||||
logout();
|
||||
} else {
|
||||
return children;
|
||||
|
|
|
|||
|
|
@ -34,11 +34,6 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
const addFlow = useAddFlow();
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||
const setLockChat = useFlowStore((state) => state.setLockChat);
|
||||
const setIsBuilding = useFlowStore((state) => state.setIsBuilding);
|
||||
const revertBuiltStatusFromBuilding = useFlowStore(
|
||||
(state) => state.revertBuiltStatusFromBuilding,
|
||||
);
|
||||
const undo = useFlowsManagerStore((state) => state.undo);
|
||||
const redo = useFlowsManagerStore((state) => state.redo);
|
||||
const saveLoading = useFlowsManagerStore((state) => state.saveLoading);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import { useLogout } from "@/controllers/API/queries/auth";
|
|||
import useAuthStore from "@/stores/authStore";
|
||||
import useAlertStore from "../../stores/alertStore";
|
||||
import { useDarkStore } from "../../stores/darkStore";
|
||||
import { useLocationStore } from "../../stores/locationStore";
|
||||
import { useStoreStore } from "../../stores/storeStore";
|
||||
import IconComponent, { ForwardedIconComponent } from "../genericIconComponent";
|
||||
import { Button } from "../ui/button";
|
||||
|
|
@ -48,29 +47,22 @@ export default function Header(): JSX.Element {
|
|||
const setDark = useDarkStore((state) => state.setDark);
|
||||
const stars = useDarkStore((state) => state.stars);
|
||||
|
||||
const routeHistory = useLocationStore((state) => state.routeHistory);
|
||||
|
||||
const profileImageUrl = `${BASE_URL_API}files/profile_pictures/${
|
||||
userData?.profile_image ?? "Space/046-rocket.svg"
|
||||
}`;
|
||||
|
||||
const redirectToLastLocation = () => {
|
||||
const lastVisitedIndex = routeHistory
|
||||
.reverse()
|
||||
.findIndex((path) => path !== location.pathname);
|
||||
|
||||
const lastFlowVisited = routeHistory[lastVisitedIndex];
|
||||
lastFlowVisited ? navigate(lastFlowVisited) : navigate("/all");
|
||||
const canGoBack = location.key !== "default";
|
||||
if (canGoBack) {
|
||||
navigate(-1);
|
||||
} else {
|
||||
navigate("/", { replace: true });
|
||||
}
|
||||
};
|
||||
|
||||
const visitedFlowPathBefore = () => {
|
||||
const last100VisitedPaths = routeHistory.slice(-99);
|
||||
return last100VisitedPaths.some((path) => path.includes("/flow/"));
|
||||
};
|
||||
|
||||
const showArrowReturnIcon =
|
||||
LOCATIONS_TO_RETURN.some((path) => location.pathname.includes(path)) &&
|
||||
visitedFlowPathBefore();
|
||||
const showArrowReturnIcon = LOCATIONS_TO_RETURN.some((path) =>
|
||||
location.pathname.includes(path),
|
||||
);
|
||||
|
||||
const handleLogout = () => {
|
||||
mutationLogout(undefined, {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import Header from "../headerComponent";
|
||||
import { Separator } from "../ui/separator";
|
||||
|
||||
export default function PageLayout({
|
||||
|
|
@ -15,25 +14,22 @@ export default function PageLayout({
|
|||
betaIcon?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex h-screen w-full flex-col">
|
||||
<Header />
|
||||
<div className="flex h-full w-full flex-col justify-between overflow-auto bg-background px-16">
|
||||
<div className="flex w-full items-center justify-between gap-4 space-y-0.5 py-8 pb-2">
|
||||
<div className="flex w-full flex-col">
|
||||
<h2
|
||||
className="text-2xl font-bold tracking-tight"
|
||||
data-testid="mainpage_title"
|
||||
>
|
||||
{title}
|
||||
{betaIcon && <span className="store-beta-icon">BETA</span>}
|
||||
</h2>
|
||||
<p className="text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0">{button && button}</div>
|
||||
<div className="flex h-full w-full flex-col justify-between overflow-auto bg-background px-16">
|
||||
<div className="flex w-full items-center justify-between gap-4 space-y-0.5 py-8 pb-2">
|
||||
<div className="flex w-full flex-col">
|
||||
<h2
|
||||
className="text-2xl font-bold tracking-tight"
|
||||
data-testid="mainpage_title"
|
||||
>
|
||||
{title}
|
||||
{betaIcon && <span className="store-beta-icon">BETA</span>}
|
||||
</h2>
|
||||
<p className="text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
<Separator className="my-6 flex" />
|
||||
{children}
|
||||
<div className="flex-shrink-0">{button && button}</div>
|
||||
</div>
|
||||
<Separator className="my-6 flex" />
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { LANGFLOW_ACCESS_TOKEN } from "@/constants/constants";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import { useUtilityStore } from "@/stores/utilityStore";
|
||||
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from "axios";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { Cookies } from "react-cookie";
|
||||
|
|
@ -89,13 +88,13 @@ function ApiInterceptor() {
|
|||
// Request interceptor to add access token to every request
|
||||
const requestInterceptor = api.interceptors.request.use(
|
||||
(config) => {
|
||||
const checkRequest = checkDuplicateRequestAndStoreRequest(config);
|
||||
|
||||
const controller = new AbortController();
|
||||
|
||||
if (!checkRequest) {
|
||||
controller.abort("Duplicate Request");
|
||||
console.error("Duplicate Request");
|
||||
try {
|
||||
checkDuplicateRequestAndStoreRequest(config);
|
||||
} catch (e) {
|
||||
const error = e as Error;
|
||||
controller.abort(error.message);
|
||||
console.error(error.message);
|
||||
}
|
||||
|
||||
const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN);
|
||||
|
|
|
|||
|
|
@ -21,13 +21,11 @@ export function checkDuplicateRequestAndStoreRequest(config) {
|
|||
currentTime - parseInt(lastRequestTime, 10) < 300 &&
|
||||
lastCurrentUrl === currentUrl
|
||||
) {
|
||||
return false;
|
||||
throw new Error("Duplicate request: " + lastUrl);
|
||||
}
|
||||
|
||||
localStorage.setItem("lastUrlCalled", config.url ?? "");
|
||||
localStorage.setItem("lastMethodCalled", config.method ?? "");
|
||||
localStorage.setItem("lastRequestTime", currentTime.toString());
|
||||
localStorage.setItem("lastCurrentUrl", currentUrl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,35 +9,22 @@ import { UseRequestProcessor } from "../../services/request-processor";
|
|||
|
||||
interface BuildsQueryParams {
|
||||
flowId?: string;
|
||||
nodeId?: string;
|
||||
}
|
||||
|
||||
export const useGetBuildsQuery: useQueryFunctionType<
|
||||
BuildsQueryParams,
|
||||
AxiosResponse<{ vertex_builds: FlowPoolType }>
|
||||
> = ({}) => {
|
||||
> = (params) => {
|
||||
const { query } = UseRequestProcessor();
|
||||
|
||||
const setFlowPool = useFlowStore((state) => state.setFlowPool);
|
||||
const currentFlow = useFlowStore((state) => state.currentFlow);
|
||||
|
||||
const getBuildsFn = async (
|
||||
params: BuildsQueryParams,
|
||||
): Promise<AxiosResponse<{ vertex_builds: FlowPoolType }>> => {
|
||||
const responseFn = async () => {
|
||||
const config = {};
|
||||
config["params"] = { flow_id: params.flowId };
|
||||
|
||||
if (params.nodeId) {
|
||||
config["params"] = { nodeId: params.nodeId };
|
||||
}
|
||||
|
||||
return await api.get<any>(`${getURL("BUILDS")}`, config);
|
||||
};
|
||||
|
||||
const responseFn = async () => {
|
||||
const response = await getBuildsFn({
|
||||
flowId: currentFlow!.id,
|
||||
});
|
||||
const response = await api.get<any>(`${getURL("BUILDS")}`, config);
|
||||
|
||||
if (currentFlow) {
|
||||
const flowPool = response.data.vertex_builds;
|
||||
|
|
@ -47,10 +34,14 @@ export const useGetBuildsQuery: useQueryFunctionType<
|
|||
return response;
|
||||
};
|
||||
|
||||
const queryResult = query(["useGetBuildsQuery"], responseFn, {
|
||||
placeholderData: keepPreviousData,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
const queryResult = query(
|
||||
["useGetBuildsQuery", { key: params.flowId }],
|
||||
responseFn,
|
||||
{
|
||||
placeholderData: keepPreviousData,
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
);
|
||||
|
||||
return queryResult;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
import { useEffect } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useLocationStore } from "../stores/locationStore";
|
||||
|
||||
function useTrackLastVisitedPath() {
|
||||
const location = useLocation();
|
||||
const setHistory = useLocationStore((state) => state.setRouteHistory);
|
||||
|
||||
useEffect(() => {
|
||||
setHistory(location.pathname);
|
||||
}, [location]);
|
||||
}
|
||||
|
||||
export default useTrackLastVisitedPath;
|
||||
|
|
@ -7,7 +7,6 @@ import {
|
|||
import { cloneDeep } from "lodash";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import Header from "../../components/headerComponent";
|
||||
import LoadingComponent from "../../components/loadingComponent";
|
||||
import PaginatorComponent from "../../components/paginatorComponent";
|
||||
import ShadTooltip from "../../components/shadTooltipComponent";
|
||||
|
|
@ -246,7 +245,6 @@ export default function AdminPage() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
{userData && (
|
||||
<div className="admin-page-panel flex h-full flex-col pb-8">
|
||||
<div className="main-page-nav-arrangement">
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import {
|
|||
TIMEOUT_ERROR_MESSAGE,
|
||||
} from "@/constants/constants";
|
||||
import { useGetHealthQuery } from "@/controllers/API/queries/health";
|
||||
import useTrackLastVisitedPath from "@/hooks/use-track-last-visited-path";
|
||||
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||
import { useUtilityStore } from "@/stores/utilityStore";
|
||||
import { cn } from "@/utils/utils";
|
||||
|
|
@ -20,8 +19,6 @@ import { ErrorBoundary } from "react-error-boundary";
|
|||
import { Outlet } from "react-router-dom";
|
||||
|
||||
export function AppWrapperPage() {
|
||||
useTrackLastVisitedPath();
|
||||
|
||||
const isLoading = useFlowsManagerStore((state) => state.isLoading);
|
||||
|
||||
const healthCheckMaxRetries = useFlowsManagerStore(
|
||||
|
|
|
|||
11
src/frontend/src/pages/DashboardWrapperPage/index.tsx
Normal file
11
src/frontend/src/pages/DashboardWrapperPage/index.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import Header from "@/components/headerComponent";
|
||||
import { Outlet } from "react-router-dom";
|
||||
|
||||
export function DashboardWrapperPage() {
|
||||
return (
|
||||
<div className="flex h-screen w-full flex-col">
|
||||
<Header />
|
||||
<Outlet />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -143,7 +143,7 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
};
|
||||
}, [lastCopiedSelection, lastSelection, takeSnapshot, selectionMenuVisible]);
|
||||
|
||||
const { isFetching, refetch } = useGetBuildsQuery({});
|
||||
const { isFetching } = useGetBuildsQuery({ flowId: currentFlowId });
|
||||
|
||||
const showCanvas =
|
||||
Object.keys(templates).length > 0 &&
|
||||
|
|
@ -151,8 +151,6 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
!isFetching;
|
||||
|
||||
useEffect(() => {
|
||||
refetch();
|
||||
useFlowStore.setState({ autoSaveFlow });
|
||||
if (checkOldComponents({ nodes })) {
|
||||
setNoticeData({
|
||||
title:
|
||||
|
|
@ -161,6 +159,10 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
}
|
||||
}, [currentFlowId]);
|
||||
|
||||
useEffect(() => {
|
||||
useFlowStore.setState({ autoSaveFlow });
|
||||
});
|
||||
|
||||
function handleUndo(e: KeyboardEvent) {
|
||||
if (!isWrappedWithClass(e, "noflow")) {
|
||||
e.preventDefault();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import { customStringify } from "@/utils/reactflowUtils";
|
|||
import { useEffect } from "react";
|
||||
import { useBlocker, useNavigate, useParams } from "react-router-dom";
|
||||
import FlowToolbar from "../../components/chatComponent";
|
||||
import Header from "../../components/headerComponent";
|
||||
import { useDarkStore } from "../../stores/darkStore";
|
||||
import useFlowStore from "../../stores/flowStore";
|
||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||
|
|
@ -81,7 +80,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
|
|||
}
|
||||
};
|
||||
awaitgetTypes();
|
||||
}, [id, flows]);
|
||||
}, [id, flows, currentFlowId]);
|
||||
|
||||
useEffect(() => {
|
||||
setOnFlowPage(true);
|
||||
|
|
@ -94,7 +93,6 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<div className="flow-page-positioning">
|
||||
{currentFlow && (
|
||||
<div className="flex h-full overflow-hidden">
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
|
||||
import { useGetGlobalVariables } from "@/controllers/API/queries/variables";
|
||||
import { useStoreStore } from "@/stores/storeStore";
|
||||
import { useTypesStore } from "@/stores/typesStore";
|
||||
import { useEffect } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import LoadingComponent from "../../components/loadingComponent";
|
||||
import { getComponent } from "../../controllers/API";
|
||||
import IOModal from "../../modals/IOModal";
|
||||
|
|
@ -8,7 +11,6 @@ import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
|||
import cloneFLowWithParent from "../../utils/storeUtils";
|
||||
|
||||
export default function PlaygroundPage() {
|
||||
const getFlowById = useFlowsManagerStore((state) => state.getFlowById);
|
||||
const flows = useFlowsManagerStore((state) => state.flows);
|
||||
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
|
||||
const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||
|
|
@ -21,19 +23,38 @@ export default function PlaygroundPage() {
|
|||
return newFlow;
|
||||
}
|
||||
|
||||
const navigate = useNavigate();
|
||||
useGetGlobalVariables();
|
||||
|
||||
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
|
||||
const { mutateAsync: refreshFlows } = useGetRefreshFlows();
|
||||
const setIsLoading = useFlowsManagerStore((state) => state.setIsLoading);
|
||||
const getTypes = useTypesStore((state) => state.getTypes);
|
||||
|
||||
// Set flow tab id
|
||||
useEffect(() => {
|
||||
if (flows) {
|
||||
const flow = getFlowById(id!);
|
||||
if (flow) {
|
||||
setCurrentFlow(flow);
|
||||
} else {
|
||||
if (validApiKey)
|
||||
getFlowData().then((flow) => {
|
||||
setCurrentFlow(flow);
|
||||
});
|
||||
const awaitgetTypes = async () => {
|
||||
if (flows && currentFlowId === "") {
|
||||
const isAnExistingFlow = flows.find((flow) => flow.id === id);
|
||||
|
||||
if (!isAnExistingFlow) {
|
||||
if (validApiKey) {
|
||||
getFlowData().then((flow) => {
|
||||
setCurrentFlow(flow);
|
||||
});
|
||||
} else {
|
||||
navigate("/");
|
||||
}
|
||||
}
|
||||
setCurrentFlow(isAnExistingFlow);
|
||||
} else if (!flows) {
|
||||
setIsLoading(true);
|
||||
await refreshFlows(undefined);
|
||||
await getTypes();
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
awaitgetTypes();
|
||||
}, [id, flows, validApiKey]);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
|
||||
import { useGetGlobalVariables } from "@/controllers/API/queries/variables";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { useTypesStore } from "@/stores/typesStore";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
|
|
@ -10,7 +9,6 @@ import Page from "../FlowPage/components/PageComponent";
|
|||
export default function ViewPage() {
|
||||
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
|
||||
|
||||
const setOnFlowPage = useFlowStore((state) => state.setOnFlowPage);
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
useGetGlobalVariables();
|
||||
|
|
@ -43,15 +41,6 @@ export default function ViewPage() {
|
|||
awaitgetTypes();
|
||||
}, [id, flows]);
|
||||
|
||||
useEffect(() => {
|
||||
setOnFlowPage(true);
|
||||
|
||||
return () => {
|
||||
setOnFlowPage(false);
|
||||
setCurrentFlow(undefined);
|
||||
};
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<div className="flow-page-positioning">
|
||||
<Page view />
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
import React, { lazy } from "react";
|
||||
import { lazy } from "react";
|
||||
import {
|
||||
createBrowserRouter,
|
||||
createRoutesFromElements,
|
||||
Navigate,
|
||||
Outlet,
|
||||
Route,
|
||||
} from "react-router-dom";
|
||||
import { ProtectedAdminRoute } from "./components/authAdminGuard";
|
||||
import { ProtectedRoute } from "./components/authGuard";
|
||||
import { ProtectedLoginRoute } from "./components/authLoginGuard";
|
||||
import { AuthSettingsGuard } from "./components/authSettingsGuard";
|
||||
import { CatchAllRoute } from "./components/catchAllRoutes";
|
||||
import { StoreGuard } from "./components/storeGuard";
|
||||
import { AppWrapperPage } from "./pages/AppWrapperPage";
|
||||
import { DashboardWrapperPage } from "./pages/DashboardWrapperPage";
|
||||
import FlowPage from "./pages/FlowPage";
|
||||
import LoginPage from "./pages/LoginPage";
|
||||
import MyCollectionComponent from "./pages/MainPage/components/myCollectionComponent";
|
||||
|
|
@ -34,132 +35,104 @@ const PlaygroundPage = lazy(() => import("./pages/Playground"));
|
|||
const SignUp = lazy(() => import("./pages/SignUpPage"));
|
||||
const router = createBrowserRouter(
|
||||
createRoutesFromElements([
|
||||
<Route path="" element={<AppWrapperPage />}>
|
||||
<Route path="/" element={<AppWrapperPage />}>
|
||||
<Route
|
||||
path="/"
|
||||
path=""
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<HomePage />
|
||||
<Outlet />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
>
|
||||
<Route index element={<Navigate replace to={"all"} />} />
|
||||
<Route
|
||||
path="flows/"
|
||||
element={<MyCollectionComponent key="flows" type="flow" />}
|
||||
>
|
||||
<Route path="" element={<DashboardWrapperPage />}>
|
||||
<Route path="" element={<HomePage />}>
|
||||
<Route index element={<Navigate replace to={"all"} />} />
|
||||
<Route
|
||||
path="flows/"
|
||||
element={<MyCollectionComponent key="flows" type="flow" />}
|
||||
>
|
||||
<Route
|
||||
path="folder/:folderId"
|
||||
element={<MyCollectionComponent key="flows" type="flow" />}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path="components/"
|
||||
element={
|
||||
<MyCollectionComponent key="components" type="component" />
|
||||
}
|
||||
>
|
||||
<Route
|
||||
path="folder/:folderId"
|
||||
element={
|
||||
<MyCollectionComponent key="components" type="component" />
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path="all/"
|
||||
element={<MyCollectionComponent key="all" type="all" />}
|
||||
>
|
||||
<Route
|
||||
path="folder/:folderId"
|
||||
element={<MyCollectionComponent key="all" type="all" />}
|
||||
/>
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="/settings" element={<SettingsPage />}>
|
||||
<Route index element={<Navigate replace to={"general"} />} />
|
||||
<Route path="global-variables" element={<GlobalVariablesPage />} />
|
||||
<Route path="api-keys" element={<ApiKeysPage />} />
|
||||
<Route
|
||||
path="general/:scrollId?"
|
||||
element={
|
||||
<AuthSettingsGuard>
|
||||
<GeneralPage />
|
||||
</AuthSettingsGuard>
|
||||
}
|
||||
/>
|
||||
<Route path="shortcuts" element={<ShortcutsPage />} />
|
||||
<Route path="messages" element={<MessagesPage />} />
|
||||
</Route>
|
||||
<Route
|
||||
path="folder/:folderId"
|
||||
element={<MyCollectionComponent key="flows" type="flow" />}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path="components/"
|
||||
element={<MyCollectionComponent key="components" type="component" />}
|
||||
>
|
||||
<Route
|
||||
path="folder/:folderId"
|
||||
path="/store"
|
||||
element={
|
||||
<MyCollectionComponent key="components" type="component" />
|
||||
<StoreGuard>
|
||||
<StorePage />
|
||||
</StoreGuard>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/store/:id/"
|
||||
element={
|
||||
<StoreGuard>
|
||||
<StorePage />
|
||||
</StoreGuard>
|
||||
}
|
||||
/>
|
||||
<Route path="/account">
|
||||
<Route path="delete" element={<DeleteAccountPage />}></Route>
|
||||
</Route>
|
||||
<Route
|
||||
path="/admin"
|
||||
element={
|
||||
<ProtectedAdminRoute>
|
||||
<AdminPage />
|
||||
</ProtectedAdminRoute>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path="all/"
|
||||
element={<MyCollectionComponent key="all" type="all" />}
|
||||
>
|
||||
<Route
|
||||
path="folder/:folderId"
|
||||
element={<MyCollectionComponent key="all" type="all" />}
|
||||
/>
|
||||
<Route path="/flow/:id/">
|
||||
<Route path="" element={<DashboardWrapperPage />}>
|
||||
<Route path="folder/:folderId/" element={<FlowPage />} />
|
||||
<Route path="" element={<FlowPage />} />
|
||||
</Route>
|
||||
<Route path="view" element={<ViewPage />} />
|
||||
</Route>
|
||||
<Route path="/playground/:id/">
|
||||
<Route path="" element={<PlaygroundPage />} />
|
||||
</Route>
|
||||
</Route>
|
||||
<Route
|
||||
path="/settings"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<SettingsPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
>
|
||||
<Route index element={<Navigate replace to={"general"} />} />
|
||||
<Route path="global-variables" element={<GlobalVariablesPage />} />
|
||||
<Route path="api-keys" element={<ApiKeysPage />} />
|
||||
<Route
|
||||
path="general/:scrollId?"
|
||||
element={
|
||||
<AuthSettingsGuard>
|
||||
<GeneralPage />
|
||||
</AuthSettingsGuard>
|
||||
}
|
||||
/>
|
||||
<Route path="shortcuts" element={<ShortcutsPage />} />
|
||||
<Route path="messages" element={<MessagesPage />} />
|
||||
</Route>
|
||||
<Route
|
||||
path="/store"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<StoreGuard>
|
||||
<StorePage />
|
||||
</StoreGuard>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/store/:id/"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<StoreGuard>
|
||||
<StorePage />
|
||||
</StoreGuard>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route path="/playground/:id/">
|
||||
<Route
|
||||
path=""
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<PlaygroundPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/flow/:id/">
|
||||
<Route
|
||||
path="folder/:folderId/"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<FlowPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path=""
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<FlowPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="view"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<ViewPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path="*"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<CatchAllRoute />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
|
|
@ -184,24 +157,7 @@ const router = createBrowserRouter(
|
|||
</ProtectedLoginRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/admin"
|
||||
element={
|
||||
<ProtectedAdminRoute>
|
||||
<AdminPage />
|
||||
</ProtectedAdminRoute>
|
||||
}
|
||||
/>
|
||||
<Route path="/account">
|
||||
<Route
|
||||
path="delete"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<DeleteAccountPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
></Route>
|
||||
</Route>
|
||||
<Route path="*" element={<Navigate replace to="/" />} />
|
||||
</Route>,
|
||||
]),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { test } from "@playwright/test";
|
||||
import * as dotenv from "dotenv";
|
||||
import path from "path";
|
||||
|
||||
|
|
@ -70,6 +70,8 @@ test("should delete rows from table message", async ({ page }) => {
|
|||
timeout: 30000,
|
||||
});
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.getByTestId("user-profile-settings").last().click();
|
||||
await page.getByText("Settings").last().click();
|
||||
await page.getByText("Messages").last().click();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue