diff --git a/web/app/components/workflow-app/components/workflow-main.tsx b/web/app/components/workflow-app/components/workflow-main.tsx index 067e9ccf93..1abd4704a4 100644 --- a/web/app/components/workflow-app/components/workflow-main.tsx +++ b/web/app/components/workflow-app/components/workflow-main.tsx @@ -23,6 +23,7 @@ import { useWorkflowRun, useWorkflowStartRun, } from '../hooks' +import { useWorkflowUpdate } from '@/app/components/workflow/hooks/use-workflow-interactions' import { useStore, useWorkflowStore } from '@/app/components/workflow/store' import { useCollaboration } from '@/app/components/workflow/collaboration' import { collaborationManager } from '@/app/components/workflow/collaboration' @@ -115,6 +116,7 @@ const WorkflowMain = ({ syncWorkflowDraftWhenPageClose, } = useNodesSyncDraft() const { handleRefreshWorkflowDraft } = useWorkflowRefreshDraft() + const { handleUpdateWorkflowCanvas } = useWorkflowUpdate() const { handleBackupDraft, handleLoadBackupDraft, @@ -139,6 +141,35 @@ const WorkflowMain = ({ return unsubscribe }, [appId, handleWorkflowDataUpdate]) + // Listen for workflow updates from other users + useEffect(() => { + if (!appId) return + + const unsubscribe = collaborationManager.onWorkflowUpdate(async () => { + console.log('Received workflow update from collaborator, fetching latest workflow data') + try { + const response = await fetchWorkflowDraft(`/apps/${appId}/workflows/draft`) + + // Handle features, variables etc. + handleWorkflowDataUpdate(response) + + // Update workflow canvas (nodes, edges, viewport) + if (response.graph) { + handleUpdateWorkflowCanvas({ + nodes: response.graph.nodes || [], + edges: response.graph.edges || [], + viewport: response.graph.viewport || { x: 0, y: 0, zoom: 1 }, + }) + } + } + catch (error) { + console.error('Failed to fetch updated workflow:', error) + } + }) + + return unsubscribe + }, [appId, handleWorkflowDataUpdate, handleUpdateWorkflowCanvas]) + // Listen for sync requests from other users (only processed by leader) useEffect(() => { if (!appId) return diff --git a/web/app/components/workflow/collaboration/core/collaboration-manager.ts b/web/app/components/workflow/collaboration/core/collaboration-manager.ts index 7cdc0aaf17..54bc67f774 100644 --- a/web/app/components/workflow/collaboration/core/collaboration-manager.ts +++ b/web/app/components/workflow/collaboration/core/collaboration-manager.ts @@ -226,6 +226,20 @@ export class CollaborationManager { } } + emitWorkflowUpdate(appId: string): void { + if (!this.currentAppId || !webSocketClient.isConnected(this.currentAppId)) return + + const socket = webSocketClient.getSocket(this.currentAppId) + if (socket) { + console.log('Emitting Workflow update event') + socket.emit('collaboration_event', { + type: 'workflowUpdate', + data: { appId, timestamp: Date.now() }, + timestamp: Date.now(), + }) + } + } + onSyncRequest(callback: () => void): () => void { return this.eventEmitter.on('syncRequest', callback) } @@ -242,6 +256,10 @@ export class CollaborationManager { return this.eventEmitter.on('onlineUsers', callback) } + onWorkflowUpdate(callback: (update: { appId: string; timestamp: number }) => void): () => void { + return this.eventEmitter.on('workflowUpdate', callback) + } + onVarsAndFeaturesUpdate(callback: (update: any) => void): () => void { return this.eventEmitter.on('varsAndFeaturesUpdate', callback) } @@ -591,6 +609,10 @@ export class CollaborationManager { console.log('Processing mcpServerUpdate event:', update) this.eventEmitter.emit('mcpServerUpdate', update) } + else if (update.type === 'workflowUpdate') { + console.log('Processing workflowUpdate event:', update) + this.eventEmitter.emit('workflowUpdate', update.data) + } else if (update.type === 'syncRequest') { console.log('Received sync request from another user') // Only process if we are the leader diff --git a/web/app/components/workflow/update-dsl-modal.tsx b/web/app/components/workflow/update-dsl-modal.tsx index 00c36cce90..bc52049ae8 100644 --- a/web/app/components/workflow/update-dsl-modal.tsx +++ b/web/app/components/workflow/update-dsl-modal.tsx @@ -39,6 +39,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter' import { useStore as useAppStore } from '@/app/components/app/store' import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants' import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks' +import { collaborationManager } from './collaboration/core/collaboration-manager' type UpdateDSLModalProps = { onCancel: () => void @@ -201,6 +202,8 @@ const UpdateDSLModal = ({ return } handleWorkflowUpdate(app_id) + // Notify other collaboration clients about the workflow update + collaborationManager.emitWorkflowUpdate(app_id) await handleCheckPluginDependencies(app_id) if (onImport) onImport()