From bc50e010d4b88dc15c390b05aa74402c3cb8d101 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:43:35 -0300 Subject: [PATCH 01/26] feat: Add Case component to App for conditional rendering --- src/frontend/src/App.tsx | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 849244999..720ffb6b2 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -18,21 +18,21 @@ import { autoLogin, getGlobalVariables, getHealth } from "./controllers/API"; import { setupAxiosDefaults } from "./controllers/API/utils"; import useTrackLastVisitedPath from "./hooks/use-track-last-visited-path"; import Router from "./routes"; +import { Case } from "./shared/components/caseComponent"; import useAlertStore from "./stores/alertStore"; import { useDarkStore } from "./stores/darkStore"; import useFlowsManagerStore from "./stores/flowsManagerStore"; import { useFolderStore } from "./stores/foldersStore"; import { useGlobalVariablesStore } from "./stores/globalVariablesStore/globalVariables"; import { useStoreStore } from "./stores/storeStore"; -import { useTypesStore } from "./stores/typesStore"; export default function App() { useTrackLastVisitedPath(); const removeFromTempNotificationList = useAlertStore( - (state) => state.removeFromTempNotificationList + (state) => state.removeFromTempNotificationList, ); const tempNotificationList = useAlertStore( - (state) => state.tempNotificationList + (state) => state.tempNotificationList, ); const [fetchError, setFetchError] = useState(false); const isLoading = useFlowsManagerStore((state) => state.isLoading); @@ -43,21 +43,18 @@ export default function App() { const { isAuthenticated, login, setUserData, setAutoLogin, getUser } = useContext(AuthContext); - const refreshFlows = useFlowsManagerStore((state) => state.refreshFlows); const setLoading = useAlertStore((state) => state.setLoading); const fetchApiData = useStoreStore((state) => state.fetchApiData); - const getTypes = useTypesStore((state) => state.getTypes); const refreshVersion = useDarkStore((state) => state.refreshVersion); const refreshStars = useDarkStore((state) => state.refreshStars); const setGlobalVariables = useGlobalVariablesStore( - (state) => state.setGlobalVariables + (state) => state.setGlobalVariables, ); const checkHasStore = useStoreStore((state) => state.checkHasStore); const navigate = useNavigate(); const dark = useDarkStore((state) => state.dark); - const getFoldersApi = useFolderStore((state) => state.getFoldersApi); - const loadingFolders = useFolderStore((state) => state.loading); + const isLoadingFolders = useFolderStore((state) => state.isLoadingFolders); const [isLoadingHealth, setIsLoadingHealth] = useState(false); @@ -115,13 +112,13 @@ export default function App() { if (isAuthenticated) { try { await setupAxiosDefaults(); - await getFoldersApi(); - await getTypes(); - await refreshFlows(); + const res = await getGlobalVariables(); setGlobalVariables(res); + checkHasStore(); fetchApiData(); + resolve(); } catch (error) { console.error("Failed to fetch data:", error); @@ -174,6 +171,8 @@ export default function App() { } }; + const isLoadingApplication = isLoading || isLoadingFolders; + return ( //need parent component with width and height
@@ -196,15 +195,15 @@ export default function App() { > } - {isLoading || loadingFolders ? ( +
- ) : ( - <> - - - )} +
+ + + +
From 75c13f4f20e9d17e48a222c9f183c391babf7705 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:44:06 -0300 Subject: [PATCH 02/26] chore: Refactor loadingFolders variable name in SidebarNav component --- src/frontend/src/components/sidebarComponent/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/components/sidebarComponent/index.tsx b/src/frontend/src/components/sidebarComponent/index.tsx index efec5da1e..8cdbe5907 100644 --- a/src/frontend/src/components/sidebarComponent/index.tsx +++ b/src/frontend/src/components/sidebarComponent/index.tsx @@ -28,7 +28,7 @@ export default function SidebarNav({ }: SidebarNavProps) { const location = useLocation(); const pathname = location.pathname; - const loadingFolders = useFolderStore((state) => state.loading); + const loadingFolders = useFolderStore((state) => state.isLoadingFolders); const folders = useFolderStore((state) => state.folders); const pathValues = ["folder", "components", "flows", "all"]; From 0bbecc9bab4c428818021d99b5ae138494ecec96 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:44:12 -0300 Subject: [PATCH 03/26] refactor: Refresh folders after adding a new folder in SideBarFoldersButtonsComponent --- .../components/sideBarFolderButtons/index.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx b/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx index 234eb9304..1b538ba20 100644 --- a/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx +++ b/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx @@ -31,14 +31,14 @@ const SideBarFoldersButtonsComponent = ({ const [foldersNames, setFoldersNames] = useState({}); const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); const [editFolders, setEditFolderName] = useState( - folders.map((obj) => ({ name: obj.name, edit: false })) + folders.map((obj) => ({ name: obj.name, edit: false })), ); const uploadFolder = useFolderStore((state) => state.uploadFolder); const currentFolder = pathname.split("/"); const urlWithoutPath = pathname.split("/").length < 4; const myCollectionId = useFolderStore((state) => state.myCollectionId); - const getFoldersApi = useFolderStore((state) => state.getFoldersApi); const folderIdDragging = useFolderStore((state) => state.folderIdDragging); + const refreshFolders = useFolderStore((state) => state.refreshFolders); const checkPathName = (itemId: string) => { if (urlWithoutPath && itemId === myCollectionId) { @@ -58,7 +58,7 @@ const SideBarFoldersButtonsComponent = ({ const { dragOver, dragEnter, dragLeave, onDrop } = useFileDrop( folderId, - handleFolderChange + handleFolderChange, ); const handleUploadFlowsToFolder = () => { @@ -85,8 +85,8 @@ const SideBarFoldersButtonsComponent = ({ function addNewFolder() { addFolder({ name: "New Folder", parent_id: null, description: "" }).then( (res) => { - getFoldersApi(true); - } + refreshFolders(); + }, ); } @@ -132,7 +132,7 @@ const SideBarFoldersButtonsComponent = ({ <> {folders.map((item, index) => { const editFolderName = editFolders?.filter( - (folder) => folder.name === item.name + (folder) => folder.name === item.name, )[0]; return (
handleChangeFolder!(item.id!)} > @@ -218,7 +218,7 @@ const SideBarFoldersButtonsComponent = ({ folders.map((obj) => ({ name: obj.name, edit: false, - })) + })), ); } if (e.key === "Enter") { @@ -251,10 +251,10 @@ const SideBarFoldersButtonsComponent = ({ }; const updatedFolder = await updateFolder( body, - item.id! + item.id!, ); const updateFolders = folders.filter( - (f) => f.name !== item.name + (f) => f.name !== item.name, ); setFolders([...updateFolders, updatedFolder]); setFoldersNames({}); @@ -262,7 +262,7 @@ const SideBarFoldersButtonsComponent = ({ folders.map((obj) => ({ name: obj.name, edit: false, - })) + })), ); } else { setFoldersNames((old) => ({ From 9cd3bd751e1e93fad764775e91178303e57be7b2 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:44:21 -0300 Subject: [PATCH 04/26] chore: Update use-on-file-drop.tsx to use refreshFolders instead of getFoldersApi --- .../sidebarComponent/hooks/use-on-file-drop.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx index f10733468..c75bf4bec 100644 --- a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx +++ b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx @@ -12,11 +12,11 @@ import { addVersionToDuplicates } from "../../../utils/reactflowUtils"; const useFileDrop = (folderId, folderChangeCallback) => { const setFolderDragging = useFolderStore((state) => state.setFolderDragging); const setFolderIdDragging = useFolderStore( - (state) => state.setFolderIdDragging + (state) => state.setFolderIdDragging, ); const setErrorData = useAlertStore((state) => state.setErrorData); - const getFoldersApi = useFolderStore((state) => state.getFoldersApi); + const refreshFolders = useFolderStore((state) => state.refreshFolders); const flows = useFlowsManagerStore((state) => state.flows); const triggerFolderChange = (folderId) => { @@ -45,7 +45,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { | React.DragEvent | React.DragEvent | React.DragEvent, - folderId: string + folderId: string, ) => { e.preventDefault(); @@ -60,7 +60,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { | React.DragEvent | React.DragEvent | React.DragEvent, - folderId: string + folderId: string, ) => { if (e.dataTransfer.types.some((types) => types === "Files")) { setFolderDragging(true); @@ -73,7 +73,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { e: | React.DragEvent | React.DragEvent - | React.DragEvent + | React.DragEvent, ) => { e.preventDefault(); if (e.target === e.currentTarget) { @@ -87,7 +87,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { | React.DragEvent | React.DragEvent | React.DragEvent, - folderId: string + folderId: string, ) => { if (e?.dataTransfer?.getData("flow")) { const data = JSON.parse(e?.dataTransfer?.getData("flow")); @@ -118,7 +118,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { setFolderIdDragging(""); updateFlowInDatabase(updatedFlow).then(() => { - getFoldersApi(true); + refreshFolders(); triggerFolderChange(folderId); }); }; @@ -129,7 +129,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { setFolderDragging(false); setFolderIdDragging(""); uploadFlowsFromFolders(formData).then(() => { - getFoldersApi(true); + refreshFolders(); triggerFolderChange(folderId); }); }; From 8980b66bec682933baefc5e407d1e44b30c3a1fd Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:44:28 -0300 Subject: [PATCH 05/26] refactor: Update TableComponent to use optional chaining for hiding overlay --- src/frontend/src/components/tableComponent/index.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/frontend/src/components/tableComponent/index.tsx b/src/frontend/src/components/tableComponent/index.tsx index 126d4f3f2..e956d8795 100644 --- a/src/frontend/src/components/tableComponent/index.tsx +++ b/src/frontend/src/components/tableComponent/index.tsx @@ -35,7 +35,7 @@ const TableComponent = forwardRef< alertDescription = DEFAULT_TABLE_ALERT_MSG, ...props }, - ref + ref, ) => { let colDef = props.columnDefs.map((col, index) => { let newCol = { @@ -105,13 +105,13 @@ const TableComponent = forwardRef< } }, 50); setTimeout(() => { - realRef.current.api.hideOverlay(); + realRef?.current?.api?.hideOverlay(); }, 1000); if (props.onGridReady) props.onGridReady(params); }; const onColumnMoved = (params) => { const updatedColumnDefs = makeLastColumnNonResizable( - params.columnApi.getAllGridColumns().map((col) => col.getColDef()) + params.columnApi.getAllGridColumns().map((col) => col.getColDef()), ); params.api.setGridOption("columnDefs", updatedColumnDefs); if (props.onColumnMoved) props.onColumnMoved(params); @@ -135,7 +135,7 @@ const TableComponent = forwardRef< className={cn( dark ? "ag-theme-quartz-dark" : "ag-theme-quartz", "ag-theme-shadcn flex h-full flex-col", - "relative" + "relative", )} // applying the grid theme > source.includes("column"))) { localStorage.setItem( storeReference, - JSON.stringify(realRef.current?.api?.getColumnState()) + JSON.stringify(realRef.current?.api?.getColumnState()), ); setColumnStateChange(true); } @@ -175,7 +175,7 @@ const TableComponent = forwardRef< )}
); - } + }, ); export default TableComponent; From 4358ff52554e62beda6b288713189ae466d178e5 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:44:36 -0300 Subject: [PATCH 06/26] chore: Update authContext to useFolderStore for getting folders --- src/frontend/src/contexts/authContext.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/frontend/src/contexts/authContext.tsx b/src/frontend/src/contexts/authContext.tsx index 1817447f1..bd5c2d02c 100644 --- a/src/frontend/src/contexts/authContext.tsx +++ b/src/frontend/src/contexts/authContext.tsx @@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom"; import Cookies from "universal-cookie"; import { getLoggedUser, requestLogout } from "../controllers/API"; import useAlertStore from "../stores/alertStore"; +import { useFolderStore } from "../stores/foldersStore"; import { Users } from "../types/api"; import { AuthContextType } from "../types/contexts/auth"; @@ -30,19 +31,20 @@ export function AuthProvider({ children }): React.ReactElement { const navigate = useNavigate(); const cookies = new Cookies(); const [accessToken, setAccessToken] = useState( - cookies.get("access_token_lf") ?? null + cookies.get("access_token_lf") ?? null, ); const [isAuthenticated, setIsAuthenticated] = useState( - !!cookies.get("access_token_lf") + !!cookies.get("access_token_lf"), ); const [isAdmin, setIsAdmin] = useState(false); const [userData, setUserData] = useState(null); const [autoLogin, setAutoLogin] = useState(false); const setLoading = useAlertStore((state) => state.setLoading); const [apiKey, setApiKey] = useState( - cookies.get("apikey_tkn_lflw") + cookies.get("apikey_tkn_lflw"), ); - // const getFoldersApi = useFolderStore((state) => state.getFoldersApi); + + const getFoldersApi = useFolderStore((state) => state.getFoldersApi); useEffect(() => { const storedAccessToken = cookies.get("access_token_lf"); @@ -64,7 +66,8 @@ export function AuthProvider({ children }): React.ReactElement { setUserData(user); const isSuperUser = user!.is_superuser; setIsAdmin(isSuperUser); - // await getFoldersApi(true); + + getFoldersApi(true, true); }) .catch((error) => { setLoading(false); From b9e1a3c0c55fb6a1937499b6e3aa6dffdcd30f54 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:44:46 -0300 Subject: [PATCH 07/26] fix: Handle duplicate requests in ApiInterceptor --- src/frontend/src/controllers/API/api.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index 2a305cf5a..0ac3efa6b 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -48,7 +48,7 @@ function ApiInterceptor() { } await clearBuildVerticesState(error); return Promise.reject(error); - } + }, ); const isAuthorizedURL = (url) => { @@ -65,10 +65,10 @@ function ApiInterceptor() { const parsedURL = new URL(url); const isDomainAllowed = authorizedDomains.some( - (domain) => parsedURL.origin === new URL(domain).origin + (domain) => parsedURL.origin === new URL(domain).origin, ); const isEndpointAllowed = authorizedEndpoints.some((endpoint) => - parsedURL.pathname.includes(endpoint) + parsedURL.pathname.includes(endpoint), ); return isDomainAllowed || isEndpointAllowed; @@ -87,6 +87,7 @@ function ApiInterceptor() { if (!checkRequest) { controller.abort("Duplicate Request"); + console.error("Duplicate Request"); } const accessToken = cookies.get("access_token_lf"); @@ -101,7 +102,7 @@ function ApiInterceptor() { }, (error) => { return Promise.reject(error); - } + }, ); return () => { @@ -133,7 +134,7 @@ function ApiInterceptor() { if (error?.config?.headers) { delete error.config.headers["Authorization"]; error.config.headers["Authorization"] = `Bearer ${cookies.get( - "access_token_lf" + "access_token_lf", )}`; const response = await axios.request(error.config); return response; From a49cd49eee35f310e26059695f1e0b3481898c87 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:45:02 -0300 Subject: [PATCH 08/26] refactor: Remove console.log statement in getMessagesTable function --- src/frontend/src/controllers/API/index.ts | 54 +++++++++++------------ 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 07a9cd06d..104b815b0 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -63,7 +63,7 @@ export async function sendAll(data: sendAllProps) { } export async function postValidateCode( - code: string + code: string, ): Promise> { return await api.post(`${BASE_URL_API}validate/code`, { code }); } @@ -78,7 +78,7 @@ export async function postValidateCode( export async function postValidatePrompt( name: string, template: string, - frontend_node: APIClassType + frontend_node: APIClassType, ): Promise> { return api.post(`${BASE_URL_API}validate/prompt`, { name, @@ -151,7 +151,7 @@ export async function saveFlowToDatabase(newFlow: { * @throws Will throw an error if the update fails. */ export async function updateFlowInDatabase( - updatedFlow: FlowType + updatedFlow: FlowType, ): Promise { try { const response = await api.patch(`${BASE_URL_API}flows/${updatedFlow.id}`, { @@ -329,7 +329,7 @@ export async function getHealth() { * */ export async function getBuildStatus( - flowId: string + flowId: string, ): Promise> { return await api.get(`${BASE_URL_API}build/${flowId}/status`); } @@ -342,7 +342,7 @@ export async function getBuildStatus( * */ export async function postBuildInit( - flow: FlowType + flow: FlowType, ): Promise> { return await api.post(`${BASE_URL_API}build/init/${flow.id}`, flow); } @@ -358,7 +358,7 @@ export async function postBuildInit( */ export async function uploadFile( file: File, - id: string + id: string, ): Promise> { const formData = new FormData(); formData.append("file", file); @@ -380,7 +380,7 @@ export async function getProfilePictures(): Promise> { // let template = apiClass.template; return await api.post(`${BASE_URL_API}custom_component`, { @@ -393,7 +393,7 @@ export async function postCustomComponentUpdate( code: string, template: APITemplateType, field: string, - field_value: any + field_value: any, ): Promise> { return await api.post(`${BASE_URL_API}custom_component/update`, { code, @@ -415,7 +415,7 @@ export async function onLogin(user: LoginType) { headers: { "Content-Type": "application/x-www-form-urlencoded", }, - } + }, ); if (response.status === 200) { @@ -477,11 +477,11 @@ export async function addUser(user: UserInputType): Promise> { export async function getUsersPage( skip: number, - limit: number + limit: number, ): Promise> { try { const res = await api.get( - `${BASE_URL_API}users/?skip=${skip}&limit=${limit}` + `${BASE_URL_API}users/?skip=${skip}&limit=${limit}`, ); if (res.status === 200) { return res.data; @@ -518,7 +518,7 @@ export async function resetPassword(user_id: string, user: resetPasswordType) { try { const res = await api.patch( `${BASE_URL_API}users/${user_id}/reset-password`, - user + user, ); if (res.status === 200) { return res.data; @@ -592,7 +592,7 @@ export async function saveFlowStore( last_tested_version?: string; }, tags: string[], - publicFlow = false + publicFlow = false, ): Promise { try { const response = await api.post(`${BASE_URL_API}store/components/`, { @@ -721,7 +721,7 @@ export async function postStoreComponents(component: Component) { export async function getComponent(component_id: string) { try { const res = await api.get( - `${BASE_URL_API}store/components/${component_id}` + `${BASE_URL_API}store/components/${component_id}`, ); if (res.status === 200) { return res.data; @@ -736,7 +736,7 @@ export async function searchComponent( page?: number | null, limit?: number | null, status?: string | null, - tags?: string[] + tags?: string[], ): Promise { try { let url = `${BASE_URL_API}store/components/`; @@ -848,7 +848,7 @@ export async function updateFlowStore( }, tags: string[], publicFlow = false, - id: string + id: string, ): Promise { try { const response = await api.patch(`${BASE_URL_API}store/components/${id}`, { @@ -932,7 +932,7 @@ export async function deleteGlobalVariable(id: string) { export async function updateGlobalVariable( name: string, value: string, - id: string + id: string, ) { try { const response = api.patch(`${BASE_URL_API}variables/${id}`, { @@ -951,7 +951,7 @@ export async function getVerticesOrder( startNodeId?: string | null, stopNodeId?: string | null, nodes?: Node[], - Edges?: Edge[] + Edges?: Edge[], ): Promise> { // nodeId is optional and is a query parameter // if nodeId is not provided, the API will return all vertices @@ -971,7 +971,7 @@ export async function getVerticesOrder( return await api.post( `${BASE_URL_API}build/${flowId}/vertices`, data, - config + config, ); } @@ -979,7 +979,7 @@ export async function postBuildVertex( flowId: string, vertexId: string, input_value: string, - files?: string[] + files?: string[], ): Promise> { // input_value is optional and is a query parameter let data = {}; @@ -991,7 +991,7 @@ export async function postBuildVertex( } return await api.post( `${BASE_URL_API}build/${flowId}/vertices/${vertexId}`, - data + data, ); } @@ -1015,7 +1015,7 @@ export async function getFlowPool({ } export async function deleteFlowPool( - flowId: string + flowId: string, ): Promise> { const config = {}; config["params"] = { flow_id: flowId }; @@ -1029,7 +1029,7 @@ export async function deleteFlowPool( * @returns A promise that resolves to an array of AxiosResponse objects representing the delete responses. */ export async function multipleDeleteFlowsComponents( - flowIds: string[] + flowIds: string[], ): Promise[]> { const batches: string[][] = []; @@ -1052,7 +1052,7 @@ export async function multipleDeleteFlowsComponents( // Execute all delete requests const responses: Promise>[] = batches.map((batch) => - deleteBatch(batch) + deleteBatch(batch), ); // Return the responses after all requests are completed @@ -1062,7 +1062,7 @@ export async function multipleDeleteFlowsComponents( export async function getTransactionTable( id: string, mode: "intersection" | "union", - params = {} + params = {}, ): Promise<{ rows: Array; columns: Array }> { const config = {}; config["params"] = { flow_id: id }; @@ -1078,7 +1078,7 @@ export async function getMessagesTable( mode: "intersection" | "union", id?: string, excludedFields?: string[], - params = {} + params = {}, ): Promise<{ rows: Array; columns: Array }> { const config = {}; if (id) { @@ -1091,8 +1091,6 @@ export async function getMessagesTable( const rowsOrganized = rows.data; - console.log(rowsOrganized); - const columns = extractColumnsFromRows(rowsOrganized, mode, excludedFields); const sessions = new Set(); rowsOrganized.forEach((row) => { From e66286662e7ec990146b9c3ab94e2307057d6615 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:45:09 -0300 Subject: [PATCH 09/26] refactor: Improve duplicate request handling in checkDuplicateRequestAndStoreRequest function --- .../controllers/API/helpers/check-duplicate-requests.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts b/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts index 6486de541..85c6608ac 100644 --- a/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts +++ b/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts @@ -4,11 +4,12 @@ export function checkDuplicateRequestAndStoreRequest(config) { const lastUrl = localStorage.getItem("lastUrlCalled"); const lastMethodCalled = localStorage.getItem("lastMethodCalled"); const lastRequestTime = localStorage.getItem("lastRequestTime"); + const lastCurrentUrl = localStorage.getItem("lastCurrentUrl"); + const currentUrl = window.location.pathname; const currentTime = Date.now(); - const isContained = AUTHORIZED_DUPLICATE_REQUESTS.some((request) => - config?.url!.includes(request) + config?.url!.includes(request), ); if ( @@ -17,7 +18,8 @@ export function checkDuplicateRequestAndStoreRequest(config) { lastMethodCalled === config.method && lastMethodCalled === "get" && // Assuming you want to check only for GET requests lastRequestTime && - currentTime - parseInt(lastRequestTime, 10) < 800 + currentTime - parseInt(lastRequestTime, 10) < 300 && + lastCurrentUrl === currentUrl ) { return false; } @@ -25,6 +27,7 @@ export function checkDuplicateRequestAndStoreRequest(config) { localStorage.setItem("lastUrlCalled", config.url ?? ""); localStorage.setItem("lastMethodCalled", config.method ?? ""); localStorage.setItem("lastRequestTime", currentTime.toString()); + localStorage.setItem("lastCurrentUrl", currentUrl); return true; } From 68201bb0d500e95e48c1962fc7f842e179c8ac45 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:45:16 -0300 Subject: [PATCH 10/26] feat: Add setLoading to LoginAdminPage for displaying loading state during login --- src/frontend/src/pages/AdminPage/LoginPage/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/frontend/src/pages/AdminPage/LoginPage/index.tsx b/src/frontend/src/pages/AdminPage/LoginPage/index.tsx index b1772baa5..0c7e073df 100644 --- a/src/frontend/src/pages/AdminPage/LoginPage/index.tsx +++ b/src/frontend/src/pages/AdminPage/LoginPage/index.tsx @@ -19,6 +19,7 @@ export default function LoginAdminPage() { const [inputState, setInputState] = useState(CONTROL_LOGIN_STATE); const { login, isAuthenticated, setUserData } = useContext(AuthContext); + const setLoading = useAlertStore((state) => state.setLoading); const { password, username } = inputState; const setErrorData = useAlertStore((state) => state.setErrorData); @@ -35,6 +36,10 @@ export default function LoginAdminPage() { }; onLogin(user) .then((user) => { + console.log("admin page"); + + setLoading(true); + login(user.access_token); navigate("/admin/"); }) From a1cd3be2373d8e590fb4d075a693f95e334bc3ba Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:45:27 -0300 Subject: [PATCH 11/26] feat: Add useFlowsManagerStore to LoginPage for managing loading state during login --- src/frontend/src/pages/LoginPage/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/frontend/src/pages/LoginPage/index.tsx b/src/frontend/src/pages/LoginPage/index.tsx index 826b2a931..d25d1c2e1 100644 --- a/src/frontend/src/pages/LoginPage/index.tsx +++ b/src/frontend/src/pages/LoginPage/index.tsx @@ -9,6 +9,7 @@ import { CONTROL_LOGIN_STATE } from "../../constants/constants"; import { AuthContext } from "../../contexts/authContext"; import { onLogin } from "../../controllers/API"; import useAlertStore from "../../stores/alertStore"; +import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { LoginType } from "../../types/api"; import { inputHandlerEventType, @@ -23,6 +24,7 @@ export default function LoginPage(): JSX.Element { const { login } = useContext(AuthContext); const navigate = useNavigate(); const setErrorData = useAlertStore((state) => state.setErrorData); + const setLoading = useFlowsManagerStore((state) => state.setIsLoading); function handleInput({ target: { name, value }, @@ -37,6 +39,9 @@ export default function LoginPage(): JSX.Element { }; onLogin(user) .then((user) => { + console.log("login page"); + + setLoading(true); login(user.access_token); navigate("/"); }) From 6450b52c402137e2d55573a36c74e539b6699ecc Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:45:41 -0300 Subject: [PATCH 12/26] chore: Remove unused code in HeaderTabsSearchComponent --- .../headerTabsSearchComponent/index.tsx | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx b/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx index 17916f05b..c6ceb44c7 100644 --- a/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx +++ b/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx @@ -1,39 +1,19 @@ import { useState } from "react"; -import { useLocation } from "react-router-dom"; -import useAlertStore from "../../../../../../stores/alertStore"; import useFlowsManagerStore from "../../../../../../stores/flowsManagerStore"; -import { useFolderStore } from "../../../../../../stores/foldersStore"; -import { handleDownloadFolderFn } from "../../../../utils/handle-download-folder"; import InputSearchComponent from "../inputSearchComponent"; import TabsSearchComponent from "../tabsComponent"; type HeaderTabsSearchComponentProps = {}; const HeaderTabsSearchComponent = ({}: HeaderTabsSearchComponentProps) => { - const location = useLocation(); - const myCollectionId = useFolderStore((state) => state.myCollectionId); - const folderId = location?.state?.folderId || myCollectionId; const isLoading = useFlowsManagerStore((state) => state.isLoading); const [tabActive, setTabActive] = useState("Flows"); - const setErrorData = useAlertStore((state) => state.setErrorData); - const allFlows = useFlowsManagerStore((state) => state.allFlows); const [inputValue, setInputValue] = useState(""); const setSearchFlowsComponents = useFlowsManagerStore( - (state) => state.setSearchFlowsComponents + (state) => state.setSearchFlowsComponents, ); - const handleDownloadFolder = () => { - if (allFlows.length === 0) { - setErrorData({ - title: "Folder is empty", - list: [], - }); - return; - } - handleDownloadFolderFn(folderId); - }; - return ( <>
From 5462aeee3e3b3128dc08bfa3c4ea7a22ea246de6 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:45:50 -0300 Subject: [PATCH 13/26] refactor: Update useDeleteFolder hook to use refreshFolders instead of getFoldersApi --- src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx b/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx index 257f1b6d2..239bf26f3 100644 --- a/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx +++ b/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx @@ -2,11 +2,12 @@ import useAlertStore from "../../../stores/alertStore"; import { useFolderStore } from "../../../stores/foldersStore"; import { deleteFolder, getFolderById } from "../services"; -const useDeleteFolder = ({ navigate, getFoldersApi }) => { +const useDeleteFolder = ({ navigate }) => { const setSuccessData = useAlertStore((state) => state.setSuccessData); const setErrorData = useAlertStore((state) => state.setErrorData); const folderToEdit = useFolderStore((state) => state.folderToEdit); const myCollectionId = useFolderStore((state) => state.myCollectionId); + const refreshFolders = useFolderStore((state) => state.refreshFolders); const handleDeleteFolder = () => { deleteFolder(folderToEdit?.id!) @@ -15,7 +16,7 @@ const useDeleteFolder = ({ navigate, getFoldersApi }) => { title: "Folder deleted successfully.", }); getFolderById(myCollectionId!); - getFoldersApi(true); + refreshFolders(); navigate("/all"); }) .catch((err) => { From 9dd56b04126eb7efe98b40722b6671c70393b6f7 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:45:58 -0300 Subject: [PATCH 14/26] refactor: Update MainPage component to remove unused code and improve folder deletion handling --- .../src/pages/MainPage/pages/mainPage/index.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx b/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx index 0daa61257..6b4892d60 100644 --- a/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx @@ -16,7 +16,7 @@ import useDropdownOptions from "../../hooks/use-dropdown-options"; export default function HomePage(): JSX.Element { const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow); const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId + (state) => state.setCurrentFlowId, ); const location = useLocation(); @@ -25,16 +25,9 @@ export default function HomePage(): JSX.Element { const [openFolderModal, setOpenFolderModal] = useState(false); const [openDeleteFolderModal, setOpenDeleteFolderModal] = useState(false); const is_component = pathname === "/components"; - const getFoldersApi = useFolderStore((state) => state.getFoldersApi); const setFolderToEdit = useFolderStore((state) => state.setFolderToEdit); const navigate = useNavigate(); - useEffect(() => { - setTimeout(() => { - getFoldersApi(); - }, 300); - }, []); - useEffect(() => { setCurrentFlowId(""); }, [pathname]); @@ -45,7 +38,7 @@ export default function HomePage(): JSX.Element { is_component, }); - const { handleDeleteFolder } = useDeleteFolder({ navigate, getFoldersApi }); + const { handleDeleteFolder } = useDeleteFolder({ navigate }); return ( <> From 33b3a9ee7ee6e1801608e82cd8d277a8ebf6d33e Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:46:06 -0300 Subject: [PATCH 15/26] refactor: Update getFoldersApi to handle startup application and improve code readability --- src/frontend/src/stores/foldersStore.tsx | 78 +++++++++++++++++------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/src/frontend/src/stores/foldersStore.tsx b/src/frontend/src/stores/foldersStore.tsx index ce858c3be..01db44247 100644 --- a/src/frontend/src/stores/foldersStore.tsx +++ b/src/frontend/src/stores/foldersStore.tsx @@ -7,15 +7,16 @@ import { } from "../pages/MainPage/services"; import { FoldersStoreType } from "../types/zustand/folders"; import useFlowsManagerStore from "./flowsManagerStore"; +import { useTypesStore } from "./typesStore"; export const useFolderStore = create((set, get) => ({ folders: [], - getFoldersApi: (refetch = false) => { + getFoldersApi: (refetch = false, startupApplication: boolean = false) => { return new Promise((resolve, reject) => { if (get()?.folders.length === 0 || refetch === true) { - get().setLoading(true); + get().setIsLoadingFolders(true); getFolders().then( - (res) => { + async (res) => { const foldersWithoutStarterProjects = res?.filter( (folder) => folder.name !== STARTER_FOLDER_NAME, ); @@ -33,38 +34,73 @@ export const useFolderStore = create((set, get) => ({ set({ myCollectionId }); - if (refetch === true) { - useFlowsManagerStore.getState().refreshFlows(); - useFlowsManagerStore.getState().setAllFlows; - } + const { refreshFlows } = useFlowsManagerStore.getState(); + const { getTypes } = useTypesStore.getState(); + const { setIsLoadingFolders } = get(); + + if (refetch) { + if (startupApplication) { + await refreshFlows(); + await getTypes(); + } else { + refreshFlows(); + getTypes(); + } + } + setIsLoadingFolders(false); - get().setLoading(false); resolve(); }, (error) => { set({ folders: [] }); - get().setLoading(false); + get().setIsLoadingFolders(false); reject(error); }, ); } }); }, - setFolders: (folders) => set(() => ({ folders: folders })), - loading: false, - setLoading: (loading) => set(() => ({ loading: loading })), - getFolderById: (id) => { - if (id) { - getFolderById(id).then( - (res) => { - const setAllFlows = useFlowsManagerStore.getState().setAllFlows; - setAllFlows(res.flows); - set({ selectedFolder: res }); + refreshFolders: () => { + return new Promise((resolve, reject) => { + getFolders().then( + async (res) => { + const foldersWithoutStarterProjects = res?.filter( + (folder) => folder.name !== STARTER_FOLDER_NAME, + ); + + const starterProjects = res?.find( + (folder) => folder.name === STARTER_FOLDER_NAME, + ); + + set({ starterProjectId: starterProjects!.id ?? "" }); + set({ folders: foldersWithoutStarterProjects }); + + const myCollectionId = res?.find( + (f) => f.name === DEFAULT_FOLDER, + )?.id; + + set({ myCollectionId }); + + resolve(); }, - () => { - get().getFoldersApi(true); + (error) => { + set({ folders: [] }); + get().setIsLoadingFolders(false); + reject(error); }, ); + }); + }, + setFolders: (folders) => set(() => ({ folders: folders })), + isLoadingFolders: false, + setIsLoadingFolders: (isLoadingFolders) => set(() => ({ isLoadingFolders })), + getFolderById: (id) => { + if (id) { + getFolderById(id).then((res) => { + const setAllFlows = useFlowsManagerStore.getState().setAllFlows; + setAllFlows(res.flows); + set({ selectedFolder: res }); + }); } }, selectedFolder: null, From 41fc8461079b7987364e6e5e6a4eb8a1dd4ea734 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 13 Jun 2024 17:46:14 -0300 Subject: [PATCH 16/26] refactor: Update FoldersStoreType to use isLoadingFolders instead of loading --- src/frontend/src/types/zustand/folders/index.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/types/zustand/folders/index.ts b/src/frontend/src/types/zustand/folders/index.ts index 5e41677b2..495d65b87 100644 --- a/src/frontend/src/types/zustand/folders/index.ts +++ b/src/frontend/src/types/zustand/folders/index.ts @@ -2,10 +2,13 @@ import { FolderType } from "../../../pages/MainPage/entities"; export type FoldersStoreType = { folders: FolderType[]; - getFoldersApi: (refetch?: boolean) => Promise; + getFoldersApi: ( + refetch?: boolean, + startupApplication?: boolean, + ) => Promise; setFolders: (folders: FolderType[]) => void; - loading: boolean; - setLoading: (loading: boolean) => void; + isLoadingFolders: boolean; + setIsLoadingFolders: (isLoadingFolders: boolean) => void; selectedFolder: FolderType | null; getFolderById: (id: string) => void; getMyCollectionFolder: () => void; @@ -23,4 +26,5 @@ export type FoldersStoreType = { setFolderIdDragging: (id: string) => void; starterProjectId: string; setStarterProjectId: (id: string) => void; + refreshFolders: () => void; }; From ec1a0fafe5be2864f71c17d5d33f9bcd5d82e396 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Fri, 14 Jun 2024 09:34:59 -0300 Subject: [PATCH 17/26] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(use-delete-folder.t?= =?UTF-8?q?sx):=20replace=20refreshFolders=20with=20getFoldersApi=20for=20?= =?UTF-8?q?better=20API=20call=20management?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx b/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx index 239bf26f3..1eb1c9c0c 100644 --- a/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx +++ b/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx @@ -8,6 +8,7 @@ const useDeleteFolder = ({ navigate }) => { const folderToEdit = useFolderStore((state) => state.folderToEdit); const myCollectionId = useFolderStore((state) => state.myCollectionId); const refreshFolders = useFolderStore((state) => state.refreshFolders); + const getFoldersApi = useFolderStore((state) => state.getFoldersApi); const handleDeleteFolder = () => { deleteFolder(folderToEdit?.id!) @@ -16,7 +17,7 @@ const useDeleteFolder = ({ navigate }) => { title: "Folder deleted successfully.", }); getFolderById(myCollectionId!); - refreshFolders(); + getFoldersApi(true); navigate("/all"); }) .catch((err) => { From 705311982c21ecae3b590af7648cef46de32b46e Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Fri, 14 Jun 2024 09:40:48 -0300 Subject: [PATCH 18/26] formatting files --- src/frontend/src/App.tsx | 6 +-- .../components/sideBarFolderButtons/index.tsx | 18 +++---- .../hooks/use-on-file-drop.tsx | 10 ++-- .../src/components/tableComponent/index.tsx | 10 ++-- src/frontend/src/contexts/authContext.tsx | 6 +-- src/frontend/src/controllers/API/api.tsx | 10 ++-- .../API/helpers/check-duplicate-requests.ts | 2 +- src/frontend/src/controllers/API/index.ts | 52 +++++++++---------- .../headerTabsSearchComponent/index.tsx | 2 +- .../pages/MainPage/pages/mainPage/index.tsx | 2 +- src/frontend/src/stores/foldersStore.tsx | 16 +++--- .../src/types/zustand/folders/index.ts | 2 +- 12 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 720ffb6b2..b84c0d792 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -29,10 +29,10 @@ export default function App() { useTrackLastVisitedPath(); const removeFromTempNotificationList = useAlertStore( - (state) => state.removeFromTempNotificationList, + (state) => state.removeFromTempNotificationList ); const tempNotificationList = useAlertStore( - (state) => state.tempNotificationList, + (state) => state.tempNotificationList ); const [fetchError, setFetchError] = useState(false); const isLoading = useFlowsManagerStore((state) => state.isLoading); @@ -48,7 +48,7 @@ export default function App() { const refreshVersion = useDarkStore((state) => state.refreshVersion); const refreshStars = useDarkStore((state) => state.refreshStars); const setGlobalVariables = useGlobalVariablesStore( - (state) => state.setGlobalVariables, + (state) => state.setGlobalVariables ); const checkHasStore = useStoreStore((state) => state.checkHasStore); const navigate = useNavigate(); diff --git a/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx b/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx index 1b538ba20..ff5c17a15 100644 --- a/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx +++ b/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx @@ -31,7 +31,7 @@ const SideBarFoldersButtonsComponent = ({ const [foldersNames, setFoldersNames] = useState({}); const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); const [editFolders, setEditFolderName] = useState( - folders.map((obj) => ({ name: obj.name, edit: false })), + folders.map((obj) => ({ name: obj.name, edit: false })) ); const uploadFolder = useFolderStore((state) => state.uploadFolder); const currentFolder = pathname.split("/"); @@ -58,7 +58,7 @@ const SideBarFoldersButtonsComponent = ({ const { dragOver, dragEnter, dragLeave, onDrop } = useFileDrop( folderId, - handleFolderChange, + handleFolderChange ); const handleUploadFlowsToFolder = () => { @@ -86,7 +86,7 @@ const SideBarFoldersButtonsComponent = ({ addFolder({ name: "New Folder", parent_id: null, description: "" }).then( (res) => { refreshFolders(); - }, + } ); } @@ -132,7 +132,7 @@ const SideBarFoldersButtonsComponent = ({ <> {folders.map((item, index) => { const editFolderName = editFolders?.filter( - (folder) => folder.name === item.name, + (folder) => folder.name === item.name )[0]; return (
handleChangeFolder!(item.id!)} > @@ -218,7 +218,7 @@ const SideBarFoldersButtonsComponent = ({ folders.map((obj) => ({ name: obj.name, edit: false, - })), + })) ); } if (e.key === "Enter") { @@ -251,10 +251,10 @@ const SideBarFoldersButtonsComponent = ({ }; const updatedFolder = await updateFolder( body, - item.id!, + item.id! ); const updateFolders = folders.filter( - (f) => f.name !== item.name, + (f) => f.name !== item.name ); setFolders([...updateFolders, updatedFolder]); setFoldersNames({}); @@ -262,7 +262,7 @@ const SideBarFoldersButtonsComponent = ({ folders.map((obj) => ({ name: obj.name, edit: false, - })), + })) ); } else { setFoldersNames((old) => ({ diff --git a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx index c75bf4bec..ab4b9d27f 100644 --- a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx +++ b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx @@ -12,7 +12,7 @@ import { addVersionToDuplicates } from "../../../utils/reactflowUtils"; const useFileDrop = (folderId, folderChangeCallback) => { const setFolderDragging = useFolderStore((state) => state.setFolderDragging); const setFolderIdDragging = useFolderStore( - (state) => state.setFolderIdDragging, + (state) => state.setFolderIdDragging ); const setErrorData = useAlertStore((state) => state.setErrorData); @@ -45,7 +45,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { | React.DragEvent | React.DragEvent | React.DragEvent, - folderId: string, + folderId: string ) => { e.preventDefault(); @@ -60,7 +60,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { | React.DragEvent | React.DragEvent | React.DragEvent, - folderId: string, + folderId: string ) => { if (e.dataTransfer.types.some((types) => types === "Files")) { setFolderDragging(true); @@ -73,7 +73,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { e: | React.DragEvent | React.DragEvent - | React.DragEvent, + | React.DragEvent ) => { e.preventDefault(); if (e.target === e.currentTarget) { @@ -87,7 +87,7 @@ const useFileDrop = (folderId, folderChangeCallback) => { | React.DragEvent | React.DragEvent | React.DragEvent, - folderId: string, + folderId: string ) => { if (e?.dataTransfer?.getData("flow")) { const data = JSON.parse(e?.dataTransfer?.getData("flow")); diff --git a/src/frontend/src/components/tableComponent/index.tsx b/src/frontend/src/components/tableComponent/index.tsx index e956d8795..954d7d257 100644 --- a/src/frontend/src/components/tableComponent/index.tsx +++ b/src/frontend/src/components/tableComponent/index.tsx @@ -35,7 +35,7 @@ const TableComponent = forwardRef< alertDescription = DEFAULT_TABLE_ALERT_MSG, ...props }, - ref, + ref ) => { let colDef = props.columnDefs.map((col, index) => { let newCol = { @@ -111,7 +111,7 @@ const TableComponent = forwardRef< }; const onColumnMoved = (params) => { const updatedColumnDefs = makeLastColumnNonResizable( - params.columnApi.getAllGridColumns().map((col) => col.getColDef()), + params.columnApi.getAllGridColumns().map((col) => col.getColDef()) ); params.api.setGridOption("columnDefs", updatedColumnDefs); if (props.onColumnMoved) props.onColumnMoved(params); @@ -135,7 +135,7 @@ const TableComponent = forwardRef< className={cn( dark ? "ag-theme-quartz-dark" : "ag-theme-quartz", "ag-theme-shadcn flex h-full flex-col", - "relative", + "relative" )} // applying the grid theme > source.includes("column"))) { localStorage.setItem( storeReference, - JSON.stringify(realRef.current?.api?.getColumnState()), + JSON.stringify(realRef.current?.api?.getColumnState()) ); setColumnStateChange(true); } @@ -175,7 +175,7 @@ const TableComponent = forwardRef< )}
); - }, + } ); export default TableComponent; diff --git a/src/frontend/src/contexts/authContext.tsx b/src/frontend/src/contexts/authContext.tsx index bd5c2d02c..f6b81a235 100644 --- a/src/frontend/src/contexts/authContext.tsx +++ b/src/frontend/src/contexts/authContext.tsx @@ -31,17 +31,17 @@ export function AuthProvider({ children }): React.ReactElement { const navigate = useNavigate(); const cookies = new Cookies(); const [accessToken, setAccessToken] = useState( - cookies.get("access_token_lf") ?? null, + cookies.get("access_token_lf") ?? null ); const [isAuthenticated, setIsAuthenticated] = useState( - !!cookies.get("access_token_lf"), + !!cookies.get("access_token_lf") ); const [isAdmin, setIsAdmin] = useState(false); const [userData, setUserData] = useState(null); const [autoLogin, setAutoLogin] = useState(false); const setLoading = useAlertStore((state) => state.setLoading); const [apiKey, setApiKey] = useState( - cookies.get("apikey_tkn_lflw"), + cookies.get("apikey_tkn_lflw") ); const getFoldersApi = useFolderStore((state) => state.getFoldersApi); diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index 0ac3efa6b..6bd73f5f1 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -48,7 +48,7 @@ function ApiInterceptor() { } await clearBuildVerticesState(error); return Promise.reject(error); - }, + } ); const isAuthorizedURL = (url) => { @@ -65,10 +65,10 @@ function ApiInterceptor() { const parsedURL = new URL(url); const isDomainAllowed = authorizedDomains.some( - (domain) => parsedURL.origin === new URL(domain).origin, + (domain) => parsedURL.origin === new URL(domain).origin ); const isEndpointAllowed = authorizedEndpoints.some((endpoint) => - parsedURL.pathname.includes(endpoint), + parsedURL.pathname.includes(endpoint) ); return isDomainAllowed || isEndpointAllowed; @@ -102,7 +102,7 @@ function ApiInterceptor() { }, (error) => { return Promise.reject(error); - }, + } ); return () => { @@ -134,7 +134,7 @@ function ApiInterceptor() { if (error?.config?.headers) { delete error.config.headers["Authorization"]; error.config.headers["Authorization"] = `Bearer ${cookies.get( - "access_token_lf", + "access_token_lf" )}`; const response = await axios.request(error.config); return response; diff --git a/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts b/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts index 85c6608ac..ec3c74268 100644 --- a/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts +++ b/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts @@ -9,7 +9,7 @@ export function checkDuplicateRequestAndStoreRequest(config) { const currentUrl = window.location.pathname; const currentTime = Date.now(); const isContained = AUTHORIZED_DUPLICATE_REQUESTS.some((request) => - config?.url!.includes(request), + config?.url!.includes(request) ); if ( diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 104b815b0..481aa2135 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -63,7 +63,7 @@ export async function sendAll(data: sendAllProps) { } export async function postValidateCode( - code: string, + code: string ): Promise> { return await api.post(`${BASE_URL_API}validate/code`, { code }); } @@ -78,7 +78,7 @@ export async function postValidateCode( export async function postValidatePrompt( name: string, template: string, - frontend_node: APIClassType, + frontend_node: APIClassType ): Promise> { return api.post(`${BASE_URL_API}validate/prompt`, { name, @@ -151,7 +151,7 @@ export async function saveFlowToDatabase(newFlow: { * @throws Will throw an error if the update fails. */ export async function updateFlowInDatabase( - updatedFlow: FlowType, + updatedFlow: FlowType ): Promise { try { const response = await api.patch(`${BASE_URL_API}flows/${updatedFlow.id}`, { @@ -329,7 +329,7 @@ export async function getHealth() { * */ export async function getBuildStatus( - flowId: string, + flowId: string ): Promise> { return await api.get(`${BASE_URL_API}build/${flowId}/status`); } @@ -342,7 +342,7 @@ export async function getBuildStatus( * */ export async function postBuildInit( - flow: FlowType, + flow: FlowType ): Promise> { return await api.post(`${BASE_URL_API}build/init/${flow.id}`, flow); } @@ -358,7 +358,7 @@ export async function postBuildInit( */ export async function uploadFile( file: File, - id: string, + id: string ): Promise> { const formData = new FormData(); formData.append("file", file); @@ -380,7 +380,7 @@ export async function getProfilePictures(): Promise> { // let template = apiClass.template; return await api.post(`${BASE_URL_API}custom_component`, { @@ -393,7 +393,7 @@ export async function postCustomComponentUpdate( code: string, template: APITemplateType, field: string, - field_value: any, + field_value: any ): Promise> { return await api.post(`${BASE_URL_API}custom_component/update`, { code, @@ -415,7 +415,7 @@ export async function onLogin(user: LoginType) { headers: { "Content-Type": "application/x-www-form-urlencoded", }, - }, + } ); if (response.status === 200) { @@ -477,11 +477,11 @@ export async function addUser(user: UserInputType): Promise> { export async function getUsersPage( skip: number, - limit: number, + limit: number ): Promise> { try { const res = await api.get( - `${BASE_URL_API}users/?skip=${skip}&limit=${limit}`, + `${BASE_URL_API}users/?skip=${skip}&limit=${limit}` ); if (res.status === 200) { return res.data; @@ -518,7 +518,7 @@ export async function resetPassword(user_id: string, user: resetPasswordType) { try { const res = await api.patch( `${BASE_URL_API}users/${user_id}/reset-password`, - user, + user ); if (res.status === 200) { return res.data; @@ -592,7 +592,7 @@ export async function saveFlowStore( last_tested_version?: string; }, tags: string[], - publicFlow = false, + publicFlow = false ): Promise { try { const response = await api.post(`${BASE_URL_API}store/components/`, { @@ -721,7 +721,7 @@ export async function postStoreComponents(component: Component) { export async function getComponent(component_id: string) { try { const res = await api.get( - `${BASE_URL_API}store/components/${component_id}`, + `${BASE_URL_API}store/components/${component_id}` ); if (res.status === 200) { return res.data; @@ -736,7 +736,7 @@ export async function searchComponent( page?: number | null, limit?: number | null, status?: string | null, - tags?: string[], + tags?: string[] ): Promise { try { let url = `${BASE_URL_API}store/components/`; @@ -848,7 +848,7 @@ export async function updateFlowStore( }, tags: string[], publicFlow = false, - id: string, + id: string ): Promise { try { const response = await api.patch(`${BASE_URL_API}store/components/${id}`, { @@ -932,7 +932,7 @@ export async function deleteGlobalVariable(id: string) { export async function updateGlobalVariable( name: string, value: string, - id: string, + id: string ) { try { const response = api.patch(`${BASE_URL_API}variables/${id}`, { @@ -951,7 +951,7 @@ export async function getVerticesOrder( startNodeId?: string | null, stopNodeId?: string | null, nodes?: Node[], - Edges?: Edge[], + Edges?: Edge[] ): Promise> { // nodeId is optional and is a query parameter // if nodeId is not provided, the API will return all vertices @@ -971,7 +971,7 @@ export async function getVerticesOrder( return await api.post( `${BASE_URL_API}build/${flowId}/vertices`, data, - config, + config ); } @@ -979,7 +979,7 @@ export async function postBuildVertex( flowId: string, vertexId: string, input_value: string, - files?: string[], + files?: string[] ): Promise> { // input_value is optional and is a query parameter let data = {}; @@ -991,7 +991,7 @@ export async function postBuildVertex( } return await api.post( `${BASE_URL_API}build/${flowId}/vertices/${vertexId}`, - data, + data ); } @@ -1015,7 +1015,7 @@ export async function getFlowPool({ } export async function deleteFlowPool( - flowId: string, + flowId: string ): Promise> { const config = {}; config["params"] = { flow_id: flowId }; @@ -1029,7 +1029,7 @@ export async function deleteFlowPool( * @returns A promise that resolves to an array of AxiosResponse objects representing the delete responses. */ export async function multipleDeleteFlowsComponents( - flowIds: string[], + flowIds: string[] ): Promise[]> { const batches: string[][] = []; @@ -1052,7 +1052,7 @@ export async function multipleDeleteFlowsComponents( // Execute all delete requests const responses: Promise>[] = batches.map((batch) => - deleteBatch(batch), + deleteBatch(batch) ); // Return the responses after all requests are completed @@ -1062,7 +1062,7 @@ export async function multipleDeleteFlowsComponents( export async function getTransactionTable( id: string, mode: "intersection" | "union", - params = {}, + params = {} ): Promise<{ rows: Array; columns: Array }> { const config = {}; config["params"] = { flow_id: id }; @@ -1078,7 +1078,7 @@ export async function getMessagesTable( mode: "intersection" | "union", id?: string, excludedFields?: string[], - params = {}, + params = {} ): Promise<{ rows: Array; columns: Array }> { const config = {}; if (id) { diff --git a/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx b/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx index c6ceb44c7..b023216ab 100644 --- a/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx +++ b/src/frontend/src/pages/MainPage/components/myCollectionComponent/components/headerTabsSearchComponent/index.tsx @@ -11,7 +11,7 @@ const HeaderTabsSearchComponent = ({}: HeaderTabsSearchComponentProps) => { const [inputValue, setInputValue] = useState(""); const setSearchFlowsComponents = useFlowsManagerStore( - (state) => state.setSearchFlowsComponents, + (state) => state.setSearchFlowsComponents ); return ( diff --git a/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx b/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx index 6b4892d60..39add5211 100644 --- a/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/pages/mainPage/index.tsx @@ -16,7 +16,7 @@ import useDropdownOptions from "../../hooks/use-dropdown-options"; export default function HomePage(): JSX.Element { const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow); const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId, + (state) => state.setCurrentFlowId ); const location = useLocation(); diff --git a/src/frontend/src/stores/foldersStore.tsx b/src/frontend/src/stores/foldersStore.tsx index 01db44247..8e42026b4 100644 --- a/src/frontend/src/stores/foldersStore.tsx +++ b/src/frontend/src/stores/foldersStore.tsx @@ -18,18 +18,18 @@ export const useFolderStore = create((set, get) => ({ getFolders().then( async (res) => { const foldersWithoutStarterProjects = res?.filter( - (folder) => folder.name !== STARTER_FOLDER_NAME, + (folder) => folder.name !== STARTER_FOLDER_NAME ); const starterProjects = res?.find( - (folder) => folder.name === STARTER_FOLDER_NAME, + (folder) => folder.name === STARTER_FOLDER_NAME ); set({ starterProjectId: starterProjects!.id ?? "" }); set({ folders: foldersWithoutStarterProjects }); const myCollectionId = res?.find( - (f) => f.name === DEFAULT_FOLDER, + (f) => f.name === DEFAULT_FOLDER )?.id; set({ myCollectionId }); @@ -55,7 +55,7 @@ export const useFolderStore = create((set, get) => ({ set({ folders: [] }); get().setIsLoadingFolders(false); reject(error); - }, + } ); } }); @@ -65,18 +65,18 @@ export const useFolderStore = create((set, get) => ({ getFolders().then( async (res) => { const foldersWithoutStarterProjects = res?.filter( - (folder) => folder.name !== STARTER_FOLDER_NAME, + (folder) => folder.name !== STARTER_FOLDER_NAME ); const starterProjects = res?.find( - (folder) => folder.name === STARTER_FOLDER_NAME, + (folder) => folder.name === STARTER_FOLDER_NAME ); set({ starterProjectId: starterProjects!.id ?? "" }); set({ folders: foldersWithoutStarterProjects }); const myCollectionId = res?.find( - (f) => f.name === DEFAULT_FOLDER, + (f) => f.name === DEFAULT_FOLDER )?.id; set({ myCollectionId }); @@ -87,7 +87,7 @@ export const useFolderStore = create((set, get) => ({ set({ folders: [] }); get().setIsLoadingFolders(false); reject(error); - }, + } ); }); }, diff --git a/src/frontend/src/types/zustand/folders/index.ts b/src/frontend/src/types/zustand/folders/index.ts index 495d65b87..45c1e0bd9 100644 --- a/src/frontend/src/types/zustand/folders/index.ts +++ b/src/frontend/src/types/zustand/folders/index.ts @@ -4,7 +4,7 @@ export type FoldersStoreType = { folders: FolderType[]; getFoldersApi: ( refetch?: boolean, - startupApplication?: boolean, + startupApplication?: boolean ) => Promise; setFolders: (folders: FolderType[]) => void; isLoadingFolders: boolean; From 57a7b2baabd0fa39a8d45cfedfb604bf27ecde3d Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Fri, 14 Jun 2024 09:45:53 -0300 Subject: [PATCH 19/26] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(use-delete-folder.t?= =?UTF-8?q?sx):=20remove=20unused=20refreshFolders=20variable=20to=20clean?= =?UTF-8?q?=20up=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx b/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx index 1eb1c9c0c..0d093bc32 100644 --- a/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx +++ b/src/frontend/src/pages/MainPage/hooks/use-delete-folder.tsx @@ -7,7 +7,6 @@ const useDeleteFolder = ({ navigate }) => { const setErrorData = useAlertStore((state) => state.setErrorData); const folderToEdit = useFolderStore((state) => state.folderToEdit); const myCollectionId = useFolderStore((state) => state.myCollectionId); - const refreshFolders = useFolderStore((state) => state.refreshFolders); const getFoldersApi = useFolderStore((state) => state.getFoldersApi); const handleDeleteFolder = () => { From 71e8aa00cf33e84134352b535ed5841f4d1c1817 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Fri, 14 Jun 2024 13:23:03 -0300 Subject: [PATCH 20/26] =?UTF-8?q?=F0=9F=90=9B=20(utils.ts):=20add=20option?= =?UTF-8?q?al=20chaining=20to=20base=5Fclasses=20to=20prevent=20runtime=20?= =?UTF-8?q?errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/utils/utils.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 5a1f6621f..0a1f99692 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -56,7 +56,7 @@ export function normalCaseToSnakeCase(str: string): string { export function toTitleCase( str: string | undefined, - isNodeField?: boolean + isNodeField?: boolean, ): string { if (!str) return ""; let result = str @@ -65,7 +65,7 @@ export function toTitleCase( if (isNodeField) return word; if (index === 0) { return checkUpperWords( - word[0].toUpperCase() + word.slice(1).toLowerCase() + word[0].toUpperCase() + word.slice(1).toLowerCase(), ); } return checkUpperWords(word.toLowerCase()); @@ -78,7 +78,7 @@ export function toTitleCase( if (isNodeField) return word; if (index === 0) { return checkUpperWords( - word[0].toUpperCase() + word.slice(1).toLowerCase() + word[0].toUpperCase() + word.slice(1).toLowerCase(), ); } return checkUpperWords(word.toLowerCase()); @@ -182,7 +182,7 @@ export function checkLocalStorageKey(key: string): boolean { export function IncrementObjectKey( object: object, - key: string + key: string, ): { newKey: string; increment: number } { let count = 1; const type = removeCountFromString(key); @@ -217,7 +217,7 @@ export function groupByFamily( data: APIDataType, baseClasses: string, left: boolean, - flow?: NodeType[] + flow?: NodeType[], ): groupedObjType[] { const baseClassesSet = new Set(baseClasses.split("\n")); let arrOfPossibleInputs: Array<{ @@ -243,7 +243,7 @@ export function groupByFamily( baseClassesSet.has(template.type)) || (template?.input_types && template?.input_types.some((inputType) => - baseClassesSet.has(inputType) + baseClassesSet.has(inputType), ))) ); }; @@ -263,7 +263,7 @@ export function groupByFamily( hasBaseClassInBaseClasses: foundNode?.hasBaseClassInBaseClasses || nodeData.node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass) + baseClassesSet.has(baseClass), ), //seta como anterior ou verifica se o node tem base class displayName: nodeData.node?.display_name, }); @@ -280,10 +280,10 @@ export function groupByFamily( if (!foundNode) { foundNode = { hasBaseClassInTemplate: Object.values(node!.template).some( - checkBaseClass + checkBaseClass, ), - hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass) + hasBaseClassInBaseClasses: node!.base_classes?.some((baseClass) => + baseClassesSet.has(baseClass), ), displayName: node?.display_name, }; @@ -355,7 +355,7 @@ export function isTimeStampString(str: string): boolean { export function extractColumnsFromRows( rows: object[], mode: "intersection" | "union", - excludeColumns?: Array + excludeColumns?: Array, ): (ColDef | ColGroupDef)[] { let columnsKeys: { [key: string]: ColDef | ColGroupDef } = {}; if (rows.length === 0) { From 3ea0c7b03a5c7a113f3c285b2fcfe999785ef9c7 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Fri, 14 Jun 2024 13:40:35 -0300 Subject: [PATCH 21/26] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(tableComponent):=20?= =?UTF-8?q?disable=20row=20animations=20to=20improve=20performance=20?= =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(flowLogsModal):=20use=20useMemo=20for=20T?= =?UTF-8?q?ableComponent=20to=20optimize=20rendering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/tableComponent/index.tsx | 1 + .../src/modals/flowLogsModal/index.tsx | 28 +++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/frontend/src/components/tableComponent/index.tsx b/src/frontend/src/components/tableComponent/index.tsx index 954d7d257..4ca1bb22e 100644 --- a/src/frontend/src/components/tableComponent/index.tsx +++ b/src/frontend/src/components/tableComponent/index.tsx @@ -144,6 +144,7 @@ const TableComponent = forwardRef< minWidth: 100, autoHeight: true, }} + animateRows={false} columnDefs={colDef} ref={realRef} onGridReady={onGridReady} diff --git a/src/frontend/src/modals/flowLogsModal/index.tsx b/src/frontend/src/modals/flowLogsModal/index.tsx index 840de14ca..27af4b734 100644 --- a/src/frontend/src/modals/flowLogsModal/index.tsx +++ b/src/frontend/src/modals/flowLogsModal/index.tsx @@ -1,5 +1,5 @@ import { ColDef, ColGroupDef } from "ag-grid-community"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import IconComponent from "../../components/genericIconComponent"; import TableComponent from "../../components/tableComponent"; import { Tabs, TabsList, TabsTrigger } from "../../components/ui/tabs"; @@ -61,6 +61,21 @@ export default function FlowLogsModal({ } }, [open, activeTab]); + const tableComponentRender = useMemo(() => { + return ( + + ); + }, [activeTab]); + return ( @@ -85,16 +100,7 @@ export default function FlowLogsModal({ Messages - + {tableComponentRender} ); From 9daf66993f77c0699a4e1368219b02ace011116a Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Fri, 14 Jun 2024 09:48:35 -0700 Subject: [PATCH 22/26] Refactor CustomComponent repr_value handling (#2173) * Refactor CustomComponent to handle repr_value more efficiently --- .../custom/custom_component/custom_component.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/backend/base/langflow/custom/custom_component/custom_component.py b/src/backend/base/langflow/custom/custom_component/custom_component.py index 5c1da081b..963de3e28 100644 --- a/src/backend/base/langflow/custom/custom_component/custom_component.py +++ b/src/backend/base/langflow/custom/custom_component/custom_component.py @@ -159,11 +159,11 @@ class CustomComponent(Component): if self.repr_value == "": self.repr_value = self.status if isinstance(self.repr_value, dict): - return yaml.dump(self.repr_value) - if isinstance(self.repr_value, str): - return self.repr_value - if isinstance(self.repr_value, BaseModel) and not isinstance(self.repr_value, Record): - return str(self.repr_value) + self.repr_value = yaml.dump(self.repr_value) + if isinstance(self.repr_value, BaseModel) and not isinstance(self.repr_value, Data): + self.repr_value = str(self.repr_value) + elif hasattr(self.repr_value, "to_json"): + self.repr_value = self.repr_value.to_json() return self.repr_value def build_config(self): From 52e472798abff3550154443e91c8ae5d5c849f33 Mon Sep 17 00:00:00 2001 From: ogabrielluiz Date: Fri, 14 Jun 2024 13:53:27 -0300 Subject: [PATCH 23/26] chore: Update lint-action to v2 in lint-js.yml and lint-py.yml workflows --- .github/workflows/lint-js.yml | 2 +- .github/workflows/lint-py.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml index 0590e8a38..84823b885 100644 --- a/.github/workflows/lint-js.yml +++ b/.github/workflows/lint-js.yml @@ -39,7 +39,7 @@ jobs: if: ${{ steps.setup-node.outputs.cache-hit != 'true' }} - name: Run linters - uses: wearerequired/lint-action@v1 + uses: wearerequired/lint-action@v2 with: github_token: ${{ secrets.github_token }} auto_fix: true diff --git a/.github/workflows/lint-py.yml b/.github/workflows/lint-py.yml index 6182f91fc..eb28b3101 100644 --- a/.github/workflows/lint-py.yml +++ b/.github/workflows/lint-py.yml @@ -41,7 +41,7 @@ jobs: ./.mypy_cache key: ${{ runner.os }}-mypy-${{ hashFiles('**/pyproject.toml') }} - name: Run linters - uses: wearerequired/lint-action@v1 + uses: wearerequired/lint-action@v2 with: github_token: ${{ secrets.github_token }} # Enable linters From 5353d2375a58d8438551c43d20f9fc2c76510dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dtalo=20Johnny?= Date: Fri, 14 Jun 2024 14:01:24 -0300 Subject: [PATCH 24/26] Sentry integration (#2172) * add sentry sdk to dependencies * add sentry attributes to settings * initialize sentry for error tracking * add sentry sdk to base dependencies --- src/backend/base/langflow/main.py | 16 ++++++ .../base/langflow/services/settings/base.py | 5 ++ src/backend/base/poetry.lock | 53 ++++++++++++++++++- src/backend/base/pyproject.toml | 1 + 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/backend/base/langflow/main.py b/src/backend/base/langflow/main.py index c81c014e2..1227d4c62 100644 --- a/src/backend/base/langflow/main.py +++ b/src/backend/base/langflow/main.py @@ -20,6 +20,7 @@ from langflow.initial_setup.setup import ( load_flows_from_directory, ) from langflow.interface.utils import setup_llm_caching +from langflow.services.deps import get_settings_service from langflow.services.plugins.langfuse_plugin import LangfuseInstance from langflow.services.utils import initialize_services, teardown_services from langflow.utils.logger import configure @@ -78,6 +79,7 @@ def create_app(): socketio_server = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*", logger=True) lifespan = get_lifespan(socketio_server=socketio_server, version=__version__) app = FastAPI(lifespan=lifespan, title="Langflow", version=__version__) + setup_sentry(app) origins = ["*"] app.add_middleware( @@ -115,6 +117,20 @@ def mount_socketio(app: FastAPI, socketio_server: socketio.AsyncServer): return app +def setup_sentry(app: FastAPI): + settings = get_settings_service().settings + if settings.sentry_dsn: + import sentry_sdk + from sentry_sdk.integrations.asgi import SentryAsgiMiddleware + + sentry_sdk.init( + dsn=settings.sentry_dsn, + traces_sample_rate=settings.sentry_traces_sample_rate, + profiles_sample_rate=settings.sentry_profiles_sample_rate, + ) + app.add_middleware(SentryAsgiMiddleware) + + def setup_static_files(app: FastAPI, static_files_dir: Path): """ Setup the static files directory. diff --git a/src/backend/base/langflow/services/settings/base.py b/src/backend/base/langflow/services/settings/base.py index 679d16627..e8c0cbf90 100644 --- a/src/backend/base/langflow/services/settings/base.py +++ b/src/backend/base/langflow/services/settings/base.py @@ -85,6 +85,11 @@ class Settings(BaseSettings): redis_url: Optional[str] = None redis_cache_expire: int = 3600 + # Sentry + sentry_dsn: Optional[str] = None + sentry_traces_sample_rate: Optional[float] = 1.0 + sentry_profiles_sample_rate: Optional[float] = 1.0 + # PLUGIN_DIR: Optional[str] = None langfuse_secret_key: Optional[str] = None diff --git a/src/backend/base/poetry.lock b/src/backend/base/poetry.lock index 8f57c7d7b..7f21e0c5f 100644 --- a/src/backend/base/poetry.lock +++ b/src/backend/base/poetry.lock @@ -2411,7 +2411,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -2499,6 +2498,56 @@ files = [ [package.dependencies] pyasn1 = ">=0.1.3" +[[package]] +name = "sentry-sdk" +version = "2.5.1" +description = "Python client for Sentry (https://sentry.io)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "sentry_sdk-2.5.1-py2.py3-none-any.whl", hash = "sha256:1f87acdce4a43a523ae5aa21a3fc37522d73ebd9ec04b1dbf01aa3d173852def"}, + {file = "sentry_sdk-2.5.1.tar.gz", hash = "sha256:fbc40a78a8a9c6675133031116144f0d0940376fa6e4e1acd5624c90b0aaf58b"}, +] + +[package.dependencies] +certifi = "*" +urllib3 = ">=1.26.11" + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +anthropic = ["anthropic (>=0.16)"] +arq = ["arq (>=0.23)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +huggingface-hub = ["huggingface-hub (>=0.22)"] +langchain = ["langchain (>=0.0.210)"] +loguru = ["loguru (>=0.5)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] +pure-eval = ["asttokens", "executing", "pure-eval"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +tornado = ["tornado (>=5)"] + [[package]] name = "shellingham" version = "1.5.4" @@ -3247,4 +3296,4 @@ local = [] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "3c83d086a178cebd83473758459c4f026907268dbf8c9ce45bc4bfb1f340e9a5" +content-hash = "72f05330f1e734596d160b45cb68ab2ebf7d0824314bec0566bddb5b2043f4e6" diff --git a/src/backend/base/pyproject.toml b/src/backend/base/pyproject.toml index a833470a2..1762b645d 100644 --- a/src/backend/base/pyproject.toml +++ b/src/backend/base/pyproject.toml @@ -63,6 +63,7 @@ cryptography = "^42.0.5" asyncer = "^0.0.5" pyperclip = "^1.8.2" uncurl = "^0.0.11" +sentry-sdk = "^2.5.1" [tool.poetry.extras] From 49962aeb571448e14ae5bf2006ad007df16ec92a Mon Sep 17 00:00:00 2001 From: ogabrielluiz Date: Fri, 14 Jun 2024 14:19:06 -0300 Subject: [PATCH 25/26] chore: Update Dockerfile and Tags setup in docker-build.yml workflow --- .github/workflows/docker-build.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index c5ea5f6f7..3450f317e 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -26,15 +26,17 @@ jobs: setup: runs-on: ubuntu-latest outputs: - base_tags: ${{ steps.set-vars.outputs.base_tags }} - main_tags: ${{ steps.set-vars.outputs.main_tags }} + tags: ${{ steps.set-vars.outputs.tags }} steps: - uses: actions/checkout@v4 - name: Set Dockerfile and Tags id: set-vars run: | - echo "base_tags=langflowai/langflow:base-${{ inputs.version }}" >> $GITHUB_OUTPUT - echo "main_tags=langflowai/langflow:${{ inputs.version }},langflowai/langflow:1.0-alpha" >> $GITHUB_OUTPUT + if [[ "${{ inputs.release_type }}" == "base" ]]; then + echo "tags=langflowai/langflow:base-${{ inputs.version }}" >> $GITHUB_OUTPUT + else + echo "tags=langflowai/langflow:${{ inputs.version }},langflowai/langflow:1.0-alpha" >> $GITHUB_OUTPUT + fi build_base: runs-on: ubuntu-latest needs: setup @@ -54,7 +56,10 @@ jobs: push: true platforms: "linux/amd64,linux/arm64/v8" file: ./docker/build_and_push_base.Dockerfile - tags: ${{ needs.setup.outputs.base_tags }} + # base_rags if release_type is base, main_tags if release_type is main + tags: ${{ needs.setup.outputs.tags }} + - name: Wait for Docker Hub to propagate + run: sleep 30 build_components: if: ${{ inputs.release_type == 'main' }} From 3c430ff397f19ab19ef2b6405f2b938fdf529355 Mon Sep 17 00:00:00 2001 From: ogabrielluiz Date: Fri, 14 Jun 2024 14:29:51 -0300 Subject: [PATCH 26/26] chore: Update Dockerfile and Tags setup in docker-build.yml workflow --- .github/workflows/docker-build.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 3450f317e..f84dead6b 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -40,6 +40,10 @@ jobs: build_base: runs-on: ubuntu-latest needs: setup + strategy: + matrix: + platform: [linux/amd64, linux/arm64/v8] + file: [./docker/build_and_push.Dockerfile, ./docker/build_and_push_base.Dockerfile] steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx @@ -54,12 +58,9 @@ jobs: with: context: . push: true - platforms: "linux/amd64,linux/arm64/v8" - file: ./docker/build_and_push_base.Dockerfile - # base_rags if release_type is base, main_tags if release_type is main + platforms: ${{ matrix.platform }} + file: ${{ matrix.file }} tags: ${{ needs.setup.outputs.tags }} - - name: Wait for Docker Hub to propagate - run: sleep 30 build_components: if: ${{ inputs.release_type == 'main' }}