diff --git a/src/frontend/feature-config.json b/src/frontend/feature-config.json deleted file mode 100644 index 04884cbc8..000000000 --- a/src/frontend/feature-config.json +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index 6453ee504..f11db681d 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -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", }, diff --git a/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx b/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx index d51695645..17d32f864 100644 --- a/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx +++ b/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx @@ -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({

{dropItem.link ? ( - Details - + ) : ( <> )} diff --git a/src/frontend/src/alerts/notice/index.tsx b/src/frontend/src/alerts/notice/index.tsx index 34c9595c6..053e382d4 100644 --- a/src/frontend/src/alerts/notice/index.tsx +++ b/src/frontend/src/alerts/notice/index.tsx @@ -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({

{link !== "" ? ( - Details - + ) : ( <> )} diff --git a/src/frontend/src/components/authAdminGuard/index.tsx b/src/frontend/src/components/authAdminGuard/index.tsx index f4a60dbaf..86a562515 100644 --- a/src/frontend/src/components/authAdminGuard/index.tsx +++ b/src/frontend/src/components/authAdminGuard/index.tsx @@ -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 ; } else if ((userData && !isAdmin) || autoLogin) { - return ; + return ; } else { return children; } diff --git a/src/frontend/src/components/authGuard/index.tsx b/src/frontend/src/components/authGuard/index.tsx index a64ba8c6d..d6b4bda42 100644 --- a/src/frontend/src/components/authGuard/index.tsx +++ b/src/frontend/src/components/authGuard/index.tsx @@ -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; } diff --git a/src/frontend/src/components/authLoginGuard/index.tsx b/src/frontend/src/components/authLoginGuard/index.tsx index 5357c505c..9c2c99beb 100644 --- a/src/frontend/src/components/authLoginGuard/index.tsx +++ b/src/frontend/src/components/authLoginGuard/index.tsx @@ -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 ; + return ; } if (isAuthenticated) { - window.location.replace("/"); - return ; + return ; } return children; diff --git a/src/frontend/src/components/authSettingsGuard/index.tsx b/src/frontend/src/components/authSettingsGuard/index.tsx index 90bf63dd9..2c7d53526 100644 --- a/src/frontend/src/components/authSettingsGuard/index.tsx +++ b/src/frontend/src/components/authSettingsGuard/index.tsx @@ -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 ; + return ; } }; diff --git a/src/frontend/src/components/catchAllRoutes/index.tsx b/src/frontend/src/components/catchAllRoutes/index.tsx index 06faa9099..1a2f471b0 100644 --- a/src/frontend/src/components/catchAllRoutes/index.tsx +++ b/src/frontend/src/components/catchAllRoutes/index.tsx @@ -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(() => { diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 1b40466e1..817d1b2f7 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -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 {

- {FeatureFlags.ENABLE_API && ( + {ENABLE_API && ( <>
{currentFlow && currentFlow.data && ( diff --git a/src/frontend/src/components/folderSidebarComponent/components/sideBarFolderButtons/index.tsx b/src/frontend/src/components/folderSidebarComponent/components/sideBarFolderButtons/index.tsx index 49b7d7d4c..ad24f2803 100644 --- a/src/frontend/src/components/folderSidebarComponent/components/sideBarFolderButtons/index.tsx +++ b/src/frontend/src/components/folderSidebarComponent/components/sideBarFolderButtons/index.tsx @@ -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); diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index 60c4eecd3..48860766c 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -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(); diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index 6bea5de6f..2e741fa22 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -1,7 +1,7 @@ import { useContext } from "react"; import { FaDiscord, FaGithub } from "react-icons/fa"; import { RiTwitterXFill } from "react-icons/ri"; -import { Link, useLocation, useNavigate } 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 (
- + ⛓️ - + {showArrowReturnIcon && ( - + {hasStore && ( - + - + )}
- {FeatureFlags.ENABLE_SOCIAL_LINKS && ( + {ENABLE_SOCIAL_LINKS && ( <> )} - {FeatureFlags.ENABLE_DARK_MODE && ( + {ENABLE_DARK_MODE && (
); diff --git a/src/frontend/src/components/storeGuard/index.tsx b/src/frontend/src/components/storeGuard/index.tsx index 87f407656..08354e8a3 100644 --- a/src/frontend/src/components/storeGuard/index.tsx +++ b/src/frontend/src/components/storeGuard/index.tsx @@ -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 ; + return ; } return children; diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index e59a47124..51a53e0f7 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -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`, ]; diff --git a/src/frontend/src/contexts/index.tsx b/src/frontend/src/contexts/index.tsx index 66bf9629e..c0c7a5b0b 100644 --- a/src/frontend/src/contexts/index.tsx +++ b/src/frontend/src/contexts/index.tsx @@ -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 ( <> - - - - - - {children} - - - - + + + + + + + {children} + + + + + ); } diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index 1a5091860..ce04a80bc 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -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"); }, }, diff --git a/src/frontend/src/controllers/API/queries/api-keys/use-delete-api-key.ts b/src/frontend/src/controllers/API/queries/api-keys/use-delete-api-key.ts index a0ec09204..b70914318 100644 --- a/src/frontend/src/controllers/API/queries/api-keys/use-delete-api-key.ts +++ b/src/frontend/src/controllers/API/queries/api-keys/use-delete-api-key.ts @@ -8,9 +8,10 @@ interface IDeleteApiKey { } // add types for error handling and success -export const useDeleteApiKey: useMutationFunctionType = ( - options, -) => { +export const useDeleteApiKey: useMutationFunctionType< + undefined, + IDeleteApiKey +> = (options) => { const { mutate } = UseRequestProcessor(); const deleteApiKeyFn = async (payload: IDeleteApiKey): Promise => { diff --git a/src/frontend/src/controllers/API/queries/auth/use-get-autologin.ts b/src/frontend/src/controllers/API/queries/auth/use-get-autologin.ts index d4bb7c710..9900e3169 100644 --- a/src/frontend/src/controllers/API/queries/auth/use-get-autologin.ts +++ b/src/frontend/src/controllers/API/queries/auth/use-get-autologin.ts @@ -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 = ( 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 { try { @@ -40,7 +41,7 @@ export const useGetAutoLogin: useQueryFunctionType = ( setAutoLogin(false); if (!isLoginPage) { if (!isAuthenticated) { - await logout(); + mutationLogout(); throw new Error("Unauthorized"); } else { getUser(); diff --git a/src/frontend/src/controllers/API/queries/auth/use-post-logout.ts b/src/frontend/src/controllers/API/queries/auth/use-post-logout.ts index 80aa0c15a..c5b2d6596 100644 --- a/src/frontend/src/controllers/API/queries/auth/use-post-logout.ts +++ b/src/frontend/src/controllers/API/queries/auth/use-post-logout.ts @@ -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 = ( options?, ) => { const { mutate } = UseRequestProcessor(); + const navigate = useCustomNavigate(); const logout = useAuthStore((state) => state.logout); async function logoutUser(): Promise { @@ -23,6 +25,7 @@ export const useLogout: useMutationFunctionType = ( const mutation = mutate(["useLogout"], logoutUser, { onSuccess: () => { logout(); + navigate("/login"); }, onError: (error) => { console.error(error); diff --git a/src/frontend/src/controllers/API/queries/config/use-get-config.ts b/src/frontend/src/controllers/API/queries/config/use-get-config.ts index 975b21b3e..da1adfcd8 100644 --- a/src/frontend/src/controllers/API/queries/config/use-get-config.ts +++ b/src/frontend/src/controllers/API/queries/config/use-get-config.ts @@ -12,7 +12,7 @@ export interface ConfigResponse { health_check_max_retries: number; } -export const useGetConfig: useQueryFunctionType = ( +export const useGetConfig: useQueryFunctionType = ( options, ) => { const setAutoSaving = useFlowsManagerStore((state) => state.setAutoSaving); @@ -38,6 +38,7 @@ export const useGetConfig: useQueryFunctionType = ( setAutoSavingInterval(data.auto_saving_interval); setHealthCheckMaxRetries(data.health_check_max_retries); } + return data; }; const queryResult = query(["useGetConfig"], getConfigFn, options); diff --git a/src/frontend/src/controllers/API/utils.tsx b/src/frontend/src/controllers/API/utils.tsx deleted file mode 100644 index 3991caa2e..000000000 --- a/src/frontend/src/controllers/API/utils.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import axios from "axios"; -import { BASE_URL_API } from "../../constants/constants"; - -/** - * Fetches the configuration data from the API. - * @returns {Promise} 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; -} diff --git a/src/frontend/src/customization/components/custom-header.tsx b/src/frontend/src/customization/components/custom-header.tsx new file mode 100644 index 000000000..c8b3cdcfe --- /dev/null +++ b/src/frontend/src/customization/components/custom-header.tsx @@ -0,0 +1,3 @@ +export function CustomHeader() { + return <>; +} diff --git a/src/frontend/src/customization/components/custom-link.tsx b/src/frontend/src/customization/components/custom-link.tsx new file mode 100644 index 000000000..68e97ac8b --- /dev/null +++ b/src/frontend/src/customization/components/custom-link.tsx @@ -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 ; +} diff --git a/src/frontend/src/customization/components/custom-navigate.tsx b/src/frontend/src/customization/components/custom-navigate.tsx new file mode 100644 index 000000000..6493bd5c9 --- /dev/null +++ b/src/frontend/src/customization/components/custom-navigate.tsx @@ -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 ; +} diff --git a/src/frontend/src/customization/config-constants.ts b/src/frontend/src/customization/config-constants.ts new file mode 100644 index 000000000..1f4a28a59 --- /dev/null +++ b/src/frontend/src/customization/config-constants.ts @@ -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, +}; diff --git a/src/frontend/src/customization/custom-wrapper.tsx b/src/frontend/src/customization/custom-wrapper.tsx new file mode 100644 index 000000000..b4be3f539 --- /dev/null +++ b/src/frontend/src/customization/custom-wrapper.tsx @@ -0,0 +1,3 @@ +export function CustomWrapper({ children }) { + return children; +} diff --git a/src/frontend/src/customization/feature-flags.ts b/src/frontend/src/customization/feature-flags.ts new file mode 100644 index 000000000..db68d0045 --- /dev/null +++ b/src/frontend/src/customization/feature-flags.ts @@ -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; diff --git a/src/frontend/src/customization/hooks/use-custom-api-headers.ts b/src/frontend/src/customization/hooks/use-custom-api-headers.ts new file mode 100644 index 000000000..edabcdd2b --- /dev/null +++ b/src/frontend/src/customization/hooks/use-custom-api-headers.ts @@ -0,0 +1,5 @@ +export function useCustomApiHeaders() { + const customHeaders = {}; + + return customHeaders; +} diff --git a/src/frontend/src/customization/hooks/use-custom-navigate.ts b/src/frontend/src/customization/hooks/use-custom-navigate.ts new file mode 100644 index 000000000..cd32efefd --- /dev/null +++ b/src/frontend/src/customization/hooks/use-custom-navigate.ts @@ -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; +} diff --git a/src/frontend/src/customization/hooks/use-primary-loading.ts b/src/frontend/src/customization/hooks/use-primary-loading.ts new file mode 100644 index 000000000..4b3853cd0 --- /dev/null +++ b/src/frontend/src/customization/hooks/use-primary-loading.ts @@ -0,0 +1,20 @@ +import { UseRequestProcessor } from "@/controllers/API/services/request-processor"; +import { useQueryFunctionType } from "@/types/api"; + +export const usePrimaryLoading: useQueryFunctionType = ( + options, +) => { + const { query } = UseRequestProcessor(); + + const getPrimaryLoadingFn = async () => { + return null; + }; + + const queryResult = query( + ["usePrimaryLoading"], + getPrimaryLoadingFn, + options, + ); + + return queryResult; +}; diff --git a/src/frontend/src/modals/IOModal/components/chatView/fileComponent/index.tsx b/src/frontend/src/modals/IOModal/components/chatView/fileComponent/index.tsx index 704d9934c..7af61165b 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/fileComponent/index.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/fileComponent/index.tsx @@ -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"; diff --git a/src/frontend/src/modals/newFlowModal/components/NewFlowCardComponent/index.tsx b/src/frontend/src/modals/newFlowModal/components/NewFlowCardComponent/index.tsx index ed7885f48..05c87c68b 100644 --- a/src/frontend/src/modals/newFlowModal/components/NewFlowCardComponent/index.tsx +++ b/src/frontend/src/modals/newFlowModal/components/NewFlowCardComponent/index.tsx @@ -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 ( diff --git a/src/frontend/src/modals/newFlowModal/components/undrawCards/index.tsx b/src/frontend/src/modals/newFlowModal/components/undrawCards/index.tsx index d0a5cd785..0bcfb75ef 100644 --- a/src/frontend/src/modals/newFlowModal/components/undrawCards/index.tsx +++ b/src/frontend/src/modals/newFlowModal/components/undrawCards/index.tsx @@ -1,5 +1,5 @@ /// -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); diff --git a/src/frontend/src/pages/AppInitPage/index.tsx b/src/frontend/src/pages/AppInitPage/index.tsx index a724a21b9..80dab69ab 100644 --- a/src/frontend/src/pages/AppInitPage/index.tsx +++ b/src/frontend/src/pages/AppInitPage/index.tsx @@ -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 }); diff --git a/src/frontend/src/pages/AppWrapperPage/index.tsx b/src/frontend/src/pages/AppWrapperPage/index.tsx index e1a0c7a93..e28cb29a3 100644 --- a/src/frontend/src/pages/AppWrapperPage/index.tsx +++ b/src/frontend/src/pages/AppWrapperPage/index.tsx @@ -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 (
+ { // any reset function @@ -107,7 +109,6 @@ export function AppWrapperPage() { -
diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx index bdfe87228..efc6a1e24 100644 --- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx @@ -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") } />
)} - {FeatureFlags.ENABLE_MVPS && ( + {ENABLE_MVPS && ( <> diff --git a/src/frontend/src/pages/FlowPage/index.tsx b/src/frontend/src/pages/FlowPage/index.tsx index 0321d9e11..9c622ded5 100644 --- a/src/frontend/src/pages/FlowPage/index.tsx +++ b/src/frontend/src/pages/FlowPage/index.tsx @@ -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 {
)} - {FeatureFlags.ENABLE_BRANDING && version && ( + {ENABLE_BRANDING && version && (
- + - +
diff --git a/src/frontend/src/pages/MainPage/components/componentsComponent/components/collectionCard/index.tsx b/src/frontend/src/pages/MainPage/components/componentsComponent/components/collectionCard/index.tsx index ed50edb1d..5b25755ff 100644 --- a/src/frontend/src/pages/MainPage/components/componentsComponent/components/collectionCard/index.tsx +++ b/src/frontend/src/pages/MainPage/components/componentsComponent/components/collectionCard/index.tsx @@ -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}`; diff --git a/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/tabsComponent/index.tsx b/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/tabsComponent/index.tsx index 083ed1fd7..08beb19fd 100644 --- a/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/tabsComponent/index.tsx +++ b/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/tabsComponent/index.tsx @@ -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); }; diff --git a/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx b/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx index bc0a83124..a351fa171 100644 --- a/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx @@ -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); diff --git a/src/frontend/src/pages/Playground/index.tsx b/src/frontend/src/pages/Playground/index.tsx index 81155b7b3..7671e58c6 100644 --- a/src/frontend/src/pages/Playground/index.tsx +++ b/src/frontend/src/pages/Playground/index.tsx @@ -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); diff --git a/src/frontend/src/pages/SettingsPage/index.tsx b/src/frontend/src/pages/SettingsPage/index.tsx index 297aba418..dd8b8ca95 100644 --- a/src/frontend/src/pages/SettingsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/index.tsx @@ -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; diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx index a4570f7c5..e5cbe5bef 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx @@ -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 = () => {
- {FeatureFlags.ENABLE_PROFILE_ICONS && ( + {ENABLE_PROFILE_ICONS && ( 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 {
- + - +
diff --git a/src/frontend/src/pages/StorePage/index.tsx b/src/frontend/src/pages/StorePage/index.tsx index d278581e9..e0cad6f3e 100644 --- a/src/frontend/src/pages/StorePage/index.tsx +++ b/src/frontend/src/pages/StorePage/index.tsx @@ -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" > - + - + {id} )} diff --git a/src/frontend/src/pages/ViewPage/index.tsx b/src/frontend/src/pages/ViewPage/index.tsx index 5c9de515a..c5bf14fc4 100644 --- a/src/frontend/src/pages/ViewPage/index.tsx +++ b/src/frontend/src/pages/ViewPage/index.tsx @@ -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); diff --git a/src/frontend/src/routes.tsx b/src/frontend/src/routes.tsx index ded7e48bd..913a19b64 100644 --- a/src/frontend/src/routes.tsx +++ b/src/frontend/src/routes.tsx @@ -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([ @@ -57,7 +59,7 @@ const router = createBrowserRouter( > }> }> - } /> + } /> } @@ -93,8 +95,11 @@ const router = createBrowserRouter( /> - }> - } /> + }> + } + /> } @@ -112,7 +117,7 @@ const router = createBrowserRouter( } /> @@ -120,18 +125,18 @@ const router = createBrowserRouter( } /> } /> - + }> @@ -139,19 +144,19 @@ const router = createBrowserRouter( } /> - + }> } /> } /> } /> - + } /> @@ -159,7 +164,7 @@ const router = createBrowserRouter( } /> @@ -167,18 +172,19 @@ const router = createBrowserRouter( } /> } /> - } /> + } /> , ]), + { basename: BASENAME || undefined }, ); export default router; diff --git a/src/frontend/src/stores/authStore.ts b/src/frontend/src/stores/authStore.ts index c821baf85..a588ed4c0 100644 --- a/src/frontend/src/stores/authStore.ts +++ b/src/frontend/src/stores/authStore.ts @@ -35,8 +35,6 @@ const useAuthStore = create((set, get) => ({ autoLogin: false, apiKey: null, }); - - window.location.href = "/login"; }, })); diff --git a/src/frontend/src/stores/storeStore.ts b/src/frontend/src/stores/storeStore.ts index aadc40141..a72e3ea9c 100644 --- a/src/frontend/src/stores/storeStore.ts +++ b/src/frontend/src/stores/storeStore.ts @@ -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((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), }); }); }, diff --git a/src/frontend/tsconfig.json b/src/frontend/tsconfig.json index 6704d97b2..1a5e31f0a 100644 --- a/src/frontend/tsconfig.json +++ b/src/frontend/tsconfig.json @@ -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" ] } diff --git a/src/frontend/vite.config.mts b/src/frontend/vite.config.mts index 24e4c1795..353f12014 100644 --- a/src/frontend/vite.config.mts +++ b/src/frontend/vite.config.mts @@ -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", },