From b4dbe90212a1ea8e64e29b25738b67210a1f7702 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Tue, 20 Feb 2024 15:08:19 -0300 Subject: [PATCH 01/13] =?UTF-8?q?=F0=9F=90=9B=20fix(buildUtils.ts):=20refa?= =?UTF-8?q?ctor=20buildVertices=20function=20to=20improve=20readability=20?= =?UTF-8?q?and=20error=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The buildVertices function has been refactored to improve readability and error handling. Instead of using Promise.all with map, it now uses a for loop to iterate over the vertices and perform the build process for each vertex. This change allows for better error handling and reporting. Additionally, the onBuildError callback is now called with the correct parameters when there is an error building a component. --- src/frontend/src/utils/buildUtils.ts | 54 ++++++++++++---------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/src/frontend/src/utils/buildUtils.ts b/src/frontend/src/utils/buildUtils.ts index 854a86f24..26a225733 100644 --- a/src/frontend/src/utils/buildUtils.ts +++ b/src/frontend/src/utils/buildUtils.ts @@ -52,42 +52,34 @@ export async function buildVertices({ const buildResults: Array = []; for (let i = 0; i < vertices.length; i += 1) { if (onBuildStart) onBuildStart(vertices[i]); - await Promise.all( - vertices[i].map(async (id) => { - try { - // Set vertex state to building - const buildRes = await postBuildVertex(flowId, id); - const buildData: VertexBuildTypeAPI = buildRes.data; - if (onBuildUpdate) { - let data = {}; - if (!buildData.valid) { - if (onBuildError) { - onBuildError( - "Error Building Component", - [buildData.params], - verticesIds - ); - } - } - data[buildData.id] = buildData; - onBuildUpdate({ data, id: buildData.id }); - } - buildResults.push(buildData.valid); - } catch (error) { - if (onBuildError) { - console.log(error); - onBuildError( + for (const id of vertices[i]) { + try { + const buildRes = await postBuildVertex(flowId, id); + const buildData: VertexBuildTypeAPI = buildRes.data; + if (onBuildUpdate) { + let data = {}; + if (!buildData.valid) { + onBuildError!( "Error Building Component", - [ - (error as AxiosError).response?.data?.detail ?? - "Unknown Error", - ], + [buildData.params], verticesIds ); } + data[buildData.id] = buildData; + onBuildUpdate({ data, id: buildData.id }); } - }) - ); + buildResults.push(buildData.valid); + } catch (error) { + onBuildError!( + "Error Building Component", + [ + (error as AxiosError).response?.data?.detail ?? + "Unknown Error", + ], + verticesIds + ); + } + } } if (onBuildComplete) { const allNodesValid = buildResults.every((result) => result); From 60c7ea3e35a83fc31d2cfaff06891f3da69b2abd Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:01:17 -0300 Subject: [PATCH 02/13] Sort vertices containing interface components first --- src/backend/langflow/graph/graph/base.py | 27 ++++++++++++++++++------ 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/backend/langflow/graph/graph/base.py b/src/backend/langflow/graph/graph/base.py index 3c772c897..370c45461 100644 --- a/src/backend/langflow/graph/graph/base.py +++ b/src/backend/langflow/graph/graph/base.py @@ -418,6 +418,7 @@ class Graph: if edge not in edges: edges.append(edge) vertices = self.layered_topological_sort(vertices, edges) + vertices = self.sort_interface_components_first(vertices) return self.sort_chat_inputs_first(vertices) def layered_topological_sort( @@ -523,11 +524,23 @@ class Graph: # and sort the layers accordingly # InterfaceComponentTypes is an enum # check all values of the enum and sort the layers - for layer in vertices: - layer.sort( - key=lambda x: any( - comp_type.value in x - for comp_type in InterfaceComponentTypes.__members__.values() - ) - ) + vertices = self.sort_interface_components_first(vertices) return self.sort_chat_inputs_first(vertices) + + def sort_interface_components_first(self, vertices: List[Vertex]) -> List[Vertex]: + """Sorts the vertices in the graph so that vertices containing ChatInput or ChatOutput come first.""" + + def contains_interface_component(vertex): + return any( + component.value in vertex for component in InterfaceComponentTypes + ) + + # Sort each inner list so that vertices containing ChatInput or ChatOutput come first + sorted_vertices = [ + sorted( + inner_list, + key=lambda vertex: not contains_interface_component(vertex), + ) + for inner_list in vertices + ] + return sorted_vertices From a4c74f099c0c0dcee83f87625c55eeb3e69388ea Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:01:23 -0300 Subject: [PATCH 03/13] Fix session retrieval in build_vertex function --- src/backend/langflow/api/v1/chat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index d49f4dc4a..e2738c0f1 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -330,7 +330,7 @@ async def build_vertex( f"No cache found for {flow_id}. Building graph starting at {vertex_id}" ) graph = build_and_cache_graph( - flow_id=flow_id, session=get_session(), chat_service=chat_service + flow_id=flow_id, session=next(get_session()), chat_service=chat_service ) else: graph = cache.get("result") From c0ee093854acdb3e0aa30967b3551b6a76ba5176 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:01:41 -0300 Subject: [PATCH 04/13] Refactor buildVertices function to extract buildVertex logic --- src/frontend/src/utils/buildUtils.ts | 68 +++++++++++++++++----------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/src/frontend/src/utils/buildUtils.ts b/src/frontend/src/utils/buildUtils.ts index 26a225733..8e91e9bac 100644 --- a/src/frontend/src/utils/buildUtils.ts +++ b/src/frontend/src/utils/buildUtils.ts @@ -53,36 +53,52 @@ export async function buildVertices({ for (let i = 0; i < vertices.length; i += 1) { if (onBuildStart) onBuildStart(vertices[i]); for (const id of vertices[i]) { - try { - const buildRes = await postBuildVertex(flowId, id); - const buildData: VertexBuildTypeAPI = buildRes.data; - if (onBuildUpdate) { - let data = {}; - if (!buildData.valid) { - onBuildError!( - "Error Building Component", - [buildData.params], - verticesIds - ); - } - data[buildData.id] = buildData; - onBuildUpdate({ data, id: buildData.id }); - } - buildResults.push(buildData.valid); - } catch (error) { - onBuildError!( - "Error Building Component", - [ - (error as AxiosError).response?.data?.detail ?? - "Unknown Error", - ], - verticesIds - ); - } + buildVertex( + flowId, + id, + onBuildUpdate, + onBuildError, + verticesIds, + buildResults + ); } } + if (onBuildComplete) { const allNodesValid = buildResults.every((result) => result); onBuildComplete(allNodesValid); } } + +async function buildVertex( + flowId, + id, + onBuildUpdate, + onBuildError, + verticesIds, + buildResults +) { + try { + const buildRes = await postBuildVertex(flowId, id); + const buildData: VertexBuildTypeAPI = buildRes.data; + if (onBuildUpdate) { + let data = {}; + if (!buildData.valid) { + onBuildError!( + "Error Building Component", + [buildData.params], + verticesIds + ); + } + data[buildData.id] = buildData; + onBuildUpdate({ data, id: buildData.id }); + } + buildResults.push(buildData.valid); + } catch (error) { + onBuildError!( + "Error Building Component", + [(error as AxiosError).response?.data?.detail ?? "Unknown Error"], + verticesIds + ); + } +} From f70d3131a58dd436d90ad19b4d21c3d283ea4a67 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:06:16 -0300 Subject: [PATCH 05/13] Refactor typing import in base.py --- src/backend/langflow/graph/vertex/base.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/graph/vertex/base.py b/src/backend/langflow/graph/vertex/base.py index 01d182142..036e92008 100644 --- a/src/backend/langflow/graph/vertex/base.py +++ b/src/backend/langflow/graph/vertex/base.py @@ -1,7 +1,8 @@ import ast import inspect import types -from typing import TYPE_CHECKING, Any, Callable, Coroutine, Dict, List, Optional +from typing import (TYPE_CHECKING, Any, Callable, Coroutine, Dict, List, + Optional) from langflow.graph.schema import InterfaceComponentTypes from langflow.graph.utils import UnbuiltObject, UnbuiltResult @@ -306,7 +307,7 @@ class Vertex: params.pop(key, None) # Add _type to params self.params = params - self._raw_params = params + self._raw_params = params.copy() async def _build(self, user_id=None): """ From bf8330e1527eec066cdaf4a65869e8b2ffa7ee10 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:18:02 -0300 Subject: [PATCH 06/13] Refactor Vertex params assignment --- src/backend/langflow/graph/vertex/base.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/backend/langflow/graph/vertex/base.py b/src/backend/langflow/graph/vertex/base.py index 036e92008..c26a2354c 100644 --- a/src/backend/langflow/graph/vertex/base.py +++ b/src/backend/langflow/graph/vertex/base.py @@ -1,8 +1,7 @@ import ast import inspect import types -from typing import (TYPE_CHECKING, Any, Callable, Coroutine, Dict, List, - Optional) +from typing import TYPE_CHECKING, Any, Callable, Coroutine, Dict, List, Optional from langflow.graph.schema import InterfaceComponentTypes from langflow.graph.utils import UnbuiltObject, UnbuiltResult @@ -306,8 +305,8 @@ class Vertex: else: params.pop(key, None) # Add _type to params - self.params = params - self._raw_params = params.copy() + self.params = {} + self._raw_params = params async def _build(self, user_id=None): """ From 9211b1c8e5bad8f97daf20b34f450798fba33320 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:22:15 -0300 Subject: [PATCH 07/13] Refactor Vertex params assignment --- src/backend/langflow/graph/vertex/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/graph/vertex/base.py b/src/backend/langflow/graph/vertex/base.py index c26a2354c..a5378b95e 100644 --- a/src/backend/langflow/graph/vertex/base.py +++ b/src/backend/langflow/graph/vertex/base.py @@ -305,8 +305,8 @@ class Vertex: else: params.pop(key, None) # Add _type to params - self.params = {} - self._raw_params = params + self.params = params + self._raw_params = params.copy() async def _build(self, user_id=None): """ From 4abff7f80cda68133b5c815b256a1dce759d58d2 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:58:56 -0300 Subject: [PATCH 08/13] Refactor build_vertex function to include timing information --- src/backend/langflow/api/v1/chat.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index e2738c0f1..b700109b4 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -20,7 +20,7 @@ from langflow.api.v1.schemas import ( BuildStatus, BuiltResponse, InitResponse, - ResultDict, + ResultData, StreamData, VertexBuildResponse, VerticesOrderResponse, @@ -322,6 +322,7 @@ async def build_vertex( inputs: dict = Body(None), ): """Build a vertex instead of the entire graph.""" + start_time = time.perf_counter() try: cache = chat_service.get_cache(flow_id) if not cache: @@ -336,7 +337,6 @@ async def build_vertex( graph = cache.get("result") result_dict = {} duration = "" - start_time = time.perf_counter() if tweaks: graph = process_tweaks_on_graph(graph, tweaks) if not (vertex := graph.get_vertex(vertex_id)): @@ -351,13 +351,9 @@ async def build_vertex( # to the frontend vertex.set_artifacts() artifacts = vertex.artifacts - timedelta = time.perf_counter() - start_time - duration = format_elapsed_time(timedelta) - result_dict = ResultDict( + result_dict = ResultData( results=result_dict, artifacts=artifacts, - duration=duration, - timedelta=timedelta, ) vertex.set_result(result_dict) elif vertex.result is not None: @@ -370,7 +366,7 @@ async def build_vertex( except Exception as exc: params = str(exc) valid = False - result_dict = ResultDict(results={}) + result_dict = ResultData(results={}) artifacts = {} # If there's an error building the vertex # we need to clear the cache @@ -383,6 +379,12 @@ async def build_vertex( data=result_dict, artifacts=artifacts, ) + + timedelta = time.perf_counter() - start_time + duration = format_elapsed_time(timedelta) + result_dict.duration = duration + result_dict.timedelta = timedelta + return VertexBuildResponse( valid=valid, params=params, From 4c4414729db9c975c937ee2aa61aa9d35b221cba Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:59:02 -0300 Subject: [PATCH 09/13] Update ResultDict class name to ResultData --- src/backend/langflow/api/v1/schemas.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/api/v1/schemas.py b/src/backend/langflow/api/v1/schemas.py index e84e65b51..228ee264f 100644 --- a/src/backend/langflow/api/v1/schemas.py +++ b/src/backend/langflow/api/v1/schemas.py @@ -222,7 +222,7 @@ class VerticesOrderResponse(BaseModel): ids: List[List[str]] -class ResultDict(BaseModel): +class ResultData(BaseModel): results: Optional[Any] = Field(default_factory=dict) artifacts: Optional[Any] = Field(default_factory=dict) timedelta: Optional[float] = None @@ -240,7 +240,7 @@ class VertexBuildResponse(BaseModel): valid: bool params: Optional[str] """JSON string of the params.""" - data: ResultDict + data: ResultData """Mapping of vertex ids to result dict containing the param name and result value.""" timestamp: Optional[datetime] = Field(default_factory=datetime.utcnow) """Timestamp of the build.""" From 35a6b8956a5808545af8a22ed500636b34607aa0 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:59:08 -0300 Subject: [PATCH 10/13] Update ResultDict to ResultData in Vertex class --- src/backend/langflow/graph/vertex/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/langflow/graph/vertex/base.py b/src/backend/langflow/graph/vertex/base.py index a5378b95e..c43b8fd0d 100644 --- a/src/backend/langflow/graph/vertex/base.py +++ b/src/backend/langflow/graph/vertex/base.py @@ -14,7 +14,7 @@ from langflow.utils.util import sync_to_async from loguru import logger if TYPE_CHECKING: - from langflow.api.v1.schemas import ResultDict + from langflow.api.v1.schemas import ResultData from langflow.graph.edge.base import ContractEdge from langflow.graph.graph.base import Graph @@ -50,7 +50,7 @@ class Vertex: self.parent_is_top_level = False self.layer = None self.should_run = True - self.result: Optional["ResultDict"] = None + self.result: Optional["ResultData"] = None try: self.is_interface_component = InterfaceComponentTypes(self.vertex_type) except ValueError: @@ -81,7 +81,7 @@ class Vertex: ) return edge_results - def set_result(self, result: "ResultDict") -> None: + def set_result(self, result: "ResultData") -> None: self.result = result def get_built_result(self): From 90cf166ef6e3ce9c9bfd008ba3e9afdb0cb01bd1 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:59:21 -0300 Subject: [PATCH 11/13] Refactor schema mismatch check and log vertex build --- .../langflow/services/monitor/utils.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/backend/langflow/services/monitor/utils.py b/src/backend/langflow/services/monitor/utils.py index 5324700a7..6ebba74eb 100644 --- a/src/backend/langflow/services/monitor/utils.py +++ b/src/backend/langflow/services/monitor/utils.py @@ -1,13 +1,12 @@ from typing import TYPE_CHECKING, Any, Dict, Optional, Type import duckdb +from langflow.services.deps import get_monitor_service from loguru import logger from pydantic import BaseModel -from langflow.services.deps import get_monitor_service - if TYPE_CHECKING: - from langflow.api.v1.schemas import ResultDict + from langflow.api.v1.schemas import ResultData INDEX_KEY = "index" @@ -44,7 +43,9 @@ def model_to_sql_column_definitions(model: Type[BaseModel]) -> dict: return columns -def drop_and_create_table_if_schema_mismatch(db_path: str, table_name: str, model: Type[BaseModel]): +def drop_and_create_table_if_schema_mismatch( + db_path: str, table_name: str, model: Type[BaseModel] +): with duckdb.connect(db_path) as conn: # Get the current schema from the database try: @@ -64,8 +65,12 @@ def drop_and_create_table_if_schema_mismatch(db_path: str, table_name: str, mode conn.execute(f"CREATE SEQUENCE seq_{table_name} START 1;") except duckdb.CatalogException: pass - desired_schema[INDEX_KEY] = f"INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq_{table_name}')" - columns_sql = ", ".join(f"{name} {data_type}" for name, data_type in desired_schema.items()) + desired_schema[INDEX_KEY] = ( + f"INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq_{table_name}')" + ) + columns_sql = ", ".join( + f"{name} {data_type}" for name, data_type in desired_schema.items() + ) create_table_sql = f"CREATE TABLE {table_name} ({columns_sql})" conn.execute(create_table_sql) @@ -133,7 +138,7 @@ async def log_vertex_build( vertex_id: str, valid: bool, params: Any, - data: "ResultDict", + data: "ResultData", artifacts: Optional[dict] = None, ): try: From 0eaed5bbcbecf0bb71dd1dbf3d679af2d96f077c Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 16:59:26 -0300 Subject: [PATCH 12/13] Update ResultDict to ResultData in build_vertex function --- src/backend/langflow/services/socket/utils.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/backend/langflow/services/socket/utils.py b/src/backend/langflow/services/socket/utils.py index 03b609919..38f1cf82b 100644 --- a/src/backend/langflow/services/socket/utils.py +++ b/src/backend/langflow/services/socket/utils.py @@ -3,7 +3,7 @@ from typing import Callable import socketio from langflow.api.utils import format_elapsed_time -from langflow.api.v1.schemas import ResultDict, VertexBuildResponse +from langflow.api.v1.schemas import ResultData, VertexBuildResponse from langflow.graph.graph.base import Graph from langflow.graph.vertex.base import StatelessVertex from langflow.services.database.models.flow.model import Flow @@ -73,11 +73,16 @@ async def build_vertex( artifacts = vertex.artifacts timedelta = time.perf_counter() - start_time duration = format_elapsed_time(timedelta) - result_dict = ResultDict(results=result_dict, artifacts=artifacts, duration=duration, timedelta=timedelta) + result_dict = ResultData( + results=result_dict, + artifacts=artifacts, + duration=duration, + timedelta=timedelta, + ) except Exception as exc: params = str(exc) valid = False - result_dict = ResultDict(results={}) + result_dict = ResultData(results={}) artifacts = {} set_cache(flow_id, graph) await log_vertex_build( @@ -90,7 +95,9 @@ async def build_vertex( ) # Emit the vertex build response - response = VertexBuildResponse(valid=valid, params=params, id=vertex.id, data=result_dict) + response = VertexBuildResponse( + valid=valid, params=params, id=vertex.id, data=result_dict + ) await sio.emit("vertex_build", data=response.model_dump(), to=sid) except Exception as exc: From 1a5a6ba35b9d55edc2989b0a49b98720d8afdd51 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Tue, 20 Feb 2024 19:52:43 -0300 Subject: [PATCH 13/13] =?UTF-8?q?=F0=9F=90=9B=20fix(api.tsx):=20import=20m?= =?UTF-8?q?issing=20BuildStatus=20enum=20from=20constants/enums=20to=20fix?= =?UTF-8?q?=20compilation=20error=20=E2=9C=A8=20feat(api.tsx):=20add=20sup?= =?UTF-8?q?port=20for=20renewing=20access=20token=20and=20handling=20authe?= =?UTF-8?q?ntication=20errors=20to=20improve=20user=20experience=20?= =?UTF-8?q?=E2=9C=A8=20feat(api.tsx):=20add=20support=20for=20updating=20b?= =?UTF-8?q?uild=20status=20of=20vertices=20to=20keep=20track=20of=20build?= =?UTF-8?q?=20progress=20=F0=9F=90=9B=20fix(flowStore.ts):=20add=20missing?= =?UTF-8?q?=20updateVerticesBuild=20function=20to=20update=20the=20list=20?= =?UTF-8?q?of=20vertices=20being=20built=20=F0=9F=90=9B=20fix(flowStore.ts?= =?UTF-8?q?):=20initialize=20verticesBuild=20array=20to=20an=20empty=20arr?= =?UTF-8?q?ay=20to=20avoid=20undefined=20errors=20=F0=9F=90=9B=20fix(flowS?= =?UTF-8?q?tore.ts):=20fix=20typo=20in=20updateVerticesBuild=20function=20?= =?UTF-8?q?name=20=F0=9F=90=9B=20fix(flowStore.ts):=20fix=20typo=20in=20up?= =?UTF-8?q?dateBuildStatus=20function=20parameter=20name=20=F0=9F=90=9B=20?= =?UTF-8?q?fix(flowStore.ts):=20fix=20typo=20in=20updateBuildStatus=20func?= =?UTF-8?q?tion=20parameter=20type=20=E2=9C=A8=20feat(flowStore.ts):=20add?= =?UTF-8?q?=20verticesBuild=20property=20to=20store=20the=20list=20of=20ve?= =?UTF-8?q?rtices=20being=20built=20=F0=9F=90=9B=20fix(index.ts):=20fix=20?= =?UTF-8?q?typo=20in=20updateBuildStatus=20function=20parameter=20name=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(index.ts):=20fix=20typo=20in=20updateBuildSt?= =?UTF-8?q?atus=20function=20parameter=20type=20=E2=9C=A8=20feat(index.ts)?= =?UTF-8?q?:=20add=20updateVerticesBuild=20function=20to=20update=20the=20?= =?UTF-8?q?list=20of=20vertices=20being=20built=20=F0=9F=90=9B=20fix(build?= =?UTF-8?q?Utils.ts):=20update=20build=20status=20and=20vertices=20build?= =?UTF-8?q?=20list=20when=20building=20vertices=20to=20keep=20track=20of?= =?UTF-8?q?=20build=20progress?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/controllers/API/api.tsx | 76 +++++++++++--------- src/frontend/src/stores/flowStore.ts | 4 ++ src/frontend/src/types/zustand/flow/index.ts | 2 + src/frontend/src/utils/buildUtils.ts | 1 + 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index c6786cc1c..b659333a1 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -3,8 +3,10 @@ import { useContext, useEffect } from "react"; import { Cookies } from "react-cookie"; import { useNavigate } from "react-router-dom"; import { renewAccessToken } from "."; +import { BuildStatus } from "../../constants/enums"; import { AuthContext } from "../../contexts/authContext"; import useAlertStore from "../../stores/alertStore"; +import useFlowStore from "../../stores/flowStore"; // Create a new Axios instance const api: AxiosInstance = axios.create({ @@ -24,45 +26,20 @@ function ApiInterceptor() { async (error: AxiosError) => { if (error.response?.status === 401) { const accessToken = cookies.get("access_token_lf"); + if (accessToken && !autoLogin) { - authenticationErrorCount = authenticationErrorCount + 1; - if (authenticationErrorCount > 3) { - authenticationErrorCount = 0; - logout(); - } - try { - const res = await renewAccessToken(); - if (res?.data?.access_token && res?.data?.refresh_token) { - login(res?.data?.access_token); - } - if (error?.config?.headers) { - delete error.config.headers["Authorization"]; - error.config.headers["Authorization"] = `Bearer ${cookies.get( - "access_token_lf" - )}`; - const response = await axios.request(error.config); - return response; - } - } catch (error) { - if (axios.isAxiosError(error) && error.response?.status === 401) { - logout(); - } else { - console.error(error); - logout(); - } - } + checkErrorCount(); + await tryToRenewAccessToken(error); } if (!accessToken && error?.config?.url?.includes("login")) { return Promise.reject(error); - } else { - logout(); } - } else { - // if (URL_EXCLUDED_FROM_ERROR_RETRIES.includes(error.config?.url)) { - return Promise.reject(error); - // } + + return logout(); } + await clearBuildVerticesState(error); + return Promise.reject(error); } ); @@ -115,6 +92,41 @@ function ApiInterceptor() { }; }, [accessToken, setErrorData]); + function checkErrorCount() { + authenticationErrorCount = authenticationErrorCount + 1; + + if (authenticationErrorCount > 3) { + authenticationErrorCount = 0; + logout(); + } + } + + async function tryToRenewAccessToken(error: AxiosError) { + try { + const res = await renewAccessToken(); + if (res?.data?.access_token && res?.data?.refresh_token) { + login(res?.data?.access_token); + } + if (error?.config?.headers) { + delete error.config.headers["Authorization"]; + error.config.headers["Authorization"] = `Bearer ${cookies.get( + "access_token_lf" + )}`; + const response = await axios.request(error.config); + return response; + } + } catch (error) { + logout(); + } + } + + async function clearBuildVerticesState(error) { + if (error?.response?.status === 500) { + const vertices = useFlowStore.getState().verticesBuild; + useFlowStore.getState().updateBuildStatus(vertices, BuildStatus.BUILT); + } + } + return null; } diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index ea424d6fb..398b2b3f3 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -431,6 +431,10 @@ const useFlowStore = create((set, get) => ({ } }); }, + updateVerticesBuild: (vertices: string[]) => { + set({ verticesBuild: vertices }); + }, + verticesBuild: [], })); export default useFlowStore; diff --git a/src/frontend/src/types/zustand/flow/index.ts b/src/frontend/src/types/zustand/flow/index.ts index 429379155..f0bad1578 100644 --- a/src/frontend/src/types/zustand/flow/index.ts +++ b/src/frontend/src/types/zustand/flow/index.ts @@ -87,4 +87,6 @@ export type FlowStoreType = { buildFlow: (nodeId?: string) => Promise; getFlow: () => { nodes: Node[]; edges: Edge[]; viewport: Viewport }; updateBuildStatus: (nodeId: string[], status: BuildStatus) => void; + updateVerticesBuild: (vertices: string[]) => void; + verticesBuild: string[]; }; diff --git a/src/frontend/src/utils/buildUtils.ts b/src/frontend/src/utils/buildUtils.ts index 8e91e9bac..638d35886 100644 --- a/src/frontend/src/utils/buildUtils.ts +++ b/src/frontend/src/utils/buildUtils.ts @@ -47,6 +47,7 @@ export async function buildVertices({ const verticesIds = vertices.flatMap((v) => v); useFlowStore.getState().updateBuildStatus(verticesIds, BuildStatus.TO_BUILD); + useFlowStore.getState().updateVerticesBuild(verticesIds); // Set each vertex state to building const buildResults: Array = [];