Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 1 addition & 30 deletions apps/sim/app/api/workflows/[id]/yaml/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
loadWorkflowFromNormalizedTables,
saveWorkflowToNormalizedTables,
} from '@/lib/workflows/db-helpers'
import { updateBlockReferences } from '@/lib/workflows/reference-utils'
import { sanitizeAgentToolsInBlocks } from '@/lib/workflows/validation'
import { getUserId } from '@/app/api/auth/oauth/utils'
import { getAllBlocks, getBlock } from '@/blocks'
Expand All @@ -31,36 +32,6 @@ const YamlWorkflowRequestSchema = z.object({
createCheckpoint: z.boolean().optional().default(false),
})

function updateBlockReferences(
value: any,
blockIdMapping: Map<string, string>,
requestId: string
): any {
if (typeof value === 'string') {
// Replace references in string values
for (const [oldId, newId] of blockIdMapping.entries()) {
if (value.includes(oldId)) {
value = value.replaceAll(`<${oldId}.`, `<${newId}.`).replaceAll(`%${oldId}.`, `%${newId}.`)
}
}
return value
}

if (Array.isArray(value)) {
return value.map((item) => updateBlockReferences(item, blockIdMapping, requestId))
}

if (value && typeof value === 'object') {
const result: Record<string, any> = {}
for (const [key, val] of Object.entries(value)) {
result[key] = updateBlockReferences(val, blockIdMapping, requestId)
}
return result
}

return value
}

/**
* Helper function to create a checkpoint before workflow changes
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import type React from 'react'
import { memo, useMemo, useRef } from 'react'
import { Trash2 } from 'lucide-react'
import { Copy, Trash2 } from 'lucide-react'
import { Handle, type NodeProps, Position, useReactFlow } from 'reactflow'
import { StartIcon } from '@/components/icons'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { createLogger } from '@/lib/logs/console/logger'
import { cn } from '@/lib/utils'
import { type DiffStatus, hasDiffStatus } from '@/lib/workflows/diff/types'
import { IterationBadges } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/components/iteration-badges/iteration-badges'
import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'

const logger = createLogger('SubflowNode')

const SubflowNodeStyles: React.FC = () => {
return (
<style jsx global>{`
Expand Down Expand Up @@ -74,7 +77,7 @@ export interface SubflowNodeData {

export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeData>) => {
const { getNodes } = useReactFlow()
const { collaborativeRemoveBlock } = useCollaborativeWorkflow()
const { collaborativeRemoveBlock, collaborativeDuplicateSubflow } = useCollaborativeWorkflow()
const blockRef = useRef<HTMLDivElement>(null)

const currentWorkflow = useCurrentWorkflow()
Expand Down Expand Up @@ -171,18 +174,37 @@ export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeDat
}}
>
{!isPreview && (
<Button
variant='ghost'
size='sm'
onClick={(e) => {
e.stopPropagation()
collaborativeRemoveBlock(id)
}}
className='absolute top-2 right-2 z-20 text-gray-500 opacity-0 transition-opacity duration-200 hover:text-red-600 group-hover:opacity-100'
<div
className='absolute top-2 right-2 z-20 flex gap-1 opacity-0 transition-opacity duration-200 group-hover:opacity-100'
style={{ pointerEvents: 'auto' }}
>
<Trash2 className='h-4 w-4' />
</Button>
<Button
variant='ghost'
size='sm'
onClick={(e) => {
e.stopPropagation()
try {
collaborativeDuplicateSubflow(id)
} catch (err) {
logger.error('Failed to duplicate subflow', { err })
}
}}
className='text-gray-500 hover:text-slate-900'
>
<Copy className='h-4 w-4' />
</Button>
<Button
variant='ghost'
size='sm'
onClick={(e) => {
e.stopPropagation()
collaborativeRemoveBlock(id)
}}
className='text-gray-500 hover:text-red-600'
>
<Trash2 className='h-4 w-4' />
</Button>
</div>
)}

{/* Subflow Start */}
Expand Down
Loading