diff --git a/skyvern-frontend/src/routes/workflows/editor/FlowRenderer.tsx b/skyvern-frontend/src/routes/workflows/editor/FlowRenderer.tsx index bdde8f1c..63430970 100644 --- a/skyvern-frontend/src/routes/workflows/editor/FlowRenderer.tsx +++ b/skyvern-frontend/src/routes/workflows/editor/FlowRenderer.tsx @@ -63,6 +63,7 @@ import { import { Button } from "@/components/ui/button"; import { ReloadIcon } from "@radix-ui/react-icons"; import { isLoopNode, LoopNode } from "./nodes/LoopNode/types"; +import { isTaskNode } from "./nodes/TaskNode/types"; function convertToParametersYAML( parameters: ParametersState, @@ -433,6 +434,40 @@ function FlowRenderer({ doLayout(newNodesWithUpdatedParameters, newEdges); } + function getWorkflowErrors(): Array { + const errors: Array = []; + + // check loop node parameters + const loopNodes: Array = nodes.filter(isLoopNode); + const emptyLoopNodes = loopNodes.filter( + (node: LoopNode) => node.data.loopValue === "", + ); + if (emptyLoopNodes.length > 0) { + emptyLoopNodes.forEach((node) => { + errors.push( + `${node.data.label}: Loop value parameter must be selected`, + ); + }); + } + + // check task node json fields + const taskNodes = nodes.filter(isTaskNode); + taskNodes.forEach((node) => { + try { + JSON.parse(node.data.dataSchema); + } catch { + errors.push(`${node.data.label}: Data schema is not valid JSON`); + } + try { + JSON.parse(node.data.errorCodeMapping); + } catch { + errors.push(`${node.data.label}: Error messages is not valid JSON`); + } + }); + + return errors; + } + return ( <> { + const errors = getWorkflowErrors(); + if (errors.length > 0) { + toast({ + title: "Can not save workflow because of errors:", + description: ( +
+ {errors.map((error) => ( +

{error}

+ ))} +
+ ), + variant: "destructive", + }); + return; + } // TODO might need to abstract this out or find different way to handle errors const loopNodes: Array = nodes.filter(isLoopNode); const emptyLoopNodes = loopNodes.filter( diff --git a/skyvern-frontend/src/routes/workflows/editor/nodes/TaskNode/types.ts b/skyvern-frontend/src/routes/workflows/editor/nodes/TaskNode/types.ts index 9b31ec2e..f3560f06 100644 --- a/skyvern-frontend/src/routes/workflows/editor/nodes/TaskNode/types.ts +++ b/skyvern-frontend/src/routes/workflows/editor/nodes/TaskNode/types.ts @@ -37,3 +37,7 @@ export const taskNodeDefaultData: TaskNodeData = { totpVerificationUrl: null, totpIdentifier: null, } as const; + +export function isTaskNode(node: Node): node is TaskNode { + return node.type === "task"; +}