diff --git a/stores/workflow/middleware.ts b/stores/workflow/middleware.ts index 3cc1839d24..71939bb828 100644 --- a/stores/workflow/middleware.ts +++ b/stores/workflow/middleware.ts @@ -17,6 +17,7 @@ export const withHistory = ( state: { blocks: initialState.blocks, edges: initialState.edges, + loops: initialState.loops, }, timestamp: Date.now(), action: 'Initial state', @@ -73,10 +74,11 @@ export const withHistory = ( const newState = { blocks: {}, edges: [], + loops: {}, history: { past: [], present: { - state: { blocks: {}, edges: [] }, + state: { blocks: {}, edges: [], loops: {} }, timestamp: Date.now(), action: 'Clear workflow', }, @@ -115,6 +117,7 @@ export const createHistoryEntry = (state: WorkflowState, action: string): Histor state: { blocks: { ...state.blocks }, edges: [...state.edges], + loops: { ...state.loops }, }, timestamp: Date.now(), action, diff --git a/stores/workflow/registry.ts b/stores/workflow/registry.ts index 6ecd3c829e..4024ce5b65 100644 --- a/stores/workflow/registry.ts +++ b/stores/workflow/registry.ts @@ -27,7 +27,8 @@ export const useWorkflowRegistry = create()( JSON.stringify({ blocks: currentState.blocks, edges: currentState.edges, - history: currentState.history, // Save history state + loops: currentState.loops, + history: currentState.history, }) ) } @@ -35,14 +36,15 @@ export const useWorkflowRegistry = create()( // Load new workflow state const savedState = localStorage.getItem(`workflow-${id}`) if (savedState) { - const { blocks, edges, history } = JSON.parse(savedState) + const { blocks, edges, history, loops } = JSON.parse(savedState) useWorkflowStore.setState({ blocks, edges, + loops: loops || {}, history: history || { past: [], present: { - state: { blocks, edges }, + state: { blocks, edges, loops: {} }, timestamp: Date.now(), action: 'Initial state', }, @@ -53,10 +55,11 @@ export const useWorkflowRegistry = create()( useWorkflowStore.setState({ blocks: {}, edges: [], + loops: {}, history: { past: [], present: { - state: { blocks: {}, edges: [] }, + state: { blocks: {}, edges: [], loops: {} }, timestamp: Date.now(), action: 'Initial state', }, @@ -123,10 +126,11 @@ export const useWorkflowRegistry = create()( useWorkflowStore.setState({ blocks: {}, edges: [], + loops: {}, history: { past: [], present: { - state: { blocks: {}, edges: [] }, + state: { blocks: {}, edges: [], loops: {} }, timestamp: Date.now(), action: 'Initial state', }, @@ -201,7 +205,6 @@ const initializeRegistry = () => { // Add event listeners for page unload window.addEventListener('beforeunload', () => { - // Save current workflow state const currentId = useWorkflowRegistry.getState().activeWorkflowId if (currentId) { const currentState = useWorkflowStore.getState() @@ -210,6 +213,7 @@ const initializeRegistry = () => { JSON.stringify({ blocks: currentState.blocks, edges: currentState.edges, + loops: currentState.loops, history: currentState.history, }) ) diff --git a/stores/workflow/store.ts b/stores/workflow/store.ts index 14dfc171de..48b681386f 100644 --- a/stores/workflow/store.ts +++ b/stores/workflow/store.ts @@ -4,17 +4,18 @@ import { devtools } from 'zustand/middleware' import { getBlock } from '@/blocks' import { resolveOutputType } from '@/blocks/utils' import { WorkflowStoreWithHistory, pushHistory, withHistory } from './middleware' -import { Position, SubBlockState } from './types' +import { Position, SubBlockState, Loop } from './types' import { detectCycle } from './utils' const initialState = { blocks: {}, edges: [], + loops: {}, lastSaved: undefined, history: { past: [], present: { - state: { blocks: {}, edges: [] }, + state: { blocks: {}, edges: [], loops: {} }, timestamp: Date.now(), action: 'Initial state', }, @@ -146,6 +147,7 @@ export const useWorkflowStore = create()( }, }, edges: [...get().edges], + loops: { ...get().loops }, } set(newState) @@ -171,6 +173,7 @@ export const useWorkflowStore = create()( const newState = { blocks: { ...get().blocks }, edges: [...get().edges].filter((edge) => edge.source !== id && edge.target !== id), + loops: { ...get().loops }, } delete newState.blocks[id] @@ -180,7 +183,6 @@ export const useWorkflowStore = create()( }, addEdge: (edge: Edge) => { - // First create the new edge const newEdge = { id: edge.id || crypto.randomUUID(), source: edge.source, @@ -189,19 +191,24 @@ export const useWorkflowStore = create()( targetHandle: edge.targetHandle, } - // Create temporary edges array with the new edge const newEdges = [...get().edges, newEdge] - - // Check for cycles starting from the source node const { hasCycle, path } = detectCycle(newEdges, edge.source) + // Create new loops state + const newLoops = { ...get().loops } + if (hasCycle) { - console.log('Loop detected through nodes:', path.join(' → ')) + const loopId = crypto.randomUUID() + newLoops[loopId] = { + id: loopId, + nodes: path + } } const newState = { blocks: { ...get().blocks }, edges: newEdges, + loops: newLoops, } set(newState) @@ -210,9 +217,31 @@ export const useWorkflowStore = create()( }, removeEdge: (edgeId: string) => { + const newEdges = get().edges.filter((edge) => edge.id !== edgeId) + + // Recalculate loops after edge removal + const newLoops: Record = {} + const processedNodes = new Set() + + // Check for cycles from each source node + newEdges.forEach(edge => { + if (!processedNodes.has(edge.source)) { + const { hasCycle, path } = detectCycle(newEdges, edge.source) + if (hasCycle) { + const loopId = crypto.randomUUID() + newLoops[loopId] = { + id: loopId, + nodes: path + } + } + processedNodes.add(edge.source) + } + }) + const newState = { blocks: { ...get().blocks }, - edges: get().edges.filter((edge) => edge.id !== edgeId), + edges: newEdges, + loops: newLoops, } set(newState) @@ -224,10 +253,11 @@ export const useWorkflowStore = create()( const newState = { blocks: {}, edges: [], + loops: {}, history: { past: [], present: { - state: { blocks: {}, edges: [] }, + state: { blocks: {}, edges: [], loops: {} }, timestamp: Date.now(), action: 'Initial state', }, @@ -297,6 +327,7 @@ export const useWorkflowStore = create()( }, }, edges: [...get().edges], + loops: { ...get().loops }, } set(newState) @@ -330,6 +361,7 @@ export const useWorkflowStore = create()( }, }, edges: [...get().edges], + loops: { ...get().loops }, } set(newState) @@ -347,6 +379,7 @@ export const useWorkflowStore = create()( }, }, edges: [...state.edges], + loops: { ...get().loops }, })) }, })), diff --git a/stores/workflow/types.ts b/stores/workflow/types.ts index 3c37c2ca30..858edc731f 100644 --- a/stores/workflow/types.ts +++ b/stores/workflow/types.ts @@ -24,10 +24,16 @@ export interface SubBlockState { value: string | number | string[][] | null } +export interface Loop { + id: string + nodes: string[] +} + export interface WorkflowState { blocks: Record edges: Edge[] lastSaved?: number + loops: Record } export interface WorkflowActions {