From d6f9124405be066237b003d98ebc261af8af72e5 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 29 Aug 2023 18:34:55 -0300 Subject: [PATCH 01/48] Feat[DropdownButtonComponent]: Create Dropdown Button component --- src/backend/langflow/api/v1/users.py | 4 +- .../DropdownButtonComponent/index.tsx | 49 ++ .../src/components/headerComponent/index.tsx | 28 +- src/frontend/src/pages/AdminPage/index.tsx | 471 +++++++++--------- .../components/PageComponent/index.tsx | 2 +- src/frontend/src/pages/loginPage/index.tsx | 3 +- src/frontend/src/types/components/index.ts | 2 +- src/frontend/src/utils/styleUtils.ts | 2 + 8 files changed, 310 insertions(+), 251 deletions(-) create mode 100644 src/frontend/src/components/DropdownButtonComponent/index.tsx diff --git a/src/backend/langflow/api/v1/users.py b/src/backend/langflow/api/v1/users.py index 7365e7cc1..5094409cb 100644 --- a/src/backend/langflow/api/v1/users.py +++ b/src/backend/langflow/api/v1/users.py @@ -43,7 +43,9 @@ def add_user( db.refresh(new_user) except IntegrityError as e: db.rollback() - raise HTTPException(status_code=400, detail="This username is unavailable.") from e + raise HTTPException( + status_code=400, detail="This username is unavailable." + ) from e return new_user diff --git a/src/frontend/src/components/DropdownButtonComponent/index.tsx b/src/frontend/src/components/DropdownButtonComponent/index.tsx new file mode 100644 index 000000000..20c956365 --- /dev/null +++ b/src/frontend/src/components/DropdownButtonComponent/index.tsx @@ -0,0 +1,49 @@ +import { useState } from "react"; +import IconComponent from "../genericIconComponent"; +import { Button } from "../ui/button"; + +export default function DropdownButton({ + firstButtonName, + onFirstBtnClick, + options, +}): JSX.Element { + const [showOptions, setShowOptions] = useState(false); + + return ( +
+
+ +
+
+ +
+ {showOptions && ( +
+ {options.map((optionName) => ( + + ))} +
+ )} +
+ ); +} diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index c74cdaa76..039b8895c 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -33,14 +33,14 @@ export default function Header(): JSX.Element { )} {!autoLogin && location.pathname !== `/flow/${tabId}` && ( { - logout(); - navigate("/login"); - }} - className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary cursor-pointer mx-5" - > - Sign out - + onClick={() => { + logout(); + navigate("/login"); + }} + className="mx-5 cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary" + > + Sign out + )} {location.pathname === "/admin" && ( @@ -48,7 +48,7 @@ export default function Header(): JSX.Element { onClick={() => { navigate("/"); }} - className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary cursor-pointer" + className="cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary" > Home @@ -59,11 +59,11 @@ export default function Header(): JSX.Element { location.pathname !== "/admin" && location.pathname !== `/flow/${tabId}` && ( navigate("/admin")} - > - Admin page - + className="cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary" + onClick={() => navigate("/admin")} + > + Admin page + )}
diff --git a/src/frontend/src/pages/AdminPage/index.tsx b/src/frontend/src/pages/AdminPage/index.tsx index fc963fee8..08e83f700 100644 --- a/src/frontend/src/pages/AdminPage/index.tsx +++ b/src/frontend/src/pages/AdminPage/index.tsx @@ -4,6 +4,7 @@ import { useContext, useEffect, useRef, useState } from "react"; import PaginatorComponent from "../../components/PaginatorComponent"; import ShadTooltip from "../../components/ShadTooltipComponent"; import IconComponent from "../../components/genericIconComponent"; +import Header from "../../components/headerComponent"; import { Button } from "../../components/ui/button"; import { Checkbox } from "../../components/ui/checkbox"; import { Input } from "../../components/ui/input"; @@ -25,9 +26,8 @@ import { } from "../../controllers/API"; import ConfirmationModal from "../../modals/ConfirmationModal"; import UserManagementModal from "../../modals/UserManagementModal"; -import { UserInputType } from "../../types/components"; -import Header from "../../components/headerComponent"; import { Users } from "../../types/api"; +import { UserInputType } from "../../types/components"; export default function AdminPage() { const [inputValue, setInputValue] = useState(""); @@ -89,7 +89,7 @@ export default function AdminPage() { if (input === "") { setFilterUserList(userList.current); } else { - const filteredList = userList.current.filter((user:Users) => + const filteredList = userList.current.filter((user: Users) => user.username.toLowerCase().includes(input.toLowerCase()) ); setFilterUserList(filteredList); @@ -183,249 +183,254 @@ export default function AdminPage() { return ( <> -
-
- {userData && ( -
-
-
-
-
-
-

- Welcome back! -

-

- Navigate through this section to efficiently oversee all - application users. From here, you can seamlessly manage - user accounts. -

+
+
+ {userData && ( +
+
+
+
+
+
+

+ Welcome back! +

+

+ Navigate through this section to efficiently oversee all + application users. From here, you can seamlessly manage + user accounts. +

+
+
-
-
- {userList.current.length === 0 && !loadingUsers && ( + {userList.current.length === 0 && !loadingUsers && ( + <> +
+

There's no users registered :)

+
+ + )} <>
-

There's no users registered :)

-
- - )} - <> -
-
- handleFilterUsers(e.target.value)} - /> - {inputValue.length > 0 && ( - + )} +
+
+ { + handleNewUser(user); }} - variant="ghost" - className="h-8 px-2 lg:px-3" > - Reset - - - )} + + +
-
- { - handleNewUser(user); - }} - > - - -
-
- {loadingUsers && ( -
- Loading... -
- )} -
- - - - Id - Username - Active - Superuser - Created At - Updated At - - - - {!loadingUsers && ( - - {filterUserList.map((user:UserInputType, index) => ( - - - - - {user.id} - - - - - - - {user.username} - - - - - { - handleDisableUser( - user.is_active, - user.id, - user - ); - }} - > - - - - - { - handleSuperUserEdit( - user.is_superuser, - user.id, - user - ); - }} - > - - - - - { - new Date(user.create_at!) - .toISOString() - .split("T")[0] - } - - - { - new Date(user.updated_at!) - .toISOString() - .split("T")[0] - } - - -
- { - handleEditUser(user.id, editUser); - }} - > - - + {loadingUsers && ( +
+ Loading... +
+ )} +
+
+ + + Id + Username + Active + Superuser + Created At + Updated At + + + + {!loadingUsers && ( + + {filterUserList.map( + (user: UserInputType, index) => ( + + + + + {user.id} + - - - { - handleDeleteUser(user); - }} - > - - + + + + + {user.username} + - - - - - ))} - - )} -
-
+ + + { + handleDisableUser( + user.is_active, + user.id, + user + ); + }} + > + + + + + { + handleSuperUserEdit( + user.is_superuser, + user.id, + user + ); + }} + > + + + + + { + new Date(user.create_at!) + .toISOString() + .split("T")[0] + } + + + { + new Date(user.updated_at!) + .toISOString() + .split("T")[0] + } + + +
+ { + handleEditUser(user.id, editUser); + }} + > + + + + - { - handleChangePagination(pageSize, pageIndex); - }} - > - + { + handleDeleteUser(user); + }} + > + + + + +
+
+ + ) + )} + + )} + +
+ + { + handleChangePagination(pageSize, pageIndex); + }} + > + +
-
- )} + )}
); diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 058be6e5c..620170fbb 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -421,7 +421,7 @@ export default function Page({ zoomOnScroll={!view} zoomOnPinch={!view} panOnDrag={!view} - proOptions={{hideAttribution: true}} + proOptions={{ hideAttribution: true }} > {!view && ( diff --git a/src/frontend/src/pages/loginPage/index.tsx b/src/frontend/src/pages/loginPage/index.tsx index 14e04708b..a3ac0fbcd 100644 --- a/src/frontend/src/pages/loginPage/index.tsx +++ b/src/frontend/src/pages/loginPage/index.tsx @@ -19,7 +19,8 @@ export default function LoginPage(): JSX.Element { useState(CONTROL_LOGIN_STATE); const { password, username } = inputState; - const { login, getAuthentication, setUserData, setIsAdmin } = useContext(AuthContext); + const { login, getAuthentication, setUserData, setIsAdmin } = + useContext(AuthContext); const navigate = useNavigate(); const { setErrorData } = useContext(alertContext); diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index f7b974a93..24e538e98 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -268,7 +268,7 @@ export type UserInputType = { is_superuser?: boolean; id?: string; create_at?: string; - updated_at?:string; + updated_at?: string; }; export type ApiKeyType = { diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index 31a7adf7e..e74bb0e34 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -5,6 +5,7 @@ import { ChevronDown, ChevronLeft, ChevronRight, + ChevronUp, ChevronsLeft, ChevronsRight, ChevronsUpDown, @@ -300,4 +301,5 @@ export const nodeIconsLucide: iconsType = { UserCog2, Key, Unplug, + ChevronUp, }; From 6240991e0c29dcff852511c9d67f4dcc8d70578e Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 29 Aug 2023 18:47:36 -0300 Subject: [PATCH 02/48] Feat: Add Dropdown Button to main page --- .../components/DropdownButtonComponent/index.tsx | 11 ++++++++--- src/frontend/src/pages/MainPage/index.tsx | 13 ++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/frontend/src/components/DropdownButtonComponent/index.tsx b/src/frontend/src/components/DropdownButtonComponent/index.tsx index 20c956365..20865e12d 100644 --- a/src/frontend/src/components/DropdownButtonComponent/index.tsx +++ b/src/frontend/src/components/DropdownButtonComponent/index.tsx @@ -37,9 +37,14 @@ export default function DropdownButton({
{showOptions && (
- {options.map((optionName) => ( - ))}
diff --git a/src/frontend/src/pages/MainPage/index.tsx b/src/frontend/src/pages/MainPage/index.tsx index 67412401a..007298f29 100644 --- a/src/frontend/src/pages/MainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/index.tsx @@ -6,6 +6,7 @@ import Header from "../../components/headerComponent"; import { Button } from "../../components/ui/button"; import { USER_PROJECTS_HEADER } from "../../constants/constants"; import { TabsContext } from "../../contexts/tabsContext"; +import DropdownButton from "../../components/DropdownButtonComponent"; export default function HomePage(): JSX.Element { const { flows, setTabId, downloadFlows, uploadFlows, addFlow, removeFlow } = useContext(TabsContext); @@ -45,17 +46,15 @@ export default function HomePage(): JSX.Element { Upload Collection - + options={[{name: "yesyes", onBtnClick: () => console.log('dips')}, {name: "dips", onBtnClick: () => console.log('yesyes')}]} + />
From da703d65e3d6f94c5066765bae5589f27c418385 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 29 Aug 2023 18:53:39 -0300 Subject: [PATCH 03/48] Feat: Add DropdownButton prop type --- .../src/components/DropdownButtonComponent/index.tsx | 3 ++- src/frontend/src/pages/MainPage/index.tsx | 2 +- src/frontend/src/types/components/index.ts | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/components/DropdownButtonComponent/index.tsx b/src/frontend/src/components/DropdownButtonComponent/index.tsx index 20865e12d..71e02c43b 100644 --- a/src/frontend/src/components/DropdownButtonComponent/index.tsx +++ b/src/frontend/src/components/DropdownButtonComponent/index.tsx @@ -1,12 +1,13 @@ import { useState } from "react"; import IconComponent from "../genericIconComponent"; import { Button } from "../ui/button"; +import { dropdownButtonPropsType } from "../../types/components"; export default function DropdownButton({ firstButtonName, onFirstBtnClick, options, -}): JSX.Element { +}: dropdownButtonPropsType): JSX.Element { const [showOptions, setShowOptions] = useState(false); return ( diff --git a/src/frontend/src/pages/MainPage/index.tsx b/src/frontend/src/pages/MainPage/index.tsx index 007298f29..bdcf76c19 100644 --- a/src/frontend/src/pages/MainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/index.tsx @@ -53,7 +53,7 @@ export default function HomePage(): JSX.Element { navigate("/flow/" + id); }); }} - options={[{name: "yesyes", onBtnClick: () => console.log('dips')}, {name: "dips", onBtnClick: () => console.log('yesyes')}]} + options={[{name: "Import from JSON", onBtnClick: () => console.log('imported')}]} />
diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 24e538e98..b61ddf07d 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -544,3 +544,9 @@ export type fetchErrorComponentType = { message: string; description: string; }; + +export type dropdownButtonPropsType = { + firstButtonName: string; + onFirstBtnClick: () => void; + options: Array<{ name: string; onBtnClick: () => void; }>; +}; From 34da83121357350a9b08ebe222f80cedc24ed43b Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 30 Aug 2023 10:34:30 -0300 Subject: [PATCH 04/48] Reset flows cache when logged out --- src/frontend/src/contexts/tabsContext.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index ac0d676e0..114c1ff93 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -72,7 +72,7 @@ export const TabsContext = createContext( export function TabsProvider({ children }: { children: ReactNode }) { const { setErrorData, setNoticeData, setSuccessData } = useContext(alertContext); - const { getAuthentication } = useContext(AuthContext); + const { getAuthentication, isAuthenticated } = useContext(AuthContext); const [tabId, setTabId] = useState(""); @@ -86,6 +86,12 @@ export function TabsProvider({ children }: { children: ReactNode }) { const [tabsState, setTabsState] = useState({}); const [getTweak, setTweak] = useState([]); + useEffect(() => { + if(!isAuthenticated){ + hardReset(); + } + }, [isAuthenticated]) + const newNodeId = useRef(uid()); function incrementNodeId() { newNodeId.current = uid(); From 3c9a6af4cdfe8fb9140b3327458c22bdda2e161b Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 30 Aug 2023 11:42:58 -0300 Subject: [PATCH 05/48] Autocomplete style fix and input type fixed for signup and login --- .../src/components/inputComponent/index.tsx | 4 ++++ src/frontend/src/pages/loginPage/index.tsx | 5 +++-- src/frontend/src/pages/signUpPage/index.tsx | 2 ++ src/frontend/src/style/classes.css | 15 +++++++++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/components/inputComponent/index.tsx b/src/frontend/src/components/inputComponent/index.tsx index 987c53a8f..46acdc1b0 100644 --- a/src/frontend/src/components/inputComponent/index.tsx +++ b/src/frontend/src/components/inputComponent/index.tsx @@ -30,6 +30,7 @@ export default function InputComponent({ {isForm ? ( ) : ( { handleInput({ target: { name: "username", value } }); }} @@ -129,12 +130,12 @@ export default function LoginPage(): JSX.Element {
- +
- diff --git a/src/frontend/src/pages/signUpPage/index.tsx b/src/frontend/src/pages/signUpPage/index.tsx index 92f3eff97..c15a905c0 100644 --- a/src/frontend/src/pages/signUpPage/index.tsx +++ b/src/frontend/src/pages/signUpPage/index.tsx @@ -84,6 +84,7 @@ export default function SignUp(): JSX.Element { { handleInput({ target: { name: "username", value } }); }} @@ -157,6 +158,7 @@ export default function SignUp(): JSX.Element {
- {showOptions && ( -
- {options.map(({ name, onBtnClick }) => ( + +
+ {options.map(({ name, onBtnClick }, index) => ( ))}
- )} +
); } diff --git a/src/frontend/src/pages/MainPage/index.tsx b/src/frontend/src/pages/MainPage/index.tsx index bdcf76c19..f3fe68a6c 100644 --- a/src/frontend/src/pages/MainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/index.tsx @@ -8,8 +8,9 @@ import { USER_PROJECTS_HEADER } from "../../constants/constants"; import { TabsContext } from "../../contexts/tabsContext"; import DropdownButton from "../../components/DropdownButtonComponent"; export default function HomePage(): JSX.Element { - const { flows, setTabId, downloadFlows, uploadFlows, addFlow, removeFlow } = + const { flows, setTabId, downloadFlows, uploadFlows, addFlow, removeFlow, uploadFlow } = useContext(TabsContext); + const dropdownOptions = [{name: "Import from JSON", onBtnClick: () => uploadFlow(true)}] // Set a null id useEffect(() => { @@ -53,12 +54,12 @@ export default function HomePage(): JSX.Element { navigate("/flow/" + id); }); }} - options={[{name: "Import from JSON", onBtnClick: () => console.log('imported')}]} + options={dropdownOptions} />
- Manage your personal projects. Download or upload your collection. + Manage your personal projects. Download or upload your collection.
{flows.map((flow, idx) => ( From 35e24610aff53861149356f9524ee22cef7a0303 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Wed, 30 Aug 2023 17:29:00 -0300 Subject: [PATCH 07/48] Refactor: Add trim() to login form --- src/frontend/src/pages/loginPage/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/pages/loginPage/index.tsx b/src/frontend/src/pages/loginPage/index.tsx index 14e04708b..c64fc8325 100644 --- a/src/frontend/src/pages/loginPage/index.tsx +++ b/src/frontend/src/pages/loginPage/index.tsx @@ -31,8 +31,8 @@ export default function LoginPage(): JSX.Element { function signIn() { const user: LoginType = { - username: username, - password: password, + username: username.trim(), + password: password.trim(), }; onLogin(user) .then((user) => { From 4739372e201a2b2028c5deb21556cda7f5aa4e7e Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Wed, 30 Aug 2023 17:40:18 -0300 Subject: [PATCH 08/48] Refactor: Add trim() to signUp page --- src/frontend/src/pages/signUpPage/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/pages/signUpPage/index.tsx b/src/frontend/src/pages/signUpPage/index.tsx index 92f3eff97..9a5de5991 100644 --- a/src/frontend/src/pages/signUpPage/index.tsx +++ b/src/frontend/src/pages/signUpPage/index.tsx @@ -33,8 +33,8 @@ export default function SignUp(): JSX.Element { function handleSignup(): void { const { username, password } = inputState; const newUser: UserInputType = { - username, - password, + username: username.trim(), + password: password.trim(), }; addUser(newUser) .then((user) => { From 158ef9a9eab7470eaf0d0d3c16dfbc97f91811bc Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Wed, 30 Aug 2023 17:48:17 -0300 Subject: [PATCH 09/48] Refactor: Remove duplicate login button and bring back button borders back --- .../src/components/headerComponent/index.tsx | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index c74cdaa76..8cbd5a591 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -32,7 +32,8 @@ export default function Header(): JSX.Element { )} {!autoLogin && location.pathname !== `/flow/${tabId}` && ( - { logout(); navigate("/login"); @@ -40,30 +41,20 @@ export default function Header(): JSX.Element { className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary cursor-pointer mx-5" > Sign out - - )} - - {location.pathname === "/admin" && ( - { - navigate("/"); - }} - className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary cursor-pointer" - > - Home - + )} {isAdmin && !autoLogin && location.pathname !== "/admin" && location.pathname !== `/flow/${tabId}` && ( - navigate("/admin")} > Admin page - + )}
From ee27839009923d7bb58aa1c79a67911204859e04 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Wed, 30 Aug 2023 22:56:43 -0300 Subject: [PATCH 10/48] Added skeleton when loading all flows --- .../skeletonCardComponent/index.tsx | 16 ++++ src/frontend/src/components/ui/skeleton.tsx | 15 ++++ src/frontend/src/contexts/tabsContext.tsx | 11 ++- src/frontend/src/pages/MainPage/index.tsx | 75 ++++++++++++------- src/frontend/src/style/applies.css | 12 +++ src/frontend/src/types/tabs/index.ts | 1 + 6 files changed, 101 insertions(+), 29 deletions(-) create mode 100644 src/frontend/src/components/skeletonCardComponent/index.tsx create mode 100644 src/frontend/src/components/ui/skeleton.tsx diff --git a/src/frontend/src/components/skeletonCardComponent/index.tsx b/src/frontend/src/components/skeletonCardComponent/index.tsx new file mode 100644 index 000000000..a9857e4f4 --- /dev/null +++ b/src/frontend/src/components/skeletonCardComponent/index.tsx @@ -0,0 +1,16 @@ +import { Skeleton } from "../ui/skeleton"; + +export const SkeletonCardComponent = (): JSX.Element => { + return ( +
+
+ + +
+
+ + +
+
+ ); +}; diff --git a/src/frontend/src/components/ui/skeleton.tsx b/src/frontend/src/components/ui/skeleton.tsx new file mode 100644 index 000000000..6556585a4 --- /dev/null +++ b/src/frontend/src/components/ui/skeleton.tsx @@ -0,0 +1,15 @@ +import { cn } from "../../utils/utils" + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
+ ) +} + +export { Skeleton } diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index 114c1ff93..97ad50329 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -39,6 +39,7 @@ const TabsContextInitialValue: TabsContextType = { save: () => {}, tabId: "", setTabId: (index: string) => {}, + isLoading: true, flows: [], removeFlow: (id: string) => {}, addFlow: async (flowData?: any) => "", @@ -76,6 +77,8 @@ export function TabsProvider({ children }: { children: ReactNode }) { const [tabId, setTabId] = useState(""); + const [isLoading, setIsLoading] = useState(true); + const [flows, setFlows] = useState>([]); const [id, setId] = useState(uid()); const { templates, reactFlowInstance } = useContext(typesContext); @@ -87,10 +90,10 @@ export function TabsProvider({ children }: { children: ReactNode }) { const [getTweak, setTweak] = useState([]); useEffect(() => { - if(!isAuthenticated){ + if (!isAuthenticated) { hardReset(); } - }, [isAuthenticated]) + }, [isAuthenticated]); const newNodeId = useRef(uid()); function incrementNodeId() { @@ -122,11 +125,13 @@ export function TabsProvider({ children }: { children: ReactNode }) { } function refreshFlows() { + setIsLoading(true); getTabsDataFromDB().then((DbData) => { if (DbData && Object.keys(templates).length > 0) { try { processDBData(DbData); updateStateWithDbData(DbData); + setIsLoading(false); } catch (e) {} } }); @@ -235,6 +240,7 @@ export function TabsProvider({ children }: { children: ReactNode }) { setTabId(""); setFlows([]); + setIsLoading(true); setId(uid()); } @@ -647,6 +653,7 @@ export function TabsProvider({ children }: { children: ReactNode }) { paste, getTweak, setTweak, + isLoading, }} > {children} diff --git a/src/frontend/src/pages/MainPage/index.tsx b/src/frontend/src/pages/MainPage/index.tsx index 67412401a..442a43e2f 100644 --- a/src/frontend/src/pages/MainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/index.tsx @@ -3,12 +3,20 @@ import { Link, useNavigate } from "react-router-dom"; import { CardComponent } from "../../components/cardComponent"; import IconComponent from "../../components/genericIconComponent"; import Header from "../../components/headerComponent"; +import { SkeletonCardComponent } from "../../components/skeletonCardComponent"; import { Button } from "../../components/ui/button"; import { USER_PROJECTS_HEADER } from "../../constants/constants"; import { TabsContext } from "../../contexts/tabsContext"; export default function HomePage(): JSX.Element { - const { flows, setTabId, downloadFlows, uploadFlows, addFlow, removeFlow } = - useContext(TabsContext); + const { + flows, + setTabId, + downloadFlows, + uploadFlows, + addFlow, + removeFlow, + isLoading, + } = useContext(TabsContext); // Set a null id useEffect(() => { @@ -16,6 +24,10 @@ export default function HomePage(): JSX.Element { }, []); const navigate = useNavigate(); + useEffect(() => { + console.log(isLoading); + }, [isLoading]); + // Personal flows display return ( <> @@ -62,31 +74,40 @@ export default function HomePage(): JSX.Element { Manage your personal projects. Download or upload your collection.
- {flows.map((flow, idx) => ( - - - - } - onDelete={() => { - removeFlow(flow.id); - }} - /> - ))} + {isLoading && flows.length == 0 ? ( + <> + + + + + + ) : ( + flows.map((flow, idx) => ( + + + + } + onDelete={() => { + removeFlow(flow.id); + }} + /> + )) + )}
diff --git a/src/frontend/src/style/applies.css b/src/frontend/src/style/applies.css index 4f6f9b3a5..685d81b05 100644 --- a/src/frontend/src/style/applies.css +++ b/src/frontend/src/style/applies.css @@ -126,6 +126,18 @@ @apply form-input block w-full truncate rounded-md border-border bg-background px-3 text-left shadow-sm placeholder:text-muted-foreground focus:border-ring focus:placeholder-transparent focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm; } + .skeleton-card { + @apply bg-background h-48 p-4 border rounded-lg flex flex-col gap-6; + } + + .skeleton-card-wrapper { + @apply flex items-center space-x-4; + } + + .skeleton-card-text { + @apply flex flex-col gap-3; + } + /* The same as primary-input but no-truncate */ .textarea-primary { @apply form-input block w-full rounded-md border-border bg-background px-3 text-left shadow-sm placeholder:text-muted-foreground focus:border-ring focus:placeholder-transparent focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm; diff --git a/src/frontend/src/types/tabs/index.ts b/src/frontend/src/types/tabs/index.ts index a87cdb35e..036f82717 100644 --- a/src/frontend/src/types/tabs/index.ts +++ b/src/frontend/src/types/tabs/index.ts @@ -5,6 +5,7 @@ export type TabsContextType = { saveFlow: (flow: FlowType) => Promise; save: () => void; tabId: string; + isLoading: boolean; setTabId: (index: string) => void; flows: Array; removeFlow: (id: string) => void; From 03599541c24db41a8f89ee4c4abb357b30082092 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Thu, 31 Aug 2023 08:20:23 -0300 Subject: [PATCH 11/48] Added user dropdown instead of buttons --- .../src/components/headerComponent/index.tsx | 79 +++++++++++-------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index c74cdaa76..2a7219fed 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -7,8 +7,17 @@ import { alertContext } from "../../contexts/alertContext"; import { AuthContext } from "../../contexts/authContext"; import { darkContext } from "../../contexts/darkContext"; import { TabsContext } from "../../contexts/tabsContext"; +import { gradients } from "../../utils/styleUtils"; import IconComponent from "../genericIconComponent"; import { Button } from "../ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "../ui/dropdown-menu"; import { Separator } from "../ui/separator"; import MenuBar from "./components/menuBar"; @@ -17,7 +26,7 @@ export default function Header(): JSX.Element { const { dark, setDark } = useContext(darkContext); const { notificationCenter } = useContext(alertContext); const location = useLocation(); - const { logout, autoLogin, isAdmin } = useContext(AuthContext); + const { logout, autoLogin, isAdmin, userData } = useContext(AuthContext); const { stars } = useContext(darkContext); const navigate = useNavigate(); @@ -31,40 +40,6 @@ export default function Header(): JSX.Element { {flows.findIndex((f) => tabId === f.id) !== -1 && tabId !== "" && ( )} - {!autoLogin && location.pathname !== `/flow/${tabId}` && ( - { - logout(); - navigate("/login"); - }} - className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary cursor-pointer mx-5" - > - Sign out - - )} - - {location.pathname === "/admin" && ( - { - navigate("/"); - }} - className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary cursor-pointer" - > - Home - - )} - - {isAdmin && - !autoLogin && - location.pathname !== "/admin" && - location.pathname !== `/flow/${tabId}` && ( - navigate("/admin")} - > - Admin page - - )}
@@ -156,6 +131,40 @@ export default function Header(): JSX.Element { /> )} + {!autoLogin && ( + <> + + + +
From 08407abe9a9cfd5d21ff347cfe85e744621be03e Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 10:20:20 -0300 Subject: [PATCH 12/48] =?UTF-8?q?=F0=9F=94=A7=20chore(main.py):=20add=20te?= =?UTF-8?q?ardown=5Fservices=20function=20to=20be=20called=20on=20app=20sh?= =?UTF-8?q?utdown=20event=20to=20properly=20clean=20up=20resources?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/langflow/main.py b/src/backend/langflow/main.py index 57f3e34dc..f567e65bb 100644 --- a/src/backend/langflow/main.py +++ b/src/backend/langflow/main.py @@ -10,7 +10,7 @@ from langflow.api import router from langflow.interface.utils import setup_llm_caching from langflow.services.database.utils import initialize_database -from langflow.services.manager import initialize_services +from langflow.services.manager import initialize_services, teardown_services from langflow.utils.logger import configure @@ -40,6 +40,7 @@ def create_app(): app.on_event("startup")(initialize_services) app.on_event("startup")(initialize_database) app.on_event("startup")(setup_llm_caching) + app.on_event("shutdown")(teardown_services) return app From 91ea879e508bbb350a0d4df573668f8cf8c32432 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 10:20:40 -0300 Subject: [PATCH 13/48] =?UTF-8?q?=F0=9F=94=A7=20fix(base.py):=20make=20Ser?= =?UTF-8?q?vice=20class=20inherit=20from=20ABC=20to=20make=20it=20an=20abs?= =?UTF-8?q?tract=20base=20class=20=E2=9C=A8=20feat(manager.py):=20add=20de?= =?UTF-8?q?bug=20log=20messages=20for=20service=20creation=20and=20update?= =?UTF-8?q?=20to=20improve=20debugging=20=E2=9C=A8=20feat(manager.py):=20a?= =?UTF-8?q?dd=20teardown=20method=20to=20ServiceManager=20to=20teardown=20?= =?UTF-8?q?all=20services=20and=20clear=20state=20=E2=9C=A8=20feat(manager?= =?UTF-8?q?.py):=20add=20teardown=5Fservices=20function=20to=20teardown=20?= =?UTF-8?q?all=20services=20and=20clear=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/services/base.py | 8 +++++++- src/backend/langflow/services/manager.py | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/backend/langflow/services/base.py b/src/backend/langflow/services/base.py index 6bca6c4e2..aaa966047 100644 --- a/src/backend/langflow/services/base.py +++ b/src/backend/langflow/services/base.py @@ -1,2 +1,8 @@ -class Service: +from abc import ABC + + +class Service(ABC): name: str + + def teardown(self): + pass diff --git a/src/backend/langflow/services/manager.py b/src/backend/langflow/services/manager.py index e9895adab..bfe83fce8 100644 --- a/src/backend/langflow/services/manager.py +++ b/src/backend/langflow/services/manager.py @@ -1,5 +1,6 @@ from langflow.services.schema import ServiceType from typing import TYPE_CHECKING, List, Optional +from langflow.utils.logger import logger if TYPE_CHECKING: from langflow.services.factory import ServiceFactory @@ -42,6 +43,7 @@ class ServiceManager: """ Create a new service given its name, handling dependencies. """ + logger.debug(f"Create service {service_name}") self._validate_service_creation(service_name) # Create dependencies first @@ -74,9 +76,21 @@ class ServiceManager: Update a service by its name. """ if service_name in self.services: + logger.debug(f"Update service {service_name}") self.services.pop(service_name, None) self.get(service_name) + def teardown(self): + """ + Teardown all the services. + """ + for service in self.services.values(): + logger.debug(f"Teardown service {service.name}") + service.teardown() + self.services = {} + self.factories = {} + self.dependencies = {} + service_manager = ServiceManager() @@ -134,3 +148,10 @@ def initialize_session_manager(): session_manager_factory.SessionManagerFactory(), dependencies=[ServiceType.CACHE_MANAGER], ) + + +def teardown_services(): + """ + Teardown all the services. + """ + service_manager.teardown() From 29a616bc77813e816590c8fc2004ece4bfc52d7e Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 10:20:53 -0300 Subject: [PATCH 14/48] =?UTF-8?q?=F0=9F=90=9B=20fix(utils.py):=20remove=20?= =?UTF-8?q?unnecessary=20code=20and=20simplify=20create=5Fsuper=5Fuser=20f?= =?UTF-8?q?unction=20=E2=9C=A8=20feat(utils.py):=20refactor=20create=5Fuse?= =?UTF-8?q?r=5Flongterm=5Ftoken=20to=20use=20settings=5Fmanager=20for=20us?= =?UTF-8?q?ername=20and=20password?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/services/auth/utils.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/backend/langflow/services/auth/utils.py b/src/backend/langflow/services/auth/utils.py index 1431ee615..a53a182c0 100644 --- a/src/backend/langflow/services/auth/utils.py +++ b/src/backend/langflow/services/auth/utils.py @@ -154,18 +154,12 @@ def create_super_user( username: Optional[str] = None, password: Optional[str] = None, ) -> User: - settings_manager = get_settings_manager() - - super_user = get_user_by_username( - db, username or settings_manager.auth_settings.FIRST_SUPERUSER - ) + super_user = get_user_by_username(db, username) if not super_user: super_user = User( - username=username or settings_manager.auth_settings.FIRST_SUPERUSER, - password=get_password_hash( - password or settings_manager.auth_settings.FIRST_SUPERUSER_PASSWORD - ), + username=username, + password=get_password_hash(password), is_superuser=True, is_active=True, last_login_at=None, @@ -179,7 +173,10 @@ def create_super_user( def create_user_longterm_token(db: Session = Depends(get_session)) -> dict: - super_user = create_super_user(db) + settings_manager = get_settings_manager() + username = settings_manager.auth_settings.FIRST_SUPERUSER + password = settings_manager.auth_settings.FIRST_SUPERUSER_PASSWORD + super_user = create_super_user(db, username=username, password=password) access_token_expires_longterm = timedelta(days=365) access_token = create_token( From 8d96c32c2b4a42dae66afaa562e6816a50cffefd Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 10:21:03 -0300 Subject: [PATCH 15/48] =?UTF-8?q?=F0=9F=94=A7=20chore(manager.py):=20add?= =?UTF-8?q?=20teardown=20method=20to=20DatabaseManager=20class=20for=20cle?= =?UTF-8?q?aning=20up=20the=20database=20=F0=9F=94=A7=20chore(manager.py):?= =?UTF-8?q?=20remove=20default=20superuser=20if=20auto=5Flogin=20is=20enab?= =?UTF-8?q?led=20during=20teardown=20to=20ensure=20clean=20database=20stat?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../langflow/services/database/manager.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/backend/langflow/services/database/manager.py b/src/backend/langflow/services/database/manager.py index 2b599a0ba..1159cbf7a 100644 --- a/src/backend/langflow/services/database/manager.py +++ b/src/backend/langflow/services/database/manager.py @@ -1,6 +1,7 @@ from pathlib import Path from typing import TYPE_CHECKING from langflow.services.base import Service +from langflow.services.database.models.user.crud import get_user_by_username from langflow.services.database.utils import Result, TableResults from langflow.services.utils import get_settings_manager from sqlalchemy import inspect @@ -159,3 +160,23 @@ class DatabaseManager(Service): ) logger.debug("Database and tables created successfully") + + def teardown(self): + logger.debug("Tearing down database") + try: + settings_manager = get_settings_manager() + # remove the default superuser if auto_login is enabled + # using the FIRST_SUPERUSER to get the user + if settings_manager.auth_settings.AUTO_LOGIN: + logger.debug("Removing default superuser") + username = settings_manager.auth_settings.FIRST_SUPERUSER + with Session(self.engine) as session: + user = get_user_by_username(session, username) + session.delete(user) + session.commit() + logger.debug("Default superuser removed") + + except Exception as exc: + logger.error(f"Error tearing down database: {exc}") + + self.engine.dispose() From d8c7450576b838ccbe21ed23a3e75257db0ed662 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 10:55:04 -0300 Subject: [PATCH 16/48] =?UTF-8?q?=F0=9F=94=A7=20chore(test=5Fuser.py):=20r?= =?UTF-8?q?efactor=20super=5Fuser=20fixture=20to=20use=20auth=20settings?= =?UTF-8?q?=20from=20settings=20manager=20for=20username=20and=20password?= =?UTF-8?q?=20=F0=9F=94=A7=20chore(test=5Fuser.py):=20refactor=20super=5Fu?= =?UTF-8?q?ser=20fixture=20to=20use=20auth=20settings=20from=20settings=20?= =?UTF-8?q?manager=20for=20username=20and=20password=20in=20create=5Fsuper?= =?UTF-8?q?=5Fuser=20function=20call?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_user.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_user.py b/tests/test_user.py index d734e4d61..35b724cc6 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -9,7 +9,13 @@ from langflow.services.database.models.user import UserUpdate @pytest.fixture def super_user(client, session): - return create_super_user(session) + settings_manager = get_settings_manager() + auth_settings = settings_manager.auth_settings + return create_super_user( + session, + username=auth_settings.FIRST_SUPERUSER, + password=auth_settings.FIRST_SUPERUSER_PASSWORD, + ) @pytest.fixture From fc0e8685151a61c1be7ef5e733e895f8275a758c Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Thu, 31 Aug 2023 11:15:12 -0300 Subject: [PATCH 17/48] Fixed UI of Dropdown Button --- .../DropdownButtonComponent/index.tsx | 90 ++++++++++--------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/src/frontend/src/components/DropdownButtonComponent/index.tsx b/src/frontend/src/components/DropdownButtonComponent/index.tsx index b9fffbb00..1ddddb3c1 100644 --- a/src/frontend/src/components/DropdownButtonComponent/index.tsx +++ b/src/frontend/src/components/DropdownButtonComponent/index.tsx @@ -1,8 +1,13 @@ -import { Fragment, useState } from "react"; +import { useState } from "react"; +import { dropdownButtonPropsType } from "../../types/components"; import IconComponent from "../genericIconComponent"; import { Button } from "../ui/button"; -import { dropdownButtonPropsType } from "../../types/components"; -import { Transition } from "@headlessui/react"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "../ui/dropdown-menu"; export default function DropdownButton({ firstButtonName, @@ -12,54 +17,51 @@ export default function DropdownButton({ const [showOptions, setShowOptions] = useState(false); return ( -
-
- -
-
- + + { event.stopPropagation(); + event.preventDefault(); setShowOptions(!showOptions); }} > - {!showOptions ? ( -
- -
{options.map(({ name, onBtnClick }, index) => ( - + ))} -
-
+ +
); } From 269cb9bc53d52f1636e4c248b208bfb73cdcb190 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 11:16:39 -0300 Subject: [PATCH 18/48] =?UTF-8?q?=F0=9F=90=9B=20fix(=5F=5Fmain=5F=5F.py):?= =?UTF-8?q?=20pass=20the=20session=20as=20a=20keyword=20argument=20'db'=20?= =?UTF-8?q?to=20the=20create=5Fsuper=5Fuser=20function=20for=20clarity=20a?= =?UTF-8?q?nd=20consistency=20=F0=9F=90=9B=20fix(test=5Fuser.py):=20pass?= =?UTF-8?q?=20the=20session=20as=20a=20keyword=20argument=20'db'=20to=20th?= =?UTF-8?q?e=20create=5Fsuper=5Fuser=20function=20for=20clarity=20and=20co?= =?UTF-8?q?nsistency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/__main__.py | 2 +- tests/test_user.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/__main__.py b/src/backend/langflow/__main__.py index b5ec034de..a08ae9fb0 100644 --- a/src/backend/langflow/__main__.py +++ b/src/backend/langflow/__main__.py @@ -356,7 +356,7 @@ def superuser( with session_getter(db_manager) as session: from langflow.services.auth.utils import create_super_user - if create_super_user(session, username, password): + if create_super_user(db=session, username=username, password=password): # Verify that the superuser was created from langflow.services.database.models.user.user import User diff --git a/tests/test_user.py b/tests/test_user.py index 35b724cc6..bc617e127 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -12,7 +12,7 @@ def super_user(client, session): settings_manager = get_settings_manager() auth_settings = settings_manager.auth_settings return create_super_user( - session, + db=session, username=auth_settings.FIRST_SUPERUSER, password=auth_settings.FIRST_SUPERUSER_PASSWORD, ) From 8429f3fe7241f6b5b814b9df00068d785e7be715 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 11:16:52 -0300 Subject: [PATCH 19/48] =?UTF-8?q?=F0=9F=90=9B=20fix(chat.py):=20fix=20typo?= =?UTF-8?q?=20in=20variable=20name=20'messsage'=20to=20'message'=20for=20b?= =?UTF-8?q?etter=20readability=20=F0=9F=94=A7=20chore(chat.py):=20refactor?= =?UTF-8?q?=20error=20handling=20in=20chat=20websocket=20to=20improve=20co?= =?UTF-8?q?de=20clarity=20and=20maintainability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/chat.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index e4fc71343..9d322b03c 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -61,14 +61,13 @@ async def chat( await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=str(exc)) except Exception as exc: logger.error(f"Error in chat websocket: {exc}") - if isinstance(exc, HTTPException): - exc = exc.detail + messsage = exc.detail if isinstance(exc, HTTPException) else str(exc) if "Could not validate credentials" in str(exc): await websocket.close( code=status.WS_1008_POLICY_VIOLATION, reason="Unauthorized" ) else: - await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=str(exc)) + await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=messsage) @router.post("/build/init/{flow_id}", response_model=InitResponse, status_code=201) From 9eca124b1700eaeb8742b1f60c7170543fcb03f5 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 11:17:16 -0300 Subject: [PATCH 20/48] =?UTF-8?q?=F0=9F=90=9B=20fix(utils.py):=20raise=20H?= =?UTF-8?q?TTPException=20with=20status=20code=20400=20and=20detail=20mess?= =?UTF-8?q?age=20when=20FIRST=5FSUPERUSER=20credentials=20are=20missing=20?= =?UTF-8?q?in=20api=5Fkey=5Fsecurity=20function=20=F0=9F=90=9B=20fix(utils?= =?UTF-8?q?.py):=20raise=20credentials=5Fexception=20when=20SECRET=5FKEY?= =?UTF-8?q?=20is=20None=20in=20get=5Fcurrent=5Fuser=20function=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(utils.py):=20raise=20HTTPException=20with=20?= =?UTF-8?q?status=20code=20400=20and=20detail=20message=20when=20FIRST=5FS?= =?UTF-8?q?UPERUSER=20credentials=20are=20missing=20in=20create=5Fuser=5Fl?= =?UTF-8?q?ongterm=5Ftoken=20function=20=F0=9F=90=9B=20fix(auth.py):=20set?= =?UTF-8?q?=20SECRET=5FKEY=20default=20value=20to=20empty=20string=20and?= =?UTF-8?q?=20disallow=20mutation=20in=20AuthSettings=20class=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(auth.py):=20set=20FIRST=5FSUPERUSER=20and=20?= =?UTF-8?q?FIRST=5FSUPERUSER=5FPASSWORD=20as=20optional=20fields=20with=20?= =?UTF-8?q?default=20values=20and=20disallow=20mutation=20in=20AuthSetting?= =?UTF-8?q?s=20class=20=F0=9F=90=9B=20fix(manager.py):=20raise=20ValueErro?= =?UTF-8?q?r=20when=20CONFIG=5FDIR=20is=20not=20set=20in=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/services/auth/utils.py | 21 +++++++++++++++---- .../langflow/services/settings/auth.py | 19 +++++++++++++---- .../langflow/services/settings/manager.py | 8 ++++++- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/backend/langflow/services/auth/utils.py b/src/backend/langflow/services/auth/utils.py index a53a182c0..485968a38 100644 --- a/src/backend/langflow/services/auth/utils.py +++ b/src/backend/langflow/services/auth/utils.py @@ -37,7 +37,12 @@ async def api_key_security( result: Optional[Union[ApiKey, User]] = None if settings_manager.auth_settings.AUTO_LOGIN: # Get the first user - settings_manager.auth_settings.FIRST_SUPERUSER + if not settings_manager.auth_settings.FIRST_SUPERUSER: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Missing first superuser credentials", + ) + result = get_user_by_username( db, settings_manager.auth_settings.FIRST_SUPERUSER ) @@ -80,6 +85,9 @@ async def get_current_user( if isinstance(token, Coroutine): token = await token + if settings_manager.auth_settings.SECRET_KEY is None: + raise credentials_exception + try: payload = jwt.decode( token, @@ -150,9 +158,9 @@ def create_token(data: dict, expires_delta: timedelta): def create_super_user( + username: str, + password: str, db: Session = Depends(get_session), - username: Optional[str] = None, - password: Optional[str] = None, ) -> User: super_user = get_user_by_username(db, username) @@ -176,7 +184,12 @@ def create_user_longterm_token(db: Session = Depends(get_session)) -> dict: settings_manager = get_settings_manager() username = settings_manager.auth_settings.FIRST_SUPERUSER password = settings_manager.auth_settings.FIRST_SUPERUSER_PASSWORD - super_user = create_super_user(db, username=username, password=password) + if not username or not password: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Missing first superuser credentials", + ) + super_user = create_super_user(db=db, username=username, password=password) access_token_expires_longterm = timedelta(days=365) access_token = create_token( diff --git a/src/backend/langflow/services/settings/auth.py b/src/backend/langflow/services/settings/auth.py index 7550d3ddd..c38417502 100644 --- a/src/backend/langflow/services/settings/auth.py +++ b/src/backend/langflow/services/settings/auth.py @@ -11,10 +11,11 @@ from langflow.utils.logger import logger class AuthSettings(BaseSettings): # Login settings CONFIG_DIR: str - SECRET_KEY: Optional[str] = Field( - None, + SECRET_KEY: str = Field( + default="", description="Secret key for JWT. If not provided, a random one will be generated.", env="LANGFLOW_SECRET_KEY", + allow_mutation=False, ) ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 @@ -30,8 +31,18 @@ class AuthSettings(BaseSettings): # If AUTO_LOGIN = True # > The application does not request login and logs in automatically as a super user. AUTO_LOGIN: bool = False - FIRST_SUPERUSER: str = "langflow" - FIRST_SUPERUSER_PASSWORD: str = "langflow" + FIRST_SUPERUSER: Optional[str] = Field( + "langflow", + description="First super user to be created if AUTO_LOGIN is True.", + env="LANGFLOW_FIRST_SUPERUSER", + allow_mutation=False, + ) + FIRST_SUPERUSER_PASSWORD: Optional[str] = Field( + "langflow", + description="First super user password to be created if AUTO_LOGIN is True.", + env="LANGFLOW_FIRST_SUPERUSER_PASSWORD", + allow_mutation=False, + ) pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") diff --git a/src/backend/langflow/services/settings/manager.py b/src/backend/langflow/services/settings/manager.py index 67e06108e..cef212c4e 100644 --- a/src/backend/langflow/services/settings/manager.py +++ b/src/backend/langflow/services/settings/manager.py @@ -35,5 +35,11 @@ class SettingsManager(Service): ) settings = Settings(**settings_dict) - auth_settings = AuthSettings(CONFIG_DIR=settings.CONFIG_DIR) + if not settings.CONFIG_DIR: + raise ValueError("CONFIG_DIR must be set in settings") + auth_settings = AuthSettings( + CONFIG_DIR=settings.CONFIG_DIR, + FIRST_SUPERUSER=None, + FIRST_SUPERUSER_PASSWORD=None, + ) return cls(settings, auth_settings) From 942c48955285aa92191900fb33a1ed79300e8420 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 11:17:28 -0300 Subject: [PATCH 21/48] =?UTF-8?q?=F0=9F=90=9B=20fix(utils.py):=20change=20?= =?UTF-8?q?file=20mode=20from=20"rb"=20to=20"r"=20when=20reading=20secret?= =?UTF-8?q?=20from=20file=20to=20fix=20incorrect=20file=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/services/settings/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/langflow/services/settings/utils.py b/src/backend/langflow/services/settings/utils.py index 5eb4cd787..bb411a299 100644 --- a/src/backend/langflow/services/settings/utils.py +++ b/src/backend/langflow/services/settings/utils.py @@ -43,5 +43,5 @@ def write_secret_to_file(path: Path, value: str) -> None: def read_secret_from_file(path: Path) -> str: - with path.open("rb") as f: + with path.open("r") as f: return f.read() From 4010f5669e42b5c2a76c60b766e712446f41ab5f Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 11:17:38 -0300 Subject: [PATCH 22/48] =?UTF-8?q?=F0=9F=94=A7=20chore(pyproject.toml):=20a?= =?UTF-8?q?dd=20types-pywin32=20as=20a=20dependency=20to=20support=20Windo?= =?UTF-8?q?ws-specific=20functionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 13 ++++++++++++- pyproject.toml | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 675118488..cdb1ffd1a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -7041,6 +7041,17 @@ files = [ {file = "types_pytz-2023.3.0.1-py3-none-any.whl", hash = "sha256:65152e872137926bb67a8fe6cc9cfd794365df86650c5d5fdc7b167b0f38892e"}, ] +[[package]] +name = "types-pywin32" +version = "306.0.0.4" +description = "Typing stubs for pywin32" +optional = false +python-versions = "*" +files = [ + {file = "types-pywin32-306.0.0.4.tar.gz", hash = "sha256:ae4bbec80d535053236d4bebedf55f58dee89cf5883d277f0fa89e857f3ff337"}, + {file = "types_pywin32-306.0.0.4-py3-none-any.whl", hash = "sha256:f76a343ed6933008af85e158063963f923e54f2f461e697b2929b4178c7b77a1"}, +] + [[package]] name = "types-pyyaml" version = "6.0.12.11" @@ -7773,4 +7784,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.11" -content-hash = "c877b4d713eef71815d858d30976ab21c42e5eadcc2df8159e940e03323681ee" +content-hash = "a3a506d483c2db7169a9790090095d1764aa5be223d135c6fc3fc2768dfef36c" diff --git a/pyproject.toml b/pyproject.toml index f852c2a7c..796145886 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -103,6 +103,7 @@ types-python-jose = "^3.3.4.8" types-passlib = "^1.7.7.13" pytest-mock = "^3.11.1" pytest-xdist = "^3.3.1" +types-pywin32 = "^306.0.0.4" [tool.poetry.extras] From c7b500dd5c8a4c753bd8eed8ca6411f48b316f4c Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 11:27:45 -0300 Subject: [PATCH 23/48] =?UTF-8?q?=F0=9F=94=A7=20fix(base.py):=20fix=20comm?= =?UTF-8?q?ent=20indentation=20for=20better=20readability=20=F0=9F=94=A7?= =?UTF-8?q?=20fix(users.py):=20fix=20code=20formatting=20and=20indentation?= =?UTF-8?q?=20for=20better=20readability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/base.py | 4 ++-- src/backend/langflow/api/v1/users.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backend/langflow/api/v1/base.py b/src/backend/langflow/api/v1/base.py index 39c8b0b9f..acffc1bc3 100644 --- a/src/backend/langflow/api/v1/base.py +++ b/src/backend/langflow/api/v1/base.py @@ -21,7 +21,7 @@ class FrontendNodeRequest(FrontendNode): class ValidatePromptRequest(BaseModel): name: str template: str - #optional for tweak call + # optional for tweak call frontend_node: Optional[FrontendNodeRequest] @@ -41,7 +41,7 @@ class CodeValidationResponse(BaseModel): class PromptValidationResponse(BaseModel): input_variables: list - #object return for tweak call + # object return for tweak call frontend_node: FrontendNodeRequest | object diff --git a/src/backend/langflow/api/v1/users.py b/src/backend/langflow/api/v1/users.py index 7365e7cc1..5094409cb 100644 --- a/src/backend/langflow/api/v1/users.py +++ b/src/backend/langflow/api/v1/users.py @@ -43,7 +43,9 @@ def add_user( db.refresh(new_user) except IntegrityError as e: db.rollback() - raise HTTPException(status_code=400, detail="This username is unavailable.") from e + raise HTTPException( + status_code=400, detail="This username is unavailable." + ) from e return new_user From 8fedf9562fcda03e6512099bbcfd40e60d4346ad Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Thu, 31 Aug 2023 11:38:40 -0300 Subject: [PATCH 24/48] Fixed usability issues on import json method --- src/frontend/src/contexts/tabsContext.tsx | 47 +++++++++++------------ src/frontend/src/pages/MainPage/index.tsx | 4 +- src/frontend/src/types/tabs/index.ts | 2 +- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index 97ad50329..339ad67b5 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -48,7 +48,7 @@ const TabsContextInitialValue: TabsContextType = { downloadFlow: (flow: FlowType) => {}, downloadFlows: () => {}, uploadFlows: () => {}, - uploadFlow: () => {}, + uploadFlow: async () => "", isBuilt: false, setIsBuilt: (state: boolean) => {}, hardReset: () => {}, @@ -298,39 +298,38 @@ export function TabsProvider({ children }: { children: ReactNode }) { * If the file type is application/json, the file is read and parsed into a JSON object. * The resulting JSON object is passed to the addFlow function. */ - function uploadFlow(newProject?: boolean, file?: File) { + async function uploadFlow( + newProject?: boolean, + file?: File + ): Promise { + let id; if (file) { - file.text().then((text) => { - // parse the text into a JSON object - let flow: FlowType = JSON.parse(text); + let text = await file.text(); + // parse the text into a JSON object + let flow: FlowType = JSON.parse(text); - addFlow(flow, newProject); - }); + id = await addFlow(flow, newProject); } else { // create a file input const input = document.createElement("input"); input.type = "file"; input.accept = ".json"; // add a change event listener to the file input - input.onchange = (e: Event) => { - // check if the file type is application/json - if ( - (e.target as HTMLInputElement).files![0].type === "application/json" - ) { - // get the file from the file input - const currentfile = (e.target as HTMLInputElement).files![0]; - // read the file as text - currentfile.text().then((text) => { - // parse the text into a JSON object + id = await new Promise(resolve => { + input.onchange = async (e: Event) => { + if ((e.target as HTMLInputElement).files![0].type === "application/json") { + const currentfile = (e.target as HTMLInputElement).files![0]; + let text = await currentfile.text(); let flow: FlowType = JSON.parse(text); - - addFlow(flow, newProject); - }); - } - }; - // trigger the file input click event to open the file dialog - input.click(); + const flowId = await addFlow(flow, newProject); + resolve(flowId); + } + }; + // trigger the file input click event to open the file dialog + input.click(); + }); } + return id; } function uploadFlows() { diff --git a/src/frontend/src/pages/MainPage/index.tsx b/src/frontend/src/pages/MainPage/index.tsx index f6f111185..364519ea8 100644 --- a/src/frontend/src/pages/MainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/index.tsx @@ -18,7 +18,9 @@ export default function HomePage(): JSX.Element { removeFlow, uploadFlow, isLoading, } = useContext(TabsContext); - const dropdownOptions = [{name: "Import from JSON", onBtnClick: () => uploadFlow(true)}] + const dropdownOptions = [{name: "Import from JSON", onBtnClick: () => uploadFlow(true).then((id) => { + navigate("/flow/" + id); + })}] // Set a null id useEffect(() => { diff --git a/src/frontend/src/types/tabs/index.ts b/src/frontend/src/types/tabs/index.ts index 036f82717..4c5b99dd7 100644 --- a/src/frontend/src/types/tabs/index.ts +++ b/src/frontend/src/types/tabs/index.ts @@ -24,7 +24,7 @@ export type TabsContextType = { uploadFlows: () => void; isBuilt: boolean; setIsBuilt: (state: boolean) => void; - uploadFlow: (newFlow?: boolean, file?: File) => void; + uploadFlow: (newFlow?: boolean, file?: File) => Promise; hardReset: () => void; getNodeId: (nodeType: string) => string; tabsState: TabsState; From 156d8bb089318c0622f25c9bedbb6899b00cc377 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 11:43:41 -0300 Subject: [PATCH 25/48] =?UTF-8?q?=F0=9F=94=A7=20chore(auth.py):=20remove?= =?UTF-8?q?=20unnecessary=20comments=20and=20fields=20in=20AuthSettings=20?= =?UTF-8?q?class=20=F0=9F=94=A7=20chore(manager.py):=20remove=20unnecessar?= =?UTF-8?q?y=20arguments=20in=20AuthSettings=20instantiation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/services/settings/auth.py | 14 ++------------ src/backend/langflow/services/settings/manager.py | 3 +-- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/backend/langflow/services/settings/auth.py b/src/backend/langflow/services/settings/auth.py index c38417502..582aecb90 100644 --- a/src/backend/langflow/services/settings/auth.py +++ b/src/backend/langflow/services/settings/auth.py @@ -31,18 +31,8 @@ class AuthSettings(BaseSettings): # If AUTO_LOGIN = True # > The application does not request login and logs in automatically as a super user. AUTO_LOGIN: bool = False - FIRST_SUPERUSER: Optional[str] = Field( - "langflow", - description="First super user to be created if AUTO_LOGIN is True.", - env="LANGFLOW_FIRST_SUPERUSER", - allow_mutation=False, - ) - FIRST_SUPERUSER_PASSWORD: Optional[str] = Field( - "langflow", - description="First super user password to be created if AUTO_LOGIN is True.", - env="LANGFLOW_FIRST_SUPERUSER_PASSWORD", - allow_mutation=False, - ) + FIRST_SUPERUSER: str = "langflow" + FIRST_SUPERUSER_PASSWORD: str = "langflow" pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") diff --git a/src/backend/langflow/services/settings/manager.py b/src/backend/langflow/services/settings/manager.py index cef212c4e..b0af8b7f1 100644 --- a/src/backend/langflow/services/settings/manager.py +++ b/src/backend/langflow/services/settings/manager.py @@ -37,9 +37,8 @@ class SettingsManager(Service): settings = Settings(**settings_dict) if not settings.CONFIG_DIR: raise ValueError("CONFIG_DIR must be set in settings") + auth_settings = AuthSettings( CONFIG_DIR=settings.CONFIG_DIR, - FIRST_SUPERUSER=None, - FIRST_SUPERUSER_PASSWORD=None, ) return cls(settings, auth_settings) From d9323cb9a7b864703d306020ba5ce310cea58c49 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Thu, 31 Aug 2023 11:44:50 -0300 Subject: [PATCH 26/48] pre-commit make init fix --- .githooks/pre-commit | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit old mode 100644 new mode 100755 From 06e5e7dc4cf57dfb20026665602da3c6ea2b9e50 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Thu, 31 Aug 2023 11:48:36 -0300 Subject: [PATCH 27/48] Formatting issues --- src/backend/langflow/api/v1/base.py | 4 +- .../components/codeTabsComponent/index.tsx | 3 +- src/frontend/src/components/ui/skeleton.tsx | 6 +- src/frontend/src/contexts/alertContext.tsx | 2 +- src/frontend/src/modals/formModal/index.tsx | 185 +++++++++--------- .../src/modals/genericModal/index.tsx | 6 +- .../extraSidebarComponent/index.tsx | 7 +- src/frontend/src/pages/loginPage/index.tsx | 4 +- 8 files changed, 111 insertions(+), 106 deletions(-) diff --git a/src/backend/langflow/api/v1/base.py b/src/backend/langflow/api/v1/base.py index 39c8b0b9f..acffc1bc3 100644 --- a/src/backend/langflow/api/v1/base.py +++ b/src/backend/langflow/api/v1/base.py @@ -21,7 +21,7 @@ class FrontendNodeRequest(FrontendNode): class ValidatePromptRequest(BaseModel): name: str template: str - #optional for tweak call + # optional for tweak call frontend_node: Optional[FrontendNodeRequest] @@ -41,7 +41,7 @@ class CodeValidationResponse(BaseModel): class PromptValidationResponse(BaseModel): input_variables: list - #object return for tweak call + # object return for tweak call frontend_node: FrontendNodeRequest | object diff --git a/src/frontend/src/components/codeTabsComponent/index.tsx b/src/frontend/src/components/codeTabsComponent/index.tsx index 2fa6563a6..d807326f0 100644 --- a/src/frontend/src/components/codeTabsComponent/index.tsx +++ b/src/frontend/src/components/codeTabsComponent/index.tsx @@ -28,7 +28,6 @@ import { TabsList, TabsTrigger, } from "../../components/ui/tabs"; -import { alertContext } from "../../contexts/alertContext"; import { darkContext } from "../../contexts/darkContext"; import { typesContext } from "../../contexts/typesContext"; import { codeTabsPropsType } from "../../types/components"; @@ -57,7 +56,7 @@ export default function CodeTabsComponent({ }, [flow]); useEffect(() => { - if(tweaks){ + if (tweaks) { unselectAllNodes({ data, updateNodes: (nodes) => { diff --git a/src/frontend/src/components/ui/skeleton.tsx b/src/frontend/src/components/ui/skeleton.tsx index 6556585a4..f7a1573f2 100644 --- a/src/frontend/src/components/ui/skeleton.tsx +++ b/src/frontend/src/components/ui/skeleton.tsx @@ -1,4 +1,4 @@ -import { cn } from "../../utils/utils" +import { cn } from "../../utils/utils"; function Skeleton({ className, @@ -9,7 +9,7 @@ function Skeleton({ className={cn("animate-pulse rounded-md bg-border", className)} {...props} /> - ) + ); } -export { Skeleton } +export { Skeleton }; diff --git a/src/frontend/src/contexts/alertContext.tsx b/src/frontend/src/contexts/alertContext.tsx index ba46dddac..0b183a297 100644 --- a/src/frontend/src/contexts/alertContext.tsx +++ b/src/frontend/src/contexts/alertContext.tsx @@ -25,7 +25,7 @@ const initialValue: alertContextType = { notificationList: [], pushNotificationList: () => {}, clearNotificationList: () => {}, - removeFromNotificationList: () => {} + removeFromNotificationList: () => {}, }; export const alertContext = createContext(initialValue); diff --git a/src/frontend/src/modals/formModal/index.tsx b/src/frontend/src/modals/formModal/index.tsx index 0a9bf7483..2982b8738 100644 --- a/src/frontend/src/modals/formModal/index.tsx +++ b/src/frontend/src/modals/formModal/index.tsx @@ -8,7 +8,7 @@ import { classNames } from "../../utils/utils"; import ChatInput from "./chatInput"; import ChatMessage from "./chatMessage"; -import _, { set } from "lodash"; +import _ from "lodash"; import AccordionComponent from "../../components/AccordionComponent"; import IconComponent from "../../components/genericIconComponent"; import ToggleShadComponent from "../../components/toggleShadComponent"; @@ -25,9 +25,9 @@ import { Textarea } from "../../components/ui/textarea"; import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants"; import { AuthContext } from "../../contexts/authContext"; import { TabsContext } from "../../contexts/tabsContext"; +import { getBuildStatus } from "../../controllers/API"; import { TabsState } from "../../types/tabs"; import { validateNodes } from "../../utils/reactflowUtils"; -import { getBuildStatus } from "../../controllers/API"; export default function FormModal({ flow, @@ -156,19 +156,21 @@ export default function FormModal({ function handleOnClose(event: CloseEvent): void { if (isOpen.current) { - getBuildStatus(flow.id).then((response) => { - if (response.data.built) { - connectWS(); - } - else { + getBuildStatus(flow.id) + .then((response) => { + if (response.data.built) { + connectWS(); + } else { + setErrorData({ + title: "Please build the flow again before using the chat.", + }); + } + }) + .catch((error) => { setErrorData({ - title: "Please build the flow again before using the chat." - }) - } - }).catch((error) => { - setErrorData({title:error.data?.detail?error.data.detail:error.message}) - - }); + title: error.data?.detail ? error.data.detail : error.message, + }); + }); setErrorData({ title: event.reason }); setTimeout(() => { setLockChat(false); @@ -186,8 +188,9 @@ export default function FormModal({ const host = isDevelopment ? "localhost:7860" : window.location.host; const chatEndpoint = `/api/v1/chat/${chatId}`; - return `${isDevelopment ? "ws" : webSocketProtocol - }://${host}${chatEndpoint}?token=${encodeURIComponent(accessToken!)}`; + return `${ + isDevelopment ? "ws" : webSocketProtocol + }://${host}${chatEndpoint}?token=${encodeURIComponent(accessToken!)}`; } function handleWsMessage(data: any) { @@ -209,20 +212,20 @@ export default function FormModal({ newChatHistory.push( chatItem.files ? { - isSend: !chatItem.is_bot, - message: chatItem.message, - template: chatItem.template, - thought: chatItem.intermediate_steps, - files: chatItem.files, - chatKey: chatItem.chatKey, - } + isSend: !chatItem.is_bot, + message: chatItem.message, + template: chatItem.template, + thought: chatItem.intermediate_steps, + files: chatItem.files, + chatKey: chatItem.chatKey, + } : { - isSend: !chatItem.is_bot, - message: chatItem.message, - template: chatItem.template, - thought: chatItem.intermediate_steps, - chatKey: chatItem.chatKey, - } + isSend: !chatItem.is_bot, + message: chatItem.message, + template: chatItem.template, + thought: chatItem.intermediate_steps, + chatKey: chatItem.chatKey, + } ); } } @@ -442,73 +445,73 @@ export default function FormModal({ {tabsState[id.current]?.formKeysData?.input_keys ? Object.keys( - tabsState[id.current].formKeysData.input_keys! - ).map((key, index) => ( -
- - - {key} - + tabsState[id.current].formKeysData.input_keys! + ).map((key, index) => ( +
+ + + {key} + -
{ - event.stopPropagation(); - }} - > - - handleOnCheckedChange(value, key) - } - size="small" - disabled={tabsState[ - id.current - ].formKeysData.handle_keys!.some( - (t) => t === key - )} - /> +
{ + event.stopPropagation(); + }} + > + + handleOnCheckedChange(value, key) + } + size="small" + disabled={tabsState[ + id.current + ].formKeysData.handle_keys!.some( + (t) => t === key + )} + /> +
-
- } - key={index} - keyValue={key} - > -
- {tabsState[id.current].formKeysData.handle_keys!.some( - (t) => t === key - ) && ( + } + key={index} + keyValue={key} + > +
+ {tabsState[id.current].formKeysData.handle_keys!.some( + (t) => t === key + ) && (
Source: Component
)} - -
- -
- )) + +
+ + + )) : null} {tabsState[id.current].formKeysData.memory_keys!.map( (key, index) => ( @@ -522,7 +525,7 @@ export default function FormModal({
{ }} + setEnabled={() => {}} size="small" disabled={true} /> diff --git a/src/frontend/src/modals/genericModal/index.tsx b/src/frontend/src/modals/genericModal/index.tsx index e0875eba3..b29c5acf8 100644 --- a/src/frontend/src/modals/genericModal/index.tsx +++ b/src/frontend/src/modals/genericModal/index.tsx @@ -136,7 +136,11 @@ export default function GenericModal({ setSuccessData({ title: "Prompt is ready", }); - if(JSON.stringify(apiReturn.data?.frontend_node)!==JSON.stringify({})) setNodeClass!(apiReturn.data?.frontend_node); + if ( + JSON.stringify(apiReturn.data?.frontend_node) !== + JSON.stringify({}) + ) + setNodeClass!(apiReturn.data?.frontend_node); setModalOpen(closeModal); setValue(inputValue); } diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx index c8dd34628..8ea74390a 100644 --- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx @@ -21,8 +21,7 @@ export default function ExtraSidebar(): JSX.Element { const { data, templates } = useContext(typesContext); const { flows, tabId, uploadFlow, tabsState, saveFlow, isBuilt } = useContext(TabsContext); - const { setSuccessData, setErrorData } = - useContext(alertContext); + const { setSuccessData, setErrorData } = useContext(alertContext); const [dataFilter, setFilterData] = useState(data); const [search, setSearch] = useState(""); const isPending = tabsState[tabId]?.isPending; @@ -101,9 +100,7 @@ export default function ExtraSidebar(): JSX.Element {
{flow && flow.data && ( -
+
- +
From 594dfb13c1f5a116268137763ef7cdd78a6972fa Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 31 Aug 2023 11:49:51 -0300 Subject: [PATCH 28/48] =?UTF-8?q?=F0=9F=94=80=20chore(manager.py):=20ignor?= =?UTF-8?q?e=20type=20error=20for=20session=5Fmanager=5Ffactory=20import?= =?UTF-8?q?=20to=20prevent=20linting=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/services/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/langflow/services/manager.py b/src/backend/langflow/services/manager.py index bfe83fce8..ca9eb4e70 100644 --- a/src/backend/langflow/services/manager.py +++ b/src/backend/langflow/services/manager.py @@ -135,7 +135,7 @@ def initialize_session_manager(): """ Initialize the session manager. """ - from langflow.services.session import factory as session_manager_factory + from langflow.services.session import factory as session_manager_factory # type: ignore from langflow.services.cache import factory as cache_factory initialize_settings_manager() From d16456d795ca79bce00b992989b0e49ab98591b5 Mon Sep 17 00:00:00 2001 From: Cristhian Zanforlin Lousa Date: Thu, 31 Aug 2023 16:07:48 -0300 Subject: [PATCH 29/48] =?UTF-8?q?=F0=9F=8E=A8=20style(headerComponent):=20?= =?UTF-8?q?add=20cursor-pointer=20class=20to=20admin=20page=20and=20logout?= =?UTF-8?q?=20menu=20items=20for=20better=20user=20experience?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/components/headerComponent/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index 2a7219fed..4388fb081 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -149,11 +149,15 @@ export default function Header(): JSX.Element { My Account {isAdmin && ( - navigate("/admin")}> + navigate("/admin")} + > Admin Page )} { logout(); navigate("/login"); From 6d6ab9a8740bc632347c5f3b40291bdb549a9a54 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 2 Sep 2023 21:36:49 +0000 Subject: [PATCH 30/48] added missing backslashes to api key request definition --- src/frontend/src/controllers/API/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 780d784e5..d9ea890c8 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -468,7 +468,7 @@ export async function updateUser(user_id: string, user: Users) { export async function getApiKey() { try { - const res = await api.get(`${BASE_URL_API}api_key`); + const res = await api.get(`${BASE_URL_API}api_key/`); if (res.status === 200) { return res.data; } @@ -480,7 +480,7 @@ export async function getApiKey() { export async function createApiKey(name: string) { try { - const res = await api.post(`${BASE_URL_API}api_key`, { name }); + const res = await api.post(`${BASE_URL_API}api_key/`, { name }); if (res.status === 200) { return res.data; } From 2bbbf44b39374546bf01fe7973d99455fc8ee211 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 06:41:34 -0300 Subject: [PATCH 31/48] =?UTF-8?q?=F0=9F=90=9B=20fix(endpoints.py):=20chang?= =?UTF-8?q?e=20get=5Fall=20function=20signature=20to=20include=20settings?= =?UTF-8?q?=5Fmanager=20as=20a=20dependency=20to=20improve=20code=20readab?= =?UTF-8?q?ility=20=F0=9F=90=9B=20fix(flows.py):=20change=20update=5Fflow?= =?UTF-8?q?=20function=20signature=20to=20include=20settings=5Fmanager=20a?= =?UTF-8?q?s=20a=20dependency=20to=20improve=20code=20readability=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(login.py):=20change=20auto=5Flogin=20functio?= =?UTF-8?q?n=20signature=20to=20include=20settings=5Fmanager=20as=20a=20de?= =?UTF-8?q?pendency=20to=20improve=20code=20readability=20=F0=9F=90=9B=20f?= =?UTF-8?q?ix(users.py):=20change=20add=5Fuser=20function=20signature=20to?= =?UTF-8?q?=20include=20session=20as=20a=20dependency=20to=20improve=20cod?= =?UTF-8?q?e=20readability=20=F0=9F=90=9B=20fix(users.py):=20change=20read?= =?UTF-8?q?=5Fall=5Fusers=20function=20signature=20to=20include=20session?= =?UTF-8?q?=20as=20a=20dependency=20to=20improve=20code=20readability=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(users.py):=20change=20patch=5Fuser=20functio?= =?UTF-8?q?n=20signature=20to=20include=20session=20as=20a=20dependency=20?= =?UTF-8?q?to=20improve=20code=20readability=20=F0=9F=90=9B=20fix(users.py?= =?UTF-8?q?):=20change=20delete=5Fuser=20function=20signature=20to=20inclu?= =?UTF-8?q?de=20session=20as=20a=20dependency=20to=20improve=20code=20read?= =?UTF-8?q?ability=20=F0=9F=90=9B=20fix(users.py):=20change=20add=5Fsuper?= =?UTF-8?q?=5Fuser=5Ffor=5Ftesting=5Fpurposes=5Fdelete=5Fme=5Fbefore=5Fmer?= =?UTF-8?q?ge=5Finto=5Fdev=20function=20signature=20to=20include=20session?= =?UTF-8?q?=20as=20a=20dependency=20to=20improve=20code=20readability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/endpoints.py | 7 +++-- src/backend/langflow/api/v1/flows.py | 2 +- src/backend/langflow/api/v1/login.py | 6 ++-- src/backend/langflow/api/v1/users.py | 38 ++++++++++++------------ 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/backend/langflow/api/v1/endpoints.py b/src/backend/langflow/api/v1/endpoints.py index 813aaf415..05477a859 100644 --- a/src/backend/langflow/api/v1/endpoints.py +++ b/src/backend/langflow/api/v1/endpoints.py @@ -34,14 +34,15 @@ from sqlmodel import Session router = APIRouter(tags=["Base"]) -@router.get("/all") -def get_all(current_user: User = Depends(get_current_active_user)): +@router.get("/all", dependencies=[Depends(get_current_active_user)]) +def get_all( + settings_manager=Depends(get_settings_manager), +): logger.debug("Building langchain types dict") native_components = build_langchain_types_dict() # custom_components is a list of dicts # need to merge all the keys into one dict custom_components_from_file: dict[str, Any] = {} - settings_manager = get_settings_manager() if settings_manager.settings.COMPONENTS_PATH: logger.info( f"Building custom components from {settings_manager.settings.COMPONENTS_PATH}" diff --git a/src/backend/langflow/api/v1/flows.py b/src/backend/langflow/api/v1/flows.py index b215b9f95..be65048d4 100644 --- a/src/backend/langflow/api/v1/flows.py +++ b/src/backend/langflow/api/v1/flows.py @@ -83,6 +83,7 @@ def update_flow( flow_id: UUID, flow: FlowUpdate, current_user: User = Depends(get_current_active_user), + settings_manager=Depends(get_settings_manager), ): """Update a flow.""" @@ -90,7 +91,6 @@ def update_flow( if not db_flow: raise HTTPException(status_code=404, detail="Flow not found") flow_data = flow.dict(exclude_unset=True) - settings_manager = get_settings_manager() if settings_manager.settings.REMOVE_API_KEYS: flow_data = remove_api_keys(flow_data) for key, value in flow_data.items(): diff --git a/src/backend/langflow/api/v1/login.py b/src/backend/langflow/api/v1/login.py index afe67a916..4241b8d47 100644 --- a/src/backend/langflow/api/v1/login.py +++ b/src/backend/langflow/api/v1/login.py @@ -34,9 +34,9 @@ async def login_to_get_access_token( @router.get("/auto_login") -async def auto_login(db: Session = Depends(get_session)): - settings_manager = get_settings_manager() - +async def auto_login( + db: Session = Depends(get_session), settings_manager=Depends(get_settings_manager) +): if settings_manager.auth_settings.AUTO_LOGIN: return create_user_longterm_token(db) diff --git a/src/backend/langflow/api/v1/users.py b/src/backend/langflow/api/v1/users.py index 5094409cb..517dd7f69 100644 --- a/src/backend/langflow/api/v1/users.py +++ b/src/backend/langflow/api/v1/users.py @@ -29,7 +29,7 @@ router = APIRouter(tags=["Users"]) @router.post("/user", response_model=UserRead, status_code=201) def add_user( user: UserCreate, - db: Session = Depends(get_session), + session: Session = Depends(get_session), ) -> User: """ Add a new user to the database. @@ -38,11 +38,11 @@ def add_user( try: new_user.password = get_password_hash(user.password) - db.add(new_user) - db.commit() - db.refresh(new_user) + session.add(new_user) + session.commit() + session.refresh(new_user) except IntegrityError as e: - db.rollback() + session.rollback() raise HTTPException( status_code=400, detail="This username is unavailable." ) from e @@ -65,16 +65,16 @@ def read_all_users( skip: int = 0, limit: int = 10, current_user: Session = Depends(get_current_active_superuser), - db: Session = Depends(get_session), + session: Session = Depends(get_session), ) -> UsersResponse: """ Retrieve a list of users from the database with pagination. """ query = select(User).offset(skip).limit(limit) - users = db.execute(query).fetchall() + users = session.execute(query).fetchall() count_query = select(func.count()).select_from(User) # type: ignore - total_count = db.execute(count_query).scalar() + total_count = session.execute(count_query).scalar() return UsersResponse( total_count=total_count, # type: ignore @@ -87,19 +87,19 @@ def patch_user( user_id: UUID, user: UserUpdate, _: Session = Depends(get_current_active_user), - db: Session = Depends(get_session), + session: Session = Depends(get_session), ) -> User: """ Update an existing user's data. """ - return update_user(user_id, user, db) + return update_user(user_id, user, session) @router.delete("/user/{user_id}") def delete_user( user_id: UUID, current_user: User = Depends(get_current_active_superuser), - db: Session = Depends(get_session), + session: Session = Depends(get_session), ) -> dict: """ Delete a user from the database. @@ -113,12 +113,12 @@ def delete_user( status_code=403, detail="You don't have the permission to delete this user" ) - user_db = db.query(User).filter(User.id == user_id).first() + user_db = session.query(User).filter(User.id == user_id).first() if not user_db: raise HTTPException(status_code=404, detail="User not found") - db.delete(user_db) - db.commit() + session.delete(user_db) + session.commit() return {"detail": "User deleted"} @@ -126,7 +126,7 @@ def delete_user( # TODO: REMOVE - Just for testing purposes @router.post("/super_user", response_model=User) def add_super_user_for_testing_purposes_delete_me_before_merge_into_dev( - db: Session = Depends(get_session), + session: Session = Depends(get_session), ) -> User: """ Add a superuser for testing purposes. @@ -141,11 +141,11 @@ def add_super_user_for_testing_purposes_delete_me_before_merge_into_dev( ) try: - db.add(new_user) - db.commit() - db.refresh(new_user) + session.add(new_user) + session.commit() + session.refresh(new_user) except IntegrityError as e: - db.rollback() + session.rollback() raise HTTPException(status_code=400, detail="User exists") from e return new_user From 84a0d3acb39c14f8e0f51a2cd8f2dac11904fc89 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 06:42:01 -0300 Subject: [PATCH 32/48] =?UTF-8?q?=F0=9F=94=A7=20fix(chat.py):=20remove=20u?= =?UTF-8?q?nused=20imports=20and=20type=20hints=20to=20improve=20code=20re?= =?UTF-8?q?adability=20=E2=9C=A8=20feat(chat.py):=20add=20dependency=20inj?= =?UTF-8?q?ection=20for=20ChatManager=20in=20chat=20and=20init=5Fbuild=20r?= =?UTF-8?q?outes=20to=20improve=20modularity=20and=20testability=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(chat.py):=20remove=20duplicate=20instantiati?= =?UTF-8?q?on=20of=20ChatManager=20in=20chat=20and=20init=5Fbuild=20routes?= =?UTF-8?q?=20to=20improve=20efficiency=20=F0=9F=94=A7=20fix(chat.py):=20r?= =?UTF-8?q?emove=20duplicate=20instantiation=20of=20ChatManager=20in=20str?= =?UTF-8?q?eam=5Fbuild=20route=20to=20improve=20efficiency=20=F0=9F=94=A7?= =?UTF-8?q?=20fix(utils.py):=20add=20missing=20import=20for=20ChatManager?= =?UTF-8?q?=20in=20get=5Fchat=5Fmanager=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/chat.py | 20 ++++++++++---------- src/backend/langflow/services/utils.py | 8 +++++++- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index 9d322b03c..2c276c75d 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -11,17 +11,14 @@ from fastapi.responses import StreamingResponse from langflow.api.utils import build_input_keys_response from langflow.api.v1.schemas import BuildStatus, BuiltResponse, InitResponse, StreamData -from langflow.services import service_manager, ServiceType from langflow.graph.graph.base import Graph from langflow.services.auth.utils import get_current_active_user, get_current_user -from langflow.services.utils import get_session +from langflow.services.utils import get_chat_manager, get_session from langflow.utils.logger import logger from cachetools import LRUCache from sqlmodel import Session -from typing import TYPE_CHECKING +from langflow.services.chat.manager import ChatManager -if TYPE_CHECKING: - from langflow.services.chat.manager import ChatManager router = APIRouter(tags=["Chat"]) @@ -34,6 +31,7 @@ async def chat( websocket: WebSocket, token: str = Query(...), db: Session = Depends(get_session), + chat_manager: "ChatManager" = Depends(get_chat_manager), ): """Websocket endpoint for chat.""" try: @@ -48,7 +46,6 @@ async def chat( code=status.WS_1008_POLICY_VIOLATION, reason="Unauthorized" ) - chat_manager: "ChatManager" = service_manager.get(ServiceType.CHAT_MANAGER) if client_id in chat_manager.in_memory_cache: await chat_manager.handle_websocket(client_id, websocket) else: @@ -72,7 +69,10 @@ async def chat( @router.post("/build/init/{flow_id}", response_model=InitResponse, status_code=201) async def init_build( - graph_data: dict, flow_id: str, current_user=Depends(get_current_active_user) + graph_data: dict, + flow_id: str, + current_user=Depends(get_current_active_user), + chat_manager: "ChatManager" = Depends(get_chat_manager), ): """Initialize the build by storing graph data and returning a unique session ID.""" @@ -87,7 +87,6 @@ async def init_build( return InitResponse(flowId=flow_id) # Delete from cache if already exists - chat_manager = service_manager.get(ServiceType.CHAT_MANAGER) if flow_id in chat_manager.in_memory_cache: with chat_manager.in_memory_cache._lock: chat_manager.in_memory_cache.delete(flow_id) @@ -123,7 +122,9 @@ async def build_status(flow_id: str): @router.get("/build/stream/{flow_id}", response_class=StreamingResponse) -async def stream_build(flow_id: str): +async def stream_build( + flow_id: str, chat_manager: "ChatManager" = Depends(get_chat_manager) +): """Stream the build process based on stored flow data.""" async def event_stream(flow_id): @@ -202,7 +203,6 @@ async def stream_build(flow_id: str): "handle_keys": [], } yield str(StreamData(event="message", data=input_keys_response)) - chat_manager = service_manager.get(ServiceType.CHAT_MANAGER) chat_manager.set_cache(flow_id, langchain_object) # We need to reset the chat history chat_manager.chat_history.empty_history(flow_id) diff --git a/src/backend/langflow/services/utils.py b/src/backend/langflow/services/utils.py index 6860f8928..708377d14 100644 --- a/src/backend/langflow/services/utils.py +++ b/src/backend/langflow/services/utils.py @@ -5,6 +5,8 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from langflow.services.database.manager import DatabaseManager from langflow.services.settings.manager import SettingsManager + from langflow.services.chat.manager import ChatManager + from sqlmodel import Session def get_settings_manager() -> "SettingsManager": @@ -15,6 +17,10 @@ def get_db_manager() -> "DatabaseManager": return service_manager.get(ServiceType.DATABASE_MANAGER) -def get_session(): +def get_session() -> "Session": db_manager = service_manager.get(ServiceType.DATABASE_MANAGER) yield from db_manager.get_session() + + +def get_chat_manager() -> "ChatManager": + return service_manager.get(ServiceType.CHAT_MANAGER) From 37ebbf4e65bfae98f54515c888df106c1b107bfd Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 06:42:41 -0300 Subject: [PATCH 33/48] Formatting --- .../DropdownButtonComponent/index.tsx | 4 +--- src/frontend/src/contexts/tabsContext.tsx | 6 ++++-- src/frontend/src/pages/MainPage/index.tsx | 19 +++++++++++++------ src/frontend/src/types/components/index.ts | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/frontend/src/components/DropdownButtonComponent/index.tsx b/src/frontend/src/components/DropdownButtonComponent/index.tsx index 1ddddb3c1..784a08528 100644 --- a/src/frontend/src/components/DropdownButtonComponent/index.tsx +++ b/src/frontend/src/components/DropdownButtonComponent/index.tsx @@ -39,9 +39,7 @@ export default function DropdownButton({ }} > {!showOptions ? ( - + ) : ( )} diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index 339ad67b5..49de70974 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -315,9 +315,11 @@ export function TabsProvider({ children }: { children: ReactNode }) { input.type = "file"; input.accept = ".json"; // add a change event listener to the file input - id = await new Promise(resolve => { + id = await new Promise((resolve) => { input.onchange = async (e: Event) => { - if ((e.target as HTMLInputElement).files![0].type === "application/json") { + if ( + (e.target as HTMLInputElement).files![0].type === "application/json" + ) { const currentfile = (e.target as HTMLInputElement).files![0]; let text = await currentfile.text(); let flow: FlowType = JSON.parse(text); diff --git a/src/frontend/src/pages/MainPage/index.tsx b/src/frontend/src/pages/MainPage/index.tsx index 364519ea8..9582d4c57 100644 --- a/src/frontend/src/pages/MainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/index.tsx @@ -1,5 +1,6 @@ import { useContext, useEffect } from "react"; import { Link, useNavigate } from "react-router-dom"; +import DropdownButton from "../../components/DropdownButtonComponent"; import { CardComponent } from "../../components/cardComponent"; import IconComponent from "../../components/genericIconComponent"; import Header from "../../components/headerComponent"; @@ -7,7 +8,6 @@ import { SkeletonCardComponent } from "../../components/skeletonCardComponent"; import { Button } from "../../components/ui/button"; import { USER_PROJECTS_HEADER } from "../../constants/constants"; import { TabsContext } from "../../contexts/tabsContext"; -import DropdownButton from "../../components/DropdownButtonComponent"; export default function HomePage(): JSX.Element { const { flows, @@ -15,12 +15,19 @@ export default function HomePage(): JSX.Element { downloadFlows, uploadFlows, addFlow, - removeFlow, uploadFlow, + removeFlow, + uploadFlow, isLoading, } = useContext(TabsContext); - const dropdownOptions = [{name: "Import from JSON", onBtnClick: () => uploadFlow(true).then((id) => { - navigate("/flow/" + id); - })}] + const dropdownOptions = [ + { + name: "Import from JSON", + onBtnClick: () => + uploadFlow(true).then((id) => { + navigate("/flow/" + id); + }), + }, + ]; // Set a null id useEffect(() => { @@ -73,7 +80,7 @@ export default function HomePage(): JSX.Element {
- Manage your personal projects. Download or upload your collection. + Manage your personal projects. Download or upload your collection.
{isLoading && flows.length == 0 ? ( diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index b61ddf07d..4b72ef36a 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -548,5 +548,5 @@ export type fetchErrorComponentType = { export type dropdownButtonPropsType = { firstButtonName: string; onFirstBtnClick: () => void; - options: Array<{ name: string; onBtnClick: () => void; }>; + options: Array<{ name: string; onBtnClick: () => void }>; }; From 43864904efd4051a91ee9e9160e9d97f7ba40a6e Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 07:00:38 -0300 Subject: [PATCH 34/48] =?UTF-8?q?=F0=9F=94=A7=20chore(Makefile):=20update?= =?UTF-8?q?=20mypy=20command=20to=20only=20check=20files=20in=20src/backen?= =?UTF-8?q?d/langflow=20directory=20to=20improve=20performance=20and=20red?= =?UTF-8?q?uce=20noise=20in=20the=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 59dd4a82d..59f326853 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ format: cd src/frontend && npm run format lint: - poetry run mypy --exclude .venv . + poetry run mypy src/backend/langflow poetry run black . --check poetry run ruff . --fix From 833fb4ad8fdefba08477c7d520293697c129265e Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 07:01:05 -0300 Subject: [PATCH 35/48] =?UTF-8?q?=F0=9F=94=80=20chore(utils.py):=20add=20t?= =?UTF-8?q?ype=20hint=20for=20get=5Fsession()=20function=20to=20indicate?= =?UTF-8?q?=20it=20returns=20a=20generator=20instead=20of=20a=20Session=20?= =?UTF-8?q?object?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/services/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/services/utils.py b/src/backend/langflow/services/utils.py index 708377d14..8b32aef02 100644 --- a/src/backend/langflow/services/utils.py +++ b/src/backend/langflow/services/utils.py @@ -1,5 +1,5 @@ from langflow.services import ServiceType, service_manager -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Generator if TYPE_CHECKING: @@ -17,7 +17,7 @@ def get_db_manager() -> "DatabaseManager": return service_manager.get(ServiceType.DATABASE_MANAGER) -def get_session() -> "Session": +def get_session() -> Generator["Session", None, None]: db_manager = service_manager.get(ServiceType.DATABASE_MANAGER) yield from db_manager.get_session() From 53c5a3ccdeef6baca22ae2136111f79091bcce88 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 07:05:10 -0300 Subject: [PATCH 36/48] =?UTF-8?q?=F0=9F=90=9B=20fix(base.py):=20make=20fro?= =?UTF-8?q?ntend=5Fnode=20field=20in=20PromptValidationResponse=20optional?= =?UTF-8?q?=20to=20handle=20cases=20where=20it=20is=20not=20provided?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/langflow/api/v1/base.py b/src/backend/langflow/api/v1/base.py index acffc1bc3..b1071bea2 100644 --- a/src/backend/langflow/api/v1/base.py +++ b/src/backend/langflow/api/v1/base.py @@ -42,7 +42,7 @@ class CodeValidationResponse(BaseModel): class PromptValidationResponse(BaseModel): input_variables: list # object return for tweak call - frontend_node: FrontendNodeRequest | object + frontend_node: Optional[FrontendNodeRequest] = None INVALID_CHARACTERS = { From b1c24054c6fbaf51b57d6a36247da15b6940181f Mon Sep 17 00:00:00 2001 From: root Date: Mon, 4 Sep 2023 11:41:34 +0000 Subject: [PATCH 37/48] added indent to index dropping on non-existing table --- .../langflow/alembic/versions/260dbcc8b680_adds_tables.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/langflow/alembic/versions/260dbcc8b680_adds_tables.py b/src/backend/langflow/alembic/versions/260dbcc8b680_adds_tables.py index 221e66933..53e049a05 100644 --- a/src/backend/langflow/alembic/versions/260dbcc8b680_adds_tables.py +++ b/src/backend/langflow/alembic/versions/260dbcc8b680_adds_tables.py @@ -30,10 +30,10 @@ def upgrade() -> None: # and other related indices if "flowstyle" in existing_tables: op.drop_table("flowstyle") - if "ix_flowstyle_flow_id" in [ - index["name"] for index in inspector.get_indexes("flowstyle") - ]: - op.drop_index("ix_flowstyle_flow_id", table_name="flowstyle") + if "ix_flowstyle_flow_id" in [ + index["name"] for index in inspector.get_indexes("flowstyle") + ]: + op.drop_index("ix_flowstyle_flow_id", table_name="flowstyle") existing_indices_flow = [] existing_fks_flow = [] From 2ab3fcb28a3fbabd3507deab7b03ae288d5555a1 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 10:04:21 -0300 Subject: [PATCH 38/48] =?UTF-8?q?=F0=9F=90=9B=20fix(base.py):=20set=20defa?= =?UTF-8?q?ult=20value=20of=20frontend=5Fnode=20to=20None=20in=20ValidateP?= =?UTF-8?q?romptRequest=20class=20to=20avoid=20potential=20NoneType=20erro?= =?UTF-8?q?rs=20=F0=9F=90=9B=20fix(validate.py):=20set=20frontend=5Fnode?= =?UTF-8?q?=20to=20None=20instead=20of=20an=20empty=20dictionary=20in=20po?= =?UTF-8?q?st=5Fvalidate=5Fprompt=20function=20to=20align=20with=20the=20d?= =?UTF-8?q?efault=20value=20in=20ValidatePromptRequest=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/base.py | 2 +- src/backend/langflow/api/v1/validate.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/api/v1/base.py b/src/backend/langflow/api/v1/base.py index b1071bea2..f2c2f3f59 100644 --- a/src/backend/langflow/api/v1/base.py +++ b/src/backend/langflow/api/v1/base.py @@ -22,7 +22,7 @@ class ValidatePromptRequest(BaseModel): name: str template: str # optional for tweak call - frontend_node: Optional[FrontendNodeRequest] + frontend_node: Optional[FrontendNodeRequest] = None # Build ValidationResponse class for {"imports": {"errors": []}, "function": {"errors": []}} diff --git a/src/backend/langflow/api/v1/validate.py b/src/backend/langflow/api/v1/validate.py index da76d25bc..64ef60549 100644 --- a/src/backend/langflow/api/v1/validate.py +++ b/src/backend/langflow/api/v1/validate.py @@ -35,7 +35,7 @@ def post_validate_prompt(prompt_request: ValidatePromptRequest): if prompt_request.frontend_node is None: return PromptValidationResponse( input_variables=input_variables, - frontend_node={}, + frontend_node=None, ) old_custom_fields = get_old_custom_fields(prompt_request) From 5f98f0bbd9997c803bf255c9a885ca8a4a0ce376 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 11:34:38 -0300 Subject: [PATCH 39/48] =?UTF-8?q?=F0=9F=93=A6=20chore(pyproject.toml):=20a?= =?UTF-8?q?dd=20loguru=20package=20as=20a=20dependency=20for=20improved=20?= =?UTF-8?q?logging=20capabilities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 10 +++++----- pyproject.toml | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index cdb1ffd1a..c2a290db4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3047,13 +3047,13 @@ server = ["fastapi (>=0.100.0)", "pydantic-settings (>=2.0.1)", "sse-starlette ( [[package]] name = "loguru" -version = "0.7.0" +version = "0.7.1" description = "Python logging made (stupidly) simple" optional = false python-versions = ">=3.5" files = [ - {file = "loguru-0.7.0-py3-none-any.whl", hash = "sha256:b93aa30099fa6860d4727f1b81f8718e965bb96253fa190fab2077aaad6d15d3"}, - {file = "loguru-0.7.0.tar.gz", hash = "sha256:1612053ced6ae84d7959dd7d5e431a0532642237ec21f7fd83ac73fe539e03e1"}, + {file = "loguru-0.7.1-py3-none-any.whl", hash = "sha256:046bf970cb3cad77a28d607cbf042ac25a407db987a1e801c7f7e692469982f9"}, + {file = "loguru-0.7.1.tar.gz", hash = "sha256:7ba2a7d81b79a412b0ded69bd921e012335e80fd39937a633570f273a343579e"}, ] [package.dependencies] @@ -3061,7 +3061,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["Sphinx (==5.3.0)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v0.990)", "pre-commit (==3.2.1)", "pytest (==6.1.2)", "pytest (==7.2.1)", "pytest-cov (==2.12.1)", "pytest-cov (==4.0.0)", "pytest-mypy-plugins (==1.10.1)", "pytest-mypy-plugins (==1.9.3)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.2.0)", "tox (==3.27.1)", "tox (==4.4.6)"] +dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "pre-commit (==3.3.1)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"] [[package]] name = "lxml" @@ -7784,4 +7784,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.11" -content-hash = "a3a506d483c2db7169a9790090095d1764aa5be223d135c6fc3fc2768dfef36c" +content-hash = "6523f2e35458c6d0b8d281e20dd2233180128805ea07199c073224b0d6f75ee7" diff --git a/pyproject.toml b/pyproject.toml index 796145886..077a0cb39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,6 +84,7 @@ python-jose = "^3.3.0" metaphor-python = "^0.1.11" markupsafe = "^2.1.3" pywin32 = { version = "^306", markers = "sys_platform == 'win32'" } +loguru = "^0.7.1" [tool.poetry.group.dev.dependencies] black = "^23.1.0" From 87eb8b1a95f6af27daf7d8212fb1e586605ce0e9 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 11:35:22 -0300 Subject: [PATCH 40/48] =?UTF-8?q?=F0=9F=94=A7=20chore(logger.py):=20refact?= =?UTF-8?q?or=20logger=20configuration=20to=20use=20loguru=20library=20and?= =?UTF-8?q?=20improve=20log=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/utils/logger.py | 36 +++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/backend/langflow/utils/logger.py b/src/backend/langflow/utils/logger.py index deb0f75ca..b881a614c 100644 --- a/src/backend/langflow/utils/logger.py +++ b/src/backend/langflow/utils/logger.py @@ -1,30 +1,34 @@ -import logging +from loguru import logger from pathlib import Path - from rich.logging import RichHandler -logger = logging.getLogger("langflow") +def configure(log_level: str = "DEBUG", log_file: Path = None): + log_format = "{time:HH:mm:ss} - {level: <8} - {message}" + logger.remove() # Remove default handlers -def configure(log_level: str = "DEBUG", log_file: Path = None): # type: ignore - log_format = "%(asctime)s - %(levelname)s - %(message)s" - log_level_value = getattr(logging, log_level.upper(), logging.INFO) - - logging.basicConfig( - level=log_level_value, - format=log_format, - datefmt="[%X]", - handlers=[RichHandler(rich_tracebacks=True)], + # Configure loguru to use RichHandler + logger.configure( + handlers=[ + { + "sink": RichHandler(rich_tracebacks=True, markup=True), + "format": log_format, + "level": log_level, + } + ] ) if log_file: log_file = Path(log_file) log_file.parent.mkdir(parents=True, exist_ok=True) - file_handler = logging.FileHandler(log_file) - file_handler.setFormatter(logging.Formatter(log_format)) - logger.addHandler(file_handler) + logger.add( + sink=str(log_file), + level=log_level, + format=log_format, + rotation="10 MB", # Log rotation based on file size + ) - logger.info(f"Logger set up with log level: {log_level_value}({log_level})") + logger.info(f"Logger set up with log level: {log_level}") if log_file: logger.info(f"Log file: {log_file}") From 58c3e5e9dc588dee88600927a2f5b21a1ed545ba Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 11:38:39 -0300 Subject: [PATCH 41/48] refactor: :sparkles: replace loggers with loguru --- src/backend/langflow/api/v1/callback.py | 2 +- src/backend/langflow/api/v1/chat.py | 2 +- src/backend/langflow/api/v1/endpoints.py | 2 +- src/backend/langflow/api/v1/validate.py | 2 +- src/backend/langflow/graph/edge/base.py | 2 +- src/backend/langflow/graph/graph/base.py | 2 +- src/backend/langflow/graph/vertex/base.py | 2 +- src/backend/langflow/interface/agents/base.py | 2 +- src/backend/langflow/interface/base.py | 2 +- src/backend/langflow/interface/chains/base.py | 2 +- src/backend/langflow/interface/custom/base.py | 2 +- src/backend/langflow/interface/custom/directory_reader.py | 2 +- src/backend/langflow/interface/document_loaders/base.py | 2 +- src/backend/langflow/interface/embeddings/base.py | 2 +- src/backend/langflow/interface/initialize/loading.py | 2 +- src/backend/langflow/interface/llms/base.py | 2 +- src/backend/langflow/interface/memories/base.py | 2 +- src/backend/langflow/interface/output_parsers/base.py | 2 +- src/backend/langflow/interface/prompts/base.py | 2 +- src/backend/langflow/interface/retrievers/base.py | 2 +- src/backend/langflow/interface/run.py | 2 +- src/backend/langflow/interface/text_splitters/base.py | 2 +- src/backend/langflow/interface/toolkits/base.py | 2 +- src/backend/langflow/interface/tools/util.py | 2 +- src/backend/langflow/interface/types.py | 2 +- src/backend/langflow/interface/utilities/base.py | 2 +- src/backend/langflow/interface/utils.py | 2 +- src/backend/langflow/interface/vector_store/base.py | 2 +- src/backend/langflow/interface/wrappers/base.py | 2 +- src/backend/langflow/processing/base.py | 2 +- src/backend/langflow/processing/process.py | 2 +- src/backend/langflow/services/chat/manager.py | 2 +- src/backend/langflow/services/chat/utils.py | 2 +- src/backend/langflow/services/database/manager.py | 2 +- src/backend/langflow/services/database/utils.py | 2 +- src/backend/langflow/services/manager.py | 2 +- src/backend/langflow/services/settings/auth.py | 2 +- src/backend/langflow/services/settings/base.py | 2 +- src/backend/langflow/services/settings/manager.py | 2 +- src/backend/langflow/services/settings/utils.py | 2 +- 40 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/backend/langflow/api/v1/callback.py b/src/backend/langflow/api/v1/callback.py index 69dbf5082..2a16a0bd2 100644 --- a/src/backend/langflow/api/v1/callback.py +++ b/src/backend/langflow/api/v1/callback.py @@ -10,7 +10,7 @@ from fastapi import WebSocket from langchain.schema import AgentAction, LLMResult, AgentFinish -from langflow.utils.logger import logger +from loguru import logger # https://github.com/hwchase17/chat-langchain/blob/master/callback.py diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index 9d322b03c..a79ed2ccd 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -15,7 +15,7 @@ from langflow.services import service_manager, ServiceType from langflow.graph.graph.base import Graph from langflow.services.auth.utils import get_current_active_user, get_current_user from langflow.services.utils import get_session -from langflow.utils.logger import logger +from loguru import logger from cachetools import LRUCache from sqlmodel import Session from typing import TYPE_CHECKING diff --git a/src/backend/langflow/api/v1/endpoints.py b/src/backend/langflow/api/v1/endpoints.py index 813aaf415..957e003bc 100644 --- a/src/backend/langflow/api/v1/endpoints.py +++ b/src/backend/langflow/api/v1/endpoints.py @@ -7,7 +7,7 @@ from langflow.services.database.models.flow import Flow from langflow.processing.process import process_graph_cached, process_tweaks from langflow.services.database.models.user.user import User from langflow.services.utils import get_settings_manager -from langflow.utils.logger import logger +from loguru import logger from fastapi import APIRouter, Depends, HTTPException, UploadFile, Body, status import sqlalchemy as sa from langflow.interface.custom.custom_component import CustomComponent diff --git a/src/backend/langflow/api/v1/validate.py b/src/backend/langflow/api/v1/validate.py index da76d25bc..4a3ee71c6 100644 --- a/src/backend/langflow/api/v1/validate.py +++ b/src/backend/langflow/api/v1/validate.py @@ -8,7 +8,7 @@ from langflow.api.v1.base import ( validate_prompt, ) from langflow.template.field.base import TemplateField -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.validate import validate_code # build router diff --git a/src/backend/langflow/graph/edge/base.py b/src/backend/langflow/graph/edge/base.py index dc7eab328..2df20cbde 100644 --- a/src/backend/langflow/graph/edge/base.py +++ b/src/backend/langflow/graph/edge/base.py @@ -1,4 +1,4 @@ -from langflow.utils.logger import logger +from loguru import logger from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/backend/langflow/graph/graph/base.py b/src/backend/langflow/graph/graph/base.py index 2b22d352c..94964e472 100644 --- a/src/backend/langflow/graph/graph/base.py +++ b/src/backend/langflow/graph/graph/base.py @@ -10,7 +10,7 @@ from langflow.graph.vertex.types import ( ) from langflow.interface.tools.constants import FILE_TOOLS from langflow.utils import payload -from langflow.utils.logger import logger +from loguru import logger from langchain.chains.base import Chain diff --git a/src/backend/langflow/graph/vertex/base.py b/src/backend/langflow/graph/vertex/base.py index d5c4beed9..0f9a5e8a9 100644 --- a/src/backend/langflow/graph/vertex/base.py +++ b/src/backend/langflow/graph/vertex/base.py @@ -3,7 +3,7 @@ from langflow.graph.utils import UnbuiltObject from langflow.interface.initialize import loading from langflow.interface.listing import lazy_load_dict from langflow.utils.constants import DIRECT_TYPES -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import sync_to_async diff --git a/src/backend/langflow/interface/agents/base.py b/src/backend/langflow/interface/agents/base.py index ec8c42aba..574264e47 100644 --- a/src/backend/langflow/interface/agents/base.py +++ b/src/backend/langflow/interface/agents/base.py @@ -8,7 +8,7 @@ from langflow.interface.base import LangChainTypeCreator from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.agents import AgentFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class, build_template_from_method diff --git a/src/backend/langflow/interface/base.py b/src/backend/langflow/interface/base.py index d1ed83b5a..b006a3174 100644 --- a/src/backend/langflow/interface/base.py +++ b/src/backend/langflow/interface/base.py @@ -8,7 +8,7 @@ from pydantic import BaseModel from langflow.template.field.base import TemplateField from langflow.template.frontend_node.base import FrontendNode from langflow.template.template.base import Template -from langflow.utils.logger import logger +from loguru import logger # Assuming necessary imports for Field, Template, and FrontendNode classes diff --git a/src/backend/langflow/interface/chains/base.py b/src/backend/langflow/interface/chains/base.py index b906dbd25..755ac82dd 100644 --- a/src/backend/langflow/interface/chains/base.py +++ b/src/backend/langflow/interface/chains/base.py @@ -6,7 +6,7 @@ from langflow.interface.importing.utils import import_class from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.chains import ChainFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class, build_template_from_method from langchain import chains from langchain_experimental.sql import SQLDatabaseChain # type: ignore diff --git a/src/backend/langflow/interface/custom/base.py b/src/backend/langflow/interface/custom/base.py index 06e874fa7..45a3ea215 100644 --- a/src/backend/langflow/interface/custom/base.py +++ b/src/backend/langflow/interface/custom/base.py @@ -8,7 +8,7 @@ from langflow.interface.custom.custom_component import CustomComponent from langflow.template.frontend_node.custom_components import ( CustomComponentFrontendNode, ) -from langflow.utils.logger import logger +from loguru import logger # Assuming necessary imports for Field, Template, and FrontendNode classes diff --git a/src/backend/langflow/interface/custom/directory_reader.py b/src/backend/langflow/interface/custom/directory_reader.py index 44b2d4f1b..01b11a4a6 100644 --- a/src/backend/langflow/interface/custom/directory_reader.py +++ b/src/backend/langflow/interface/custom/directory_reader.py @@ -1,7 +1,7 @@ import os import ast import zlib -from langflow.utils.logger import logger +from loguru import logger class CustomComponentPathValueError(ValueError): diff --git a/src/backend/langflow/interface/document_loaders/base.py b/src/backend/langflow/interface/document_loaders/base.py index db0832ff3..a2c147e16 100644 --- a/src/backend/langflow/interface/document_loaders/base.py +++ b/src/backend/langflow/interface/document_loaders/base.py @@ -5,7 +5,7 @@ from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.documentloaders import DocumentLoaderFrontNode from langflow.interface.custom_lists import documentloaders_type_to_cls_dict -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class diff --git a/src/backend/langflow/interface/embeddings/base.py b/src/backend/langflow/interface/embeddings/base.py index 169985d37..1063d10d1 100644 --- a/src/backend/langflow/interface/embeddings/base.py +++ b/src/backend/langflow/interface/embeddings/base.py @@ -6,7 +6,7 @@ from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.base import FrontendNode from langflow.template.frontend_node.embeddings import EmbeddingFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class diff --git a/src/backend/langflow/interface/initialize/loading.py b/src/backend/langflow/interface/initialize/loading.py index 589d4b3ff..b600fb5b2 100644 --- a/src/backend/langflow/interface/initialize/loading.py +++ b/src/backend/langflow/interface/initialize/loading.py @@ -34,7 +34,7 @@ from langflow.utils import validate from langchain.chains.base import Chain from langchain.vectorstores.base import VectorStore from langchain.document_loaders.base import BaseLoader -from langflow.utils.logger import logger +from loguru import logger if TYPE_CHECKING: from langflow import CustomComponent diff --git a/src/backend/langflow/interface/llms/base.py b/src/backend/langflow/interface/llms/base.py index f562b99ed..87e4937cf 100644 --- a/src/backend/langflow/interface/llms/base.py +++ b/src/backend/langflow/interface/llms/base.py @@ -5,7 +5,7 @@ from langflow.interface.custom_lists import llm_type_to_cls_dict from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.llms import LLMFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class diff --git a/src/backend/langflow/interface/memories/base.py b/src/backend/langflow/interface/memories/base.py index 70665602c..61c6cc430 100644 --- a/src/backend/langflow/interface/memories/base.py +++ b/src/backend/langflow/interface/memories/base.py @@ -6,7 +6,7 @@ from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.base import FrontendNode from langflow.template.frontend_node.memories import MemoryFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class, build_template_from_method from langflow.custom.customs import get_custom_nodes diff --git a/src/backend/langflow/interface/output_parsers/base.py b/src/backend/langflow/interface/output_parsers/base.py index 256b521e1..b6eb36a0e 100644 --- a/src/backend/langflow/interface/output_parsers/base.py +++ b/src/backend/langflow/interface/output_parsers/base.py @@ -7,7 +7,7 @@ from langflow.interface.importing.utils import import_class from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.output_parsers import OutputParserFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class, build_template_from_method diff --git a/src/backend/langflow/interface/prompts/base.py b/src/backend/langflow/interface/prompts/base.py index 5aa41dfb2..70818429e 100644 --- a/src/backend/langflow/interface/prompts/base.py +++ b/src/backend/langflow/interface/prompts/base.py @@ -8,7 +8,7 @@ from langflow.interface.importing.utils import import_class from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.prompts import PromptFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class diff --git a/src/backend/langflow/interface/retrievers/base.py b/src/backend/langflow/interface/retrievers/base.py index db1cfd165..92e3f2f61 100644 --- a/src/backend/langflow/interface/retrievers/base.py +++ b/src/backend/langflow/interface/retrievers/base.py @@ -7,7 +7,7 @@ from langflow.interface.importing.utils import import_class from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.retrievers import RetrieverFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_method, build_template_from_class diff --git a/src/backend/langflow/interface/run.py b/src/backend/langflow/interface/run.py index 42cea0e98..9d3d95cda 100644 --- a/src/backend/langflow/interface/run.py +++ b/src/backend/langflow/interface/run.py @@ -1,7 +1,7 @@ from typing import Any, Dict, Tuple from langflow.services.cache.utils import memoize_dict from langflow.graph import Graph -from langflow.utils.logger import logger +from loguru import logger @memoize_dict(maxsize=10) diff --git a/src/backend/langflow/interface/text_splitters/base.py b/src/backend/langflow/interface/text_splitters/base.py index 87b778c4c..8b21303ce 100644 --- a/src/backend/langflow/interface/text_splitters/base.py +++ b/src/backend/langflow/interface/text_splitters/base.py @@ -5,7 +5,7 @@ from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.textsplitters import TextSplittersFrontendNode from langflow.interface.custom_lists import textsplitter_type_to_cls_dict -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class diff --git a/src/backend/langflow/interface/toolkits/base.py b/src/backend/langflow/interface/toolkits/base.py index c13ffdbd9..fe0003b15 100644 --- a/src/backend/langflow/interface/toolkits/base.py +++ b/src/backend/langflow/interface/toolkits/base.py @@ -6,7 +6,7 @@ from langflow.interface.base import LangChainTypeCreator from langflow.interface.importing.utils import import_class, import_module from langflow.services.utils import get_settings_manager -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class diff --git a/src/backend/langflow/interface/tools/util.py b/src/backend/langflow/interface/tools/util.py index 38276c620..f92386f18 100644 --- a/src/backend/langflow/interface/tools/util.py +++ b/src/backend/langflow/interface/tools/util.py @@ -3,7 +3,7 @@ import inspect from typing import Dict, Union from langchain.agents.tools import Tool -from langflow.utils.logger import logger +from loguru import logger def get_func_tool_params(func, **kwargs) -> Union[Dict, None]: diff --git a/src/backend/langflow/interface/types.py b/src/backend/langflow/interface/types.py index 824b0af50..47743560e 100644 --- a/src/backend/langflow/interface/types.py +++ b/src/backend/langflow/interface/types.py @@ -29,7 +29,7 @@ from langflow.template.frontend_node.custom_components import ( from langflow.interface.retrievers.base import retriever_creator from langflow.interface.custom.directory_reader import DirectoryReader -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import get_base_classes import re diff --git a/src/backend/langflow/interface/utilities/base.py b/src/backend/langflow/interface/utilities/base.py index eb8cd60af..9009983b0 100644 --- a/src/backend/langflow/interface/utilities/base.py +++ b/src/backend/langflow/interface/utilities/base.py @@ -8,7 +8,7 @@ from langflow.interface.importing.utils import import_class from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.utilities import UtilitiesFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class diff --git a/src/backend/langflow/interface/utils.py b/src/backend/langflow/interface/utils.py index 1fddbf80f..75e854e16 100644 --- a/src/backend/langflow/interface/utils.py +++ b/src/backend/langflow/interface/utils.py @@ -8,7 +8,7 @@ import re import yaml from langchain.base_language import BaseLanguageModel from PIL.Image import Image -from langflow.utils.logger import logger +from loguru import logger from langflow.services.chat.config import ChatConfig from langflow.services.utils import get_settings_manager diff --git a/src/backend/langflow/interface/vector_store/base.py b/src/backend/langflow/interface/vector_store/base.py index 4b8ca2b64..f7aca8c9c 100644 --- a/src/backend/langflow/interface/vector_store/base.py +++ b/src/backend/langflow/interface/vector_store/base.py @@ -7,7 +7,7 @@ from langflow.interface.importing.utils import import_class from langflow.services.utils import get_settings_manager from langflow.template.frontend_node.vectorstores import VectorStoreFrontendNode -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_method diff --git a/src/backend/langflow/interface/wrappers/base.py b/src/backend/langflow/interface/wrappers/base.py index 77e38f921..c4399fb3e 100644 --- a/src/backend/langflow/interface/wrappers/base.py +++ b/src/backend/langflow/interface/wrappers/base.py @@ -3,7 +3,7 @@ from typing import Dict, List, Optional from langchain import requests, sql_database from langflow.interface.base import LangChainTypeCreator -from langflow.utils.logger import logger +from loguru import logger from langflow.utils.util import build_template_from_class, build_template_from_method diff --git a/src/backend/langflow/processing/base.py b/src/backend/langflow/processing/base.py index 13ff6a385..c3d766f15 100644 --- a/src/backend/langflow/processing/base.py +++ b/src/backend/langflow/processing/base.py @@ -4,7 +4,7 @@ from langflow.api.v1.callback import ( StreamingLLMCallbackHandler, ) from langflow.processing.process import fix_memory_inputs, format_actions -from langflow.utils.logger import logger +from loguru import logger from langchain.agents.agent import AgentExecutor diff --git a/src/backend/langflow/processing/process.py b/src/backend/langflow/processing/process.py index 4b2e7b178..c60a53de5 100644 --- a/src/backend/langflow/processing/process.py +++ b/src/backend/langflow/processing/process.py @@ -6,7 +6,7 @@ from langflow.interface.run import ( get_memory_key, update_memory_keys, ) -from langflow.utils.logger import logger +from loguru import logger from langflow.graph import Graph from langchain.chains.base import Chain from langchain.vectorstores.base import VectorStore diff --git a/src/backend/langflow/services/chat/manager.py b/src/backend/langflow/services/chat/manager.py index 6751e97e7..d8492e961 100644 --- a/src/backend/langflow/services/chat/manager.py +++ b/src/backend/langflow/services/chat/manager.py @@ -7,7 +7,7 @@ from langflow.services.cache.manager import Subject from langflow.services.chat.utils import process_graph from langflow.interface.utils import pil_to_base64 from langflow.services.schema import ServiceType -from langflow.utils.logger import logger +from loguru import logger import asyncio diff --git a/src/backend/langflow/services/chat/utils.py b/src/backend/langflow/services/chat/utils.py index 17c976eb9..d9c291757 100644 --- a/src/backend/langflow/services/chat/utils.py +++ b/src/backend/langflow/services/chat/utils.py @@ -2,7 +2,7 @@ from fastapi import WebSocket from langflow.api.v1.schemas import ChatMessage from langflow.processing.base import get_result_and_steps from langflow.interface.utils import try_setting_streaming_options -from langflow.utils.logger import logger +from loguru import logger async def process_graph( diff --git a/src/backend/langflow/services/database/manager.py b/src/backend/langflow/services/database/manager.py index 1159cbf7a..c8826e31b 100644 --- a/src/backend/langflow/services/database/manager.py +++ b/src/backend/langflow/services/database/manager.py @@ -7,7 +7,7 @@ from langflow.services.utils import get_settings_manager from sqlalchemy import inspect import sqlalchemy as sa from sqlmodel import SQLModel, Session, create_engine -from langflow.utils.logger import logger +from loguru import logger from alembic.config import Config from alembic import command from langflow.services.database import models # noqa diff --git a/src/backend/langflow/services/database/utils.py b/src/backend/langflow/services/database/utils.py index e6afae184..fd0a8856a 100644 --- a/src/backend/langflow/services/database/utils.py +++ b/src/backend/langflow/services/database/utils.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from typing import TYPE_CHECKING -from langflow.utils.logger import logger +from loguru import logger from contextlib import contextmanager from alembic.util.exc import CommandError from sqlmodel import Session diff --git a/src/backend/langflow/services/manager.py b/src/backend/langflow/services/manager.py index ca9eb4e70..60a93fe16 100644 --- a/src/backend/langflow/services/manager.py +++ b/src/backend/langflow/services/manager.py @@ -1,6 +1,6 @@ from langflow.services.schema import ServiceType from typing import TYPE_CHECKING, List, Optional -from langflow.utils.logger import logger +from loguru import logger if TYPE_CHECKING: from langflow.services.factory import ServiceFactory diff --git a/src/backend/langflow/services/settings/auth.py b/src/backend/langflow/services/settings/auth.py index 582aecb90..d1f8197f0 100644 --- a/src/backend/langflow/services/settings/auth.py +++ b/src/backend/langflow/services/settings/auth.py @@ -5,7 +5,7 @@ from langflow.services.settings.utils import read_secret_from_file, write_secret from pydantic import BaseSettings, Field, validator from passlib.context import CryptContext -from langflow.utils.logger import logger +from loguru import logger class AuthSettings(BaseSettings): diff --git a/src/backend/langflow/services/settings/base.py b/src/backend/langflow/services/settings/base.py index 00cd2085f..366ff474d 100644 --- a/src/backend/langflow/services/settings/base.py +++ b/src/backend/langflow/services/settings/base.py @@ -8,7 +8,7 @@ from pathlib import Path import yaml from pydantic import BaseSettings, root_validator, validator -from langflow.utils.logger import logger +from loguru import logger # BASE_COMPONENTS_PATH = str(Path(__file__).parent / "components") BASE_COMPONENTS_PATH = str(Path(__file__).parent.parent.parent / "components") diff --git a/src/backend/langflow/services/settings/manager.py b/src/backend/langflow/services/settings/manager.py index b0af8b7f1..2d687d784 100644 --- a/src/backend/langflow/services/settings/manager.py +++ b/src/backend/langflow/services/settings/manager.py @@ -1,7 +1,7 @@ from langflow.services.base import Service from langflow.services.settings.auth import AuthSettings from langflow.services.settings.base import Settings -from langflow.utils.logger import logger +from loguru import logger import os import yaml diff --git a/src/backend/langflow/services/settings/utils.py b/src/backend/langflow/services/settings/utils.py index bb411a299..fae96ff28 100644 --- a/src/backend/langflow/services/settings/utils.py +++ b/src/backend/langflow/services/settings/utils.py @@ -2,7 +2,7 @@ import os from pathlib import Path import platform -from langflow.utils.logger import logger +from loguru import logger def set_secure_permissions(file_path): From 7e336bbee685099f67ff6f80fcdbf6dce446a64e Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 16:13:01 -0300 Subject: [PATCH 42/48] =?UTF-8?q?=F0=9F=90=9B=20fix(logger.py):=20change?= =?UTF-8?q?=20log=5Flevel=20variable=20to=20uppercase=20to=20improve=20con?= =?UTF-8?q?sistency=20and=20semantics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/utils/logger.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/utils/logger.py b/src/backend/langflow/utils/logger.py index b881a614c..4e93874af 100644 --- a/src/backend/langflow/utils/logger.py +++ b/src/backend/langflow/utils/logger.py @@ -13,7 +13,7 @@ def configure(log_level: str = "DEBUG", log_file: Path = None): { "sink": RichHandler(rich_tracebacks=True, markup=True), "format": log_format, - "level": log_level, + "level": log_level.upper(), } ] ) @@ -24,7 +24,7 @@ def configure(log_level: str = "DEBUG", log_file: Path = None): logger.add( sink=str(log_file), - level=log_level, + level=log_level.upper(), format=log_format, rotation="10 MB", # Log rotation based on file size ) From 28b487dc33cc097425fdc61b0a3a06e5dd146892 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 4 Sep 2023 16:15:41 -0300 Subject: [PATCH 43/48] =?UTF-8?q?=F0=9F=94=A7=20fix(manager.py):=20change?= =?UTF-8?q?=20logger.warn=20to=20logger.warning=20for=20consistency=20and?= =?UTF-8?q?=20clarity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔧 fix(logger.py): change log_file parameter type annotation to Optional[Path] to indicate that it is an optional argument --- src/backend/langflow/services/database/manager.py | 2 +- src/backend/langflow/utils/logger.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/services/database/manager.py b/src/backend/langflow/services/database/manager.py index c8826e31b..7f8afab6f 100644 --- a/src/backend/langflow/services/database/manager.py +++ b/src/backend/langflow/services/database/manager.py @@ -89,7 +89,7 @@ class DatabaseManager(Service): for table in legacy_tables: if table in inspector.get_table_names(): - logger.warn(f"Legacy table exists: {table}") + logger.warning(f"Legacy table exists: {table}") return True diff --git a/src/backend/langflow/utils/logger.py b/src/backend/langflow/utils/logger.py index 4e93874af..1f616486b 100644 --- a/src/backend/langflow/utils/logger.py +++ b/src/backend/langflow/utils/logger.py @@ -1,9 +1,10 @@ +from typing import Optional from loguru import logger from pathlib import Path from rich.logging import RichHandler -def configure(log_level: str = "DEBUG", log_file: Path = None): +def configure(log_level: str = "DEBUG", log_file: Optional[Path] = None): log_format = "{time:HH:mm:ss} - {level: <8} - {message}" logger.remove() # Remove default handlers From 5df8b11d9fbfce56833ab584a0eeab799e789420 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 4 Sep 2023 16:37:43 -0300 Subject: [PATCH 44/48] Changed autocomplete to only fill when on form --- src/frontend/src/components/inputComponent/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/components/inputComponent/index.tsx b/src/frontend/src/components/inputComponent/index.tsx index 46acdc1b0..490be0fb0 100644 --- a/src/frontend/src/components/inputComponent/index.tsx +++ b/src/frontend/src/components/inputComponent/index.tsx @@ -54,7 +54,7 @@ export default function InputComponent({ ) : ( Date: Mon, 4 Sep 2023 18:48:50 -0300 Subject: [PATCH 45/48] revert to default animation of radixUI --- src/frontend/src/components/ui/dialog.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/components/ui/dialog.tsx b/src/frontend/src/components/ui/dialog.tsx index 57dda0fef..ee673bf2b 100644 --- a/src/frontend/src/components/ui/dialog.tsx +++ b/src/frontend/src/components/ui/dialog.tsx @@ -27,7 +27,7 @@ const DialogOverlay = React.forwardRef< Date: Mon, 4 Sep 2023 19:29:20 -0300 Subject: [PATCH 46/48] fix animation --- src/frontend/src/components/ui/dialog.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/components/ui/dialog.tsx b/src/frontend/src/components/ui/dialog.tsx index ee673bf2b..93680ce7e 100644 --- a/src/frontend/src/components/ui/dialog.tsx +++ b/src/frontend/src/components/ui/dialog.tsx @@ -27,7 +27,7 @@ const DialogOverlay = React.forwardRef< Date: Mon, 4 Sep 2023 19:33:21 -0300 Subject: [PATCH 47/48] refactor(codeTabsComponent): wrap code tabs in a div with flex column layout for better styling and readability --- src/frontend/src/components/codeTabsComponent/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/components/codeTabsComponent/index.tsx b/src/frontend/src/components/codeTabsComponent/index.tsx index d807326f0..9868b709a 100644 --- a/src/frontend/src/components/codeTabsComponent/index.tsx +++ b/src/frontend/src/components/codeTabsComponent/index.tsx @@ -180,7 +180,7 @@ export default function CodeTabsComponent({ key={idx} // Remember to add a unique key prop > {idx < 4 ? ( - <> +
{tab.description && (
{tab.code} - +
) : idx === 4 ? ( <>
From e50b59368101a0af72ed431017ea94944133892d Mon Sep 17 00:00:00 2001 From: Cristhian Zanforlin Lousa Date: Mon, 4 Sep 2023 20:18:10 -0300 Subject: [PATCH 48/48] =?UTF-8?q?=F0=9F=90=9B=20fix(API/index.ts):=20handl?= =?UTF-8?q?e=20potential=20undefined=20response=20object=20properties=20to?= =?UTF-8?q?=20prevent=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/controllers/API/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index d9ea890c8..bdf7e5221 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -164,7 +164,7 @@ export async function readFlowsFromDatabase() { try { const response = await api.get(`${BASE_URL_API}flows/`); if (response?.status !== 200) { - throw new Error(`HTTP error! status: ${response.status}`); + throw new Error(`HTTP error! status: ${response?.status}`); } return response.data; } catch (error) { @@ -177,7 +177,7 @@ export async function downloadFlowsFromDatabase() { try { const response = await api.get(`${BASE_URL_API}flows/download/`); if (response?.status !== 200) { - throw new Error(`HTTP error! status: ${response.status}`); + throw new Error(`HTTP error! status: ${response?.status}`); } return response.data; } catch (error) { @@ -190,8 +190,8 @@ export async function uploadFlowsToDatabase(flows: FormData) { try { const response = await api.post(`${BASE_URL_API}flows/upload/`, flows); - if (response.status !== 201) { - throw new Error(`HTTP error! status: ${response.status}`); + if (response?.status !== 201) { + throw new Error(`HTTP error! status: ${response?.status}`); } return response.data; } catch (error) {