diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index 0f64c8af7eaf..647608ab24a6 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -195,82 +195,81 @@ function ApiInterceptor() { } export type StreamingRequestParams = { - method: string, - url: string, - onData: (event: object) => Promise, - body?: object, - onError?: (statusCode: number) => void, -} + method: string; + url: string; + onData: (event: object) => Promise; + body?: object; + onError?: (statusCode: number) => void; +}; async function performStreamingRequest({ - method, - url, - onData, - body, - onError}: StreamingRequestParams) { - - let headers = { - "Content-Type": "application/json", - // this flag is fundamental to ensure server stops tasks when client disconnects - "Connection": "close" - }; - const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN); - if (accessToken) { - headers["Authorization"] = `Bearer ${accessToken}`; - } - const params = { - method: method, - headers: headers + method, + url, + onData, + body, + onError, +}: StreamingRequestParams) { + let headers = { + "Content-Type": "application/json", + // this flag is fundamental to ensure server stops tasks when client disconnects + Connection: "close", + }; + const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN); + if (accessToken) { + headers["Authorization"] = `Bearer ${accessToken}`; } + const params = { + method: method, + headers: headers, + }; if (body) { - params["body"] = JSON.stringify(body) + params["body"] = JSON.stringify(body); } - const response = await fetch(url, params) + const response = await fetch(url, params); if (!response.ok) { - if (onError) { - onError(response.status) - } else { - throw new Error("error in streaming request") - } + if (onError) { + onError(response.status); + } else { + throw new Error("error in streaming request"); + } } if (response.body === null) { - return + return; } - let current: string[] = [] + let current: string[] = []; let textDecoder = new TextDecoder(); for await (const chunk of response.body) { - const decodedChunk = await textDecoder.decode(chunk); - let all = decodedChunk.split("\n\n"); - for (const string of all) { - if (string.endsWith("}")) { - const allString = current.join("") + string - let data: object - try { - data = JSON.parse(allString) - current = [] - } catch (e) { - current.push(string) - continue - } - const shouldContinue = await onData(data) - if (!shouldContinue) { - current = [] - break - } - } else { - current.push(string) - } + const decodedChunk = await textDecoder.decode(chunk); + let all = decodedChunk.split("\n\n"); + for (const string of all) { + if (string.endsWith("}")) { + const allString = current.join("") + string; + let data: object; + try { + data = JSON.parse(allString); + current = []; + } catch (e) { + current.push(string); + continue; + } + const shouldContinue = await onData(data); + if (!shouldContinue) { + current = []; + break; + } + } else { + current.push(string); } + } } if (current.length > 0) { - const allString = current.join("") - if (allString) { - const data = JSON.parse(current.join("")) - await onData(data) - } + const allString = current.join(""); + if (allString) { + const data = JSON.parse(current.join("")); + await onData(data); + } } - } export { ApiInterceptor, api, performStreamingRequest }; diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 91745bccfa73..2b66670998e6 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -904,7 +904,7 @@ export async function getVerticesOrder( data["data"]["nodes"] = nodes; data["data"]["edges"] = Edges; } - return await api.post( + return await api.post( `${BASE_URL_API}build/${flowId}/vertices`, data, config, diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index 971c642041c7..280444e1bddb 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -29,7 +29,11 @@ import { targetHandleType, } from "../types/flow"; import { FlowStoreType, VertexLayerElementType } from "../types/zustand/flow"; -import {buildVertices, buildFlowVertices, buildFlowVerticesWithFallback} from "../utils/buildUtils"; +import { + buildFlowVertices, + buildFlowVerticesWithFallback, + buildVertices, +} from "../utils/buildUtils"; import { checkChatInput, checkOldComponents, diff --git a/src/frontend/src/utils/buildUtils.ts b/src/frontend/src/utils/buildUtils.ts index 182d9554ea2d..963981d287ff 100644 --- a/src/frontend/src/utils/buildUtils.ts +++ b/src/frontend/src/utils/buildUtils.ts @@ -1,486 +1,483 @@ -import {AxiosError} from "axios"; -import {Edge, Node} from "reactflow"; -import {BuildStatus} from "../constants/enums"; -import {getVerticesOrder, postBuildVertex} from "../controllers/API"; +import { BASE_URL_API } from "@/constants/constants"; +import { performStreamingRequest } from "@/controllers/API/api"; +import { AxiosError } from "axios"; +import { Edge, Node } from "reactflow"; +import { BuildStatus } from "../constants/enums"; +import { getVerticesOrder, postBuildVertex } from "../controllers/API"; import useAlertStore from "../stores/alertStore"; import useFlowStore from "../stores/flowStore"; -import {VertexBuildTypeAPI} from "../types/api"; -import {isErrorLogType} from "../types/utils/typeCheckingUtils"; -import {VertexLayerElementType} from "../types/zustand/flow"; -import {BASE_URL_API} from "@/constants/constants"; -import {performStreamingRequest} from "@/controllers/API/api"; +import { VertexBuildTypeAPI } from "../types/api"; +import { isErrorLogType } from "../types/utils/typeCheckingUtils"; +import { VertexLayerElementType } from "../types/zustand/flow"; type BuildVerticesParams = { - setLockChat?: (lock: boolean) => void; - flowId: string; // Assuming FlowType is the type for your flow - input_value?: any; // Replace any with the actual type if it's not any - files?: string[]; - startNodeId?: string | null; // Assuming nodeId is of type string, and it's optional - stopNodeId?: string | null; // Assuming nodeId is of type string, and it's optional - onGetOrderSuccess?: () => void; - onBuildUpdate?: ( - data: VertexBuildTypeAPI, - status: BuildStatus, - buildId: string, - ) => void; // Replace any with the actual type if it's not any - onBuildComplete?: (allNodesValid: boolean) => void; - onBuildError?: (title, list, idList: VertexLayerElementType[]) => void; - onBuildStart?: (idList: VertexLayerElementType[]) => void; - onValidateNodes?: (nodes: string[]) => void; - nodes?: Node[]; - edges?: Edge[]; + setLockChat?: (lock: boolean) => void; + flowId: string; // Assuming FlowType is the type for your flow + input_value?: any; // Replace any with the actual type if it's not any + files?: string[]; + startNodeId?: string | null; // Assuming nodeId is of type string, and it's optional + stopNodeId?: string | null; // Assuming nodeId is of type string, and it's optional + onGetOrderSuccess?: () => void; + onBuildUpdate?: ( + data: VertexBuildTypeAPI, + status: BuildStatus, + buildId: string, + ) => void; // Replace any with the actual type if it's not any + onBuildComplete?: (allNodesValid: boolean) => void; + onBuildError?: (title, list, idList: VertexLayerElementType[]) => void; + onBuildStart?: (idList: VertexLayerElementType[]) => void; + onValidateNodes?: (nodes: string[]) => void; + nodes?: Node[]; + edges?: Edge[]; }; function getInactiveVertexData(vertexId: string): VertexBuildTypeAPI { - // Build VertexBuildTypeAPI - let inactiveData = { - results: {}, - outputs: {}, - messages: [], - inactive: true, - }; - let inactiveVertexData = { - id: vertexId, - data: inactiveData, - inactivated_vertices: null, - run_id: "", - next_vertices_ids: [], - top_level_vertices: [], - inactive_vertices: null, - valid: false, - params: null, - messages: [], - artifacts: null, - timestamp: new Date().toISOString(), - }; - - return inactiveVertexData; + // Build VertexBuildTypeAPI + let inactiveData = { + results: {}, + outputs: {}, + messages: [], + inactive: true, + }; + let inactiveVertexData = { + id: vertexId, + data: inactiveData, + inactivated_vertices: null, + run_id: "", + next_vertices_ids: [], + top_level_vertices: [], + inactive_vertices: null, + valid: false, + params: null, + messages: [], + artifacts: null, + timestamp: new Date().toISOString(), + }; + + return inactiveVertexData; } export async function updateVerticesOrder( - flowId: string, - setLockChat?: (lock: boolean) => void, - startNodeId?: string | null, - stopNodeId?: string | null, - nodes?: Node[], - edges?: Edge[], + flowId: string, + setLockChat?: (lock: boolean) => void, + startNodeId?: string | null, + stopNodeId?: string | null, + nodes?: Node[], + edges?: Edge[], ): Promise<{ - verticesLayers: VertexLayerElementType[][]; - verticesIds: string[]; - runId?: string; - verticesToRun: string[]; + verticesLayers: VertexLayerElementType[][]; + verticesIds: string[]; + runId?: string; + verticesToRun: string[]; }> { - return new Promise(async (resolve, reject) => { - const setErrorData = useAlertStore.getState().setErrorData; - let orderResponse; - try { - orderResponse = await getVerticesOrder( - flowId, - startNodeId, - stopNodeId, - nodes, - edges, - ); - } catch (error: any) { - setErrorData({ - title: "Oops! Looks like you missed something", - list: [error.response?.data?.detail ?? "Unknown Error"], - }); - useFlowStore.getState().setIsBuilding(false); - setLockChat && setLockChat(false); - throw new Error("Invalid components"); - } - // orderResponse.data.ids, - // for each id we need to build the VertexLayerElementType object as - // {id: id, reference: id} - let verticesLayers: Array> = - orderResponse.data.ids.map((id: string) => { - return [{id: id, reference: id}]; - }); - - const runId = orderResponse.data.run_id; - const verticesToRun = orderResponse.data.vertices_to_run; - - useFlowStore - .getState() - .updateBuildStatus(verticesToRun, BuildStatus.TO_BUILD); - - const verticesIds = orderResponse.data.ids; - useFlowStore.getState().updateVerticesBuild({ - verticesLayers, - verticesIds, - runId, - verticesToRun, - }); - resolve({verticesLayers, verticesIds, runId, verticesToRun}); + return new Promise(async (resolve, reject) => { + const setErrorData = useAlertStore.getState().setErrorData; + let orderResponse; + try { + orderResponse = await getVerticesOrder( + flowId, + startNodeId, + stopNodeId, + nodes, + edges, + ); + } catch (error: any) { + setErrorData({ + title: "Oops! Looks like you missed something", + list: [error.response?.data?.detail ?? "Unknown Error"], + }); + useFlowStore.getState().setIsBuilding(false); + setLockChat && setLockChat(false); + throw new Error("Invalid components"); + } + // orderResponse.data.ids, + // for each id we need to build the VertexLayerElementType object as + // {id: id, reference: id} + let verticesLayers: Array> = + orderResponse.data.ids.map((id: string) => { + return [{ id: id, reference: id }]; + }); + + const runId = orderResponse.data.run_id; + const verticesToRun = orderResponse.data.vertices_to_run; + + useFlowStore + .getState() + .updateBuildStatus(verticesToRun, BuildStatus.TO_BUILD); + + const verticesIds = orderResponse.data.ids; + useFlowStore.getState().updateVerticesBuild({ + verticesLayers, + verticesIds, + runId, + verticesToRun, }); + resolve({ verticesLayers, verticesIds, runId, verticesToRun }); + }); } -export async function buildFlowVerticesWithFallback(params: BuildVerticesParams) { - try { - return await buildFlowVertices(params) - } catch (e: any) { - if (e.message === "endpoint not available") { - return await buildVertices(params) - } - throw e +export async function buildFlowVerticesWithFallback( + params: BuildVerticesParams, +) { + try { + return await buildFlowVertices(params); + } catch (e: any) { + if (e.message === "endpoint not available") { + return await buildVertices(params); } + throw e; + } } const MIN_VISUAL_BUILD_TIME_MS = 300; export async function buildFlowVertices({ - flowId, - input_value, - files, - startNodeId, - stopNodeId, - onGetOrderSuccess, - onBuildUpdate, - onBuildComplete, - onBuildError, - onBuildStart, - onValidateNodes, - nodes, - edges, - setLockChat, - }: BuildVerticesParams) { - - - let url = `${BASE_URL_API}build/${flowId}/flow?`; - if (startNodeId) { - url = `${url}&start_component_id=${startNodeId}`; - } - if (stopNodeId) { - url = `${url}&stop_component_id=${stopNodeId}`; - } - const postData = {} - if (typeof input_value !== "undefined") { - postData["inputs"] = { input_value: input_value }; - } - if (files) { - postData["files"] = files; - } - - - - - const buildResults: Array = []; - - const verticesStartTimeMs: Map = new Map(); + flowId, + input_value, + files, + startNodeId, + stopNodeId, + onGetOrderSuccess, + onBuildUpdate, + onBuildComplete, + onBuildError, + onBuildStart, + onValidateNodes, + nodes, + edges, + setLockChat, +}: BuildVerticesParams) { + let url = `${BASE_URL_API}build/${flowId}/flow?`; + if (startNodeId) { + url = `${url}&start_component_id=${startNodeId}`; + } + if (stopNodeId) { + url = `${url}&stop_component_id=${stopNodeId}`; + } + const postData = {}; + if (typeof input_value !== "undefined") { + postData["inputs"] = { input_value: input_value }; + } + if (files) { + postData["files"] = files; + } + + const buildResults: Array = []; + + const verticesStartTimeMs: Map = new Map(); + + const onEvent = async (type, data): Promise => { + const onStartVertex = (id: string) => { + verticesStartTimeMs.set(id, Date.now()); + useFlowStore.getState().updateBuildStatus([id], BuildStatus.TO_BUILD); + + if (onBuildStart) onBuildStart([{ id: id, reference: id }]); + }; + switch (type) { + case "vertices_sorted": { + const verticesToRun = data.to_run; + const verticesIds = data.ids; - const onEvent = async (type, data): Promise => { - const onStartVertex = (id: string) => { - verticesStartTimeMs.set(id, Date.now()); - useFlowStore.getState().updateBuildStatus([id], BuildStatus.TO_BUILD); + verticesIds.forEach(onStartVertex); - if (onBuildStart) onBuildStart([{id: id, reference: id}]); + let verticesLayers: Array> = + verticesIds.map((id: string) => { + return [{ id: id, reference: id }]; + }); + useFlowStore.getState().updateVerticesBuild({ + verticesLayers, + verticesIds, + verticesToRun, + }); + if (onValidateNodes) { + try { + onValidateNodes(data.to_run); + if (onGetOrderSuccess) onGetOrderSuccess(); + useFlowStore.getState().setIsBuilding(true); + return true; + } catch (e) { + useFlowStore.getState().setIsBuilding(false); + setLockChat && setLockChat(false); + return false; + } + } + return true; + } + case "end_vertex": { + const buildData = data.build_data; + const startTimeMs = verticesStartTimeMs.get(buildData.id); + if (startTimeMs) { + const delta = Date.now() - startTimeMs; + if (delta < MIN_VISUAL_BUILD_TIME_MS) { + // this is a visual trick to make the build process look more natural + await new Promise((resolve) => + setTimeout(resolve, MIN_VISUAL_BUILD_TIME_MS - delta), + ); + } } - switch (type) { - case "vertices_sorted": { - const verticesToRun = data.to_run; - const verticesIds = data.ids; - - verticesIds.forEach(onStartVertex) - - let verticesLayers: Array> = - verticesIds.map((id: string) => { - return [{id: id, reference: id}]; - }); - useFlowStore.getState().updateVerticesBuild({ - verticesLayers, - verticesIds, - verticesToRun, - }); - if (onValidateNodes) { - try { - onValidateNodes(data.to_run); - if (onGetOrderSuccess) onGetOrderSuccess(); - useFlowStore.getState().setIsBuilding(true); - return true - } catch (e) { - useFlowStore.getState().setIsBuilding(false); - setLockChat && setLockChat(false); - return false; - } + if (onBuildUpdate) { + if (!buildData.valid) { + // lots is a dictionary with the key the output field name and the value the log object + // logs: { [key: string]: { message: any; type: string }[] }; + const errorMessages = Object.keys(buildData.data.outputs).map( + (key) => { + const outputs = buildData.data.outputs[key]; + if (Array.isArray(outputs)) { + return outputs + .filter((log) => isErrorLogType(log.message)) + .map((log) => log.message.errorMessage); } - return true - } - case "end_vertex": { - const buildData = data.build_data - const startTimeMs = verticesStartTimeMs.get(buildData.id) - if (startTimeMs) { - const delta = Date.now() - startTimeMs - if (delta < MIN_VISUAL_BUILD_TIME_MS) { - // this is a visual trick to make the build process look more natural - await new Promise(resolve => setTimeout(resolve, MIN_VISUAL_BUILD_TIME_MS - delta)); - } + if (!isErrorLogType(outputs.message)) { + return []; } - - if (onBuildUpdate) { - if (!buildData.valid) { - // lots is a dictionary with the key the output field name and the value the log object - // logs: { [key: string]: { message: any; type: string }[] }; - const errorMessages = Object.keys(buildData.data.outputs).map((key) => { - const outputs = buildData.data.outputs[key]; - if (Array.isArray(outputs)) { - return outputs - .filter((log) => isErrorLogType(log.message)) - .map((log) => log.message.errorMessage); - } - if (!isErrorLogType(outputs.message)) { - return []; - } - return [outputs.message.errorMessage]; - }); - onBuildError!( - "Error Building Component", - errorMessages, - [{id: buildData.id}], - ); - onBuildUpdate(buildData, BuildStatus.ERROR, ""); - buildResults.push(false) - return false - } else { - onBuildUpdate(buildData, BuildStatus.BUILT, ""); - buildResults.push(true) - } - } - buildData.next_vertices_ids?.forEach(onStartVertex) - return true - } - case "end": { - const allNodesValid = buildResults.every((result) => result); - onBuildComplete!(allNodesValid) - useFlowStore.getState().setIsBuilding(false); - return true - } + return [outputs.message.errorMessage]; + }, + ); + onBuildError!("Error Building Component", errorMessages, [ + { id: buildData.id }, + ]); + onBuildUpdate(buildData, BuildStatus.ERROR, ""); + buildResults.push(false); + return false; + } else { + onBuildUpdate(buildData, BuildStatus.BUILT, ""); + buildResults.push(true); + } } - return true - }; - return performStreamingRequest({ - method: "POST", - url, - body: postData, - onData: async (event) => { - const type = event["event"]; - const data = event["data"]; - return await onEvent(type, data); - }, - onError: (statusCode) => { - if (statusCode === 404) { - throw new Error("endpoint not available") - } - throw new Error("error in streaming request") - } - }) + buildData.next_vertices_ids?.forEach(onStartVertex); + return true; + } + case "end": { + const allNodesValid = buildResults.every((result) => result); + onBuildComplete!(allNodesValid); + useFlowStore.getState().setIsBuilding(false); + return true; + } + } + return true; + }; + return performStreamingRequest({ + method: "POST", + url, + body: postData, + onData: async (event) => { + const type = event["event"]; + const data = event["data"]; + return await onEvent(type, data); + }, + onError: (statusCode) => { + if (statusCode === 404) { + throw new Error("endpoint not available"); + } + throw new Error("error in streaming request"); + }, + }); } export async function buildVertices({ - flowId, - input_value, - files, - startNodeId, - stopNodeId, - onGetOrderSuccess, - onBuildUpdate, - onBuildComplete, - onBuildError, - onBuildStart, - onValidateNodes, - nodes, - edges, - setLockChat, - }: BuildVerticesParams) { - // if startNodeId and stopNodeId are provided - // something is wrong - if (startNodeId && stopNodeId) { - return; + flowId, + input_value, + files, + startNodeId, + stopNodeId, + onGetOrderSuccess, + onBuildUpdate, + onBuildComplete, + onBuildError, + onBuildStart, + onValidateNodes, + nodes, + edges, + setLockChat, +}: BuildVerticesParams) { + // if startNodeId and stopNodeId are provided + // something is wrong + if (startNodeId && stopNodeId) { + return; + } + let verticesOrderResponse = await updateVerticesOrder( + flowId, + setLockChat, + startNodeId, + stopNodeId, + nodes, + edges, + ); + if (onValidateNodes) { + try { + onValidateNodes(verticesOrderResponse.verticesToRun); + } catch (e) { + useFlowStore.getState().setIsBuilding(false); + setLockChat && setLockChat(false); + return; } - let verticesOrderResponse = await updateVerticesOrder( - flowId, - setLockChat, - startNodeId, - stopNodeId, - nodes, - edges, - ); - if (onValidateNodes) { - try { - onValidateNodes(verticesOrderResponse.verticesToRun); - } catch (e) { - useFlowStore.getState().setIsBuilding(false); - setLockChat && setLockChat(false); - return; - } + } + if (onGetOrderSuccess) onGetOrderSuccess(); + let verticesBuild = useFlowStore.getState().verticesBuild; + + const verticesIds = verticesBuild?.verticesIds!; + const verticesLayers = verticesBuild?.verticesLayers!; + const runId = verticesBuild?.runId!; + let stop = false; + + useFlowStore.getState().updateBuildStatus(verticesIds, BuildStatus.TO_BUILD); + useFlowStore.getState().setIsBuilding(true); + let currentLayerIndex = 0; // Start with the first layer + // Set each vertex state to building + const buildResults: Array = []; + + // Build each layer + while ( + currentLayerIndex < + (useFlowStore.getState().verticesBuild?.verticesLayers! || []).length + ) { + // Get the current layer + const currentLayer = + useFlowStore.getState().verticesBuild?.verticesLayers![currentLayerIndex]; + // If there are no more layers, we are done + if (!currentLayer) { + if (onBuildComplete) { + const allNodesValid = buildResults.every((result) => result); + onBuildComplete(allNodesValid); + useFlowStore.getState().setIsBuilding(false); + } + return; } - if (onGetOrderSuccess) onGetOrderSuccess(); - let verticesBuild = useFlowStore.getState().verticesBuild; - - const verticesIds = verticesBuild?.verticesIds!; - const verticesLayers = verticesBuild?.verticesLayers!; - const runId = verticesBuild?.runId!; - let stop = false; - - useFlowStore.getState().updateBuildStatus(verticesIds, BuildStatus.TO_BUILD); - useFlowStore.getState().setIsBuilding(true); - let currentLayerIndex = 0; // Start with the first layer - // Set each vertex state to building - const buildResults: Array = []; - - - // Build each layer - while ( - currentLayerIndex < - (useFlowStore.getState().verticesBuild?.verticesLayers! || []).length + // If there is a callback for the start of the build, call it + if (onBuildStart) onBuildStart(currentLayer); + // Build each vertex in the current layer + await Promise.all( + currentLayer.map(async (element) => { + // Check if id is in the list of inactive nodes + if ( + !useFlowStore + .getState() + .verticesBuild?.verticesIds.includes(element.id) && + !useFlowStore + .getState() + .verticesBuild?.verticesIds.includes(element.reference ?? "") && + onBuildUpdate ) { - // Get the current layer - const currentLayer = - useFlowStore.getState().verticesBuild?.verticesLayers![currentLayerIndex]; - // If there are no more layers, we are done - if (!currentLayer) { - if (onBuildComplete) { - const allNodesValid = buildResults.every((result) => result); - onBuildComplete(allNodesValid); - useFlowStore.getState().setIsBuilding(false); - } - return; + // If it is, skip building and set the state to inactive + if (element.id) { + onBuildUpdate( + getInactiveVertexData(element.id), + BuildStatus.INACTIVE, + runId, + ); + } + if (element.reference) { + onBuildUpdate( + getInactiveVertexData(element.reference), + BuildStatus.INACTIVE, + runId, + ); + } + buildResults.push(false); + return; } - // If there is a callback for the start of the build, call it - if (onBuildStart) onBuildStart(currentLayer); - // Build each vertex in the current layer - await Promise.all( - currentLayer.map(async (element) => { - // Check if id is in the list of inactive nodes - if ( - !useFlowStore - .getState() - .verticesBuild?.verticesIds.includes(element.id) && - !useFlowStore - .getState() - .verticesBuild?.verticesIds.includes(element.reference ?? "") && - onBuildUpdate - ) { - // If it is, skip building and set the state to inactive - if (element.id) { - onBuildUpdate( - getInactiveVertexData(element.id), - BuildStatus.INACTIVE, - runId, - ); - } - if (element.reference) { - onBuildUpdate( - getInactiveVertexData(element.reference), - BuildStatus.INACTIVE, - runId, - ); - } - buildResults.push(false); - return; - } - - // Build the vertex - await buildVertex({ - flowId, - id: element.id, - input_value, - files, - onBuildUpdate: (data: VertexBuildTypeAPI, status: BuildStatus) => { - if (onBuildUpdate) onBuildUpdate(data, status, runId); - }, - onBuildError, - verticesIds, - buildResults, - stopBuild: () => { - stop = true; - }, - }); - if (stop) { - return; - } - }), - ); - // Once the current layer is built, move to the next layer - currentLayerIndex += 1; + // Build the vertex + await buildVertex({ + flowId, + id: element.id, + input_value, + files, + onBuildUpdate: (data: VertexBuildTypeAPI, status: BuildStatus) => { + if (onBuildUpdate) onBuildUpdate(data, status, runId); + }, + onBuildError, + verticesIds, + buildResults, + stopBuild: () => { + stop = true; + }, + }); if (stop) { - break; + return; } + }), + ); + // Once the current layer is built, move to the next layer + currentLayerIndex += 1; + + if (stop) { + break; } - if (onBuildComplete) { - const allNodesValid = buildResults.every((result) => result); - onBuildComplete(allNodesValid); - useFlowStore.getState().setIsBuilding(false); - } + } + if (onBuildComplete) { + const allNodesValid = buildResults.every((result) => result); + onBuildComplete(allNodesValid); + useFlowStore.getState().setIsBuilding(false); + } } async function buildVertex({ - flowId, - id, - input_value, - files, - onBuildUpdate, - onBuildError, - verticesIds, - buildResults, - stopBuild, - }: { - flowId: string; - id: string; - input_value: string; - files?: string[]; - onBuildUpdate?: (data: any, status: BuildStatus) => void; - onBuildError?: (title, list, idList: VertexLayerElementType[]) => void; - verticesIds: string[]; - buildResults: boolean[]; - stopBuild: () => void; + flowId, + id, + input_value, + files, + onBuildUpdate, + onBuildError, + verticesIds, + buildResults, + stopBuild, +}: { + flowId: string; + id: string; + input_value: string; + files?: string[]; + onBuildUpdate?: (data: any, status: BuildStatus) => void; + onBuildError?: (title, list, idList: VertexLayerElementType[]) => void; + verticesIds: string[]; + buildResults: boolean[]; + stopBuild: () => void; }) { - try { - const buildRes = await postBuildVertex(flowId, id, input_value, files); - - const buildData: VertexBuildTypeAPI = buildRes.data; - if (onBuildUpdate) { - if (!buildData.valid) { - // lots is a dictionary with the key the output field name and the value the log object - // logs: { [key: string]: { message: any; type: string }[] }; - const errorMessages = Object.keys(buildData.data.outputs).map((key) => { - const outputs = buildData.data.outputs[key]; - if (Array.isArray(outputs)) { - return outputs - .filter((log) => isErrorLogType(log.message)) - .map((log) => log.message.errorMessage); - } - if (!isErrorLogType(outputs.message)) { - return []; - } - return [outputs.message.errorMessage]; - }); - onBuildError!( - "Error Building Component", - errorMessages, - verticesIds.map((id) => ({id})), - ); - stopBuild(); - onBuildUpdate(buildData, BuildStatus.ERROR); - } else { - onBuildUpdate(buildData, BuildStatus.BUILT); - } - } - buildResults.push(buildData.valid); - } catch (error) { - console.error(error); + try { + const buildRes = await postBuildVertex(flowId, id, input_value, files); + + const buildData: VertexBuildTypeAPI = buildRes.data; + if (onBuildUpdate) { + if (!buildData.valid) { + // lots is a dictionary with the key the output field name and the value the log object + // logs: { [key: string]: { message: any; type: string }[] }; + const errorMessages = Object.keys(buildData.data.outputs).map((key) => { + const outputs = buildData.data.outputs[key]; + if (Array.isArray(outputs)) { + return outputs + .filter((log) => isErrorLogType(log.message)) + .map((log) => log.message.errorMessage); + } + if (!isErrorLogType(outputs.message)) { + return []; + } + return [outputs.message.errorMessage]; + }); onBuildError!( - "Error Building Component", - [ - (error as AxiosError).response?.data?.detail ?? - "An unexpected error occurred while building the Component. Please try again.", - ], - verticesIds.map((id) => ({id})), + "Error Building Component", + errorMessages, + verticesIds.map((id) => ({ id })), ); - buildResults.push(false); stopBuild(); + onBuildUpdate(buildData, BuildStatus.ERROR); + } else { + onBuildUpdate(buildData, BuildStatus.BUILT); + } } + buildResults.push(buildData.valid); + } catch (error) { + console.error(error); + onBuildError!( + "Error Building Component", + [ + (error as AxiosError).response?.data?.detail ?? + "An unexpected error occurred while building the Component. Please try again.", + ], + verticesIds.map((id) => ({ id })), + ); + buildResults.push(false); + stopBuild(); + } }