diff --git a/apps/sim/lib/workflows/yaml-generator.ts b/apps/sim/lib/workflows/yaml-generator.ts index e51cd6b0ee..40182b8870 100644 --- a/apps/sim/lib/workflows/yaml-generator.ts +++ b/apps/sim/lib/workflows/yaml-generator.ts @@ -10,8 +10,18 @@ interface YamlBlock { type: string name: string inputs?: Record - preceding?: string[] - following?: string[] + connections?: { + incoming?: Array<{ + source: string + sourceHandle?: string + targetHandle?: string + }> + outgoing?: Array<{ + target: string + sourceHandle?: string + targetHandle?: string + }> + } parentId?: string // Add parentId for nested blocks } @@ -153,23 +163,37 @@ function extractBlockInputs( } /** - * Find preceding blocks for a given block ID + * Find incoming connections for a given block ID */ -function findPrecedingBlocks(blockId: string, edges: any[]): string[] { +function findIncomingConnections(blockId: string, edges: any[]): Array<{ + source: string + sourceHandle?: string + targetHandle?: string +}> { return edges .filter((edge) => edge.target === blockId) - .map((edge) => edge.source) - .filter((source, index, arr) => arr.indexOf(source) === index) // Remove duplicates + .map((edge) => ({ + source: edge.source, + sourceHandle: edge.sourceHandle, + targetHandle: edge.targetHandle, + })) } /** - * Find following blocks for a given block ID + * Find outgoing connections for a given block ID */ -function findFollowingBlocks(blockId: string, edges: any[]): string[] { +function findOutgoingConnections(blockId: string, edges: any[]): Array<{ + target: string + sourceHandle?: string + targetHandle?: string +}> { return edges .filter((edge) => edge.source === blockId) - .map((edge) => edge.target) - .filter((target, index, arr) => arr.indexOf(target) === index) // Remove duplicates + .map((edge) => ({ + target: edge.target, + sourceHandle: edge.sourceHandle, + targetHandle: edge.targetHandle, + })) } /** @@ -189,8 +213,8 @@ export function generateWorkflowYaml( // Process each block Object.entries(workflowState.blocks).forEach(([blockId, blockState]) => { const inputs = extractBlockInputs(blockState, blockId, subBlockValues) - const preceding = findPrecedingBlocks(blockId, workflowState.edges) - const following = findFollowingBlocks(blockId, workflowState.edges) + const incoming = findIncomingConnections(blockId, workflowState.edges) + const outgoing = findOutgoingConnections(blockId, workflowState.edges) const yamlBlock: YamlBlock = { type: blockState.type, @@ -203,12 +227,16 @@ export function generateWorkflowYaml( } // Only include connections if they exist - if (preceding.length > 0) { - yamlBlock.preceding = preceding - } - - if (following.length > 0) { - yamlBlock.following = following + if (incoming.length > 0 || outgoing.length > 0) { + yamlBlock.connections = {} + + if (incoming.length > 0) { + yamlBlock.connections.incoming = incoming + } + + if (outgoing.length > 0) { + yamlBlock.connections.outgoing = outgoing + } } // Include parent-child relationship for nested blocks diff --git a/apps/sim/stores/workflows/yaml/importer.ts b/apps/sim/stores/workflows/yaml/importer.ts index 18c5305864..0309ea5419 100644 --- a/apps/sim/stores/workflows/yaml/importer.ts +++ b/apps/sim/stores/workflows/yaml/importer.ts @@ -9,8 +9,18 @@ interface YamlBlock { type: string name: string inputs?: Record - preceding?: string[] - following?: string[] + connections?: { + incoming?: Array<{ + source: string + sourceHandle?: string + targetHandle?: string + }> + outgoing?: Array<{ + target: string + sourceHandle?: string + targetHandle?: string + }> + } parentId?: string // Add parentId for nested blocks } @@ -120,23 +130,28 @@ function validateBlockReferences(yamlWorkflow: YamlWorkflow): string[] { const blockIds = new Set(Object.keys(yamlWorkflow.blocks)) Object.entries(yamlWorkflow.blocks).forEach(([blockId, block]) => { - // Check preceding references - if (block.preceding) { - block.preceding.forEach((precedingId) => { - if (!blockIds.has(precedingId)) { - errors.push(`Block '${blockId}' references non-existent preceding block '${precedingId}'`) + // Check incoming connection references + if (block.connections?.incoming) { + block.connections.incoming.forEach((connection) => { + if (!blockIds.has(connection.source)) { + errors.push(`Block '${blockId}' references non-existent source block '${connection.source}'`) } }) } - // Check following references - if (block.following) { - block.following.forEach((followingId) => { - if (!blockIds.has(followingId)) { - errors.push(`Block '${blockId}' references non-existent following block '${followingId}'`) + // Check outgoing connection references + if (block.connections?.outgoing) { + block.connections.outgoing.forEach((connection) => { + if (!blockIds.has(connection.target)) { + errors.push(`Block '${blockId}' references non-existent target block '${connection.target}'`) } }) } + + // Check parent references + if (block.parentId && !blockIds.has(block.parentId)) { + errors.push(`Block '${blockId}' references non-existent parent block '${block.parentId}'`) + } }) return errors @@ -190,10 +205,10 @@ function calculateBlockPositions( const positions: Record = {} const blockIds = Object.keys(yamlWorkflow.blocks) - // Find starter blocks (no preceding connections) + // Find starter blocks (no incoming connections) const starterBlocks = blockIds.filter((id) => { const block = yamlWorkflow.blocks[id] - return !block.preceding || block.preceding.length === 0 + return !block.connections?.incoming || block.connections.incoming.length === 0 }) // If no starter blocks found, use first block as starter @@ -220,10 +235,10 @@ function calculateBlockPositions( // Add following blocks to queue const block = yamlWorkflow.blocks[blockId] - if (block.following) { - block.following.forEach((followingId) => { - if (!visited.has(followingId)) { - queue.push(followingId) + if (block.connections?.outgoing) { + block.connections.outgoing.forEach((connection) => { + if (!visited.has(connection.target)) { + queue.push(connection.target) } }) } @@ -375,16 +390,16 @@ export function convertYamlToWorkflow(yamlWorkflow: YamlWorkflow): ImportResult // Convert edges from connections Object.entries(yamlWorkflow.blocks).forEach(([blockId, yamlBlock]) => { - if (yamlBlock.following) { - yamlBlock.following.forEach((targetId) => { - const edgeId = `${blockId}-${targetId}-${Date.now()}` + if (yamlBlock.connections?.outgoing) { + yamlBlock.connections.outgoing.forEach((connection) => { + const edgeId = `${blockId}-${connection.target}-${Date.now()}` const edge: ImportedEdge = { id: edgeId, source: blockId, - target: targetId, - sourceHandle: 'source', - targetHandle: 'target', + target: connection.target, + sourceHandle: connection.sourceHandle || 'source', + targetHandle: connection.targetHandle || 'target', type: 'workflowEdge', }