diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index 4230dd6ba..a37489700 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -1,6 +1,7 @@ import ForwardedIconComponent from "@/components/common/genericIconComponent"; import ShadTooltip from "@/components/common/shadTooltipComponent"; import { usePostValidateComponentCode } from "@/controllers/API/queries/nodes/use-post-validate-component-code"; +import { CustomNodeStatus } from "@/customization/components/custom-NodeStatus"; import UpdateComponentModal from "@/modals/updateComponentModal"; import { useAlternate } from "@/shared/hooks/use-alternate"; import { FlowStoreType } from "@/types/zustand/flow"; @@ -40,7 +41,7 @@ const MemoizedOutputParameter = memo(OutputParameter); const MemoizedRenderInputParameters = memo(RenderInputParameters); const MemoizedNodeIcon = memo(NodeIcon); const MemoizedNodeName = memo(NodeName); -const MemoizedNodeStatus = memo(NodeStatus); +const MemoizedNodeStatus = memo(CustomNodeStatus); const MemoizedNodeDescription = memo(NodeDescription); const HiddenOutputsButton = memo( diff --git a/src/frontend/src/assets/langflow_logo_black.svg b/src/frontend/src/assets/langflow_logo_black.svg new file mode 100644 index 000000000..393a9d409 --- /dev/null +++ b/src/frontend/src/assets/langflow_logo_black.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/frontend/src/assets/langflow_logo_white.svg b/src/frontend/src/assets/langflow_logo_white.svg new file mode 100644 index 000000000..503064951 --- /dev/null +++ b/src/frontend/src/assets/langflow_logo_white.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/frontend/src/components/common/storeCardComponent/index.tsx b/src/frontend/src/components/common/storeCardComponent/index.tsx index d3e3b17a0..85bb6ce22 100644 --- a/src/frontend/src/components/common/storeCardComponent/index.tsx +++ b/src/frontend/src/components/common/storeCardComponent/index.tsx @@ -266,16 +266,6 @@ export default function StoreCardComponent({ - {/* {openPlayground && ( - - <> - - )} */} ); } diff --git a/src/frontend/src/components/core/appHeaderComponent/components/AccountMenu/index.tsx b/src/frontend/src/components/core/appHeaderComponent/components/AccountMenu/index.tsx index 286b6829d..be5367531 100644 --- a/src/frontend/src/components/core/appHeaderComponent/components/AccountMenu/index.tsx +++ b/src/frontend/src/components/core/appHeaderComponent/components/AccountMenu/index.tsx @@ -7,6 +7,7 @@ import { TWITTER_URL, } from "@/constants/constants"; import { useLogout } from "@/controllers/API/queries/auth"; +import { CustomProfileIcon } from "@/customization/components/custom-profile-icon"; import { ENABLE_DATASTAX_LANGFLOW } from "@/customization/feature-flags"; import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate"; import useAuthStore from "@/stores/authStore"; @@ -50,7 +51,7 @@ export const AccountMenu = () => { className="h-6 w-6 rounded-lg focus-visible:outline-0" data-testid="user-profile-settings" > - + diff --git a/src/frontend/src/components/core/appHeaderComponent/index.tsx b/src/frontend/src/components/core/appHeaderComponent/index.tsx index 11a4eecf2..e9f88b8ad 100644 --- a/src/frontend/src/components/core/appHeaderComponent/index.tsx +++ b/src/frontend/src/components/core/appHeaderComponent/index.tsx @@ -5,6 +5,8 @@ import ForwardedIconComponent from "@/components/common/genericIconComponent"; import ShadTooltip from "@/components/common/shadTooltipComponent"; import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; +import CustomAccountMenu from "@/customization/components/custom-AccountMenu"; +import CustomLangflowCounts from "@/customization/components/custom-langflow-counts"; import { CustomOrgSelector } from "@/customization/components/custom-org-selector"; import { CustomProductSelector } from "@/customization/components/custom-product-selector"; import { ENABLE_DATASTAX_LANGFLOW } from "@/customization/feature-flags"; @@ -94,7 +96,7 @@ export default function AppHeader(): JSX.Element { unstyled className="hidden items-center whitespace-nowrap pr-2 lg:inline" > - +
- +
diff --git a/src/frontend/src/components/core/flowToolbarComponent/components/deploy-dropdown.tsx b/src/frontend/src/components/core/flowToolbarComponent/components/deploy-dropdown.tsx index 758ebba68..dea0559dc 100644 --- a/src/frontend/src/components/core/flowToolbarComponent/components/deploy-dropdown.tsx +++ b/src/frontend/src/components/core/flowToolbarComponent/components/deploy-dropdown.tsx @@ -11,6 +11,7 @@ import { Switch } from "@/components/ui/switch"; import { usePatchUpdateFlow } from "@/controllers/API/queries/flows/use-patch-update-flow"; import { CustomLink } from "@/customization/components/custom-link"; import { ENABLE_PUBLISH, ENABLE_WIDGET } from "@/customization/feature-flags"; +import { customMcpOpen } from "@/customization/utils/custom-mcp-open"; import ApiModal from "@/modals/apiModal/new-api-modal"; import EmbedModal from "@/modals/EmbedModal/embed-modal"; import useAlertStore from "@/stores/alertStore"; @@ -120,7 +121,7 @@ export default function PublishDropdown() { { return hasIO ? ( - - + ) : (
diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/header-buttons.tsx b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/header-buttons.tsx index f37e5fb49..2b852e5b3 100644 --- a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/header-buttons.tsx +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/header-buttons.tsx @@ -2,6 +2,7 @@ import IconComponent from "@/components/common/genericIconComponent"; import { GetStartedProgress } from "@/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/get-started-progress"; import { SidebarTrigger } from "@/components/ui/sidebar"; import { useUpdateUser } from "@/controllers/API/queries/auth"; +import CustomGetStartedProgress from "@/customization/components/custom-get-started-progress"; import useAuthStore from "@/stores/authStore"; import { Separator } from "@radix-ui/react-separator"; import { useState } from "react"; @@ -45,7 +46,7 @@ export const HeaderButtons = ({ <> {!isDismissedDialog && ( <> -
- {!ENABLE_DATASTAX_LANGFLOW && ( -
- { - window.open("/store", "_blank"); - }} - > - - Store - -
- )} + {!ENABLE_DATASTAX_LANGFLOW && } handleFilesClick?.()} diff --git a/src/frontend/src/components/core/parameterRenderComponent/components/connectionComponent/index.tsx b/src/frontend/src/components/core/parameterRenderComponent/components/connectionComponent/index.tsx index 7469cf926..b65b9b5f8 100644 --- a/src/frontend/src/components/core/parameterRenderComponent/components/connectionComponent/index.tsx +++ b/src/frontend/src/components/core/parameterRenderComponent/components/connectionComponent/index.tsx @@ -10,7 +10,7 @@ import { memo, useEffect, useRef, useState } from "react"; import { InputProps } from "../../types"; import HelperTextComponent from "../helperTextComponent"; -type ConnectionComponentProps = { +export type ConnectionComponentProps = { tooltip?: string; name: string; helperText?: string; diff --git a/src/frontend/src/components/core/parameterRenderComponent/components/linkComponent/index.tsx b/src/frontend/src/components/core/parameterRenderComponent/components/linkComponent/index.tsx index fdfd4fe5f..89afbb5e3 100644 --- a/src/frontend/src/components/core/parameterRenderComponent/components/linkComponent/index.tsx +++ b/src/frontend/src/components/core/parameterRenderComponent/components/linkComponent/index.tsx @@ -11,8 +11,6 @@ export default function LinkComponent({ id = "", text, icon, - editNode = false, - handleOnNewValue, }: InputProps): JSX.Element { function handleOpenLink() { if (value) { diff --git a/src/frontend/src/components/core/parameterRenderComponent/index.tsx b/src/frontend/src/components/core/parameterRenderComponent/index.tsx index b489961d1..211fef762 100644 --- a/src/frontend/src/components/core/parameterRenderComponent/index.tsx +++ b/src/frontend/src/components/core/parameterRenderComponent/index.tsx @@ -4,10 +4,11 @@ import CodeAreaComponent from "@/components/core/parameterRenderComponent/compon import SliderComponent from "@/components/core/parameterRenderComponent/components/sliderComponent"; import TabComponent from "@/components/core/parameterRenderComponent/components/tabComponent"; import { TEXT_FIELD_TYPES } from "@/constants/constants"; +import CustomConnectionComponent from "@/customization/components/custom-connectionComponent"; +import CustomLinkComponent from "@/customization/components/custom-linkComponent"; import { APIClassType, InputFieldType } from "@/types/api"; import { useMemo } from "react"; import ToolsComponent from "./components/ToolsComponent"; -import ConnectionComponent from "./components/connectionComponent"; import DictComponent from "./components/dictComponent"; import { EmptyParameterComponent } from "./components/emptyParameterComponent"; import FloatComponent from "./components/floatComponent"; @@ -146,7 +147,7 @@ export function ParameterRenderComponent({ ); case "link": return ( - = { nodeId?: string; nodeInformationMetadata?: NodeInfoType; hasRefreshButton?: boolean; + helperMetadata?: any; + options?: any[]; + searchCategory?: string[]; + buttonMetadata?: { variant?: string; icon?: string }; + connectionLink?: string; }; // Generic type for composing input props diff --git a/src/frontend/src/components/ui/dialog.tsx b/src/frontend/src/components/ui/dialog.tsx index d4d5f300a..edcde99ef 100644 --- a/src/frontend/src/components/ui/dialog.tsx +++ b/src/frontend/src/components/ui/dialog.tsx @@ -1,9 +1,10 @@ +import DialogContentWithouFixed from "@/customization/components/custom-dialog-content-without-fixed"; +import { dialogClass } from "@/customization/utils/dialog-class"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { Cross2Icon } from "@radix-ui/react-icons"; import * as React from "react"; import { cn } from "../../utils/utils"; import ShadTooltip from "../common/shadTooltipComponent"; - const Dialog = DialogPrimitive.Root; const DialogTrigger = DialogPrimitive.Trigger; @@ -26,10 +27,7 @@ const DialogOverlay = React.forwardRef< >(({ className, ...props }, ref) => ( )); @@ -105,7 +103,6 @@ const DialogContent = React.forwardRef< ); }, ); -DialogContent.displayName = DialogPrimitive.Content.displayName; const DialogHeader = ({ className, @@ -162,6 +159,7 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName; export { Dialog, DialogContent, + DialogContentWithouFixed, DialogDescription, DialogFooter, DialogHeader, diff --git a/src/frontend/src/components/ui/text-loop.tsx b/src/frontend/src/components/ui/text-loop.tsx new file mode 100644 index 000000000..db8b91700 --- /dev/null +++ b/src/frontend/src/components/ui/text-loop.tsx @@ -0,0 +1,100 @@ +"use client"; + +import { cn } from "@/utils/utils"; +import { + AnimatePresence, + AnimatePresenceProps, + motion, + Transition, + Variants, +} from "framer-motion"; +import { Children, useCallback, useEffect, useRef, useState } from "react"; + +export type TextLoopProps = { + children: React.ReactNode | React.ReactNode[]; + className?: string; + interval?: number; + transition?: Transition; + variants?: Variants; + onIndexChange?: (index: number) => void; + trigger?: boolean; + mode?: AnimatePresenceProps["mode"]; + style?: React.CSSProperties; +}; + +export function TextLoop({ + children, + className, + interval = 2, + transition = { duration: 0.3 }, + variants, + onIndexChange, + trigger = true, + mode = "popLayout", + style, +}: TextLoopProps) { + const [currentIndex, setCurrentIndex] = useState(0); + const items = Children.toArray(children); + const timerRef = useRef(); + + const updateIndex = useCallback(() => { + setCurrentIndex((current) => { + const next = (current + 1) % items.length; + onIndexChange?.(next); + return next; + }); + }, [items.length, onIndexChange]); + + useEffect(() => { + if (!trigger || items.length <= 1) return; + + const intervalMs = interval * 1000; + timerRef.current = setInterval(updateIndex, intervalMs); + + return () => { + if (timerRef.current) { + clearInterval(timerRef.current); + } + }; + }, [trigger, interval, items.length, updateIndex]); + + const motionVariants: Variants = { + initial: { y: 20, opacity: 0 }, + animate: { y: 0, opacity: 1 }, + exit: { y: -20, opacity: 0 }, + }; + + if (items.length === 1) { + return ( +
+ + {items[0]} + +
+ ); + } + + return ( +
+ + + {items[currentIndex]} + + +
+ ); +} diff --git a/src/frontend/src/contexts/authContext.tsx b/src/frontend/src/contexts/authContext.tsx index cb8108001..2411c09be 100644 --- a/src/frontend/src/contexts/authContext.tsx +++ b/src/frontend/src/contexts/authContext.tsx @@ -7,6 +7,7 @@ import { import { useGetUserData } from "@/controllers/API/queries/auth"; import { useGetGlobalVariablesMutation } from "@/controllers/API/queries/variables/use-get-mutation-global-variables"; import useAuthStore from "@/stores/authStore"; +import { setLocalStorage } from "@/utils/local-storage-util"; import { createContext, useEffect, useState } from "react"; import { Cookies } from "react-cookie"; import { useStoreStore } from "../stores/storeStore"; @@ -81,7 +82,10 @@ export function AuthProvider({ children }): React.ReactElement { autoLogin: string, refreshToken?: string, ) { + cookies.set(LANGFLOW_ACCESS_TOKEN, newAccessToken, { path: "/" }); cookies.set(LANGFLOW_AUTO_LOGIN_OPTION, autoLogin, { path: "/" }); + setLocalStorage(LANGFLOW_ACCESS_TOKEN, newAccessToken); + if (refreshToken) { cookies.set(LANGFLOW_REFRESH_TOKEN, refreshToken, { path: "/" }); } diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index e013a739c..dd696cf34 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -1,5 +1,7 @@ -import { IS_AUTO_LOGIN, LANGFLOW_ACCESS_TOKEN } from "@/constants/constants"; +import { IS_AUTO_LOGIN } from "@/constants/constants"; +import { baseURL } from "@/customization/constants"; import { useCustomApiHeaders } from "@/customization/hooks/use-custom-api-headers"; +import { customGetAccessToken } from "@/customization/utils/custom-get-access-token"; import useAuthStore from "@/stores/authStore"; import { useUtilityStore } from "@/stores/utilityStore"; import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from "axios"; @@ -14,7 +16,7 @@ import { useLogout, useRefreshAccessToken } from "./queries/auth"; // Create a new Axios instance const api: AxiosInstance = axios.create({ - baseURL: "", + baseURL: baseURL, }); const cookies = new Cookies(); @@ -41,7 +43,8 @@ function ApiInterceptor() { useEffect(() => { const unregister = fetchIntercept.register({ request: function (url, config) { - const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN); + const accessToken = customGetAccessToken(); + if (accessToken && !isAuthorizedURL(config?.url)) { config.headers["Authorization"] = `Bearer ${accessToken}`; } @@ -83,7 +86,8 @@ function ApiInterceptor() { await tryToRenewAccessToken(error); - const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN); + const accessToken = customGetAccessToken(); + if (!accessToken && error?.config?.url?.includes("login")) { return Promise.reject(error); } @@ -142,7 +146,7 @@ function ApiInterceptor() { // Request interceptor to add access token to every request const requestInterceptor = api.interceptors.request.use( - (config) => { + async (config) => { const controller = new AbortController(); try { checkDuplicateRequestAndStoreRequest(config); @@ -152,7 +156,8 @@ function ApiInterceptor() { console.error(error.message); } - const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN); + const accessToken = customGetAccessToken(); + if (accessToken && !isAuthorizedURL(config?.url)) { config.headers["Authorization"] = `Bearer ${accessToken}`; } @@ -234,7 +239,8 @@ function ApiInterceptor() { const originalRequest = error.config as AxiosRequestConfig; try { - const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN); + const accessToken = customGetAccessToken(); + if (!accessToken) { throw new Error("Access token not found in cookies"); } diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 495ba4e2f..28f17c183 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -1,3 +1,7 @@ +import { + customGetAppVersions, + customGetLatestVersion, +} from "@/customization/utils/custom-get-app-latest-version"; import { Edge, Node, ReactFlowJsonObject } from "@xyflow/react"; import { AxiosRequestConfig, AxiosResponse } from "axios"; import { BASE_URL_API } from "../../constants/constants"; @@ -32,6 +36,10 @@ export async function getDiscordCount() { return null; } } + +export const getAppVersions = customGetAppVersions; +export const getLatestVersion = customGetLatestVersion; + export async function createApiKey(name: string) { try { const res = await api.post(`${BASE_URL_API}api_key/`, { name }); diff --git a/src/frontend/src/controllers/API/queries/version/use-get-version.ts b/src/frontend/src/controllers/API/queries/version/use-get-version.ts index 134c74e08..bf72fa9a7 100644 --- a/src/frontend/src/controllers/API/queries/version/use-get-version.ts +++ b/src/frontend/src/controllers/API/queries/version/use-get-version.ts @@ -1,3 +1,4 @@ +import { customRefreshLatestVersion } from "@/customization/utils/custom-refresh-latest-version"; import { useDarkStore } from "@/stores/darkStore"; import { useQueryFunctionType } from "@/types/api"; import { api } from "../../api"; @@ -23,9 +24,10 @@ export const useGetVersionQuery: useQueryFunctionType< const responseFn = async () => { const { data } = await getVersionFn(); const refreshVersion = useDarkStore.getState().refreshVersion; - const refreshLatestVersion = useDarkStore.getState().refreshLatestVersion; refreshVersion(data.version); - refreshLatestVersion(data.main_version); + + customRefreshLatestVersion(data.main_version); + return data; }; diff --git a/src/frontend/src/customization/components/custom-AccountMenu.tsx b/src/frontend/src/customization/components/custom-AccountMenu.tsx new file mode 100644 index 000000000..bada41ab9 --- /dev/null +++ b/src/frontend/src/customization/components/custom-AccountMenu.tsx @@ -0,0 +1,7 @@ +import { AccountMenu } from "@/components/core/appHeaderComponent/components/AccountMenu"; + +export function CustomAccountMenu() { + return ; +} + +export default CustomAccountMenu; diff --git a/src/frontend/src/customization/components/custom-DashboardWrapperPage.tsx b/src/frontend/src/customization/components/custom-DashboardWrapperPage.tsx new file mode 100644 index 000000000..e0abde0c7 --- /dev/null +++ b/src/frontend/src/customization/components/custom-DashboardWrapperPage.tsx @@ -0,0 +1,7 @@ +import { DashboardWrapperPage } from "@/pages/DashboardWrapperPage"; + +export const CustomDashboardWrapperPage = () => { + return ; +}; + +export default CustomDashboardWrapperPage; diff --git a/src/frontend/src/customization/components/custom-McpServerTab.tsx b/src/frontend/src/customization/components/custom-McpServerTab.tsx new file mode 100644 index 000000000..b23f7e753 --- /dev/null +++ b/src/frontend/src/customization/components/custom-McpServerTab.tsx @@ -0,0 +1,7 @@ +import McpServerTab from "@/pages/MainPage/pages/homePage/components/McpServerTab"; + +export const CustomMcpServerTab = ({ folderName }: { folderName: string }) => { + return ; +}; + +export default CustomMcpServerTab; diff --git a/src/frontend/src/customization/components/custom-NodeStatus.tsx b/src/frontend/src/customization/components/custom-NodeStatus.tsx new file mode 100644 index 000000000..943f7ebfc --- /dev/null +++ b/src/frontend/src/customization/components/custom-NodeStatus.tsx @@ -0,0 +1,54 @@ +import { BuildStatus } from "@/constants/enums"; +import NodeStatus from "@/CustomNodes/GenericNode/components/NodeStatus"; +import { VertexBuildTypeAPI } from "@/types/api"; +import { NodeDataType } from "@/types/flow"; + +export function CustomNodeStatus({ + nodeId, + display_name, + selected, + setBorderColor, + frozen, + showNode, + data, + buildStatus, + dismissAll, + isOutdated, + isUserEdited, + isBreakingChange, + getValidationStatus, +}: { + nodeId: string; + display_name: string; + selected?: boolean; + setBorderColor: (color: string) => void; + frozen?: boolean; + showNode: boolean; + data: NodeDataType; + buildStatus: BuildStatus; + dismissAll: boolean; + isOutdated: boolean; + isUserEdited: boolean; + isBreakingChange: boolean; + getValidationStatus: (data) => VertexBuildTypeAPI | null; +}) { + return ( + + ); +} + +export default CustomNodeStatus; diff --git a/src/frontend/src/customization/components/custom-connectionComponent.tsx b/src/frontend/src/customization/components/custom-connectionComponent.tsx new file mode 100644 index 000000000..45676398c --- /dev/null +++ b/src/frontend/src/customization/components/custom-connectionComponent.tsx @@ -0,0 +1,30 @@ +import ConnectionComponent, { + ConnectionComponentProps, +} from "@/components/core/parameterRenderComponent/components/connectionComponent"; +import { InputProps } from "@/components/core/parameterRenderComponent/types"; + +const CustomConnectionComponent = ({ + tooltip = "", + name, + helperText = "", + helperMetadata = { icon: undefined, variant: "muted-foreground" }, + options = [], + searchCategory = [], + buttonMetadata = { variant: "destructive", icon: "unplug" }, + connectionLink = "", + ...baseInputProps +}: InputProps) => { + return ( + + ); +}; + +export default CustomConnectionComponent; diff --git a/src/frontend/src/customization/components/custom-dialog-content-without-fixed.tsx b/src/frontend/src/customization/components/custom-dialog-content-without-fixed.tsx new file mode 100644 index 000000000..b9a4b65f0 --- /dev/null +++ b/src/frontend/src/customization/components/custom-dialog-content-without-fixed.tsx @@ -0,0 +1,21 @@ +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { DialogContent } from "@radix-ui/react-dialog"; +import React from "react"; + +export const DialogContentWithouFixed = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + hideTitle?: boolean; + closeButtonClassName?: string; + } +>( + ( + { className, children, hideTitle = false, closeButtonClassName, ...props }, + ref, + ) => { + return <>; + }, +); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +export default DialogContentWithouFixed; diff --git a/src/frontend/src/customization/components/custom-empty-page.tsx b/src/frontend/src/customization/components/custom-empty-page.tsx new file mode 100644 index 000000000..d50170b5f --- /dev/null +++ b/src/frontend/src/customization/components/custom-empty-page.tsx @@ -0,0 +1,10 @@ +import { EmptyPageCommunity } from "@/pages/MainPage/pages/empty-page"; + +export const CustomEmptyPageCommunity = ({ + setOpenModal, +}: { + setOpenModal: (open: boolean) => void; +}) => { + return ; +}; +export default CustomEmptyPageCommunity; diff --git a/src/frontend/src/customization/components/custom-fetch-error-component.tsx b/src/frontend/src/customization/components/custom-fetch-error-component.tsx new file mode 100644 index 000000000..e560a5fde --- /dev/null +++ b/src/frontend/src/customization/components/custom-fetch-error-component.tsx @@ -0,0 +1,22 @@ +import FetchErrorComponent from "@/components/common/fetchErrorComponent"; +import { fetchErrorComponentType } from "@/types/components"; + +export function CustomFetchErrorComponent({ + message, + description, + openModal, + setRetry, + isLoadingHealth, +}: fetchErrorComponentType) { + return ( + + ); +} + +export default CustomFetchErrorComponent; diff --git a/src/frontend/src/customization/components/custom-file-card.tsx b/src/frontend/src/customization/components/custom-file-card.tsx new file mode 100644 index 000000000..4fbc22aff --- /dev/null +++ b/src/frontend/src/customization/components/custom-file-card.tsx @@ -0,0 +1,12 @@ +import FileCard from "@/modals/IOModal/components/chatView/fileComponent/components/file-card"; +import { fileCardPropsType } from "@/types/components"; + +export function CustomFileCard({ + fileName, + path, + fileType, +}: fileCardPropsType) { + return ; +} + +export default CustomFileCard; diff --git a/src/frontend/src/customization/components/custom-file-input.tsx b/src/frontend/src/customization/components/custom-file-input.tsx new file mode 100644 index 000000000..5172cff47 --- /dev/null +++ b/src/frontend/src/customization/components/custom-file-input.tsx @@ -0,0 +1,8 @@ +import IOFileInput from "@/modals/IOModal/components/IOFieldView/components/file-input"; +import { IOFileInputProps } from "@/types/components"; + +export function CustomIOFileInput({ field, updateValue }: IOFileInputProps) { + return ; +} + +export default CustomIOFileInput; diff --git a/src/frontend/src/customization/components/custom-get-started-progress.tsx b/src/frontend/src/customization/components/custom-get-started-progress.tsx new file mode 100644 index 000000000..58998b2f7 --- /dev/null +++ b/src/frontend/src/customization/components/custom-get-started-progress.tsx @@ -0,0 +1,25 @@ +import { GetStartedProgress } from "@/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/get-started-progress"; +import { Users } from "@/types/api"; + +export function CustomGetStartedProgress({ + userData, + isGithubStarred, + isDiscordJoined, + handleDismissDialog, +}: { + userData: Users; + isGithubStarred: boolean; + isDiscordJoined: boolean; + handleDismissDialog: () => void; +}) { + return ( + + ); +} + +export default CustomGetStartedProgress; diff --git a/src/frontend/src/customization/components/custom-langflow-counts.tsx b/src/frontend/src/customization/components/custom-langflow-counts.tsx new file mode 100644 index 000000000..568297796 --- /dev/null +++ b/src/frontend/src/customization/components/custom-langflow-counts.tsx @@ -0,0 +1,7 @@ +import { LangflowCounts } from "@/components/core/appHeaderComponent/components/langflow-counts"; + +export function CustomLangflowCounts() { + return ; +} + +export default CustomLangflowCounts; diff --git a/src/frontend/src/customization/components/custom-linkComponent.tsx b/src/frontend/src/customization/components/custom-linkComponent.tsx new file mode 100644 index 000000000..a2fd7d553 --- /dev/null +++ b/src/frontend/src/customization/components/custom-linkComponent.tsx @@ -0,0 +1,29 @@ +import LinkComponent from "@/components/core/parameterRenderComponent/components/linkComponent"; +import { + InputProps, + LinkComponentType, +} from "@/components/core/parameterRenderComponent/types"; + +export function CustomLinkComponent({ + value, + disabled = false, + id = "", + text, + icon, + editNode, + handleOnNewValue, +}: InputProps) { + return ( + + ); +} + +export default CustomLinkComponent; diff --git a/src/frontend/src/customization/components/custom-new-modal.tsx b/src/frontend/src/customization/components/custom-new-modal.tsx new file mode 100644 index 000000000..9c95cd270 --- /dev/null +++ b/src/frontend/src/customization/components/custom-new-modal.tsx @@ -0,0 +1,24 @@ +import IOModal from "@/modals/IOModal/new-modal"; +import { IOModalPropsType } from "@/types/components"; + +export function CustomIOModal({ + children, + open, + setOpen, + disable, + isPlayground, + canvasOpen, + playgroundPage, +}: IOModalPropsType) { + return ( + + ); +} diff --git a/src/frontend/src/customization/components/custom-profile-icon.tsx b/src/frontend/src/customization/components/custom-profile-icon.tsx index 2bd0f530b..407cd0e5e 100644 --- a/src/frontend/src/customization/components/custom-profile-icon.tsx +++ b/src/frontend/src/customization/components/custom-profile-icon.tsx @@ -1,3 +1,7 @@ +import { ProfileIcon } from "@/components/core/appHeaderComponent/components/ProfileIcon"; + export function CustomProfileIcon() { - return <>; + return ; } + +export default CustomProfileIcon; diff --git a/src/frontend/src/customization/components/custom-profile-picture-chooser.tsx b/src/frontend/src/customization/components/custom-profile-picture-chooser.tsx new file mode 100644 index 000000000..ac9ec05bd --- /dev/null +++ b/src/frontend/src/customization/components/custom-profile-picture-chooser.tsx @@ -0,0 +1,20 @@ +import ProfilePictureChooserComponent, { + ProfilePictureChooserComponentProps, +} from "@/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent"; +export function CustomProfilePictureChooserComponent({ + profilePictures, + loading, + value, + onChange, +}: ProfilePictureChooserComponentProps) { + return ( + + ); +} + +export default CustomProfilePictureChooserComponent; diff --git a/src/frontend/src/customization/components/custom-store-button.tsx b/src/frontend/src/customization/components/custom-store-button.tsx new file mode 100644 index 000000000..187fab388 --- /dev/null +++ b/src/frontend/src/customization/components/custom-store-button.tsx @@ -0,0 +1,21 @@ +import ForwardedIconComponent from "@/components/common/genericIconComponent"; +import { SidebarMenuButton } from "@/components/ui/sidebar"; + +export const CustomStoreButton = () => { + return ( + <> +
+ { + window.open("/store", "_blank"); + }} + > + + Store + +
+ + ); +}; diff --git a/src/frontend/src/customization/components/custom-store-sidebar.tsx b/src/frontend/src/customization/components/custom-store-sidebar.tsx new file mode 100644 index 000000000..47e2afa71 --- /dev/null +++ b/src/frontend/src/customization/components/custom-store-sidebar.tsx @@ -0,0 +1,26 @@ +import { ForwardedIconComponent } from "@/components/common/genericIconComponent"; + +export const CustomStoreSidebar = () => { + return [ + { + title: "Langflow API Keys", + href: "/settings/api-keys", + icon: ( + + ), + }, + { + title: "Langflow Store", + href: "/settings/store", + icon: ( + + ), + }, + ]; +}; diff --git a/src/frontend/src/customization/components/custom-voice-assistant.tsx b/src/frontend/src/customization/components/custom-voice-assistant.tsx new file mode 100644 index 000000000..f7d581165 --- /dev/null +++ b/src/frontend/src/customization/components/custom-voice-assistant.tsx @@ -0,0 +1,15 @@ +import { + VoiceAssistant, + VoiceAssistantProps, +} from "@/modals/IOModal/components/chatView/chatInput/components/voice-assistant/voice-assistant"; + +export function CustomVoiceAssistant({ + flowId, + setShowAudioInput, +}: VoiceAssistantProps) { + return ( + + ); +} + +export default CustomVoiceAssistant; diff --git a/src/frontend/src/customization/constants.ts b/src/frontend/src/customization/constants.ts new file mode 100644 index 000000000..0b4fc96a6 --- /dev/null +++ b/src/frontend/src/customization/constants.ts @@ -0,0 +1,2 @@ +//Langflow Desktop Base URL +export const baseURL = ""; diff --git a/src/frontend/src/customization/custom-App.tsx b/src/frontend/src/customization/custom-App.tsx new file mode 100644 index 000000000..2338da3cf --- /dev/null +++ b/src/frontend/src/customization/custom-App.tsx @@ -0,0 +1,5 @@ +import App from "../App"; + +export default function CustomApp() { + return ; +} diff --git a/src/frontend/src/customization/hooks/use-generate-token.ts b/src/frontend/src/customization/hooks/use-custom-generate-token.ts similarity index 100% rename from src/frontend/src/customization/hooks/use-generate-token.ts rename to src/frontend/src/customization/hooks/use-custom-generate-token.ts diff --git a/src/frontend/src/customization/hooks/use-custom-start-conversation.ts b/src/frontend/src/customization/hooks/use-custom-start-conversation.ts new file mode 100644 index 000000000..4f0e0b5c1 --- /dev/null +++ b/src/frontend/src/customization/hooks/use-custom-start-conversation.ts @@ -0,0 +1,23 @@ +import { useStartConversation } from "@/modals/IOModal/components/chatView/chatInput/components/voice-assistant/hooks/use-start-conversation"; + +export const customUseStartConversation = ( + flowId: string, + wsRef: React.MutableRefObject, + setStatus: (status: string) => void, + startRecording: () => void, + handleWebSocketMessage: (event: MessageEvent) => void, + stopRecording: () => void, + currentSessionId: string, +) => { + return useStartConversation( + flowId, + wsRef, + setStatus, + startRecording, + handleWebSocketMessage, + stopRecording, + currentSessionId, + ); +}; + +export default customUseStartConversation; diff --git a/src/frontend/src/customization/hooks/use-custom-start-recording.ts b/src/frontend/src/customization/hooks/use-custom-start-recording.ts new file mode 100644 index 000000000..0c87ac0d2 --- /dev/null +++ b/src/frontend/src/customization/hooks/use-custom-start-recording.ts @@ -0,0 +1,32 @@ +import { useStartRecording } from "@/modals/IOModal/components/chatView/chatInput/components/voice-assistant/hooks/use-start-recording"; +import { MutableRefObject } from "react"; + +export const customUseStartRecording = ( + audioContextRef: React.MutableRefObject, + microphoneRef: MutableRefObject, + analyserRef: React.MutableRefObject, + wsRef: React.MutableRefObject, + setIsRecording: (isRecording: boolean) => void, + playNextAudioChunk: () => void, + isPlayingRef: React.MutableRefObject, + audioQueueRef: MutableRefObject, + workletCode: string, + processorRef: MutableRefObject, + setStatus: (status: string) => void, +) => { + return useStartRecording( + audioContextRef, + microphoneRef, + analyserRef, + wsRef, + setIsRecording, + playNextAudioChunk, + isPlayingRef, + audioQueueRef, + workletCode, + processorRef, + setStatus, + ); +}; + +export default customUseStartRecording; diff --git a/src/frontend/src/customization/types/updater.ts b/src/frontend/src/customization/types/updater.ts new file mode 100644 index 000000000..c1fede5ab --- /dev/null +++ b/src/frontend/src/customization/types/updater.ts @@ -0,0 +1,21 @@ +export type Version = { + name: string; + url: string; + description_section?: { + section?: string; + descriptions?: string[]; + }[]; + version_oss: string; + is_lf_oss_update?: boolean; + date?: string; +}; + +export type UpdaterStoreType = { + openUpdaterModal: boolean; + setOpenUpdaterModal: (open: boolean) => void; + latestVersion: Version | null; + versionApp: string | null; + version_oss: string | null; + showVersionChangelog: boolean; + isLatestVersion: boolean; +}; diff --git a/src/frontend/src/customization/utils/custom-buildUtils.ts b/src/frontend/src/customization/utils/custom-buildUtils.ts new file mode 100644 index 000000000..308d0526b --- /dev/null +++ b/src/frontend/src/customization/utils/custom-buildUtils.ts @@ -0,0 +1,13 @@ +import { BASE_URL_API } from "@/constants/constants"; + +export const customBuildUrl = (flowId: string, playgroundPage?: boolean) => { + return `${BASE_URL_API}${playgroundPage ? "build_public_tmp" : "build"}/${flowId}/flow`; +}; + +export const customCancelBuildUrl = (jobId: string) => { + return `${BASE_URL_API}build/${jobId}/cancel`; +}; + +export const customEventsUrl = (jobId: string) => { + return `${BASE_URL_API}build/${jobId}/events`; +}; diff --git a/src/frontend/src/customization/utils/custom-get-access-token.ts b/src/frontend/src/customization/utils/custom-get-access-token.ts new file mode 100644 index 000000000..d71551804 --- /dev/null +++ b/src/frontend/src/customization/utils/custom-get-access-token.ts @@ -0,0 +1,7 @@ +import { LANGFLOW_ACCESS_TOKEN } from "@/constants/constants"; +import { Cookies } from "react-cookie"; + +export const customGetAccessToken = () => { + const cookies = new Cookies(); + return cookies.get(LANGFLOW_ACCESS_TOKEN); +}; diff --git a/src/frontend/src/customization/utils/custom-get-app-latest-version.ts b/src/frontend/src/customization/utils/custom-get-app-latest-version.ts new file mode 100644 index 000000000..8a8839058 --- /dev/null +++ b/src/frontend/src/customization/utils/custom-get-app-latest-version.ts @@ -0,0 +1,7 @@ +export async function customGetAppVersions() { + return null; +} + +export async function customGetLatestVersion() { + return null; +} diff --git a/src/frontend/src/customization/utils/custom-get-host-protocol.ts b/src/frontend/src/customization/utils/custom-get-host-protocol.ts new file mode 100644 index 000000000..357820314 --- /dev/null +++ b/src/frontend/src/customization/utils/custom-get-host-protocol.ts @@ -0,0 +1,6 @@ +export const customGetHostProtocol = () => { + return { + host: window.location.host, + protocol: window.location.protocol, + }; +}; diff --git a/src/frontend/src/customization/utils/custom-mcp-open.ts b/src/frontend/src/customization/utils/custom-mcp-open.ts new file mode 100644 index 000000000..e57841a20 --- /dev/null +++ b/src/frontend/src/customization/utils/custom-mcp-open.ts @@ -0,0 +1,3 @@ +export const customMcpOpen = () => { + return "_blank"; +}; diff --git a/src/frontend/src/customization/utils/custom-pre-load-image-url.ts b/src/frontend/src/customization/utils/custom-pre-load-image-url.ts new file mode 100644 index 000000000..d89b63758 --- /dev/null +++ b/src/frontend/src/customization/utils/custom-pre-load-image-url.ts @@ -0,0 +1,5 @@ +import { BASE_URL_API } from "@/constants/constants"; + +export const customPreLoadImageUrl = (imageUrl: string) => { + return `${BASE_URL_API}files/profile_pictures/${imageUrl}`; +}; diff --git a/src/frontend/src/customization/utils/custom-reactFlowUtils.ts b/src/frontend/src/customization/utils/custom-reactFlowUtils.ts new file mode 100644 index 000000000..8746c57cc --- /dev/null +++ b/src/frontend/src/customization/utils/custom-reactFlowUtils.ts @@ -0,0 +1,14 @@ +import { FlowType } from "@/types/flow"; + +export const customDownloadFlow = ( + flow: FlowType, + sortedJsonString: string, + flowName: string, +) => { + const dataUri = `data:text/json;chatset=utf-8,${encodeURIComponent(sortedJsonString)}`; + const downloadLink = document.createElement("a"); + downloadLink.href = dataUri; + downloadLink.download = `${flowName || flow.name}.json`; + + downloadLink.click(); +}; diff --git a/src/frontend/src/customization/utils/custom-refresh-latest-version.ts b/src/frontend/src/customization/utils/custom-refresh-latest-version.ts new file mode 100644 index 000000000..27572e508 --- /dev/null +++ b/src/frontend/src/customization/utils/custom-refresh-latest-version.ts @@ -0,0 +1,6 @@ +import { useDarkStore } from "@/stores/darkStore"; + +export const customRefreshLatestVersion = (version: string) => { + const refreshLatestVersion = useDarkStore.getState().refreshLatestVersion; + refreshLatestVersion(version); +}; diff --git a/src/frontend/src/customization/utils/custom-routes-store-pages.tsx b/src/frontend/src/customization/utils/custom-routes-store-pages.tsx new file mode 100644 index 000000000..ead6da8d2 --- /dev/null +++ b/src/frontend/src/customization/utils/custom-routes-store-pages.tsx @@ -0,0 +1,29 @@ +import { StoreGuard } from "@/components/authorization/storeGuard"; +import StoreApiKeyPage from "@/pages/SettingsPage/pages/StoreApiKeyPage"; +import StorePage from "@/pages/StorePage"; +import { Route } from "react-router-dom"; + +export const CustomRoutesStorePages = () => { + return ( + <> + + + + } + /> + + + + } + /> + + ); +}; + +export default CustomRoutesStorePages; diff --git a/src/frontend/src/customization/utils/custom-routes-store.tsx b/src/frontend/src/customization/utils/custom-routes-store.tsx new file mode 100644 index 000000000..b640932b9 --- /dev/null +++ b/src/frontend/src/customization/utils/custom-routes-store.tsx @@ -0,0 +1,14 @@ +import { StoreGuard } from "@/components/authorization/storeGuard"; +import StoreApiKeyPage from "@/pages/SettingsPage/pages/StoreApiKeyPage"; +import StorePage from "@/pages/StorePage"; +import { Route } from "react-router-dom"; + +export const CustomRoutesStore = () => { + return ( + <> + } /> + + ); +}; + +export default CustomRoutesStore; diff --git a/src/frontend/src/customization/utils/dialog-class.ts b/src/frontend/src/customization/utils/dialog-class.ts new file mode 100644 index 000000000..febd7f0ab --- /dev/null +++ b/src/frontend/src/customization/utils/dialog-class.ts @@ -0,0 +1,4 @@ +export const dialogClass = { + dialogContent: + "fixed inset-0 bottom-0 left-0 right-0 top-0 z-40 overflow-auto bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", +}; diff --git a/src/frontend/src/index.tsx b/src/frontend/src/index.tsx index ca3d58b86..96da8bb29 100644 --- a/src/frontend/src/index.tsx +++ b/src/frontend/src/index.tsx @@ -9,7 +9,7 @@ import "./App.css"; import "./style/applies.css"; // @ts-ignore -import App from "./App"; +import App from "./customization/custom-App"; const root = ReactDOM.createRoot( document.getElementById("root") as HTMLElement, diff --git a/src/frontend/src/modals/IOModal/components/IOFieldView/io-field-view.tsx b/src/frontend/src/modals/IOModal/components/IOFieldView/io-field-view.tsx index 5daf4042c..b85c8dccf 100644 --- a/src/frontend/src/modals/IOModal/components/IOFieldView/io-field-view.tsx +++ b/src/frontend/src/modals/IOModal/components/IOFieldView/io-field-view.tsx @@ -1,3 +1,4 @@ +import CustomIOFileInput from "@/customization/components/custom-file-input"; import useHandleNewValue from "@/CustomNodes/hooks/use-handle-new-value"; import { AllNodeType } from "@/types/flow"; import { cloneDeep } from "lodash"; @@ -91,7 +92,7 @@ export default function IOFieldView({ ); case IOInputTypes.FILE_LOADER: return ( - { if (node) { diff --git a/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/voice-assistant/voice-assistant.tsx b/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/voice-assistant/voice-assistant.tsx index 94273f662..966ea4dd2 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/voice-assistant/voice-assistant.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/voice-assistant/voice-assistant.tsx @@ -7,6 +7,8 @@ import { usePatchGlobalVariables, usePostGlobalVariables, } from "@/controllers/API/queries/variables"; +import { customUseStartConversation } from "@/customization/hooks/use-custom-start-conversation"; +import { customUseStartRecording } from "@/customization/hooks/use-custom-start-recording"; import useAlertStore from "@/stores/alertStore"; import useFlowStore from "@/stores/flowStore"; import { useGlobalVariablesStore } from "@/stores/globalVariablesStore/globalVariables"; @@ -25,11 +27,9 @@ import { useHandleWebsocketMessage } from "./hooks/use-handle-websocket-message" import { useInitializeAudio } from "./hooks/use-initialize-audio"; import { useInterruptPlayback } from "./hooks/use-interrupt-playback"; import { usePlayNextAudioChunk } from "./hooks/use-play-next-audio-chunk"; -import { useStartConversation } from "./hooks/use-start-conversation"; -import { useStartRecording } from "./hooks/use-start-recording"; import { useStopRecording } from "./hooks/use-stop-recording"; -interface VoiceAssistantProps { +export interface VoiceAssistantProps { flowId: string; setShowAudioInput: (value: boolean) => void; } @@ -133,7 +133,7 @@ export function VoiceAssistant({ }; const startRecording = async () => { - useStartRecording( + customUseStartRecording( audioContextRef, microphoneRef, analyserRef, @@ -187,7 +187,7 @@ export function VoiceAssistant({ }; const startConversation = () => { - useStartConversation( + customUseStartConversation( flowId, wsRef, setStatus, diff --git a/src/frontend/src/modals/IOModal/components/chatView/chatMessage/chat-message.tsx b/src/frontend/src/modals/IOModal/components/chatView/chatMessage/chat-message.tsx index 8da96095b..5b927b321 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/chatMessage/chat-message.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/chatMessage/chat-message.tsx @@ -255,7 +255,7 @@ export default function ChatMessage({ ) ) : !ENABLE_DATASTAX_LANGFLOW && !playgroundPage ? ( - + ) : playgroundPage ? ( ) : ( diff --git a/src/frontend/src/modals/IOModal/components/chatView/chatMessage/components/file-card-wrapper.tsx b/src/frontend/src/modals/IOModal/components/chatView/chatMessage/components/file-card-wrapper.tsx index 671e2376c..c49002c23 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/chatMessage/components/file-card-wrapper.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/chatMessage/components/file-card-wrapper.tsx @@ -1,6 +1,6 @@ +import CustomFileCard from "@/customization/components/custom-file-card"; import { useState } from "react"; import ForwardedIconComponent from "../../../../../../components/common/genericIconComponent"; -import FileCard from "../../fileComponent/components/file-card"; import formatFileName from "../../fileComponent/utils/format-file-name"; export default function FileCardWrapper({ @@ -33,7 +33,7 @@ export default function FileCardWrapper({ {formatFileName(name, 50)} - '\\` : "" } @@ -54,7 +56,8 @@ export function getCurlWebhookCode({ endpointName, format = "multiline", }: GetCodeType & { format?: "multiline" | "singleline" }) { - const baseUrl = `${window.location.protocol}//${window.location.host}/api/v1/webhook/${endpointName || flowId}`; + const { protocol, host } = customGetHostProtocol(); + const baseUrl = `${protocol}//${host}/api/v1/webhook/${endpointName || flowId}`; const authHeader = !isAuth ? `-H 'x-api-key: '` : ""; if (format === "singleline") { @@ -93,8 +96,7 @@ export function getNewCurlCode({ activeTweaks: boolean; endpointName: string; }): string { - const host = window.location.host; - const protocol = window.location.protocol; + const { protocol, host } = customGetHostProtocol(); const apiUrl = `${protocol}//${host}/api/v1/run/${endpointName || flowId}`; const tweaksString = diff --git a/src/frontend/src/modals/apiModal/utils/get-js-api-code.tsx b/src/frontend/src/modals/apiModal/utils/get-js-api-code.tsx index 515f332d3..b37b536f6 100644 --- a/src/frontend/src/modals/apiModal/utils/get-js-api-code.tsx +++ b/src/frontend/src/modals/apiModal/utils/get-js-api-code.tsx @@ -1,3 +1,4 @@ +import { customGetHostProtocol } from "@/customization/utils/custom-get-host-protocol"; import useFlowStore from "@/stores/flowStore"; import { GetCodeType } from "@/types/tweaks"; @@ -24,8 +25,10 @@ export default function getJsApiCode({ const hasChatInput = inputs.some((input) => input.type === "ChatInput"); const hasChatOutput = outputs.some((output) => output.type === "ChatOutput"); + const { protocol, host } = customGetHostProtocol(); + return `${activeTweaks ? "" : 'let inputValue = ""; // Insert input value here\n\n'}fetch( - "${window.location.protocol}//${window.location.host}/api/v1/run/${endpointName || flowId}?stream=false", + "${protocol}//${host}/api/v1/run/${endpointName || flowId}?stream=false", { method: "POST", headers: { @@ -76,8 +79,7 @@ export function getNewJsApiCode({ activeTweaks: boolean; endpointName: string; }): string { - const host = window.location.host; - const protocol = window.location.protocol; + const { protocol, host } = customGetHostProtocol(); const apiUrl = `${protocol}//${host}/api/v1/run/${endpointName || flowId}`; const tweaksString = diff --git a/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx b/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx index 82087febf..29eaf283b 100644 --- a/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx +++ b/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx @@ -1,3 +1,4 @@ +import { customGetHostProtocol } from "@/customization/utils/custom-get-host-protocol"; import { GetCodeType } from "@/types/tweaks"; /** @@ -134,8 +135,7 @@ export function getNewPythonApiCode({ activeTweaks: boolean; endpointName: string; }): string { - const host = window.location.host; - const protocol = window.location.protocol; + const { protocol, host } = customGetHostProtocol(); const apiUrl = `${protocol}//${host}/api/v1/run/${endpointName || flowId}`; const tweaksString = diff --git a/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx b/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx index a1ab03ebb..baac7e322 100644 --- a/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx +++ b/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx @@ -1,3 +1,4 @@ +import { customGetHostProtocol } from "@/customization/utils/custom-get-host-protocol"; import { GetCodeType } from "@/types/tweaks"; /** @@ -20,11 +21,13 @@ export default function getWidgetCode({ build/static/js/bundle.min.js"> `; + const { protocol, host } = customGetHostProtocol(); + return `${source} void; onEscapeKeyDown?: (e: KeyboardEvent) => void; closeButtonClassName?: string; + dialogContentWithouFixed?: boolean; } function BaseModal({ className, @@ -208,6 +210,7 @@ function BaseModal({ onSubmit, onEscapeKeyDown, closeButtonClassName, + dialogContentWithouFixed = false, }: BaseModalProps) { const headerChild = React.Children.toArray(children).find( (child) => (child as React.ReactElement).type === Header, @@ -262,27 +265,51 @@ function BaseModal({ ) : ( {triggerChild} - e.stopPropagation()} - onOpenAutoFocus={(event) => event.preventDefault()} - onEscapeKeyDown={onEscapeKeyDown} - className={contentClasses} - closeButtonClassName={closeButtonClassName} - > - {onSubmit ? ( - { - event.preventDefault(); - onSubmit(); - }} - className={formClasses} - > - {modalContent} - - ) : ( - modalContent - )} - + {dialogContentWithouFixed ? ( + e.stopPropagation()} + onOpenAutoFocus={(event) => event.preventDefault()} + onEscapeKeyDown={onEscapeKeyDown} + className={contentClasses} + closeButtonClassName={closeButtonClassName} + > + {onSubmit ? ( + { + event.preventDefault(); + onSubmit(); + }} + className={formClasses} + > + {modalContent} + + ) : ( + modalContent + )} + + ) : ( + e.stopPropagation()} + onOpenAutoFocus={(event) => event.preventDefault()} + onEscapeKeyDown={onEscapeKeyDown} + className={contentClasses} + closeButtonClassName={closeButtonClassName} + > + {onSubmit ? ( + { + event.preventDefault(); + onSubmit(); + }} + className={formClasses} + > + {modalContent} + + ) : ( + modalContent + )} + + )} )} diff --git a/src/frontend/src/modals/secretKeyModal/index.tsx b/src/frontend/src/modals/secretKeyModal/index.tsx index daa5a8b48..05e2af852 100644 --- a/src/frontend/src/modals/secretKeyModal/index.tsx +++ b/src/frontend/src/modals/secretKeyModal/index.tsx @@ -1,5 +1,5 @@ import { ENABLE_DATASTAX_LANGFLOW } from "@/customization/feature-flags"; -import { useGenerateToken } from "@/customization/hooks/use-generate-token"; +import { useGenerateToken } from "@/customization/hooks/use-custom-generate-token"; import { useEffect, useRef, useState } from "react"; import { COPIED_NOTICE_ALERT } from "../../constants/alerts_constants"; import { createApiKey } from "../../controllers/API"; diff --git a/src/frontend/src/pages/AppWrapperPage/components/GenericErrorComponent/index.tsx b/src/frontend/src/pages/AppWrapperPage/components/GenericErrorComponent/index.tsx index 5d652a7ab..6072bbf9b 100644 --- a/src/frontend/src/pages/AppWrapperPage/components/GenericErrorComponent/index.tsx +++ b/src/frontend/src/pages/AppWrapperPage/components/GenericErrorComponent/index.tsx @@ -1,4 +1,3 @@ -import FetchErrorComponent from "@/components/common/fetchErrorComponent"; import TimeoutErrorComponent from "@/components/common/timeoutErrorComponent"; import { FETCH_ERROR_DESCRIPION, @@ -6,18 +5,19 @@ import { TIMEOUT_ERROR_DESCRIPION, TIMEOUT_ERROR_MESSAGE, } from "@/constants/constants"; +import CustomFetchErrorComponent from "@/customization/components/custom-fetch-error-component"; export function GenericErrorComponent({ healthCheckTimeout, fetching, retry }) { switch (healthCheckTimeout) { case "serverDown": return ( - + > ); case "timeout": return ( diff --git a/src/frontend/src/pages/MainPage/pages/homePage/index.tsx b/src/frontend/src/pages/MainPage/pages/homePage/index.tsx index 4c14aa9b1..3dacb523b 100644 --- a/src/frontend/src/pages/MainPage/pages/homePage/index.tsx +++ b/src/frontend/src/pages/MainPage/pages/homePage/index.tsx @@ -3,6 +3,7 @@ import CardsWrapComponent from "@/components/core/cardsWrapComponent"; import { IS_MAC } from "@/constants/constants"; import { useGetFolderQuery } from "@/controllers/API/queries/folders/use-get-folder"; import { CustomBanner } from "@/customization/components/custom-banner"; +import { CustomMcpServerTab } from "@/customization/components/custom-McpServerTab"; import { ENABLE_DATASTAX_LANGFLOW } from "@/customization/feature-flags"; import useFlowsManagerStore from "@/stores/flowsManagerStore"; import { useFolderStore } from "@/stores/foldersStore"; @@ -15,7 +16,6 @@ import ListSkeleton from "../../components/listSkeleton"; import ModalsComponent from "../../components/modalsComponent"; import useFileDrop from "../../hooks/use-on-file-drop"; import EmptyFolder from "../emptyFolder"; -import McpServerTab from "./components/McpServerTab"; const HomePage = ({ type }: { type: "flows" | "components" | "mcp" }) => { const [view, setView] = useState<"grid" | "list">(() => { @@ -211,7 +211,7 @@ const HomePage = ({ type }: { type: "flows" | "components" | "mcp" }) => {
) ) : flowType === "mcp" ? ( - + ) : (flowType === "flows" || flowType === "components") && data && data.pagination.total > 0 ? ( diff --git a/src/frontend/src/pages/MainPage/pages/main-page.tsx b/src/frontend/src/pages/MainPage/pages/main-page.tsx index 2f7ccb4fe..27d5bf02a 100644 --- a/src/frontend/src/pages/MainPage/pages/main-page.tsx +++ b/src/frontend/src/pages/MainPage/pages/main-page.tsx @@ -1,6 +1,7 @@ import SideBarFoldersButtonsComponent from "@/components/core/folderSidebarComponent/components/sideBarFolderButtons"; import { SidebarProvider } from "@/components/ui/sidebar"; import { useDeleteFolders } from "@/controllers/API/queries/folders"; +import CustomEmptyPageCommunity from "@/customization/components/custom-empty-page"; import CustomLoader from "@/customization/components/custom-loader"; import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate"; import useAlertStore from "@/stores/alertStore"; @@ -80,9 +81,7 @@ export default function CollectionPage(): JSX.Element { {flows?.length !== examples?.length || folders?.length > 1 ? ( ) : ( - // - - + )}
) : ( diff --git a/src/frontend/src/pages/Playground/index.tsx b/src/frontend/src/pages/Playground/index.tsx index 96f7272f7..57277359f 100644 --- a/src/frontend/src/pages/Playground/index.tsx +++ b/src/frontend/src/pages/Playground/index.tsx @@ -1,8 +1,8 @@ import { useGetConfig } from "@/controllers/API/queries/config/use-get-config"; import { useGetFlow } from "@/controllers/API/queries/flows/use-get-flow"; +import { CustomIOModal } from "@/customization/components/custom-new-modal"; import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate"; import { track } from "@/customization/utils/analytics"; -import IOModal from "@/modals/IOModal/new-modal"; import useFlowStore from "@/stores/flowStore"; import { useUtilityStore } from "@/stores/utilityStore"; import { CookieOptions, getCookie, setCookie } from "@/utils/utils"; @@ -93,9 +93,14 @@ export default function PlaygroundPage() { return (
{currentSavedFlow && ( - {}} isPlayground playgroundPage> + {}} + isPlayground + playgroundPage + > <> - + )}
); diff --git a/src/frontend/src/pages/SettingsPage/index.tsx b/src/frontend/src/pages/SettingsPage/index.tsx index f6936010e..b6ecb228b 100644 --- a/src/frontend/src/pages/SettingsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/index.tsx @@ -1,5 +1,6 @@ import SideBarButtonsComponent from "@/components/core/sidebarComponent"; import { SidebarProvider } from "@/components/ui/sidebar"; +import { CustomStoreSidebar } from "@/customization/components/custom-store-sidebar"; import { ENABLE_DATASTAX_LANGFLOW, ENABLE_PROFILE_ICONS, @@ -9,7 +10,6 @@ import { useStoreStore } from "@/stores/storeStore"; import { Outlet } from "react-router-dom"; import ForwardedIconComponent from "../../components/common/genericIconComponent"; import PageLayout from "../../components/common/pageLayout"; - export default function SettingsPage(): JSX.Element { const autoLogin = useAuthStore((state) => state.autoLogin); const hasStore = useStoreStore((state) => state.hasStore); @@ -71,28 +71,7 @@ export default function SettingsPage(): JSX.Element { ); if (!ENABLE_DATASTAX_LANGFLOW) { - const langflowItems = [ - { - title: "Langflow API Keys", - href: "/settings/api-keys", - icon: ( - - ), - }, - { - title: "Langflow Store", - href: "/settings/store", - icon: ( - - ), - }, - ]; + const langflowItems = CustomStoreSidebar(); sidebarNavItems.splice(2, 0, ...langflowItems); } diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-preload-images.ts b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-preload-images.ts index 2b2c4a489..f98eb59bf 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-preload-images.ts +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-preload-images.ts @@ -1,5 +1,5 @@ +import { customPreLoadImageUrl } from "@/customization/utils/custom-pre-load-image-url"; import { useEffect } from "react"; -import { BASE_URL_API } from "../../../../../../../../../constants/constants"; const usePreloadImages = ( setImagesLoaded: (value: boolean) => void, @@ -26,9 +26,7 @@ const usePreloadImages = ( Object.keys(profilePictures).flatMap((folder) => profilePictures[folder].map((path) => - imageArray.push( - `${BASE_URL_API}files/profile_pictures/${folder}/${path}`, - ), + imageArray.push(customPreLoadImageUrl(`${folder}/${path}`)), ), ); diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx index 24ef1324b..26fa73411 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx @@ -1,13 +1,13 @@ import { ProfilePicturesQueryResponse } from "@/controllers/API/queries/files"; +import { customPreLoadImageUrl } from "@/customization/utils/custom-pre-load-image-url"; import { useEffect, useRef, useState } from "react"; import { Button } from "../../../../../../../../components/ui/button"; import Loading from "../../../../../../../../components/ui/loading"; -import { BASE_URL_API } from "../../../../../../../../constants/constants"; import { useDarkStore } from "../../../../../../../../stores/darkStore"; import { cn } from "../../../../../../../../utils/utils"; import usePreloadImages from "./hooks/use-preload-images"; -type ProfilePictureChooserComponentProps = { +export type ProfilePictureChooserComponentProps = { profilePictures?: ProfilePicturesQueryResponse; loading: boolean; value: string; @@ -54,9 +54,7 @@ export default function ProfilePictureChooserComponent({ > import("./pages/AdminPage")); @@ -43,6 +42,7 @@ const DeleteAccountPage = lazy(() => import("./pages/DeleteAccountPage")); const PlaygroundPage = lazy(() => import("./pages/Playground")); const SignUp = lazy(() => import("./pages/SignUpPage")); + const router = createBrowserRouter( createRoutesFromElements([ @@ -74,7 +74,7 @@ const router = createBrowserRouter( } > }> - }> + }> }> } /> } /> - } /> + {CustomRoutesStore()} - - - - } - /> - - - - } - /> + {CustomRoutesStorePages()} }> @@ -166,7 +151,7 @@ const router = createBrowserRouter( /> - }> + }> } /> } /> diff --git a/src/frontend/src/utils/buildUtils.ts b/src/frontend/src/utils/buildUtils.ts index df3b97755..51304b1bd 100644 --- a/src/frontend/src/utils/buildUtils.ts +++ b/src/frontend/src/utils/buildUtils.ts @@ -5,6 +5,11 @@ import { POLLING_MESSAGES, } from "@/constants/constants"; import { performStreamingRequest } from "@/controllers/API/api"; +import { + customBuildUrl, + customCancelBuildUrl, + customEventsUrl, +} from "@/customization/utils/custom-buildUtils"; import { useMessagesStore } from "@/stores/messagesStore"; import { Edge, Node } from "@xyflow/react"; import { AxiosError } from "axios"; @@ -268,7 +273,7 @@ export async function buildFlowVertices({ }: BuildVerticesParams) { const inputs = {}; - let buildUrl = `${BASE_URL_API}${playgroundPage ? "build_public_tmp" : "build"}/${flowId}/flow`; + let buildUrl = customBuildUrl(flowId, playgroundPage); const queryParams = new URLSearchParams(); @@ -381,7 +386,7 @@ export async function buildFlowVertices({ const { job_id } = await buildResponse.json(); - const cancelBuildUrl = `${BASE_URL_API}build/${job_id}/cancel`; + const cancelBuildUrl = customCancelBuildUrl(job_id); // Get the buildController from flowStore const buildController = new AbortController(); @@ -399,7 +404,7 @@ export async function buildFlowVertices({ }); useFlowStore.getState().setBuildController(buildController); // Then stream the events - const eventsUrl = `${BASE_URL_API}build/${job_id}/events`; + const eventsUrl = customEventsUrl(job_id); const buildResults: Array = []; const verticesStartTimeMs: Map = new Map(); diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index d7fafbcf7..e218d6f7f 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -16,6 +16,7 @@ import { getRightHandleId, } from "@/CustomNodes/utils/get-handle-id"; import { INCOMPLETE_LOOP_ERROR_ALERT } from "@/constants/alerts_constants"; +import { customDownloadFlow } from "@/customization/utils/custom-reactFlowUtils"; import { Connection, Edge, @@ -1792,7 +1793,7 @@ function sortJsonStructure(obj: T): T { * @param flowName - The name to use for the flow * @param flowDescription - Optional description for the flow */ -export function downloadFlow( +export async function downloadFlow( flow: FlowType, flowName: string, flowDescription?: string, @@ -1811,12 +1812,7 @@ export function downloadFlow( const sortedData = sortJsonStructure(flowData); const sortedJsonString = JSON.stringify(sortedData, null, 2); - const dataUri = `data:text/json;chatset=utf-8,${encodeURIComponent(sortedJsonString)}`; - const downloadLink = document.createElement("a"); - downloadLink.href = dataUri; - downloadLink.download = `${flowName || flow.name}.json`; - - downloadLink.click(); + customDownloadFlow(flow, sortedJsonString, flowName); } catch (error) { console.error("Error downloading flow:", error); }