refactor: modular navigation and custom api calls (#3613)
* Added customization files * Added custom API headers and changed logout mutation * Changed mutationLogout on authGuard * Renamed feature flags * Changed auto login to run after primary loading * Removed unused code * Added undefined on mutationfunctiontype to have options * Changed logout to mutationLogout * Return data on getConfig * Added custom wrapper * changed hasStore to be the constant by default * Added custom header * Added customParam feature flag * Fix routes and custom link and navigate to consider absolute and relative paths * Fixed regex on tabs search component * Added CustomNavigate * Added basename and ports and URLs config * [autofix.ci] apply automated fixes * Update config-constants.ts * Update index.tsx * Fixed path comparations --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
cb1a2f24b3
commit
06ea6c408b
54 changed files with 300 additions and 215 deletions
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"ENABLE_DARK_MODE": true,
|
||||
"ENABLE_API": true,
|
||||
"ENABLE_LANGFLOW_STORE": true,
|
||||
"ENABLE_PROFILE_ICONS": true,
|
||||
"ENABLE_SOCIAL_LINKS": true,
|
||||
"ENABLE_BRANDING": true,
|
||||
"ENABLE_MVPS": false
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { defineConfig, devices } from "@playwright/test";
|
||||
import * as dotenv from "dotenv";
|
||||
import path from "path";
|
||||
import { PORT } from "./src/customization/config-constants";
|
||||
dotenv.config();
|
||||
dotenv.config({ path: path.resolve(__dirname, "../../.env") });
|
||||
|
||||
|
|
@ -31,7 +32,7 @@ export default defineConfig({
|
|||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: "http://localhost:3000/",
|
||||
baseURL: `http://localhost:${PORT || 3000}/`,
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry",
|
||||
|
|
@ -85,7 +86,7 @@ export default defineConfig({
|
|||
},
|
||||
{
|
||||
command: "npm start",
|
||||
port: 3000,
|
||||
port: PORT || 3000,
|
||||
env: {
|
||||
VITE_PROXY_TARGET: "http://127.0.0.1:7860",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { CustomLink } from "@/customization/components/custom-link";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import IconComponent from "../../../../components/genericIconComponent";
|
||||
import { SingleAlertComponentType } from "../../../../types/alerts";
|
||||
|
||||
|
|
@ -93,12 +93,12 @@ export default function SingleAlert({
|
|||
</p>
|
||||
<p className="mt-3 text-sm md:ml-6 md:mt-0">
|
||||
{dropItem.link ? (
|
||||
<Link
|
||||
<CustomLink
|
||||
to={dropItem.link}
|
||||
className="whitespace-nowrap font-medium text-info-foreground hover:text-accent-foreground"
|
||||
>
|
||||
Details
|
||||
</Link>
|
||||
</CustomLink>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { CustomLink } from "@/customization/components/custom-link";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import { NoticeAlertType } from "../../types/alerts";
|
||||
|
||||
|
|
@ -52,12 +52,12 @@ export default function NoticeAlert({
|
|||
</p>
|
||||
<p className="mt-3 text-sm md:ml-6 md:mt-0">
|
||||
{link !== "" ? (
|
||||
<Link
|
||||
<CustomLink
|
||||
to={link}
|
||||
className="whitespace-nowrap font-medium text-info-foreground hover:text-accent-foreground"
|
||||
>
|
||||
Details
|
||||
</Link>
|
||||
</CustomLink>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { CustomNavigate } from "@/customization/components/custom-navigate";
|
||||
import { LoadingPage } from "@/pages/LoadingPage";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import { useContext } from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { AuthContext } from "../../contexts/authContext";
|
||||
|
||||
export const ProtectedAdminRoute = ({ children }) => {
|
||||
|
|
@ -13,7 +13,7 @@ export const ProtectedAdminRoute = ({ children }) => {
|
|||
if (!isAuthenticated) {
|
||||
return <LoadingPage />;
|
||||
} else if ((userData && !isAdmin) || autoLogin) {
|
||||
return <Navigate to="/" replace />;
|
||||
return <CustomNavigate to="/" replace />;
|
||||
} else {
|
||||
return children;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@ import {
|
|||
LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS_ENV,
|
||||
LANGFLOW_AUTO_LOGIN_OPTION,
|
||||
} from "@/constants/constants";
|
||||
import { useRefreshAccessToken } from "@/controllers/API/queries/auth";
|
||||
import {
|
||||
useLogout,
|
||||
useRefreshAccessToken,
|
||||
} from "@/controllers/API/queries/auth";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import { useEffect } from "react";
|
||||
import { Cookies } from "react-cookie";
|
||||
|
|
@ -11,11 +14,11 @@ import { Cookies } from "react-cookie";
|
|||
export const ProtectedRoute = ({ children }) => {
|
||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
||||
const hasToken = !!localStorage.getItem(LANGFLOW_AUTO_LOGIN_OPTION);
|
||||
const logout = useAuthStore((state) => state.logout);
|
||||
|
||||
const cookies = new Cookies();
|
||||
const refreshToken = cookies.get("refresh_token");
|
||||
const { mutate: mutateRefresh } = useRefreshAccessToken();
|
||||
const { mutate: mutationLogout } = useLogout();
|
||||
|
||||
useEffect(() => {
|
||||
const envRefreshTime = LANGFLOW_ACCESS_TOKEN_EXPIRE_SECONDS_ENV;
|
||||
|
|
@ -38,7 +41,7 @@ export const ProtectedRoute = ({ children }) => {
|
|||
}, [isAuthenticated]);
|
||||
|
||||
if (!isAuthenticated && hasToken) {
|
||||
logout();
|
||||
mutationLogout();
|
||||
} else {
|
||||
return children;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
import { CustomNavigate } from "@/customization/components/custom-navigate";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import { Navigate } from "react-router-dom";
|
||||
|
||||
export const ProtectedLoginRoute = ({ children }) => {
|
||||
const autoLogin = useAuthStore((state) => state.autoLogin);
|
||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
||||
|
||||
if (autoLogin === true) {
|
||||
window.location.replace("/");
|
||||
return <Navigate to="/" replace />;
|
||||
return <CustomNavigate to="/" replace />;
|
||||
}
|
||||
|
||||
if (isAuthenticated) {
|
||||
window.location.replace("/");
|
||||
return <Navigate to="/" replace />;
|
||||
return <CustomNavigate to="/" replace />;
|
||||
}
|
||||
|
||||
return children;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
import FeatureFlags from "@/../feature-config.json";
|
||||
import { CustomNavigate } from "@/customization/components/custom-navigate";
|
||||
import { ENABLE_PROFILE_ICONS } from "@/customization/feature-flags";
|
||||
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;
|
||||
const showGeneralSettings = ENABLE_PROFILE_ICONS || hasStore || !autoLogin;
|
||||
|
||||
if (showGeneralSettings) {
|
||||
return children;
|
||||
} else {
|
||||
return <Navigate replace to="global-variables" />;
|
||||
return <CustomNavigate replace to="global-variables" />;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export const CatchAllRoute = () => {
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
|
||||
// Redirect to the root ("/") when the catch-all route is matched
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import FeatureFlags from "@/../feature-config.json";
|
||||
import { ENABLE_API } from "@/customization/feature-flags";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
|
|
@ -138,7 +138,7 @@ export default function FlowToolbar(): JSX.Element {
|
|||
<div>
|
||||
<Separator orientation="vertical" />
|
||||
</div>
|
||||
{FeatureFlags.ENABLE_API && (
|
||||
{ENABLE_API && (
|
||||
<>
|
||||
<div className="flex cursor-pointer items-center gap-2">
|
||||
{currentFlow && currentFlow.data && (
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
usePostUploadFolders,
|
||||
} from "@/controllers/API/queries/folders";
|
||||
import { useGetDownloadFolders } from "@/controllers/API/queries/folders/use-get-download-folders";
|
||||
import { ENABLE_CUSTOM_PARAM } from "@/customization/feature-flags";
|
||||
import { createFileUpload } from "@/helpers/create-file-upload";
|
||||
import { getObjectsFromFilelist } from "@/helpers/get-objects-from-filelist";
|
||||
import useUploadFlow from "@/hooks/flows/use-upload-flow";
|
||||
|
|
@ -44,7 +45,8 @@ const SideBarFoldersButtonsComponent = ({
|
|||
folders.map((obj) => ({ name: obj.name, edit: false })) ?? [],
|
||||
);
|
||||
const currentFolder = pathname.split("/");
|
||||
const urlWithoutPath = pathname.split("/").length < 4;
|
||||
const urlWithoutPath =
|
||||
pathname.split("/").length < (ENABLE_CUSTOM_PARAM ? 5 : 4);
|
||||
const myCollectionId = useFolderStore((state) => state.myCollectionId);
|
||||
const folderIdDragging = useFolderStore((state) => state.folderIdDragging);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ import {
|
|||
DropdownMenuTrigger,
|
||||
} from "../../../ui/dropdown-menu";
|
||||
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import useAddFlow from "@/hooks/flows/use-add-flow";
|
||||
import useSaveFlow from "@/hooks/flows/use-save-flow";
|
||||
import useUploadFlow from "@/hooks/flows/use-upload-flow";
|
||||
import { customStringify } from "@/utils/reactflowUtils";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { UPLOAD_ERROR_ALERT } from "../../../../constants/alerts_constants";
|
||||
import { SAVED_HOVER } from "../../../../constants/constants";
|
||||
import ExportModal from "../../../../modals/exportModal";
|
||||
|
|
@ -40,7 +40,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
const [openSettings, setOpenSettings] = useState(false);
|
||||
const [openLogs, setOpenLogs] = useState(false);
|
||||
const uploadFlow = useUploadFlow();
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
const isBuilding = useFlowStore((state) => state.isBuilding);
|
||||
const getTypes = useTypesStore((state) => state.getTypes);
|
||||
const saveFlow = useSaveFlow();
|
||||
|
|
|
|||
|
|
@ -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 } from "react-router-dom";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import AlertDropdown from "../../alerts/alertDropDown";
|
||||
import {
|
||||
BASE_URL_API,
|
||||
|
|
@ -10,8 +10,14 @@ import {
|
|||
} from "../../constants/constants";
|
||||
import { AuthContext } from "../../contexts/authContext";
|
||||
|
||||
import FeatureFlags from "@/../feature-config.json";
|
||||
import { useLogout } from "@/controllers/API/queries/auth";
|
||||
import { CustomLink } from "@/customization/components/custom-link";
|
||||
import {
|
||||
ENABLE_DARK_MODE,
|
||||
ENABLE_PROFILE_ICONS,
|
||||
ENABLE_SOCIAL_LINKS,
|
||||
} from "@/customization/feature-flags";
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import useAlertStore from "../../stores/alertStore";
|
||||
import { useDarkStore } from "../../stores/darkStore";
|
||||
|
|
@ -38,9 +44,8 @@ export default function Header(): JSX.Element {
|
|||
const autoLogin = useAuthStore((state) => state.autoLogin);
|
||||
|
||||
const { mutate: mutationLogout } = useLogout();
|
||||
const logout = useAuthStore((state) => state.logout);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
const hasStore = useStoreStore((state) => state.hasStore);
|
||||
|
||||
const dark = useDarkStore((state) => state.dark);
|
||||
|
|
@ -65,22 +70,15 @@ export default function Header(): JSX.Element {
|
|||
);
|
||||
|
||||
const handleLogout = () => {
|
||||
mutationLogout(undefined, {
|
||||
onSuccess: () => {
|
||||
logout();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
},
|
||||
});
|
||||
mutationLogout();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="header-arrangement relative">
|
||||
<div className="header-start-display">
|
||||
<Link to="/all" className="cursor-pointer">
|
||||
<CustomLink to="/all" className="cursor-pointer">
|
||||
<span className="ml-4 text-2xl">⛓️</span>
|
||||
</Link>
|
||||
</CustomLink>
|
||||
{showArrowReturnIcon && (
|
||||
<Button
|
||||
unstyled
|
||||
|
|
@ -96,12 +94,12 @@ export default function Header(): JSX.Element {
|
|||
</div>
|
||||
|
||||
<div className="flex items-center xl:absolute xl:left-1/2 xl:-translate-x-1/2">
|
||||
<Link to="/all">
|
||||
<CustomLink to="/all">
|
||||
<Button
|
||||
className="gap-2"
|
||||
variant={
|
||||
location.pathname === "/all" ||
|
||||
location.pathname === "/components"
|
||||
location.pathname.includes("/all") ||
|
||||
location.pathname.includes("/components")
|
||||
? "primary"
|
||||
: "secondary"
|
||||
}
|
||||
|
|
@ -110,25 +108,27 @@ export default function Header(): JSX.Element {
|
|||
<IconComponent name="Home" className="h-4 w-4" />
|
||||
<div className="hidden flex-1 lg:block">{USER_PROJECTS_HEADER}</div>
|
||||
</Button>
|
||||
</Link>
|
||||
</CustomLink>
|
||||
|
||||
{hasStore && (
|
||||
<Link to="/store">
|
||||
<CustomLink to="/store">
|
||||
<Button
|
||||
className="gap-2"
|
||||
variant={location.pathname === "/store" ? "primary" : "secondary"}
|
||||
variant={
|
||||
location.pathname.includes("/store") ? "primary" : "secondary"
|
||||
}
|
||||
size="sm"
|
||||
data-testid="button-store"
|
||||
>
|
||||
<IconComponent name="Store" className="h-4 w-4" />
|
||||
<div className="hidden flex-1 lg:block">Store</div>
|
||||
</Button>
|
||||
</Link>
|
||||
</CustomLink>
|
||||
)}
|
||||
</div>
|
||||
<div className="header-end-division">
|
||||
<div className="header-end-display">
|
||||
{FeatureFlags.ENABLE_SOCIAL_LINKS && (
|
||||
{ENABLE_SOCIAL_LINKS && (
|
||||
<>
|
||||
<a
|
||||
href="https://github.com/langflow-ai/langflow"
|
||||
|
|
@ -160,7 +160,7 @@ export default function Header(): JSX.Element {
|
|||
<Separator orientation="vertical" />
|
||||
</>
|
||||
)}
|
||||
{FeatureFlags.ENABLE_DARK_MODE && (
|
||||
{ENABLE_DARK_MODE && (
|
||||
<button
|
||||
className="extra-side-bar-save-disable"
|
||||
onClick={() => {
|
||||
|
|
@ -202,7 +202,7 @@ export default function Header(): JSX.Element {
|
|||
data-testid="user-profile-settings"
|
||||
className="shrink-0"
|
||||
>
|
||||
{FeatureFlags.ENABLE_PROFILE_ICONS ? (
|
||||
{ENABLE_PROFILE_ICONS ? (
|
||||
<img
|
||||
src={profileImageUrl}
|
||||
className="h-7 w-7 shrink-0 focus-visible:outline-0"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Link } from "react-router-dom";
|
||||
import { CustomLink } from "@/customization/components/custom-link";
|
||||
import { cn } from "../../../../utils/utils";
|
||||
import { buttonVariants } from "../../../ui/button";
|
||||
|
||||
|
|
@ -18,13 +18,13 @@ const SideBarButtonsComponent = ({
|
|||
return (
|
||||
<div className="flex gap-2 overflow-auto lg:h-[70vh] lg:flex-col">
|
||||
{items.map((item) => (
|
||||
<Link to={item.href!}>
|
||||
<CustomLink to={item.href!}>
|
||||
<div
|
||||
key={item.title}
|
||||
data-testid={`sidebar-nav-${item.title}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "ghost" }),
|
||||
pathname === item.href
|
||||
item.href && pathname.endsWith(item.href)
|
||||
? "border border-border bg-muted hover:bg-muted"
|
||||
: "border border-transparent hover:border-border hover:bg-transparent",
|
||||
"flex w-full shrink-0 justify-start gap-4",
|
||||
|
|
@ -35,7 +35,7 @@ const SideBarButtonsComponent = ({
|
|||
{item.title}
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
</CustomLink>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { Navigate } from "react-router-dom";
|
||||
import { CustomNavigate } from "@/customization/components/custom-navigate";
|
||||
import { useStoreStore } from "../../stores/storeStore";
|
||||
|
||||
export const StoreGuard = ({ children }) => {
|
||||
const hasStore = useStoreStore((state) => state.hasStore);
|
||||
|
||||
if (!hasStore) {
|
||||
return <Navigate to="/all" replace />;
|
||||
return <CustomNavigate to="/all" replace />;
|
||||
}
|
||||
|
||||
return children;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// src/constants/constants.ts
|
||||
|
||||
import custom from "../customization/config-constants";
|
||||
import { languageMap } from "../types/components";
|
||||
|
||||
/**
|
||||
|
|
@ -567,9 +568,7 @@ export const ADMIN_HEADER_TITLE = "Admin Page";
|
|||
export const ADMIN_HEADER_DESCRIPTION =
|
||||
"Navigate through this section to efficiently oversee all application users. From here, you can seamlessly manage user accounts.";
|
||||
|
||||
export const BASE_URL_API = "/api/v1/";
|
||||
|
||||
export const BACKEND_URL = process.env.BACKEND_URL || "http://localhost:7860/";
|
||||
export const BASE_URL_API = custom.BASE_URL_API || "/api/v1/";
|
||||
|
||||
/**
|
||||
* URLs excluded from error retries.
|
||||
|
|
@ -580,7 +579,7 @@ export const URL_EXCLUDED_FROM_ERROR_RETRIES = [
|
|||
`${BASE_URL_API}validate/code`,
|
||||
`${BASE_URL_API}custom_component`,
|
||||
`${BASE_URL_API}validate/prompt`,
|
||||
`http://localhost:7860/login`,
|
||||
`${BASE_URL_API}/login`,
|
||||
`${BASE_URL_API}api_key/store`,
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { CustomWrapper } from "@/customization/custom-wrapper";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { ReactNode } from "react";
|
||||
import { ReactFlowProvider } from "reactflow";
|
||||
|
|
@ -10,16 +11,18 @@ export default function ContextWrapper({ children }: { children: ReactNode }) {
|
|||
//element to wrap all context
|
||||
return (
|
||||
<>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<AuthProvider>
|
||||
<TooltipProvider skipDelayDuration={0}>
|
||||
<ReactFlowProvider>
|
||||
<ApiInterceptor />
|
||||
{children}
|
||||
</ReactFlowProvider>
|
||||
</TooltipProvider>
|
||||
</AuthProvider>
|
||||
</QueryClientProvider>
|
||||
<CustomWrapper>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<AuthProvider>
|
||||
<TooltipProvider skipDelayDuration={0}>
|
||||
<ReactFlowProvider>
|
||||
<ApiInterceptor />
|
||||
{children}
|
||||
</ReactFlowProvider>
|
||||
</TooltipProvider>
|
||||
</AuthProvider>
|
||||
</QueryClientProvider>
|
||||
</CustomWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { LANGFLOW_ACCESS_TOKEN } from "@/constants/constants";
|
||||
import { useCustomApiHeaders } from "@/customization/hooks/use-custom-api-headers";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from "axios";
|
||||
import { useContext, useEffect } from "react";
|
||||
|
|
@ -22,8 +23,8 @@ function ApiInterceptor() {
|
|||
let { accessToken, authenticationErrorCount } = useContext(AuthContext);
|
||||
const { mutate: mutationLogout } = useLogout();
|
||||
const { mutate: mutationRenewAccessToken } = useRefreshAccessToken();
|
||||
const logout = useAuthStore((state) => state.logout);
|
||||
const isLoginPage = location.pathname.includes("login");
|
||||
const customHeaders = useCustomApiHeaders();
|
||||
|
||||
useEffect(() => {
|
||||
const interceptor = api.interceptors.response.use(
|
||||
|
|
@ -102,6 +103,10 @@ function ApiInterceptor() {
|
|||
config.headers["Authorization"] = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(customHeaders)) {
|
||||
config.headers[key] = value;
|
||||
}
|
||||
|
||||
return {
|
||||
...config,
|
||||
signal: controller.signal,
|
||||
|
|
@ -117,7 +122,7 @@ function ApiInterceptor() {
|
|||
api.interceptors.response.eject(interceptor);
|
||||
api.interceptors.request.eject(requestInterceptor);
|
||||
};
|
||||
}, [accessToken, setErrorData]);
|
||||
}, [accessToken, setErrorData, customHeaders]);
|
||||
|
||||
function checkErrorCount() {
|
||||
if (isLoginPage) return;
|
||||
|
|
@ -126,14 +131,7 @@ function ApiInterceptor() {
|
|||
|
||||
if (authenticationErrorCount > 3) {
|
||||
authenticationErrorCount = 0;
|
||||
mutationLogout(undefined, {
|
||||
onSuccess: () => {
|
||||
logout();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
},
|
||||
});
|
||||
mutationLogout();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +140,11 @@ function ApiInterceptor() {
|
|||
|
||||
async function tryToRenewAccessToken(error: AxiosError) {
|
||||
if (isLoginPage) return;
|
||||
if (error.config?.headers) {
|
||||
for (const [key, value] of Object.entries(customHeaders)) {
|
||||
error.config.headers[key] = value;
|
||||
}
|
||||
}
|
||||
mutationRenewAccessToken(
|
||||
{},
|
||||
{
|
||||
|
|
@ -152,14 +155,7 @@ function ApiInterceptor() {
|
|||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
mutationLogout(undefined, {
|
||||
onSuccess: () => {
|
||||
logout();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
},
|
||||
});
|
||||
mutationLogout();
|
||||
return Promise.reject("Authentication error");
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ interface IDeleteApiKey {
|
|||
}
|
||||
|
||||
// add types for error handling and success
|
||||
export const useDeleteApiKey: useMutationFunctionType<IDeleteApiKey> = (
|
||||
options,
|
||||
) => {
|
||||
export const useDeleteApiKey: useMutationFunctionType<
|
||||
undefined,
|
||||
IDeleteApiKey
|
||||
> = (options) => {
|
||||
const { mutate } = UseRequestProcessor();
|
||||
|
||||
const deleteApiKeyFn = async (payload: IDeleteApiKey): Promise<any> => {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { useQueryFunctionType, Users } from "../../../../types/api";
|
|||
import { api } from "../../api";
|
||||
import { getURL } from "../../helpers/constants";
|
||||
import { UseRequestProcessor } from "../../services/request-processor";
|
||||
import { useLogout } from "./use-post-logout";
|
||||
|
||||
export interface AutoLoginResponse {
|
||||
frontend_timeout: number;
|
||||
|
|
@ -21,8 +22,8 @@ export const useGetAutoLogin: useQueryFunctionType<undefined, undefined> = (
|
|||
const { login, setUserData, getUser } = useContext(AuthContext);
|
||||
const setAutoLogin = useAuthStore((state) => state.setAutoLogin);
|
||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
||||
const logout = useAuthStore((state) => state.logout);
|
||||
const isLoginPage = location.pathname.includes("login");
|
||||
const { mutate: mutationLogout } = useLogout();
|
||||
|
||||
async function getAutoLoginFn(): Promise<null> {
|
||||
try {
|
||||
|
|
@ -40,7 +41,7 @@ export const useGetAutoLogin: useQueryFunctionType<undefined, undefined> = (
|
|||
setAutoLogin(false);
|
||||
if (!isLoginPage) {
|
||||
if (!isAuthenticated) {
|
||||
await logout();
|
||||
mutationLogout();
|
||||
throw new Error("Unauthorized");
|
||||
} else {
|
||||
getUser();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import useAuthStore from "@/stores/authStore";
|
||||
import { useMutationFunctionType } from "@/types/api";
|
||||
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import { api } from "../../api";
|
||||
import { getURL } from "../../helpers/constants";
|
||||
import { UseRequestProcessor } from "../../services/request-processor";
|
||||
|
|
@ -9,6 +10,7 @@ export const useLogout: useMutationFunctionType<undefined, void> = (
|
|||
options?,
|
||||
) => {
|
||||
const { mutate } = UseRequestProcessor();
|
||||
const navigate = useCustomNavigate();
|
||||
const logout = useAuthStore((state) => state.logout);
|
||||
|
||||
async function logoutUser(): Promise<any> {
|
||||
|
|
@ -23,6 +25,7 @@ export const useLogout: useMutationFunctionType<undefined, void> = (
|
|||
const mutation = mutate(["useLogout"], logoutUser, {
|
||||
onSuccess: () => {
|
||||
logout();
|
||||
navigate("/login");
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export interface ConfigResponse {
|
|||
health_check_max_retries: number;
|
||||
}
|
||||
|
||||
export const useGetConfig: useQueryFunctionType<undefined, undefined> = (
|
||||
export const useGetConfig: useQueryFunctionType<undefined, ConfigResponse> = (
|
||||
options,
|
||||
) => {
|
||||
const setAutoSaving = useFlowsManagerStore((state) => state.setAutoSaving);
|
||||
|
|
@ -38,6 +38,7 @@ export const useGetConfig: useQueryFunctionType<undefined, undefined> = (
|
|||
setAutoSavingInterval(data.auto_saving_interval);
|
||||
setHealthCheckMaxRetries(data.health_check_max_retries);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
const queryResult = query(["useGetConfig"], getConfigFn, options);
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
import axios from "axios";
|
||||
import { BASE_URL_API } from "../../constants/constants";
|
||||
|
||||
/**
|
||||
* Fetches the configuration data from the API.
|
||||
* @returns {Promise<any>} A promise that resolves to the configuration data.
|
||||
* @throws {Error} If there was an error fetching the configuration data.
|
||||
*/
|
||||
export async function fetchConfig() {
|
||||
try {
|
||||
const response = await axios.get(`${BASE_URL_API}config`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch configuration:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up default configurations for Axios.
|
||||
* Fetches the timeout configuration and sets it as the default timeout for Axios requests.
|
||||
*/
|
||||
export async function setupAxiosDefaults() {
|
||||
const config = await fetchConfig();
|
||||
// Create Axios instance with the fetched timeout configuration
|
||||
|
||||
const timeoutInMilliseconds = config.frontend_timeout
|
||||
? config.frontend_timeout * 1000
|
||||
: 30000;
|
||||
axios.defaults.baseURL = "";
|
||||
axios.defaults.timeout = timeoutInMilliseconds;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export function CustomHeader() {
|
||||
return <></>;
|
||||
}
|
||||
11
src/frontend/src/customization/components/custom-link.tsx
Normal file
11
src/frontend/src/customization/components/custom-link.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { Link, LinkProps, useParams } from "react-router-dom";
|
||||
import { ENABLE_CUSTOM_PARAM } from "../feature-flags";
|
||||
|
||||
export function CustomLink({ to, ...props }: LinkProps) {
|
||||
const { customParam } = useParams();
|
||||
|
||||
const newLocation =
|
||||
ENABLE_CUSTOM_PARAM && to[0] === "/" ? `/${customParam}${to}` : to;
|
||||
|
||||
return <Link to={newLocation} {...props} />;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { Navigate, NavigateProps, useParams } from "react-router-dom";
|
||||
import { ENABLE_CUSTOM_PARAM } from "../feature-flags";
|
||||
|
||||
export function CustomNavigate({ to, ...props }: NavigateProps) {
|
||||
const { customParam } = useParams();
|
||||
const newLocation =
|
||||
ENABLE_CUSTOM_PARAM && to[0] === "/" ? `/${customParam}${to}` : to;
|
||||
|
||||
return <Navigate to={newLocation} {...props} />;
|
||||
}
|
||||
13
src/frontend/src/customization/config-constants.ts
Normal file
13
src/frontend/src/customization/config-constants.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export const BASENAME = "";
|
||||
export const PORT = 3000;
|
||||
export const PROXY_TARGET = "http://127.0.0.1:7860";
|
||||
export const API_ROUTES = ["^/api/v1/", "/health"];
|
||||
export const BASE_URL_API = "/api/v1/";
|
||||
|
||||
export default {
|
||||
BASENAME,
|
||||
PORT,
|
||||
PROXY_TARGET,
|
||||
API_ROUTES,
|
||||
BASE_URL_API,
|
||||
};
|
||||
3
src/frontend/src/customization/custom-wrapper.tsx
Normal file
3
src/frontend/src/customization/custom-wrapper.tsx
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export function CustomWrapper({ children }) {
|
||||
return children;
|
||||
}
|
||||
8
src/frontend/src/customization/feature-flags.ts
Normal file
8
src/frontend/src/customization/feature-flags.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export const ENABLE_DARK_MODE = true;
|
||||
export const ENABLE_API = true;
|
||||
export const ENABLE_LANGFLOW_STORE = true;
|
||||
export const ENABLE_PROFILE_ICONS = true;
|
||||
export const ENABLE_SOCIAL_LINKS = true;
|
||||
export const ENABLE_BRANDING = true;
|
||||
export const ENABLE_MVPS = false;
|
||||
export const ENABLE_CUSTOM_PARAM = false;
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export function useCustomApiHeaders() {
|
||||
const customHeaders = {};
|
||||
|
||||
return customHeaders;
|
||||
}
|
||||
27
src/frontend/src/customization/hooks/use-custom-navigate.ts
Normal file
27
src/frontend/src/customization/hooks/use-custom-navigate.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import {
|
||||
NavigateFunction,
|
||||
NavigateOptions,
|
||||
To,
|
||||
useNavigate,
|
||||
useParams,
|
||||
} from "react-router-dom";
|
||||
import { ENABLE_CUSTOM_PARAM } from "../feature-flags";
|
||||
|
||||
export function useCustomNavigate(): NavigateFunction {
|
||||
const domNavigate = useNavigate();
|
||||
|
||||
const { customParam } = useParams();
|
||||
|
||||
function navigate(to: To | number, options?: NavigateOptions) {
|
||||
if (typeof to === "number") {
|
||||
domNavigate(to);
|
||||
} else {
|
||||
domNavigate(
|
||||
ENABLE_CUSTOM_PARAM && to[0] === "/" ? `/${customParam}${to}` : to,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return navigate;
|
||||
}
|
||||
20
src/frontend/src/customization/hooks/use-primary-loading.ts
Normal file
20
src/frontend/src/customization/hooks/use-primary-loading.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { UseRequestProcessor } from "@/controllers/API/services/request-processor";
|
||||
import { useQueryFunctionType } from "@/types/api";
|
||||
|
||||
export const usePrimaryLoading: useQueryFunctionType<undefined, null> = (
|
||||
options,
|
||||
) => {
|
||||
const { query } = UseRequestProcessor();
|
||||
|
||||
const getPrimaryLoadingFn = async () => {
|
||||
return null;
|
||||
};
|
||||
|
||||
const queryResult = query(
|
||||
["usePrimaryLoading"],
|
||||
getPrimaryLoadingFn,
|
||||
options,
|
||||
);
|
||||
|
||||
return queryResult;
|
||||
};
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
import { useGetDownloadFileMutation } from "@/controllers/API/queries/files";
|
||||
import { useState } from "react";
|
||||
import { ForwardedIconComponent } from "../../../../../components/genericIconComponent";
|
||||
import { BACKEND_URL, BASE_URL_API } from "../../../../../constants/constants";
|
||||
import useFlowsManagerStore from "../../../../../stores/flowsManagerStore";
|
||||
import { BASE_URL_API } from "../../../../../constants/constants";
|
||||
import { fileCardPropsType } from "../../../../../types/components";
|
||||
import formatFileName from "../filePreviewChat/utils/format-file-name";
|
||||
import DownloadButton from "./components/downloadButton/downloadButton";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import useAddFlow from "@/hooks/flows/use-add-flow";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useParams } from "react-router-dom";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
|
|
@ -9,7 +10,7 @@ import {
|
|||
|
||||
export default function NewFlowCardComponent() {
|
||||
const addFlow = useAddFlow();
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
const { folderId } = useParams();
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="vite-plugin-svgr/client" />
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useParams } from "react-router-dom";
|
||||
import BlogPost from "../../../../assets/undraw_blog_post_re_fy5x.svg?react";
|
||||
import ChatBot from "../../../../assets/undraw_chat_bot_re_e2gj.svg?react";
|
||||
import PromptChaining from "../../../../assets/undraw_cloud_docs_re_xjht.svg?react";
|
||||
|
|
@ -10,6 +10,7 @@ import APIRequest from "../../../../assets/undraw_real_time_analytics_re_yliv.sv
|
|||
import BasicPrompt from "../../../../assets/undraw_short_bio_re_fmx0.svg?react";
|
||||
import TransferFiles from "../../../../assets/undraw_transfer_files_re_a2a9.svg?react";
|
||||
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import useAddFlow from "@/hooks/flows/use-add-flow";
|
||||
import {
|
||||
Card,
|
||||
|
|
@ -25,7 +26,7 @@ export default function UndrawCardComponent({
|
|||
flow,
|
||||
}: UndrawCardComponentProps): JSX.Element {
|
||||
const addFlow = useAddFlow();
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
const { folderId } = useParams();
|
||||
const myCollectionId = useFolderStore((state) => state.myCollectionId);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { useGetAutoLogin } from "@/controllers/API/queries/auth";
|
||||
import { useGetConfig } from "@/controllers/API/queries/config/use-get-config";
|
||||
import { useGetVersionQuery } from "@/controllers/API/queries/version";
|
||||
import { usePrimaryLoading } from "@/customization/hooks/use-primary-loading";
|
||||
import { useDarkStore } from "@/stores/darkStore";
|
||||
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||
import { useEffect } from "react";
|
||||
|
|
@ -12,7 +13,8 @@ export function AppInitPage() {
|
|||
const refreshStars = useDarkStore((state) => state.refreshStars);
|
||||
const isLoading = useFlowsManagerStore((state) => state.isLoading);
|
||||
|
||||
const { isFetched } = useGetAutoLogin();
|
||||
const { isFetched: isLoaded } = usePrimaryLoading();
|
||||
const { isFetched } = useGetAutoLogin({ enabled: isLoaded });
|
||||
useGetVersionQuery({ enabled: isFetched });
|
||||
useGetConfig({ enabled: isFetched });
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
TIMEOUT_ERROR_MESSAGE,
|
||||
} from "@/constants/constants";
|
||||
import { useGetHealthQuery } from "@/controllers/API/queries/health";
|
||||
import { CustomHeader } from "@/customization/components/custom-header";
|
||||
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||
import { useUtilityStore } from "@/stores/utilityStore";
|
||||
import { AxiosError } from "axios";
|
||||
|
|
@ -96,6 +97,7 @@ export function AppWrapperPage() {
|
|||
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
<CustomHeader />
|
||||
<ErrorBoundary
|
||||
onReset={() => {
|
||||
// any reset function
|
||||
|
|
@ -107,7 +109,6 @@ export function AppWrapperPage() {
|
|||
<Outlet />
|
||||
</>
|
||||
</ErrorBoundary>
|
||||
<div></div>
|
||||
<div className="app-div">
|
||||
<AlertDisplayArea />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import FeatureFlags from "@/../feature-config.json";
|
||||
import { ENABLE_MVPS } from "@/customization/feature-flags";
|
||||
import { useStoreStore } from "@/stores/storeStore";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useEffect, useState } from "react";
|
||||
|
|
@ -193,10 +193,10 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
// Set search input state
|
||||
setSearch(event.target.value);
|
||||
}}
|
||||
autocomplete="off"
|
||||
readonly="readonly"
|
||||
autoComplete="off"
|
||||
readOnly
|
||||
onClick={() =>
|
||||
document.getElementById("search").removeAttribute("readonly")
|
||||
document?.getElementById("search")?.removeAttribute("readonly")
|
||||
}
|
||||
/>
|
||||
<div
|
||||
|
|
@ -298,7 +298,7 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
</a>
|
||||
)}
|
||||
</ParentDisclosureComponent>
|
||||
{FeatureFlags.ENABLE_MVPS && (
|
||||
{ENABLE_MVPS && (
|
||||
<>
|
||||
<Separator />
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import FeatureFlags from "@/../feature-config.json";
|
||||
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
|
||||
import { useGetGlobalVariables } from "@/controllers/API/queries/variables";
|
||||
import { ENABLE_BRANDING } from "@/customization/feature-flags";
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import useSaveFlow from "@/hooks/flows/use-save-flow";
|
||||
import { SaveChangesModal } from "@/modals/saveChangesModal";
|
||||
import { useTypesStore } from "@/stores/typesStore";
|
||||
import { customStringify } from "@/utils/reactflowUtils";
|
||||
import { useEffect } from "react";
|
||||
import { useBlocker, useNavigate, useParams } from "react-router-dom";
|
||||
import { useBlocker, useParams } from "react-router-dom";
|
||||
import FlowToolbar from "../../components/chatComponent";
|
||||
import { useDarkStore } from "../../stores/darkStore";
|
||||
import useFlowStore from "../../stores/flowStore";
|
||||
|
|
@ -27,7 +28,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
|
|||
const version = useDarkStore((state) => state.version);
|
||||
const setOnFlowPage = useFlowStore((state) => state.setOnFlowPage);
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
useGetGlobalVariables();
|
||||
const saveFlow = useSaveFlow();
|
||||
|
||||
|
|
@ -106,7 +107,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
|
|||
</main>
|
||||
</div>
|
||||
)}
|
||||
{FeatureFlags.ENABLE_BRANDING && version && (
|
||||
{ENABLE_BRANDING && version && (
|
||||
<a
|
||||
target={"_blank"}
|
||||
href="https://medium.com/logspace/langflow-datastax-better-together-1b7462cebc4d"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useLoginUser } from "@/controllers/API/queries/auth";
|
||||
import { CustomLink } from "@/customization/components/custom-link";
|
||||
import * as Form from "@radix-ui/react-form";
|
||||
import { useContext, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import InputComponent from "../../components/inputComponent";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { Input } from "../../components/ui/input";
|
||||
|
|
@ -124,11 +124,11 @@ export default function LoginPage(): JSX.Element {
|
|||
</Form.Submit>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<Link to="/signup">
|
||||
<CustomLink to="/signup">
|
||||
<Button className="w-full" variant="outline" type="button">
|
||||
Don't have an account? <b>Sign Up</b>
|
||||
</Button>
|
||||
</Link>
|
||||
</CustomLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { Link, useNavigate, useParams } from "react-router-dom";
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import { useParams } from "react-router-dom";
|
||||
import CollectionCardComponent from "../../../../../../components/cardComponent";
|
||||
import IconComponent from "../../../../../../components/genericIconComponent";
|
||||
import { Button } from "../../../../../../components/ui/button";
|
||||
const CollectionCard = ({ item, type, isLoading, control }) => {
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
const isComponent = item.is_component ?? false;
|
||||
const editFlowButtonTestId = `edit-flow-button-${item.id}`;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
type TabsSearchComponentProps = {
|
||||
tabsOptions: string[];
|
||||
|
|
@ -14,23 +14,23 @@ const TabsSearchComponent = ({
|
|||
loading,
|
||||
tabActive,
|
||||
}: TabsSearchComponentProps) => {
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
|
||||
const changeLocation = (tabOption) => {
|
||||
const location = window.location.pathname;
|
||||
let newLocation = "";
|
||||
switch (tabOption) {
|
||||
case "Flows":
|
||||
newLocation = location.replace(/components|all/, "flows");
|
||||
newLocation = location.replace(/.*\/(?:all|components)/, "/flows");
|
||||
break;
|
||||
case "Components":
|
||||
newLocation = location.replace(/flows|all/, "components");
|
||||
newLocation = location.replace(/.*\/(?:flows|all)/, "/components");
|
||||
break;
|
||||
default:
|
||||
newLocation = location.replace(/flows|components/, "all");
|
||||
newLocation = location.replace(/.*\/(?:flows|components)/, "/all");
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(newLocation);
|
||||
navigate(newLocation);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import FolderSidebarNav from "@/components/folderSidebarComponent";
|
||||
import { useDeleteFolders } from "@/controllers/API/queries/folders";
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import useAlertStore from "@/stores/alertStore";
|
||||
import { useState } from "react";
|
||||
import { Outlet, useLocation, useNavigate } from "react-router-dom";
|
||||
import { Outlet, useLocation } from "react-router-dom";
|
||||
import DropdownButton from "../../../../components/dropdownButtonComponent";
|
||||
import PageLayout from "../../../../components/pageLayout";
|
||||
import {
|
||||
|
|
@ -18,9 +19,9 @@ export default function HomePage(): JSX.Element {
|
|||
const pathname = location.pathname;
|
||||
const [openModal, setOpenModal] = useState(false);
|
||||
const [openDeleteFolderModal, setOpenDeleteFolderModal] = useState(false);
|
||||
const is_component = pathname === "/components";
|
||||
const is_component = pathname.includes("/components");
|
||||
const setFolderToEdit = useFolderStore((state) => state.setFolderToEdit);
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
|
||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
|
||||
import { useGetGlobalVariables } from "@/controllers/API/queries/variables";
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import { useStoreStore } from "@/stores/storeStore";
|
||||
import { useTypesStore } from "@/stores/typesStore";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getComponent } from "../../controllers/API";
|
||||
import IOModal from "../../modals/IOModal";
|
||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||
|
|
@ -22,7 +23,7 @@ export default function PlaygroundPage() {
|
|||
return newFlow;
|
||||
}
|
||||
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
useGetGlobalVariables();
|
||||
|
||||
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import FeatureFlags from "@/../feature-config.json";
|
||||
import { ENABLE_PROFILE_ICONS } from "@/customization/feature-flags";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import { useStoreStore } from "@/stores/storeStore";
|
||||
import { Outlet } from "react-router-dom";
|
||||
|
|
@ -11,8 +11,7 @@ export default function SettingsPage(): JSX.Element {
|
|||
const hasStore = useStoreStore((state) => state.hasStore);
|
||||
|
||||
// Hides the General settings if there is nothing to show
|
||||
const showGeneralSettings =
|
||||
FeatureFlags.ENABLE_PROFILE_ICONS || hasStore || !autoLogin;
|
||||
const showGeneralSettings = ENABLE_PROFILE_ICONS || hasStore || !autoLogin;
|
||||
|
||||
const sidebarNavItems: {
|
||||
href?: string;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import FeatureFlags from "@/../feature-config.json";
|
||||
import {
|
||||
EDIT_PASSWORD_ALERT_LIST,
|
||||
EDIT_PASSWORD_ERROR_ALERT,
|
||||
|
|
@ -11,6 +10,7 @@ import {
|
|||
useUpdateUser,
|
||||
} from "@/controllers/API/queries/auth";
|
||||
import { useGetProfilePicturesQuery } from "@/controllers/API/queries/files";
|
||||
import { ENABLE_PROFILE_ICONS } from "@/customization/feature-flags";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useContext, useState } from "react";
|
||||
|
|
@ -146,7 +146,7 @@ export const GeneralPage = () => {
|
|||
<GeneralPageHeaderComponent />
|
||||
|
||||
<div className="grid gap-6">
|
||||
{FeatureFlags.ENABLE_PROFILE_ICONS && (
|
||||
{ENABLE_PROFILE_ICONS && (
|
||||
<ProfilePictureFormComponent
|
||||
profilePicture={profilePicture}
|
||||
handleInput={handleInput}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { useAddUser } from "@/controllers/API/queries/auth";
|
||||
import { CustomLink } from "@/customization/components/custom-link";
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import * as Form from "@radix-ui/react-form";
|
||||
import { FormEvent, useEffect, useState } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import InputComponent from "../../components/inputComponent";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { Input } from "../../components/ui/input";
|
||||
|
|
@ -26,7 +27,7 @@ export default function SignUp(): JSX.Element {
|
|||
const { password, cnfPassword, username } = inputState;
|
||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
|
||||
const { mutate: mutateAddUser } = useAddUser();
|
||||
|
||||
|
|
@ -184,11 +185,11 @@ export default function SignUp(): JSX.Element {
|
|||
</Form.Submit>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<Link to="/login">
|
||||
<CustomLink to="/login">
|
||||
<Button className="w-full" variant="outline">
|
||||
Already have an account? <b>Sign in</b>
|
||||
</Button>
|
||||
</Link>
|
||||
</CustomLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { uniqueId } from "lodash";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import CollectionCardComponent from "../../components/cardComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import PageLayout from "../../components/pageLayout";
|
||||
import ShadTooltip from "../../components/shadTooltipComponent";
|
||||
|
|
@ -9,7 +8,9 @@ import { Button } from "../../components/ui/button";
|
|||
|
||||
import StoreCardComponent from "@/components/storeCardComponent";
|
||||
import { useGetTagsQuery } from "@/controllers/API/queries/store";
|
||||
import { Link, useNavigate, useParams } from "react-router-dom";
|
||||
import { CustomLink } from "@/customization/components/custom-link";
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import { useParams } from "react-router-dom";
|
||||
import PaginatorComponent from "../../components/paginatorComponent";
|
||||
import { TagsSelector } from "../../components/tagsSelectorComponent";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
|
|
@ -62,7 +63,7 @@ export default function StorePage(): JSX.Element {
|
|||
const [selectFilter, setSelectFilter] = useState("all");
|
||||
const { isFetching, data } = useGetTagsQuery();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
if (!loadingApiKey) {
|
||||
|
|
@ -289,9 +290,9 @@ export default function StorePage(): JSX.Element {
|
|||
size="sq"
|
||||
className="gap-2 bg-beta-foreground text-background hover:bg-beta-foreground"
|
||||
>
|
||||
<Link to={"/store"} className="cursor-pointer">
|
||||
<CustomLink to={"/store"} className="cursor-pointer">
|
||||
<IconComponent name="X" className="h-4 w-4" />
|
||||
</Link>
|
||||
</CustomLink>
|
||||
{id}
|
||||
</Badge>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
|
||||
import { useGetGlobalVariables } from "@/controllers/API/queries/variables";
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import { useTypesStore } from "@/stores/typesStore";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useParams } from "react-router-dom";
|
||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||
import Page from "../FlowPage/components/PageComponent";
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ export default function ViewPage() {
|
|||
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
|
||||
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const navigate = useCustomNavigate();
|
||||
useGetGlobalVariables();
|
||||
|
||||
const flows = useFlowsManagerStore((state) => state.flows);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { lazy } from "react";
|
|||
import {
|
||||
createBrowserRouter,
|
||||
createRoutesFromElements,
|
||||
Navigate,
|
||||
Outlet,
|
||||
Route,
|
||||
} from "react-router-dom";
|
||||
|
|
@ -12,6 +11,9 @@ import { ProtectedLoginRoute } from "./components/authLoginGuard";
|
|||
import { AuthSettingsGuard } from "./components/authSettingsGuard";
|
||||
import { StoreGuard } from "./components/storeGuard";
|
||||
import ContextWrapper from "./contexts";
|
||||
import { CustomNavigate } from "./customization/components/custom-navigate";
|
||||
import { BASENAME } from "./customization/config-constants";
|
||||
import { ENABLE_CUSTOM_PARAM } from "./customization/feature-flags";
|
||||
import { AppInitPage } from "./pages/AppInitPage";
|
||||
import { AppWrapperPage } from "./pages/AppWrapperPage";
|
||||
import { DashboardWrapperPage } from "./pages/DashboardWrapperPage";
|
||||
|
|
@ -38,7 +40,7 @@ const SignUp = lazy(() => import("./pages/SignUpPage"));
|
|||
const router = createBrowserRouter(
|
||||
createRoutesFromElements([
|
||||
<Route
|
||||
path="/"
|
||||
path={ENABLE_CUSTOM_PARAM ? "/:customParam" : "/"}
|
||||
element={
|
||||
<ContextWrapper>
|
||||
<Outlet />
|
||||
|
|
@ -57,7 +59,7 @@ const router = createBrowserRouter(
|
|||
>
|
||||
<Route path="" element={<DashboardWrapperPage />}>
|
||||
<Route path="" element={<HomePage />}>
|
||||
<Route index element={<Navigate replace to={"all"} />} />
|
||||
<Route index element={<CustomNavigate replace to={"all"} />} />
|
||||
<Route
|
||||
path="flows/"
|
||||
element={<MyCollectionComponent key="flows" type="flow" />}
|
||||
|
|
@ -93,8 +95,11 @@ const router = createBrowserRouter(
|
|||
/>
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="/settings" element={<SettingsPage />}>
|
||||
<Route index element={<Navigate replace to={"general"} />} />
|
||||
<Route path="settings" element={<SettingsPage />}>
|
||||
<Route
|
||||
index
|
||||
element={<CustomNavigate replace to={"general"} />}
|
||||
/>
|
||||
<Route
|
||||
path="global-variables"
|
||||
element={<GlobalVariablesPage />}
|
||||
|
|
@ -112,7 +117,7 @@ const router = createBrowserRouter(
|
|||
<Route path="messages" element={<MessagesPage />} />
|
||||
</Route>
|
||||
<Route
|
||||
path="/store"
|
||||
path="store"
|
||||
element={
|
||||
<StoreGuard>
|
||||
<StorePage />
|
||||
|
|
@ -120,18 +125,18 @@ const router = createBrowserRouter(
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/store/:id/"
|
||||
path="store/:id/"
|
||||
element={
|
||||
<StoreGuard>
|
||||
<StorePage />
|
||||
</StoreGuard>
|
||||
}
|
||||
/>
|
||||
<Route path="/account">
|
||||
<Route path="account">
|
||||
<Route path="delete" element={<DeleteAccountPage />}></Route>
|
||||
</Route>
|
||||
<Route
|
||||
path="/admin"
|
||||
path="admin"
|
||||
element={
|
||||
<ProtectedAdminRoute>
|
||||
<AdminPage />
|
||||
|
|
@ -139,19 +144,19 @@ const router = createBrowserRouter(
|
|||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/flow/:id/">
|
||||
<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="playground/:id/">
|
||||
<Route path="" element={<PlaygroundPage />} />
|
||||
</Route>
|
||||
</Route>
|
||||
<Route
|
||||
path="/login"
|
||||
path="login"
|
||||
element={
|
||||
<ProtectedLoginRoute>
|
||||
<LoginPage />
|
||||
|
|
@ -159,7 +164,7 @@ const router = createBrowserRouter(
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/signup"
|
||||
path="signup"
|
||||
element={
|
||||
<ProtectedLoginRoute>
|
||||
<SignUp />
|
||||
|
|
@ -167,18 +172,19 @@ const router = createBrowserRouter(
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/login/admin"
|
||||
path="login/admin"
|
||||
element={
|
||||
<ProtectedLoginRoute>
|
||||
<LoginAdminPage />
|
||||
</ProtectedLoginRoute>
|
||||
}
|
||||
/>
|
||||
<Route path="*" element={<Navigate replace to="/" />} />
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="*" element={<CustomNavigate replace to="/" />} />
|
||||
</Route>,
|
||||
]),
|
||||
{ basename: BASENAME || undefined },
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@ const useAuthStore = create<AuthStoreType>((set, get) => ({
|
|||
autoLogin: false,
|
||||
apiKey: null,
|
||||
});
|
||||
|
||||
window.location.href = "/login";
|
||||
},
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import FeatureFlags from "@/../feature-config.json";
|
||||
import { ENABLE_LANGFLOW_STORE } from "@/customization/feature-flags";
|
||||
import { create } from "zustand";
|
||||
import { checkHasApiKey, checkHasStore } from "../controllers/API";
|
||||
import { StoreStoreType } from "../types/zustand/store";
|
||||
|
||||
export const useStoreStore = create<StoreStoreType>((set) => ({
|
||||
hasStore: true,
|
||||
hasStore: ENABLE_LANGFLOW_STORE,
|
||||
validApiKey: false,
|
||||
hasApiKey: false,
|
||||
loadingApiKey: true,
|
||||
checkHasStore: () => {
|
||||
checkHasStore().then((res) => {
|
||||
set({
|
||||
hasStore: FeatureFlags.ENABLE_LANGFLOW_STORE && (res?.enabled ?? false),
|
||||
hasStore: ENABLE_LANGFLOW_STORE && (res?.enabled ?? false),
|
||||
});
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -58,6 +58,5 @@
|
|||
"tests/scheduled-end-to-end/twoEdges.spec.ts",
|
||||
"tests/scheduled-end-to-end/userSettings.spec.ts",
|
||||
"tests/end-to-end/store.spec.ts",
|
||||
"tests/end-to-end/logs.spec.ts"
|
||||
]
|
||||
"tests/end-to-end/logs.spec.ts" ]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,17 +4,24 @@ import path from "path";
|
|||
import { defineConfig } from "vite";
|
||||
import svgr from "vite-plugin-svgr";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
import {
|
||||
API_ROUTES,
|
||||
BASENAME,
|
||||
PORT,
|
||||
PROXY_TARGET,
|
||||
} from "./src/customization/config-constants";
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
dotenv.config({ path: path.resolve(__dirname, "../../.env") });
|
||||
|
||||
const apiRoutes = ["^/api/v1/", "/health"];
|
||||
const apiRoutes = API_ROUTES || ["^/api/v1/", "/health"];
|
||||
|
||||
// Use environment variable to determine the target.
|
||||
const target = process.env.VITE_PROXY_TARGET || "http://127.0.0.1:7860";
|
||||
const target =
|
||||
process.env.VITE_PROXY_TARGET || PROXY_TARGET || "http://127.0.0.1:7860";
|
||||
|
||||
// Use environment variable to determine the UI server port
|
||||
const port = Number(process.env.VITE_PORT) || 3000;
|
||||
const port = Number(process.env.VITE_PORT) || PORT || 3000;
|
||||
|
||||
const proxyTargets = apiRoutes.reduce((proxyObj, route) => {
|
||||
proxyObj[route] = {
|
||||
|
|
@ -27,6 +34,7 @@ export default defineConfig(({ mode }) => {
|
|||
}, {});
|
||||
|
||||
return {
|
||||
basename: (BASENAME || "") + "/",
|
||||
build: {
|
||||
outDir: "build",
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue