mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-24 22:38:00 -05:00
Compare commits
2 Commits
fix/edge-v
...
fix/blog-0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8f6747f1a | ||
|
|
5cda60c246 |
@@ -1260,6 +1260,7 @@ async function handleRun(
|
||||
const instance = getClientTool(toolCall.id)
|
||||
|
||||
if (!instance && isIntegrationTool(toolCall.name)) {
|
||||
setToolCallState(toolCall, 'executing')
|
||||
onStateChange?.('executing')
|
||||
try {
|
||||
await useCopilotStore.getState().executeIntegrationTool(toolCall.id)
|
||||
|
||||
@@ -496,7 +496,7 @@ export function DeployModal({
|
||||
</div>
|
||||
)}
|
||||
{apiDeployWarnings.length > 0 && (
|
||||
<div className='mb-3 rounded-[4px] border border-amber-500/30 bg-amber-500/10 p-3 text-amber-700 text-sm dark:text-amber-400'>
|
||||
<div className='mb-3 rounded-[4px] border border-amber-500/30 bg-amber-500/10 p-3 text-amber-700 dark:text-amber-400 text-sm'>
|
||||
<div className='font-semibold'>Deployment Warning</div>
|
||||
{apiDeployWarnings.map((warning, index) => (
|
||||
<div key={index}>{warning}</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ import { useUndoRedoStore } from '@/stores/undo-redo'
|
||||
import { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
|
||||
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import { filterNewEdges, filterValidEdges, mergeSubblockState } from '@/stores/workflows/utils'
|
||||
import { filterNewEdges, mergeSubblockState } from '@/stores/workflows/utils'
|
||||
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
|
||||
import type { BlockState, Loop, Parallel, Position } from '@/stores/workflows/workflow/types'
|
||||
|
||||
@@ -226,12 +226,9 @@ export function useCollaborativeWorkflow() {
|
||||
case EDGES_OPERATIONS.BATCH_ADD_EDGES: {
|
||||
const { edges } = payload
|
||||
if (Array.isArray(edges) && edges.length > 0) {
|
||||
const blocks = useWorkflowStore.getState().blocks
|
||||
const currentEdges = useWorkflowStore.getState().edges
|
||||
const validEdges = filterValidEdges(edges, blocks)
|
||||
const newEdges = filterNewEdges(validEdges, currentEdges)
|
||||
const newEdges = filterNewEdges(edges, useWorkflowStore.getState().edges)
|
||||
if (newEdges.length > 0) {
|
||||
useWorkflowStore.getState().batchAddEdges(newEdges, { skipValidation: true })
|
||||
useWorkflowStore.getState().batchAddEdges(newEdges)
|
||||
}
|
||||
}
|
||||
break
|
||||
@@ -1007,11 +1004,7 @@ export function useCollaborativeWorkflow() {
|
||||
|
||||
if (edges.length === 0) return false
|
||||
|
||||
// Filter out invalid edges (e.g., edges targeting trigger blocks) and duplicates
|
||||
const blocks = useWorkflowStore.getState().blocks
|
||||
const currentEdges = useWorkflowStore.getState().edges
|
||||
const validEdges = filterValidEdges(edges, blocks)
|
||||
const newEdges = filterNewEdges(validEdges, currentEdges)
|
||||
const newEdges = filterNewEdges(edges, useWorkflowStore.getState().edges)
|
||||
if (newEdges.length === 0) return false
|
||||
|
||||
const operationId = crypto.randomUUID()
|
||||
@@ -1027,7 +1020,7 @@ export function useCollaborativeWorkflow() {
|
||||
userId: session?.user?.id || 'unknown',
|
||||
})
|
||||
|
||||
useWorkflowStore.getState().batchAddEdges(newEdges, { skipValidation: true })
|
||||
useWorkflowStore.getState().batchAddEdges(newEdges)
|
||||
|
||||
if (!options?.skipUndoRedo) {
|
||||
newEdges.forEach((edge) => undoRedo.recordAddEdge(edge.id))
|
||||
@@ -1491,23 +1484,9 @@ export function useCollaborativeWorkflow() {
|
||||
|
||||
if (blocks.length === 0) return false
|
||||
|
||||
// Filter out invalid edges (e.g., edges targeting trigger blocks)
|
||||
// Combine existing blocks with new blocks for validation
|
||||
const existingBlocks = useWorkflowStore.getState().blocks
|
||||
const newBlocksMap = blocks.reduce(
|
||||
(acc, block) => {
|
||||
acc[block.id] = block
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, BlockState>
|
||||
)
|
||||
const allBlocks = { ...existingBlocks, ...newBlocksMap }
|
||||
const validEdges = filterValidEdges(edges, allBlocks)
|
||||
|
||||
logger.info('Batch adding blocks collaboratively', {
|
||||
blockCount: blocks.length,
|
||||
edgeCount: validEdges.length,
|
||||
filteredEdges: edges.length - validEdges.length,
|
||||
edgeCount: edges.length,
|
||||
})
|
||||
|
||||
const operationId = crypto.randomUUID()
|
||||
@@ -1517,18 +1496,16 @@ export function useCollaborativeWorkflow() {
|
||||
operation: {
|
||||
operation: BLOCKS_OPERATIONS.BATCH_ADD_BLOCKS,
|
||||
target: OPERATION_TARGETS.BLOCKS,
|
||||
payload: { blocks, edges: validEdges, loops, parallels, subBlockValues },
|
||||
payload: { blocks, edges, loops, parallels, subBlockValues },
|
||||
},
|
||||
workflowId: activeWorkflowId || '',
|
||||
userId: session?.user?.id || 'unknown',
|
||||
})
|
||||
|
||||
useWorkflowStore.getState().batchAddBlocks(blocks, validEdges, subBlockValues, {
|
||||
skipEdgeValidation: true,
|
||||
})
|
||||
useWorkflowStore.getState().batchAddBlocks(blocks, edges, subBlockValues)
|
||||
|
||||
if (!options?.skipUndoRedo) {
|
||||
undoRedo.recordBatchAddBlocks(blocks, validEdges, subBlockValues)
|
||||
undoRedo.recordBatchAddBlocks(blocks, edges, subBlockValues)
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
@@ -2,9 +2,8 @@ import type { Edge } from 'reactflow'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { getBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
|
||||
import { mergeSubBlockValues, mergeSubblockStateWithValues } from '@/lib/workflows/subblocks'
|
||||
import { TriggerUtils } from '@/lib/workflows/triggers/triggers'
|
||||
import { getBlock } from '@/blocks'
|
||||
import { isAnnotationOnlyBlock, normalizeName } from '@/executor/constants'
|
||||
import { normalizeName } from '@/executor/constants'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import type {
|
||||
BlockState,
|
||||
@@ -18,32 +17,6 @@ import { TRIGGER_RUNTIME_SUBBLOCK_IDS } from '@/triggers/constants'
|
||||
|
||||
const WEBHOOK_SUBBLOCK_FIELDS = ['webhookId', 'triggerPath']
|
||||
|
||||
/**
|
||||
* Checks if an edge is valid (source and target exist, not annotation-only, target is not a trigger)
|
||||
*/
|
||||
function isValidEdge(
|
||||
edge: Edge,
|
||||
blocks: Record<string, { type: string; triggerMode?: boolean }>
|
||||
): boolean {
|
||||
const sourceBlock = blocks[edge.source]
|
||||
const targetBlock = blocks[edge.target]
|
||||
if (!sourceBlock || !targetBlock) return false
|
||||
if (isAnnotationOnlyBlock(sourceBlock.type)) return false
|
||||
if (isAnnotationOnlyBlock(targetBlock.type)) return false
|
||||
if (TriggerUtils.isTriggerBlock(targetBlock)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters edges to only include valid ones (target exists and is not a trigger block)
|
||||
*/
|
||||
export function filterValidEdges(
|
||||
edges: Edge[],
|
||||
blocks: Record<string, { type: string; triggerMode?: boolean }>
|
||||
): Edge[] {
|
||||
return edges.filter((edge) => isValidEdge(edge, blocks))
|
||||
}
|
||||
|
||||
export function filterNewEdges(edgesToAdd: Edge[], currentEdges: Edge[]): Edge[] {
|
||||
return edgesToAdd.filter((edge) => {
|
||||
if (edge.source === edge.target) return false
|
||||
|
||||
@@ -4,17 +4,13 @@ import { create } from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
import { DEFAULT_DUPLICATE_OFFSET } from '@/lib/workflows/autolayout/constants'
|
||||
import { getBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
|
||||
import { TriggerUtils } from '@/lib/workflows/triggers/triggers'
|
||||
import { getBlock } from '@/blocks'
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import { normalizeName, RESERVED_BLOCK_NAMES } from '@/executor/constants'
|
||||
import { isAnnotationOnlyBlock, normalizeName, RESERVED_BLOCK_NAMES } from '@/executor/constants'
|
||||
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import {
|
||||
filterNewEdges,
|
||||
filterValidEdges,
|
||||
getUniqueBlockName,
|
||||
mergeSubblockState,
|
||||
} from '@/stores/workflows/utils'
|
||||
import { filterNewEdges, getUniqueBlockName, mergeSubblockState } from '@/stores/workflows/utils'
|
||||
import type {
|
||||
Position,
|
||||
SubBlockState,
|
||||
@@ -95,6 +91,26 @@ function resolveInitialSubblockValue(config: SubBlockConfig): unknown {
|
||||
return null
|
||||
}
|
||||
|
||||
function isValidEdge(
|
||||
edge: Edge,
|
||||
blocks: Record<string, { type: string; triggerMode?: boolean }>
|
||||
): boolean {
|
||||
const sourceBlock = blocks[edge.source]
|
||||
const targetBlock = blocks[edge.target]
|
||||
if (!sourceBlock || !targetBlock) return false
|
||||
if (isAnnotationOnlyBlock(sourceBlock.type)) return false
|
||||
if (isAnnotationOnlyBlock(targetBlock.type)) return false
|
||||
if (TriggerUtils.isTriggerBlock(targetBlock)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
function filterValidEdges(
|
||||
edges: Edge[],
|
||||
blocks: Record<string, { type: string; triggerMode?: boolean }>
|
||||
): Edge[] {
|
||||
return edges.filter((edge) => isValidEdge(edge, blocks))
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
blocks: {},
|
||||
edges: [],
|
||||
@@ -340,8 +356,7 @@ export const useWorkflowStore = create<WorkflowStore>()(
|
||||
data?: Record<string, any>
|
||||
}>,
|
||||
edges?: Edge[],
|
||||
subBlockValues?: Record<string, Record<string, unknown>>,
|
||||
options?: { skipEdgeValidation?: boolean }
|
||||
subBlockValues?: Record<string, Record<string, unknown>>
|
||||
) => {
|
||||
const currentBlocks = get().blocks
|
||||
const currentEdges = get().edges
|
||||
@@ -366,10 +381,7 @@ export const useWorkflowStore = create<WorkflowStore>()(
|
||||
}
|
||||
|
||||
if (edges && edges.length > 0) {
|
||||
// Skip validation if already validated by caller (e.g., collaborative layer)
|
||||
const validEdges = options?.skipEdgeValidation
|
||||
? edges
|
||||
: filterValidEdges(edges, newBlocks)
|
||||
const validEdges = filterValidEdges(edges, newBlocks)
|
||||
const existingEdgeIds = new Set(currentEdges.map((e) => e.id))
|
||||
for (const edge of validEdges) {
|
||||
if (!existingEdgeIds.has(edge.id)) {
|
||||
@@ -504,12 +516,11 @@ export const useWorkflowStore = create<WorkflowStore>()(
|
||||
get().updateLastSaved()
|
||||
},
|
||||
|
||||
batchAddEdges: (edges: Edge[], options?: { skipValidation?: boolean }) => {
|
||||
batchAddEdges: (edges: Edge[]) => {
|
||||
const blocks = get().blocks
|
||||
const currentEdges = get().edges
|
||||
|
||||
// Skip validation if already validated by caller (e.g., collaborative layer)
|
||||
const validEdges = options?.skipValidation ? edges : filterValidEdges(edges, blocks)
|
||||
const validEdges = filterValidEdges(edges, blocks)
|
||||
const filtered = filterNewEdges(validEdges, currentEdges)
|
||||
const newEdges = [...currentEdges]
|
||||
|
||||
|
||||
@@ -203,13 +203,12 @@ export interface WorkflowActions {
|
||||
batchAddBlocks: (
|
||||
blocks: BlockState[],
|
||||
edges?: Edge[],
|
||||
subBlockValues?: Record<string, Record<string, unknown>>,
|
||||
options?: { skipEdgeValidation?: boolean }
|
||||
subBlockValues?: Record<string, Record<string, unknown>>
|
||||
) => void
|
||||
batchRemoveBlocks: (ids: string[]) => void
|
||||
batchToggleEnabled: (ids: string[]) => void
|
||||
batchToggleHandles: (ids: string[]) => void
|
||||
batchAddEdges: (edges: Edge[], options?: { skipValidation?: boolean }) => void
|
||||
batchAddEdges: (edges: Edge[]) => void
|
||||
batchRemoveEdges: (ids: string[]) => void
|
||||
clear: () => Partial<WorkflowState>
|
||||
updateLastSaved: () => void
|
||||
|
||||
Reference in New Issue
Block a user