diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index ac12eee3f..904a94b79 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -275,7 +275,8 @@ export default function GenericNode({ name="Play" className="absolute ml-0.5 h-5 fill-current stroke-2 text-status-green opacity-30 transition-all group-hover:opacity-0" /> - ) : validationStatus && !validationStatus.valid ? ( + ) : buildStatus === BuildStatus.ERROR || + (validationStatus && !validationStatus.valid) ? ( state.buildFlow); const nodes = useFlowStore((state) => state.nodes); const edges = useFlowStore((state) => state.edges); + const updateBuildStatus = useFlowStore((state) => state.updateBuildStatus); const setErrorData = useAlertStore((state) => state.setErrorData); const eventClick = isBuilding ? "pointer-events-none" : ""; @@ -32,12 +34,15 @@ export default function BuildTrigger({ if (isBuilding) { return; } - const errors = validateNodes(nodes, edges); + const errorsObjs = validateNodes(nodes, edges); + const errors = errorsObjs.flatMap((errorObj) => errorObj.errors); if (errors.length > 0) { setErrorData({ title: MISSED_ERROR_ALERT, list: errors, }); + const ids = errorsObjs.map((errorObj) => errorObj.id); + updateBuildStatus(ids, BuildStatus.ERROR); return; } const minimumLoadingTime = 200; // in milliseconds diff --git a/src/frontend/src/modals/formModal/index.tsx b/src/frontend/src/modals/formModal/index.tsx index 9d9b343c1..0348280fe 100644 --- a/src/frontend/src/modals/formModal/index.tsx +++ b/src/frontend/src/modals/formModal/index.tsx @@ -31,6 +31,7 @@ import { CHAT_SECOND_INITIAL_TEXT, LANGFLOW_CHAT_TITLE, } from "../../constants/constants"; +import { BuildStatus } from "../../constants/enums"; import { AuthContext } from "../../contexts/authContext"; import { getBuildStatus } from "../../controllers/API"; import useAlertStore from "../../stores/alertStore"; @@ -49,6 +50,7 @@ export default function FormModal({ }): JSX.Element { const nodes = useFlowStore((state) => state.nodes); const edges = useFlowStore((state) => state.edges); + const updateBuildStatus = useFlowStore((state) => state.updateBuildStatus); const flowState = useFlowStore((state) => state.flowState); const setFlowState = useFlowStore((state) => state.setFlowState); const [chatValue, setChatValue] = useState(() => { @@ -388,7 +390,8 @@ export default function FormModal({ function sendMessage(): void { let nodeValidationErrors = validateNodes(nodes, edges); - if (nodeValidationErrors.length === 0) { + const errors = nodeValidationErrors.flatMap((error) => error.errors); + if (errors.length === 0) { setLockChat(true); let inputs = flowState?.input_keys; setChatValue(""); @@ -412,8 +415,10 @@ export default function FormModal({ } else { setErrorData({ title: INFO_MISSING_ALERT, - list: nodeValidationErrors, + list: errors, }); + const ids = nodeValidationErrors.map((error) => error.id); + updateBuildStatus(ids, BuildStatus.ERROR); } } function clearChat(): void { diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index 4b991e829..a7cec5573 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -438,16 +438,20 @@ const useFlowStore = create((set, get) => ({ const setErrorData = useAlertStore.getState().setErrorData; const setNoticeData = useAlertStore.getState().setNoticeData; function validateSubgraph(nodes: string[]) { - const errors = validateNodes( + const errorsObjs = validateNodes( get().nodes.filter((node) => nodes.includes(node.id)), get().edges ); + const errors = errorsObjs.map((obj) => obj.errors).flat(); if (errors.length > 0) { setErrorData({ title: MISSED_ERROR_ALERT, list: errors, }); get().setIsBuilding(false); + const ids = errorsObjs.map((obj) => obj.id).flat(); + console.log("ids", ids); + get().updateBuildStatus(ids, BuildStatus.ERROR); throw new Error("Invalid nodes"); } } @@ -538,7 +542,7 @@ const useFlowStore = create((set, get) => ({ .filter(Boolean) as string[]; useFlowStore.getState().updateBuildStatus(idList, BuildStatus.BUILDING); }, - validateNodes: validateSubgraph, + onValidateNodes: validateSubgraph, }); get().setIsBuilding(false); get().revertBuiltStatusFromBuilding(); diff --git a/src/frontend/src/utils/buildUtils.ts b/src/frontend/src/utils/buildUtils.ts index e702ec64b..1121fca04 100644 --- a/src/frontend/src/utils/buildUtils.ts +++ b/src/frontend/src/utils/buildUtils.ts @@ -20,7 +20,7 @@ type BuildVerticesParams = { onBuildComplete?: (allNodesValid: boolean) => void; onBuildError?: (title, list, idList: VertexLayerElementType[]) => void; onBuildStart?: (idList: VertexLayerElementType[]) => void; - validateNodes?: (nodes: string[]) => void; + onValidateNodes?: (nodes: string[]) => void; }; function getInactiveVertexData(vertexId: string): VertexBuildTypeAPI { @@ -114,7 +114,7 @@ export async function buildVertices({ onBuildComplete, onBuildError, onBuildStart, - validateNodes, + onValidateNodes, }: BuildVerticesParams) { let verticesBuild = useFlowStore.getState().verticesBuild; // if startNodeId and stopNodeId are provided @@ -133,10 +133,10 @@ export async function buildVertices({ if (onGetOrderSuccess) onGetOrderSuccess(); - if (validateNodes) { + if (onValidateNodes) { try { const nodes = useFlowStore.getState().nodes; - validateNodes(nodes.map((node) => node.id)); + onValidateNodes(nodes.map((node) => node.id)); } catch (e) { return; } diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index ba2ddb81b..0c74979a5 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -330,13 +330,23 @@ export function validateNode(node: NodeType, edges: Edge[]): Array { }, [] as string[]); } -export function validateNodes(nodes: Node[], edges: Edge[]) { +export function validateNodes( + nodes: Node[], + edges: Edge[] +): // this returns an array of tuples with the node id and the errors +Array<{ id: string; errors: Array }> { if (nodes.length === 0) { return [ - "No nodes found in the flow. Please add at least one node to the flow.", + { + id: "", + errors: [ + "No nodes found in the flow. Please add at least one node to the flow.", + ], + }, ]; } - return nodes.flatMap((n: NodeType) => validateNode(n, edges)); + // validateNode(n, edges) returns an array of errors for the node + return nodes.map((n) => ({ id: n.id, errors: validateNode(n, edges) })); } export function updateEdges(edges: Edge[]) {