'use client' import type { FC } from 'react' import { memo, useCallback, useEffect, useMemo, } from 'react' import { setAutoFreeze } from 'immer' import { useKeyPress, } from 'ahooks' import ReactFlow, { Background, ReactFlowProvider, useOnViewportChange, } from 'reactflow' import type { Viewport } from 'reactflow' import 'reactflow/dist/style.css' import './style.css' import type { Edge, Node, } from './types' import { WorkflowContextProvider } from './context' import { useEdgesInteractions, useNodesInteractions, useNodesReadOnly, useNodesSyncDraft, useWorkflow, useWorkflowInit, useWorkflowReadOnly, } from './hooks' import Header from './header' import CustomNode from './nodes' import Operator from './operator' import CustomEdge from './custom-edge' import CustomConnectionLine from './custom-connection-line' import Panel from './panel' import Features from './features' import HelpLine from './help-line' import { useStore } from './store' import { initialEdges, initialNodes, } from './utils' import Loading from '@/app/components/base/loading' import { FeaturesProvider } from '@/app/components/base/features' import type { Features as FeaturesData } from '@/app/components/base/features/types' const nodeTypes = { custom: CustomNode, } const edgeTypes = { custom: CustomEdge, } type WorkflowProps = { nodes: Node[] edges: Edge[] viewport?: Viewport } const Workflow: FC = memo(({ nodes, edges, viewport, }) => { const showFeaturesPanel = useStore(state => state.showFeaturesPanel) const nodeAnimation = useStore(s => s.nodeAnimation) const { handleSyncWorkflowDraft, syncWorkflowDraftWhenPageClose, } = useNodesSyncDraft() const { workflowReadOnly } = useWorkflowReadOnly() const { nodesReadOnly } = useNodesReadOnly() useEffect(() => { setAutoFreeze(false) return () => { setAutoFreeze(true) } }, []) useEffect(() => { return () => { handleSyncWorkflowDraft(true) } }, []) const handleSyncWorkflowDraftWhenPageClose = useCallback(() => { if (document.visibilityState === 'hidden') syncWorkflowDraftWhenPageClose() }, [syncWorkflowDraftWhenPageClose]) useEffect(() => { document.addEventListener('visibilitychange', handleSyncWorkflowDraftWhenPageClose) return () => { document.removeEventListener('visibilitychange', handleSyncWorkflowDraftWhenPageClose) } }, [handleSyncWorkflowDraftWhenPageClose]) const { handleNodeDragStart, handleNodeDrag, handleNodeDragStop, handleNodeEnter, handleNodeLeave, handleNodeClick, handleNodeConnect, handleNodeConnectStart, handleNodeConnectEnd, handleNodeDuplicateSelected, handleNodeCopySelected, handleNodeCut, handleNodeDeleteSelected, handleNodePaste, } = useNodesInteractions() const { handleEdgeEnter, handleEdgeLeave, handleEdgeDelete, handleEdgesChange, } = useEdgesInteractions() const { isValidConnection, enableShortcuts, disableShortcuts, } = useWorkflow() useOnViewportChange({ onEnd: () => { handleSyncWorkflowDraft() }, }) useKeyPress(['delete', 'backspace'], handleNodeDeleteSelected) useKeyPress(['delete', 'backspace'], handleEdgeDelete) useKeyPress(['ctrl.c', 'meta.c'], handleNodeCopySelected) useKeyPress(['ctrl.x', 'meta.x'], handleNodeCut) useKeyPress(['ctrl.v', 'meta.v'], handleNodePaste) useKeyPress(['ctrl.alt.d', 'meta.shift.d'], handleNodeDuplicateSelected) return (
{ showFeaturesPanel && }
) }) Workflow.displayName = 'Workflow' const WorkflowWrap = memo(() => { const { data, isLoading, } = useWorkflowInit() const nodesData = useMemo(() => { if (data) return initialNodes(data.graph.nodes, data.graph.edges) return [] }, [data]) const edgesData = useMemo(() => { if (data) return initialEdges(data.graph.edges, data.graph.nodes) return [] }, [data]) if (!data || isLoading) { return (
) } const features = data.features || {} const initialFeatures: FeaturesData = { file: { image: { enabled: !!features.file_upload?.image.enabled, number_limits: features.file_upload?.image.number_limits || 3, transfer_methods: features.file_upload?.image.transfer_methods || ['local_file', 'remote_url'], }, }, opening: { enabled: !!features.opening_statement, opening_statement: features.opening_statement, suggested_questions: features.suggested_questions, }, suggested: features.suggested_questions_after_answer || { enabled: false }, speech2text: features.speech_to_text || { enabled: false }, text2speech: features.text_to_speech || { enabled: false }, citation: features.retriever_resource || { enabled: false }, moderation: features.sensitive_word_avoidance || { enabled: false }, } return ( ) }) WorkflowWrap.displayName = 'WorkflowWrap' const WorkflowContainer = () => { return ( ) } export default memo(WorkflowContainer)