diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index 545b61f8b..5a4a29739 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -629,7 +629,7 @@ export const TIMEOUT_ERROR_DESCRIPION = "Server is busy."; export const SIGN_UP_SUCCESS = "Account created! Await admin activation. "; export const API_PAGE_PARAGRAPH = - "Your secret API keys are listed below. Do not share your API key with others, or expose it in the browser or other client-side code."; + "Your secret Langflow API keys are listed below. Do not share your API key with others, or expose it in the browser or other client-side code."; export const API_PAGE_USER_KEYS = "This user does not have any keys assigned at the moment."; diff --git a/src/frontend/src/pages/SettingsPage/index.tsx b/src/frontend/src/pages/SettingsPage/index.tsx index 0e6e19606..f6936010e 100644 --- a/src/frontend/src/pages/SettingsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/index.tsx @@ -1,6 +1,9 @@ import SideBarButtonsComponent from "@/components/core/sidebarComponent"; import { SidebarProvider } from "@/components/ui/sidebar"; -import { ENABLE_PROFILE_ICONS } from "@/customization/feature-flags"; +import { + ENABLE_DATASTAX_LANGFLOW, + ENABLE_PROFILE_ICONS, +} from "@/customization/feature-flags"; import useAuthStore from "@/stores/authStore"; import { useStoreStore } from "@/stores/storeStore"; import { Outlet } from "react-router-dom"; @@ -44,16 +47,7 @@ export default function SettingsPage(): JSX.Element { /> ), }, - { - title: "Langflow API", - href: "/settings/api-keys", - icon: ( - - ), - }, + { title: "Shortcuts", href: "/settings/shortcuts", @@ -75,6 +69,34 @@ 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: ( + + ), + }, + ]; + + sidebarNavItems.splice(2, 0, ...langflowItems); + } + return (

- Langflow API + Langflow API Keys { const { scrollId } = useParams(); @@ -164,16 +164,6 @@ export const GeneralPage = () => { handlePatchPassword={handlePatchPassword} /> )} - {hasStore && ( - - )}

); diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/StoreApiKeyForm/index.tsx b/src/frontend/src/pages/SettingsPage/pages/StoreApiKeyPage/components/StoreApiKeyForm.tsx similarity index 91% rename from src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/StoreApiKeyForm/index.tsx rename to src/frontend/src/pages/SettingsPage/pages/StoreApiKeyPage/components/StoreApiKeyForm.tsx index f8038aeff..14b83e46a 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/StoreApiKeyForm/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/StoreApiKeyPage/components/StoreApiKeyForm.tsx @@ -1,6 +1,6 @@ import * as Form from "@radix-ui/react-form"; -import InputComponent from "../../../../../../components/core/parameterRenderComponent/components/inputComponent"; -import { Button } from "../../../../../../components/ui/button"; +import InputComponent from "../../../../../components/core/parameterRenderComponent/components/inputComponent"; +import { Button } from "../../../../../components/ui/button"; import { Card, CardContent, @@ -8,13 +8,13 @@ import { CardFooter, CardHeader, CardTitle, -} from "../../../../../../components/ui/card"; +} from "../../../../../components/ui/card"; import { CREATE_API_KEY, INSERT_API_KEY, INVALID_API_KEY, NO_API_KEY, -} from "../../../../../../constants/constants"; +} from "../../../../../constants/constants"; type StoreApiKeyFormComponentProps = { apikey: string; diff --git a/src/frontend/src/pages/SettingsPage/pages/StoreApiKeyPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/StoreApiKeyPage/index.tsx new file mode 100644 index 000000000..4d164d384 --- /dev/null +++ b/src/frontend/src/pages/SettingsPage/pages/StoreApiKeyPage/index.tsx @@ -0,0 +1,88 @@ +import ForwardedIconComponent from "@/components/common/genericIconComponent"; +import { CONTROL_PATCH_USER_STATE } from "@/constants/constants"; +import { AuthContext } from "@/contexts/authContext"; +import { usePostAddApiKey } from "@/controllers/API/queries/api-keys"; +import useAlertStore from "@/stores/alertStore"; +import { useStoreStore } from "@/stores/storeStore"; +import { inputHandlerEventType } from "@/types/components"; +import { useContext, useState } from "react"; +import { useParams } from "react-router-dom"; +import useScrollToElement from "../hooks/use-scroll-to-element"; +import StoreApiKeyFormComponent from "./components/StoreApiKeyForm"; + +const StoreApiKeyPage = () => { + const { scrollId } = useParams(); + const [inputState, setInputState] = useState(CONTROL_PATCH_USER_STATE); + const { storeApiKey } = useContext(AuthContext); + useScrollToElement(scrollId); + + const setSuccessData = useAlertStore((state) => state.setSuccessData); + const setErrorData = useAlertStore((state) => state.setErrorData); + const { + validApiKey, + hasApiKey, + loadingApiKey, + updateHasApiKey: setHasApiKey, + updateValidApiKey: setValidApiKey, + updateLoadingApiKey: setLoadingApiKey, + } = useStoreStore(); + + const { mutate: addApiKey } = usePostAddApiKey({ + onSuccess: () => { + setSuccessData({ title: "API key saved successfully" }); + setHasApiKey(true); + setValidApiKey(true); + setLoadingApiKey(false); + handleInput({ target: { name: "apikey", value: "" } }); + }, + onError: (error) => { + setErrorData({ + title: "API key save error", + list: [(error as any)?.response?.data?.detail], + }); + setHasApiKey(false); + setValidApiKey(false); + setLoadingApiKey(false); + }, + }); + + const handleSaveKey = (apikey: string) => { + if (apikey) { + addApiKey({ key: apikey }); + storeApiKey(apikey); + } + }; + + const handleInput = ({ target: { name, value } }: inputHandlerEventType) => { + setInputState((prev) => ({ ...prev, [name]: value })); + }; + + return ( +
+
+
+

+ Langflow Store + +

+

+ Manage access to the Langflow Store. +

+
+
+ +
+ ); +}; + +export default StoreApiKeyPage; diff --git a/src/frontend/src/pages/SettingsPage/pages/StorePage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/StorePage/index.tsx new file mode 100644 index 000000000..b8605a87b --- /dev/null +++ b/src/frontend/src/pages/SettingsPage/pages/StorePage/index.tsx @@ -0,0 +1,71 @@ +import { CONTROL_PATCH_USER_STATE } from "@/constants/constants"; +import { AuthContext } from "@/contexts/authContext"; +import { usePostAddApiKey } from "@/controllers/API/queries/api-keys"; +import useAlertStore from "@/stores/alertStore"; +import { useStoreStore } from "@/stores/storeStore"; +import { inputHandlerEventType } from "@/types/components"; +import { useContext, useState } from "react"; +import { useParams } from "react-router-dom"; +import StoreApiKeyFormComponent from "../StoreApiKeyPage/components/StoreApiKeyForm"; +import useScrollToElement from "../hooks/use-scroll-to-element"; + +const StoreApiKeyPage = () => { + const { scrollId } = useParams(); + const [inputState, setInputState] = useState(CONTROL_PATCH_USER_STATE); + const { storeApiKey } = useContext(AuthContext); + useScrollToElement(scrollId); + + const setSuccessData = useAlertStore((state) => state.setSuccessData); + const setErrorData = useAlertStore((state) => state.setErrorData); + const { + validApiKey, + hasApiKey, + loadingApiKey, + updateHasApiKey: setHasApiKey, + updateValidApiKey: setValidApiKey, + updateLoadingApiKey: setLoadingApiKey, + } = useStoreStore(); + + const { mutate: addApiKey } = usePostAddApiKey({ + onSuccess: () => { + setSuccessData({ title: "API key saved successfully" }); + setHasApiKey(true); + setValidApiKey(true); + setLoadingApiKey(false); + handleInput({ target: { name: "apikey", value: "" } }); + }, + onError: (error) => { + setErrorData({ + title: "API key save error", + list: [(error as any)?.response?.data?.detail], + }); + setHasApiKey(false); + setValidApiKey(false); + setLoadingApiKey(false); + }, + }); + + const handleSaveKey = (apikey: string) => { + if (apikey) { + addApiKey({ key: apikey }); + storeApiKey(apikey); + } + }; + + const handleInput = ({ target: { name, value } }: inputHandlerEventType) => { + setInputState((prev) => ({ ...prev, [name]: value })); + }; + + return ( + + ); +}; + +export default StoreApiKeyPage; diff --git a/src/frontend/src/routes.tsx b/src/frontend/src/routes.tsx index c5fd39127..d75b4da10 100644 --- a/src/frontend/src/routes.tsx +++ b/src/frontend/src/routes.tsx @@ -33,6 +33,7 @@ import GeneralPage from "./pages/SettingsPage/pages/GeneralPage"; import GlobalVariablesPage from "./pages/SettingsPage/pages/GlobalVariablesPage"; import MessagesPage from "./pages/SettingsPage/pages/messagesPage"; import ShortcutsPage from "./pages/SettingsPage/pages/ShortcutsPage"; +import StoreApiKeyPage from "./pages/SettingsPage/pages/StoreApiKeyPage"; import StorePage from "./pages/StorePage"; import ViewPage from "./pages/ViewPage"; @@ -165,6 +166,7 @@ const router = createBrowserRouter( /> } /> } /> + } />