mirror of
https://github.com/langgenius/dify.git
synced 2026-04-29 04:26:30 +08:00
split hooks
This commit is contained in:
parent
64fa343d16
commit
a55a7603dd
@ -4,7 +4,7 @@ import {
|
|||||||
} from 'react'
|
} from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useStore } from './store'
|
import { useStore } from './store'
|
||||||
import { useWorkflow } from './hooks'
|
import { useNodesSyncDraft } from './hooks'
|
||||||
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
|
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
import {
|
import {
|
||||||
FeaturesChoose,
|
FeaturesChoose,
|
||||||
@ -14,7 +14,7 @@ import {
|
|||||||
const Features = () => {
|
const Features = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const setShowFeaturesPanel = useStore(state => state.setShowFeaturesPanel)
|
const setShowFeaturesPanel = useStore(state => state.setShowFeaturesPanel)
|
||||||
const { handleSyncWorkflowDraft } = useWorkflow()
|
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||||
|
|
||||||
const handleFeaturesChange = useCallback(() => {
|
const handleFeaturesChange = useCallback(() => {
|
||||||
handleSyncWorkflowDraft()
|
handleSyncWorkflowDraft()
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { useStore } from '../store'
|
import { useStore } from '../store'
|
||||||
import {
|
import {
|
||||||
useIsChatMode,
|
useIsChatMode,
|
||||||
useWorkflow,
|
useWorkflowRun,
|
||||||
} from '../hooks'
|
} from '../hooks'
|
||||||
import RunAndHistory from './run-and-history'
|
import RunAndHistory from './run-and-history'
|
||||||
import EditingTitle from './editing-title'
|
import EditingTitle from './editing-title'
|
||||||
@ -24,15 +24,15 @@ const Header: FC = () => {
|
|||||||
const appSidebarExpand = useAppStore(s => s.appSidebarExpand)
|
const appSidebarExpand = useAppStore(s => s.appSidebarExpand)
|
||||||
const isChatMode = useIsChatMode()
|
const isChatMode = useIsChatMode()
|
||||||
const runningStatus = useStore(s => s.runningStatus)
|
const runningStatus = useStore(s => s.runningStatus)
|
||||||
const { handleRunInit } = useWorkflow()
|
const { handleRunSetting } = useWorkflowRun()
|
||||||
|
|
||||||
const handleShowFeatures = useCallback(() => {
|
const handleShowFeatures = useCallback(() => {
|
||||||
useStore.setState({ showFeaturesPanel: true })
|
useStore.setState({ showFeaturesPanel: true })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleGoBackToEdit = useCallback(() => {
|
const handleGoBackToEdit = useCallback(() => {
|
||||||
handleRunInit(true)
|
handleRunSetting(true)
|
||||||
}, [handleRunInit])
|
}, [handleRunSetting])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { useStore } from '../store'
|
import { useStore } from '../store'
|
||||||
import {
|
import {
|
||||||
useIsChatMode,
|
useIsChatMode,
|
||||||
useWorkflow,
|
useWorkflowRun,
|
||||||
} from '../hooks'
|
} from '../hooks'
|
||||||
import { WorkflowRunningStatus } from '../types'
|
import { WorkflowRunningStatus } from '../types'
|
||||||
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||||
@ -54,11 +54,11 @@ RunMode.displayName = 'RunMode'
|
|||||||
|
|
||||||
const PreviewMode = memo(() => {
|
const PreviewMode = memo(() => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { handleRunInit } = useWorkflow()
|
const { handleRunSetting } = useWorkflowRun()
|
||||||
const runningStatus = useStore(s => s.runningStatus)
|
const runningStatus = useStore(s => s.runningStatus)
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
handleRunInit()
|
handleRunSetting()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
7
web/app/components/workflow/hooks/index.ts
Normal file
7
web/app/components/workflow/hooks/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export * from './use-edges-interactions'
|
||||||
|
export * from './use-node-data-update'
|
||||||
|
export * from './use-nodes-interactions'
|
||||||
|
export * from './use-nodes-data'
|
||||||
|
export * from './use-nodes-sync-draft'
|
||||||
|
export * from './use-workflow'
|
||||||
|
export * from './use-workflow-run'
|
||||||
118
web/app/components/workflow/hooks/use-edges-interactions.ts
Normal file
118
web/app/components/workflow/hooks/use-edges-interactions.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
import produce from 'immer'
|
||||||
|
import type {
|
||||||
|
EdgeMouseHandler,
|
||||||
|
OnEdgesChange,
|
||||||
|
} from 'reactflow'
|
||||||
|
import { useStoreApi } from 'reactflow'
|
||||||
|
import { useStore } from '../store'
|
||||||
|
import { useNodesSyncDraft } from './use-nodes-sync-draft'
|
||||||
|
|
||||||
|
export const useEdgesInteractions = () => {
|
||||||
|
const store = useStoreApi()
|
||||||
|
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||||
|
|
||||||
|
const handleEdgeEnter = useCallback<EdgeMouseHandler>((_, edge) => {
|
||||||
|
const { runningStatus } = useStore.getState()
|
||||||
|
|
||||||
|
if (runningStatus)
|
||||||
|
return
|
||||||
|
|
||||||
|
const {
|
||||||
|
edges,
|
||||||
|
setEdges,
|
||||||
|
} = store.getState()
|
||||||
|
const newEdges = produce(edges, (draft) => {
|
||||||
|
const currentEdge = draft.find(e => e.id === edge.id)!
|
||||||
|
|
||||||
|
currentEdge.data = { ...currentEdge.data, _hovering: true }
|
||||||
|
})
|
||||||
|
setEdges(newEdges)
|
||||||
|
}, [store])
|
||||||
|
|
||||||
|
const handleEdgeLeave = useCallback<EdgeMouseHandler>((_, edge) => {
|
||||||
|
const { runningStatus } = useStore.getState()
|
||||||
|
|
||||||
|
if (runningStatus)
|
||||||
|
return
|
||||||
|
|
||||||
|
const {
|
||||||
|
edges,
|
||||||
|
setEdges,
|
||||||
|
} = store.getState()
|
||||||
|
const newEdges = produce(edges, (draft) => {
|
||||||
|
const currentEdge = draft.find(e => e.id === edge.id)!
|
||||||
|
|
||||||
|
currentEdge.data = { ...currentEdge.data, _hovering: false }
|
||||||
|
})
|
||||||
|
setEdges(newEdges)
|
||||||
|
}, [store])
|
||||||
|
|
||||||
|
const handleEdgeDeleteByDeleteBranch = useCallback((nodeId: string, branchId: string) => {
|
||||||
|
const { runningStatus } = useStore.getState()
|
||||||
|
|
||||||
|
if (runningStatus)
|
||||||
|
return
|
||||||
|
|
||||||
|
const {
|
||||||
|
edges,
|
||||||
|
setEdges,
|
||||||
|
} = store.getState()
|
||||||
|
const newEdges = produce(edges, (draft) => {
|
||||||
|
const index = draft.findIndex(edge => edge.source === nodeId && edge.sourceHandle === branchId)
|
||||||
|
|
||||||
|
if (index > -1)
|
||||||
|
draft.splice(index, 1)
|
||||||
|
})
|
||||||
|
setEdges(newEdges)
|
||||||
|
handleSyncWorkflowDraft()
|
||||||
|
}, [store, handleSyncWorkflowDraft])
|
||||||
|
|
||||||
|
const handleEdgeDelete = useCallback(() => {
|
||||||
|
const { runningStatus } = useStore.getState()
|
||||||
|
|
||||||
|
if (runningStatus)
|
||||||
|
return
|
||||||
|
|
||||||
|
const {
|
||||||
|
edges,
|
||||||
|
setEdges,
|
||||||
|
} = store.getState()
|
||||||
|
const newEdges = produce(edges, (draft) => {
|
||||||
|
const index = draft.findIndex(edge => edge.selected)
|
||||||
|
|
||||||
|
if (index > -1)
|
||||||
|
draft.splice(index, 1)
|
||||||
|
})
|
||||||
|
setEdges(newEdges)
|
||||||
|
handleSyncWorkflowDraft()
|
||||||
|
}, [store, handleSyncWorkflowDraft])
|
||||||
|
|
||||||
|
const handleEdgesChange = useCallback<OnEdgesChange>((changes) => {
|
||||||
|
const { runningStatus } = useStore.getState()
|
||||||
|
|
||||||
|
if (runningStatus)
|
||||||
|
return
|
||||||
|
|
||||||
|
const {
|
||||||
|
edges,
|
||||||
|
setEdges,
|
||||||
|
} = store.getState()
|
||||||
|
|
||||||
|
const newEdges = produce(edges, (draft) => {
|
||||||
|
changes.forEach((change) => {
|
||||||
|
if (change.type === 'select')
|
||||||
|
draft.find(edge => edge.id === change.id)!.selected = change.selected
|
||||||
|
})
|
||||||
|
})
|
||||||
|
setEdges(newEdges)
|
||||||
|
}, [store])
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleEdgeEnter,
|
||||||
|
handleEdgeLeave,
|
||||||
|
handleEdgeDeleteByDeleteBranch,
|
||||||
|
handleEdgeDelete,
|
||||||
|
handleEdgesChange,
|
||||||
|
}
|
||||||
|
}
|
||||||
43
web/app/components/workflow/hooks/use-node-data-update.ts
Normal file
43
web/app/components/workflow/hooks/use-node-data-update.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
import produce from 'immer'
|
||||||
|
import { useStoreApi } from 'reactflow'
|
||||||
|
import { useStore } from '../store'
|
||||||
|
import { useNodesSyncDraft } from './use-nodes-sync-draft'
|
||||||
|
|
||||||
|
type NodeDataUpdatePayload = {
|
||||||
|
id: string
|
||||||
|
data: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNodeDataUpdate = () => {
|
||||||
|
const store = useStoreApi()
|
||||||
|
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||||
|
|
||||||
|
const handleNodeDataUpdate = useCallback(({ id, data }: NodeDataUpdatePayload) => {
|
||||||
|
const {
|
||||||
|
getNodes,
|
||||||
|
setNodes,
|
||||||
|
} = store.getState()
|
||||||
|
const newNodes = produce(getNodes(), (draft) => {
|
||||||
|
const currentNode = draft.find(node => node.id === id)!
|
||||||
|
|
||||||
|
currentNode.data = { ...currentNode.data, ...data }
|
||||||
|
})
|
||||||
|
setNodes(newNodes)
|
||||||
|
}, [store])
|
||||||
|
|
||||||
|
const handleNodeDataUpdateWithSyncDraft = useCallback((payload: NodeDataUpdatePayload) => {
|
||||||
|
const { runningStatus } = useStore.getState()
|
||||||
|
|
||||||
|
if (runningStatus)
|
||||||
|
return
|
||||||
|
|
||||||
|
handleNodeDataUpdate(payload)
|
||||||
|
handleSyncWorkflowDraft(true)
|
||||||
|
}, [handleSyncWorkflowDraft, handleNodeDataUpdate])
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleNodeDataUpdate,
|
||||||
|
handleNodeDataUpdateWithSyncDraft,
|
||||||
|
}
|
||||||
|
}
|
||||||
27
web/app/components/workflow/hooks/use-nodes-data.ts
Normal file
27
web/app/components/workflow/hooks/use-nodes-data.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import produce from 'immer'
|
||||||
|
import type { BlockEnum } from '../types'
|
||||||
|
import {
|
||||||
|
NODES_EXTRA_DATA,
|
||||||
|
NODES_INITIAL_DATA,
|
||||||
|
} from '../constants'
|
||||||
|
|
||||||
|
export const useNodesInitialData = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return produce(NODES_INITIAL_DATA, (draft) => {
|
||||||
|
Object.keys(draft).forEach((key) => {
|
||||||
|
draft[key as BlockEnum].title = t(`workflow.blocks.${key}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNodesExtraData = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return produce(NODES_EXTRA_DATA, (draft) => {
|
||||||
|
Object.keys(draft).forEach((key) => {
|
||||||
|
draft[key as BlockEnum].about = t(`workflow.blocksAbout.${key}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,162 +1,34 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import { useDebounceFn } from 'ahooks'
|
|
||||||
import type {
|
import type {
|
||||||
EdgeMouseHandler,
|
|
||||||
NodeDragHandler,
|
NodeDragHandler,
|
||||||
NodeMouseHandler,
|
NodeMouseHandler,
|
||||||
OnConnect,
|
OnConnect,
|
||||||
OnEdgesChange,
|
|
||||||
Viewport,
|
|
||||||
} from 'reactflow'
|
} from 'reactflow'
|
||||||
import {
|
import {
|
||||||
Position,
|
Position,
|
||||||
getConnectedEdges,
|
getConnectedEdges,
|
||||||
getIncomers,
|
getIncomers,
|
||||||
getOutgoers,
|
getOutgoers,
|
||||||
useReactFlow,
|
|
||||||
useStoreApi,
|
useStoreApi,
|
||||||
} from 'reactflow'
|
} from 'reactflow'
|
||||||
import type { Node } from './types'
|
import type { ToolDefaultValue } from '../block-selector/types'
|
||||||
|
import type {
|
||||||
|
Node,
|
||||||
|
} from '../types'
|
||||||
|
import { BlockEnum } from '../types'
|
||||||
|
import { useStore } from '../store'
|
||||||
import {
|
import {
|
||||||
BlockEnum,
|
|
||||||
NodeRunningStatus,
|
|
||||||
WorkflowRunningStatus,
|
|
||||||
} from './types'
|
|
||||||
import {
|
|
||||||
NODES_EXTRA_DATA,
|
|
||||||
NODES_INITIAL_DATA,
|
|
||||||
NODE_WIDTH_X_OFFSET,
|
NODE_WIDTH_X_OFFSET,
|
||||||
Y_OFFSET,
|
Y_OFFSET,
|
||||||
} from './constants'
|
} from '../constants'
|
||||||
import {
|
import { useNodesInitialData } from './use-nodes-data'
|
||||||
getLayoutByDagre,
|
import { useNodesSyncDraft } from './use-nodes-sync-draft'
|
||||||
} from './utils'
|
|
||||||
import { useStore } from './store'
|
|
||||||
import type { ToolDefaultValue } from './block-selector/types'
|
|
||||||
import { syncWorkflowDraft } from '@/service/workflow'
|
|
||||||
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
|
||||||
import { ssePost } from '@/service/base'
|
|
||||||
import type { IOtherOptions } from '@/service/base'
|
|
||||||
|
|
||||||
export const useIsChatMode = () => {
|
export const useNodesInteractions = () => {
|
||||||
const appDetail = useAppStore(s => s.appDetail)
|
|
||||||
|
|
||||||
return appDetail?.mode === 'advanced-chat'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useNodesInitialData = () => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
return produce(NODES_INITIAL_DATA, (draft) => {
|
|
||||||
Object.keys(draft).forEach((key) => {
|
|
||||||
draft[key as BlockEnum].title = t(`workflow.blocks.${key}`)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useNodesExtraData = () => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
return produce(NODES_EXTRA_DATA, (draft) => {
|
|
||||||
Object.keys(draft).forEach((key) => {
|
|
||||||
draft[key as BlockEnum].about = t(`workflow.blocksAbout.${key}`)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useWorkflow = () => {
|
|
||||||
const store = useStoreApi()
|
const store = useStoreApi()
|
||||||
const reactFlow = useReactFlow()
|
|
||||||
const nodesInitialData = useNodesInitialData()
|
const nodesInitialData = useNodesInitialData()
|
||||||
const featuresStore = useFeaturesStore()
|
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||||
|
|
||||||
const shouldDebouncedSyncWorkflowDraft = useCallback(() => {
|
|
||||||
const {
|
|
||||||
getNodes,
|
|
||||||
edges,
|
|
||||||
} = store.getState()
|
|
||||||
const { getViewport } = reactFlow
|
|
||||||
const appId = useAppStore.getState().appDetail?.id
|
|
||||||
|
|
||||||
if (appId) {
|
|
||||||
const features = featuresStore!.getState().features
|
|
||||||
const producedNodes = produce(getNodes(), (draft) => {
|
|
||||||
draft.forEach((node) => {
|
|
||||||
Object.keys(node.data).forEach((key) => {
|
|
||||||
if (key.startsWith('_'))
|
|
||||||
delete node.data[key]
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
const producedEdges = produce(edges, (draft) => {
|
|
||||||
draft.forEach((edge) => {
|
|
||||||
delete edge.data
|
|
||||||
})
|
|
||||||
})
|
|
||||||
syncWorkflowDraft({
|
|
||||||
url: `/apps/${appId}/workflows/draft`,
|
|
||||||
params: {
|
|
||||||
graph: {
|
|
||||||
nodes: producedNodes,
|
|
||||||
edges: producedEdges,
|
|
||||||
viewport: getViewport(),
|
|
||||||
},
|
|
||||||
features: {
|
|
||||||
opening_statement: features.opening.opening_statement,
|
|
||||||
suggested_questions: features.opening.suggested_questions,
|
|
||||||
suggested_questions_after_answer: features.suggested,
|
|
||||||
text_to_speech: features.text2speech,
|
|
||||||
speech_to_text: features.speech2text,
|
|
||||||
retriever_resource: features.citation,
|
|
||||||
sensitive_word_avoidance: features.moderation,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).then((res) => {
|
|
||||||
useStore.setState({ draftUpdatedAt: res.updated_at })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, [store, reactFlow, featuresStore])
|
|
||||||
|
|
||||||
const { run: debouncedSyncWorkflowDraft } = useDebounceFn(shouldDebouncedSyncWorkflowDraft, {
|
|
||||||
wait: 2000,
|
|
||||||
trailing: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleSyncWorkflowDraft = useCallback((shouldDelay?: boolean) => {
|
|
||||||
if (shouldDelay)
|
|
||||||
debouncedSyncWorkflowDraft()
|
|
||||||
else
|
|
||||||
shouldDebouncedSyncWorkflowDraft()
|
|
||||||
}, [debouncedSyncWorkflowDraft, shouldDebouncedSyncWorkflowDraft])
|
|
||||||
|
|
||||||
const handleLayout = useCallback(async () => {
|
|
||||||
const {
|
|
||||||
getNodes,
|
|
||||||
edges,
|
|
||||||
setNodes,
|
|
||||||
} = store.getState()
|
|
||||||
|
|
||||||
const layout = getLayoutByDagre(getNodes(), edges)
|
|
||||||
|
|
||||||
const newNodes = produce(getNodes(), (draft) => {
|
|
||||||
draft.forEach((node) => {
|
|
||||||
const nodeWithPosition = layout.node(node.id)
|
|
||||||
node.position = {
|
|
||||||
x: nodeWithPosition.x,
|
|
||||||
y: nodeWithPosition.y,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
setNodes(newNodes)
|
|
||||||
}, [store])
|
|
||||||
|
|
||||||
const handleSetViewport = useCallback((viewPort: Viewport) => {
|
|
||||||
reactFlow.setViewport(viewPort)
|
|
||||||
handleSyncWorkflowDraft()
|
|
||||||
}, [reactFlow, handleSyncWorkflowDraft])
|
|
||||||
|
|
||||||
const handleNodeDragStart = useCallback<NodeDragHandler>(() => {
|
const handleNodeDragStart = useCallback<NodeDragHandler>(() => {
|
||||||
const {
|
const {
|
||||||
@ -164,8 +36,10 @@ export const useWorkflow = () => {
|
|||||||
setIsDragging,
|
setIsDragging,
|
||||||
} = useStore.getState()
|
} = useStore.getState()
|
||||||
|
|
||||||
if (!runningStatus)
|
if (runningStatus)
|
||||||
setIsDragging(true)
|
return
|
||||||
|
|
||||||
|
setIsDragging(true)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleNodeDrag = useCallback<NodeDragHandler>((e, node: Node) => {
|
const handleNodeDrag = useCallback<NodeDragHandler>((e, node: Node) => {
|
||||||
@ -433,25 +307,6 @@ export const useWorkflow = () => {
|
|||||||
handleSyncWorkflowDraft()
|
handleSyncWorkflowDraft()
|
||||||
}, [store, handleSyncWorkflowDraft])
|
}, [store, handleSyncWorkflowDraft])
|
||||||
|
|
||||||
const handleNodeDataUpdate = useCallback(({ id, data }: { id: string; data: Record<string, any> }) => {
|
|
||||||
const { runningStatus } = useStore.getState()
|
|
||||||
|
|
||||||
if (runningStatus)
|
|
||||||
return
|
|
||||||
|
|
||||||
const {
|
|
||||||
getNodes,
|
|
||||||
setNodes,
|
|
||||||
} = store.getState()
|
|
||||||
const newNodes = produce(getNodes(), (draft) => {
|
|
||||||
const currentNode = draft.find(node => node.id === id)!
|
|
||||||
|
|
||||||
currentNode.data = { ...currentNode.data, ...data }
|
|
||||||
})
|
|
||||||
setNodes(newNodes)
|
|
||||||
handleSyncWorkflowDraft(true)
|
|
||||||
}, [store, handleSyncWorkflowDraft])
|
|
||||||
|
|
||||||
const handleNodeAddNext = useCallback((
|
const handleNodeAddNext = useCallback((
|
||||||
currentNodeId: string,
|
currentNodeId: string,
|
||||||
nodeType: BlockEnum,
|
nodeType: BlockEnum,
|
||||||
@ -636,196 +491,7 @@ export const useWorkflow = () => {
|
|||||||
}
|
}
|
||||||
}, [store, nodesInitialData, handleSyncWorkflowDraft])
|
}, [store, nodesInitialData, handleSyncWorkflowDraft])
|
||||||
|
|
||||||
const handleEdgeEnter = useCallback<EdgeMouseHandler>((_, edge) => {
|
|
||||||
const { runningStatus } = useStore.getState()
|
|
||||||
|
|
||||||
if (runningStatus)
|
|
||||||
return
|
|
||||||
|
|
||||||
const {
|
|
||||||
edges,
|
|
||||||
setEdges,
|
|
||||||
} = store.getState()
|
|
||||||
const newEdges = produce(edges, (draft) => {
|
|
||||||
const currentEdge = draft.find(e => e.id === edge.id)!
|
|
||||||
|
|
||||||
currentEdge.data = { ...currentEdge.data, _hovering: true }
|
|
||||||
})
|
|
||||||
setEdges(newEdges)
|
|
||||||
}, [store])
|
|
||||||
|
|
||||||
const handleEdgeLeave = useCallback<EdgeMouseHandler>((_, edge) => {
|
|
||||||
const { runningStatus } = useStore.getState()
|
|
||||||
|
|
||||||
if (runningStatus)
|
|
||||||
return
|
|
||||||
|
|
||||||
const {
|
|
||||||
edges,
|
|
||||||
setEdges,
|
|
||||||
} = store.getState()
|
|
||||||
const newEdges = produce(edges, (draft) => {
|
|
||||||
const currentEdge = draft.find(e => e.id === edge.id)!
|
|
||||||
|
|
||||||
currentEdge.data = { ...currentEdge.data, _hovering: false }
|
|
||||||
})
|
|
||||||
setEdges(newEdges)
|
|
||||||
}, [store])
|
|
||||||
|
|
||||||
const handleEdgeDeleteByDeleteBranch = useCallback((nodeId: string, branchId: string) => {
|
|
||||||
const { runningStatus } = useStore.getState()
|
|
||||||
|
|
||||||
if (runningStatus)
|
|
||||||
return
|
|
||||||
|
|
||||||
const {
|
|
||||||
edges,
|
|
||||||
setEdges,
|
|
||||||
} = store.getState()
|
|
||||||
const newEdges = produce(edges, (draft) => {
|
|
||||||
const index = draft.findIndex(edge => edge.source === nodeId && edge.sourceHandle === branchId)
|
|
||||||
|
|
||||||
if (index > -1)
|
|
||||||
draft.splice(index, 1)
|
|
||||||
})
|
|
||||||
setEdges(newEdges)
|
|
||||||
handleSyncWorkflowDraft()
|
|
||||||
}, [store, handleSyncWorkflowDraft])
|
|
||||||
|
|
||||||
const handleEdgeDelete = useCallback(() => {
|
|
||||||
const { runningStatus } = useStore.getState()
|
|
||||||
|
|
||||||
if (runningStatus)
|
|
||||||
return
|
|
||||||
|
|
||||||
const {
|
|
||||||
edges,
|
|
||||||
setEdges,
|
|
||||||
} = store.getState()
|
|
||||||
const newEdges = produce(edges, (draft) => {
|
|
||||||
const index = draft.findIndex(edge => edge.selected)
|
|
||||||
|
|
||||||
if (index > -1)
|
|
||||||
draft.splice(index, 1)
|
|
||||||
})
|
|
||||||
setEdges(newEdges)
|
|
||||||
handleSyncWorkflowDraft()
|
|
||||||
}, [store, handleSyncWorkflowDraft])
|
|
||||||
|
|
||||||
const handleEdgesChange = useCallback<OnEdgesChange>((changes) => {
|
|
||||||
const { runningStatus } = useStore.getState()
|
|
||||||
|
|
||||||
if (runningStatus)
|
|
||||||
return
|
|
||||||
|
|
||||||
const {
|
|
||||||
edges,
|
|
||||||
setEdges,
|
|
||||||
} = store.getState()
|
|
||||||
|
|
||||||
const newEdges = produce(edges, (draft) => {
|
|
||||||
changes.forEach((change) => {
|
|
||||||
if (change.type === 'select')
|
|
||||||
draft.find(edge => edge.id === change.id)!.selected = change.selected
|
|
||||||
})
|
|
||||||
})
|
|
||||||
setEdges(newEdges)
|
|
||||||
}, [store])
|
|
||||||
|
|
||||||
const handleRunInit = useCallback((shouldClear?: boolean) => {
|
|
||||||
useStore.setState({ runningStatus: shouldClear ? undefined : WorkflowRunningStatus.Waiting })
|
|
||||||
const { setNodes, getNodes } = store.getState()
|
|
||||||
const newNodes = produce(getNodes(), (draft) => {
|
|
||||||
draft.forEach((node) => {
|
|
||||||
node.data._runningStatus = shouldClear ? undefined : NodeRunningStatus.Waiting
|
|
||||||
})
|
|
||||||
})
|
|
||||||
setNodes(newNodes)
|
|
||||||
}, [store])
|
|
||||||
|
|
||||||
const getTreeLeafNodes = useCallback(() => {
|
|
||||||
const {
|
|
||||||
getNodes,
|
|
||||||
edges,
|
|
||||||
} = store.getState()
|
|
||||||
const nodes = getNodes()
|
|
||||||
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
|
|
||||||
|
|
||||||
if (!startNode)
|
|
||||||
return []
|
|
||||||
|
|
||||||
const list: Node[] = []
|
|
||||||
const preOrder = (root: Node, callback: (node: Node) => void) => {
|
|
||||||
const outgoers = getOutgoers(root, nodes, edges)
|
|
||||||
|
|
||||||
if (outgoers.length) {
|
|
||||||
outgoers.forEach((outgoer) => {
|
|
||||||
preOrder(outgoer, callback)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
callback(root)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
preOrder(startNode, (node) => {
|
|
||||||
list.push(node)
|
|
||||||
})
|
|
||||||
|
|
||||||
return list.filter((item) => {
|
|
||||||
if (item.data.type === BlockEnum.IfElse)
|
|
||||||
return false
|
|
||||||
|
|
||||||
if (item.data.type === BlockEnum.QuestionClassifier)
|
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}, [store])
|
|
||||||
|
|
||||||
const getBeforeNodesInSameBranch = useCallback((nodeId: string) => {
|
|
||||||
const {
|
|
||||||
getNodes,
|
|
||||||
edges,
|
|
||||||
} = store.getState()
|
|
||||||
const nodes = getNodes()
|
|
||||||
const currentNode = nodes.find(node => node.id === nodeId)!
|
|
||||||
const list: Node[] = []
|
|
||||||
|
|
||||||
const traverse = (root: Node, callback: (node: Node) => void) => {
|
|
||||||
const incomers = getIncomers(root, nodes, edges)
|
|
||||||
|
|
||||||
if (incomers.length) {
|
|
||||||
incomers.forEach((node) => {
|
|
||||||
callback(node)
|
|
||||||
traverse(node, callback)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
traverse(currentNode, (node) => {
|
|
||||||
list.push(node)
|
|
||||||
})
|
|
||||||
|
|
||||||
const length = list.length
|
|
||||||
if (length && list.some(item => item.data.type === BlockEnum.Start)) {
|
|
||||||
return list.reverse().filter((item) => {
|
|
||||||
if (item.data.type === BlockEnum.IfElse)
|
|
||||||
return false
|
|
||||||
|
|
||||||
if (item.data.type === BlockEnum.QuestionClassifier)
|
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return []
|
|
||||||
}, [store])
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleSyncWorkflowDraft,
|
|
||||||
handleLayout,
|
|
||||||
handleSetViewport,
|
|
||||||
|
|
||||||
handleNodeDragStart,
|
handleNodeDragStart,
|
||||||
handleNodeDrag,
|
handleNodeDrag,
|
||||||
handleNodeDragStop,
|
handleNodeDragStop,
|
||||||
@ -835,94 +501,8 @@ export const useWorkflow = () => {
|
|||||||
handleNodeClick,
|
handleNodeClick,
|
||||||
handleNodeConnect,
|
handleNodeConnect,
|
||||||
handleNodeDelete,
|
handleNodeDelete,
|
||||||
handleNodeDataUpdate,
|
|
||||||
handleNodeAddNext,
|
handleNodeAddNext,
|
||||||
handleNodeAddPrev,
|
handleNodeAddPrev,
|
||||||
handleNodeChange,
|
handleNodeChange,
|
||||||
|
|
||||||
handleEdgeEnter,
|
|
||||||
handleEdgeLeave,
|
|
||||||
handleEdgeDeleteByDeleteBranch,
|
|
||||||
handleEdgeDelete,
|
|
||||||
handleEdgesChange,
|
|
||||||
|
|
||||||
handleRunInit,
|
|
||||||
getTreeLeafNodes,
|
|
||||||
getBeforeNodesInSameBranch,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useWorkflowRun = () => {
|
|
||||||
const store = useStoreApi()
|
|
||||||
const reactflow = useReactFlow()
|
|
||||||
|
|
||||||
const run = useCallback((params: any, callback?: IOtherOptions) => {
|
|
||||||
const {
|
|
||||||
getNodes,
|
|
||||||
setNodes,
|
|
||||||
} = store.getState()
|
|
||||||
const appDetail = useAppStore.getState().appDetail
|
|
||||||
|
|
||||||
let url = ''
|
|
||||||
if (appDetail?.mode === 'advanced-chat')
|
|
||||||
url = `/apps/${appDetail.id}/advanced-chat/workflows/draft/run`
|
|
||||||
|
|
||||||
if (appDetail?.mode === 'workflow')
|
|
||||||
url = `/apps/${appDetail.id}/workflows/draft/run`
|
|
||||||
|
|
||||||
ssePost(
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
body: params,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onWorkflowStarted: ({ task_id, workflow_run_id, sequence_number }) => {
|
|
||||||
useStore.setState({ runningStatus: WorkflowRunningStatus.Running })
|
|
||||||
useStore.setState({ taskId: task_id })
|
|
||||||
useStore.setState({ currentSequenceNumber: sequence_number })
|
|
||||||
useStore.setState({ workflowRunId: workflow_run_id })
|
|
||||||
const newNodes = produce(getNodes(), (draft) => {
|
|
||||||
draft.forEach((node) => {
|
|
||||||
node.data._runningStatus = NodeRunningStatus.Waiting
|
|
||||||
})
|
|
||||||
})
|
|
||||||
setNodes(newNodes)
|
|
||||||
},
|
|
||||||
onWorkflowFinished: ({ data }) => {
|
|
||||||
useStore.setState({ runningStatus: data.status as WorkflowRunningStatus })
|
|
||||||
},
|
|
||||||
onNodeStarted: ({ data }) => {
|
|
||||||
const nodes = getNodes()
|
|
||||||
const {
|
|
||||||
getViewport,
|
|
||||||
setViewport,
|
|
||||||
} = reactflow
|
|
||||||
const viewport = getViewport()
|
|
||||||
const currentNodeIndex = nodes.findIndex(node => node.id === data.node_id)
|
|
||||||
const position = nodes[currentNodeIndex].position
|
|
||||||
const zoom = 1
|
|
||||||
setViewport({
|
|
||||||
zoom,
|
|
||||||
x: 200 / viewport.zoom - position.x,
|
|
||||||
y: 200 / viewport.zoom - position.y,
|
|
||||||
})
|
|
||||||
const newNodes = produce(nodes, (draft) => {
|
|
||||||
draft[currentNodeIndex].data._runningStatus = NodeRunningStatus.Running
|
|
||||||
})
|
|
||||||
setNodes(newNodes)
|
|
||||||
},
|
|
||||||
onNodeFinished: ({ data }) => {
|
|
||||||
const newNodes = produce(getNodes(), (draft) => {
|
|
||||||
const currentNode = draft.find(node => node.id === data.node_id)!
|
|
||||||
|
|
||||||
currentNode.data._runningStatus = data.status
|
|
||||||
})
|
|
||||||
setNodes(newNodes)
|
|
||||||
},
|
|
||||||
...callback,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}, [store, reactflow])
|
|
||||||
|
|
||||||
return run
|
|
||||||
}
|
|
||||||
85
web/app/components/workflow/hooks/use-nodes-sync-draft.ts
Normal file
85
web/app/components/workflow/hooks/use-nodes-sync-draft.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
import produce from 'immer'
|
||||||
|
import { useDebounceFn } from 'ahooks'
|
||||||
|
import {
|
||||||
|
useReactFlow,
|
||||||
|
useStoreApi,
|
||||||
|
} from 'reactflow'
|
||||||
|
import { useStore } from '../store'
|
||||||
|
import { syncWorkflowDraft } from '@/service/workflow'
|
||||||
|
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||||
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
|
||||||
|
export const useNodesSyncDraft = () => {
|
||||||
|
const store = useStoreApi()
|
||||||
|
const reactFlow = useReactFlow()
|
||||||
|
const featuresStore = useFeaturesStore()
|
||||||
|
|
||||||
|
const shouldDebouncedSyncWorkflowDraft = useCallback(() => {
|
||||||
|
const {
|
||||||
|
getNodes,
|
||||||
|
edges,
|
||||||
|
} = store.getState()
|
||||||
|
const { getViewport } = reactFlow
|
||||||
|
const appId = useAppStore.getState().appDetail?.id
|
||||||
|
|
||||||
|
if (appId) {
|
||||||
|
const features = featuresStore!.getState().features
|
||||||
|
const producedNodes = produce(getNodes(), (draft) => {
|
||||||
|
draft.forEach((node) => {
|
||||||
|
Object.keys(node.data).forEach((key) => {
|
||||||
|
if (key.startsWith('_'))
|
||||||
|
delete node.data[key]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const producedEdges = produce(edges, (draft) => {
|
||||||
|
draft.forEach((edge) => {
|
||||||
|
delete edge.data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
syncWorkflowDraft({
|
||||||
|
url: `/apps/${appId}/workflows/draft`,
|
||||||
|
params: {
|
||||||
|
graph: {
|
||||||
|
nodes: producedNodes,
|
||||||
|
edges: producedEdges,
|
||||||
|
viewport: getViewport(),
|
||||||
|
},
|
||||||
|
features: {
|
||||||
|
opening_statement: features.opening.opening_statement,
|
||||||
|
suggested_questions: features.opening.suggested_questions,
|
||||||
|
suggested_questions_after_answer: features.suggested,
|
||||||
|
text_to_speech: features.text2speech,
|
||||||
|
speech_to_text: features.speech2text,
|
||||||
|
retriever_resource: features.citation,
|
||||||
|
sensitive_word_avoidance: features.moderation,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).then((res) => {
|
||||||
|
useStore.setState({ draftUpdatedAt: res.updated_at })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [store, reactFlow, featuresStore])
|
||||||
|
|
||||||
|
const { run: debouncedSyncWorkflowDraft } = useDebounceFn(shouldDebouncedSyncWorkflowDraft, {
|
||||||
|
wait: 2000,
|
||||||
|
trailing: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSyncWorkflowDraft = useCallback((shouldDelay?: boolean) => {
|
||||||
|
const { runningStatus } = useStore.getState()
|
||||||
|
|
||||||
|
if (runningStatus)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (shouldDelay)
|
||||||
|
debouncedSyncWorkflowDraft()
|
||||||
|
else
|
||||||
|
shouldDebouncedSyncWorkflowDraft()
|
||||||
|
}, [debouncedSyncWorkflowDraft, shouldDebouncedSyncWorkflowDraft])
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleSyncWorkflowDraft,
|
||||||
|
}
|
||||||
|
}
|
||||||
103
web/app/components/workflow/hooks/use-workflow-run.ts
Normal file
103
web/app/components/workflow/hooks/use-workflow-run.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
import {
|
||||||
|
useReactFlow,
|
||||||
|
useStoreApi,
|
||||||
|
} from 'reactflow'
|
||||||
|
import produce from 'immer'
|
||||||
|
import { useStore } from '../store'
|
||||||
|
import {
|
||||||
|
NodeRunningStatus,
|
||||||
|
WorkflowRunningStatus,
|
||||||
|
} from '../types'
|
||||||
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
import type { IOtherOptions } from '@/service/base'
|
||||||
|
import { ssePost } from '@/service/base'
|
||||||
|
|
||||||
|
export const useWorkflowRun = () => {
|
||||||
|
const store = useStoreApi()
|
||||||
|
const reactflow = useReactFlow()
|
||||||
|
|
||||||
|
const handleRunSetting = useCallback((shouldClear?: boolean) => {
|
||||||
|
useStore.setState({ runningStatus: shouldClear ? undefined : WorkflowRunningStatus.Waiting })
|
||||||
|
const { setNodes, getNodes } = store.getState()
|
||||||
|
const newNodes = produce(getNodes(), (draft) => {
|
||||||
|
draft.forEach((node) => {
|
||||||
|
node.data._runningStatus = shouldClear ? undefined : NodeRunningStatus.Waiting
|
||||||
|
})
|
||||||
|
})
|
||||||
|
setNodes(newNodes)
|
||||||
|
}, [store])
|
||||||
|
|
||||||
|
const handleRun = useCallback((params: any, callback?: IOtherOptions) => {
|
||||||
|
const {
|
||||||
|
getNodes,
|
||||||
|
setNodes,
|
||||||
|
} = store.getState()
|
||||||
|
const appDetail = useAppStore.getState().appDetail
|
||||||
|
|
||||||
|
let url = ''
|
||||||
|
if (appDetail?.mode === 'advanced-chat')
|
||||||
|
url = `/apps/${appDetail.id}/advanced-chat/workflows/draft/run`
|
||||||
|
|
||||||
|
if (appDetail?.mode === 'workflow')
|
||||||
|
url = `/apps/${appDetail.id}/workflows/draft/run`
|
||||||
|
|
||||||
|
ssePost(
|
||||||
|
url,
|
||||||
|
{
|
||||||
|
body: params,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onWorkflowStarted: ({ task_id, workflow_run_id, sequence_number }) => {
|
||||||
|
useStore.setState({ runningStatus: WorkflowRunningStatus.Running })
|
||||||
|
useStore.setState({ taskId: task_id })
|
||||||
|
useStore.setState({ currentSequenceNumber: sequence_number })
|
||||||
|
useStore.setState({ workflowRunId: workflow_run_id })
|
||||||
|
const newNodes = produce(getNodes(), (draft) => {
|
||||||
|
draft.forEach((node) => {
|
||||||
|
node.data._runningStatus = NodeRunningStatus.Waiting
|
||||||
|
})
|
||||||
|
})
|
||||||
|
setNodes(newNodes)
|
||||||
|
},
|
||||||
|
onWorkflowFinished: ({ data }) => {
|
||||||
|
useStore.setState({ runningStatus: data.status as WorkflowRunningStatus })
|
||||||
|
},
|
||||||
|
onNodeStarted: ({ data }) => {
|
||||||
|
const nodes = getNodes()
|
||||||
|
const {
|
||||||
|
getViewport,
|
||||||
|
setViewport,
|
||||||
|
} = reactflow
|
||||||
|
const viewport = getViewport()
|
||||||
|
const currentNodeIndex = nodes.findIndex(node => node.id === data.node_id)
|
||||||
|
const position = nodes[currentNodeIndex].position
|
||||||
|
const zoom = 1
|
||||||
|
setViewport({
|
||||||
|
zoom,
|
||||||
|
x: 200 / viewport.zoom - position.x,
|
||||||
|
y: 200 / viewport.zoom - position.y,
|
||||||
|
})
|
||||||
|
const newNodes = produce(nodes, (draft) => {
|
||||||
|
draft[currentNodeIndex].data._runningStatus = NodeRunningStatus.Running
|
||||||
|
})
|
||||||
|
setNodes(newNodes)
|
||||||
|
},
|
||||||
|
onNodeFinished: ({ data }) => {
|
||||||
|
const newNodes = produce(getNodes(), (draft) => {
|
||||||
|
const currentNode = draft.find(node => node.id === data.node_id)!
|
||||||
|
|
||||||
|
currentNode.data._runningStatus = data.status
|
||||||
|
})
|
||||||
|
setNodes(newNodes)
|
||||||
|
},
|
||||||
|
...callback,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}, [store, reactflow])
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleRunSetting,
|
||||||
|
handleRun,
|
||||||
|
}
|
||||||
|
}
|
||||||
126
web/app/components/workflow/hooks/use-workflow.ts
Normal file
126
web/app/components/workflow/hooks/use-workflow.ts
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
import produce from 'immer'
|
||||||
|
import {
|
||||||
|
getIncomers,
|
||||||
|
getOutgoers,
|
||||||
|
useStoreApi,
|
||||||
|
} from 'reactflow'
|
||||||
|
import { getLayoutByDagre } from '../utils'
|
||||||
|
import type { Node } from '../types'
|
||||||
|
import { BlockEnum } from '../types'
|
||||||
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
|
||||||
|
export const useIsChatMode = () => {
|
||||||
|
const appDetail = useAppStore(s => s.appDetail)
|
||||||
|
|
||||||
|
return appDetail?.mode === 'advanced-chat'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useWorkflow = () => {
|
||||||
|
const store = useStoreApi()
|
||||||
|
|
||||||
|
const handleLayout = useCallback(async () => {
|
||||||
|
const {
|
||||||
|
getNodes,
|
||||||
|
edges,
|
||||||
|
setNodes,
|
||||||
|
} = store.getState()
|
||||||
|
|
||||||
|
const layout = getLayoutByDagre(getNodes(), edges)
|
||||||
|
|
||||||
|
const newNodes = produce(getNodes(), (draft) => {
|
||||||
|
draft.forEach((node) => {
|
||||||
|
const nodeWithPosition = layout.node(node.id)
|
||||||
|
node.position = {
|
||||||
|
x: nodeWithPosition.x,
|
||||||
|
y: nodeWithPosition.y,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
setNodes(newNodes)
|
||||||
|
}, [store])
|
||||||
|
|
||||||
|
const getTreeLeafNodes = useCallback(() => {
|
||||||
|
const {
|
||||||
|
getNodes,
|
||||||
|
edges,
|
||||||
|
} = store.getState()
|
||||||
|
const nodes = getNodes()
|
||||||
|
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
|
||||||
|
|
||||||
|
if (!startNode)
|
||||||
|
return []
|
||||||
|
|
||||||
|
const list: Node[] = []
|
||||||
|
const preOrder = (root: Node, callback: (node: Node) => void) => {
|
||||||
|
const outgoers = getOutgoers(root, nodes, edges)
|
||||||
|
|
||||||
|
if (outgoers.length) {
|
||||||
|
outgoers.forEach((outgoer) => {
|
||||||
|
preOrder(outgoer, callback)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preOrder(startNode, (node) => {
|
||||||
|
list.push(node)
|
||||||
|
})
|
||||||
|
|
||||||
|
return list.filter((item) => {
|
||||||
|
if (item.data.type === BlockEnum.IfElse)
|
||||||
|
return false
|
||||||
|
|
||||||
|
if (item.data.type === BlockEnum.QuestionClassifier)
|
||||||
|
return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}, [store])
|
||||||
|
|
||||||
|
const getBeforeNodesInSameBranch = useCallback((nodeId: string) => {
|
||||||
|
const {
|
||||||
|
getNodes,
|
||||||
|
edges,
|
||||||
|
} = store.getState()
|
||||||
|
const nodes = getNodes()
|
||||||
|
const currentNode = nodes.find(node => node.id === nodeId)!
|
||||||
|
const list: Node[] = []
|
||||||
|
|
||||||
|
const traverse = (root: Node, callback: (node: Node) => void) => {
|
||||||
|
const incomers = getIncomers(root, nodes, edges)
|
||||||
|
|
||||||
|
if (incomers.length) {
|
||||||
|
incomers.forEach((node) => {
|
||||||
|
callback(node)
|
||||||
|
traverse(node, callback)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
traverse(currentNode, (node) => {
|
||||||
|
list.push(node)
|
||||||
|
})
|
||||||
|
|
||||||
|
const length = list.length
|
||||||
|
if (length && list.some(item => item.data.type === BlockEnum.Start)) {
|
||||||
|
return list.reverse().filter((item) => {
|
||||||
|
if (item.data.type === BlockEnum.IfElse)
|
||||||
|
return false
|
||||||
|
|
||||||
|
if (item.data.type === BlockEnum.QuestionClassifier)
|
||||||
|
return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}, [store])
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleLayout,
|
||||||
|
getTreeLeafNodes,
|
||||||
|
getBeforeNodesInSameBranch,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,8 +20,10 @@ import type {
|
|||||||
Node,
|
Node,
|
||||||
} from './types'
|
} from './types'
|
||||||
import {
|
import {
|
||||||
|
useEdgesInteractions,
|
||||||
useNodesInitialData,
|
useNodesInitialData,
|
||||||
useWorkflow,
|
useNodesInteractions,
|
||||||
|
useNodesSyncDraft,
|
||||||
} from './hooks'
|
} from './hooks'
|
||||||
import Header from './header'
|
import Header from './header'
|
||||||
import CustomNode from './nodes'
|
import CustomNode from './nodes'
|
||||||
@ -65,6 +67,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
}) => {
|
}) => {
|
||||||
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
|
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
|
||||||
const runningStatus = useStore(s => s.runningStatus)
|
const runningStatus = useStore(s => s.runningStatus)
|
||||||
|
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAutoFreeze(false)
|
setAutoFreeze(false)
|
||||||
@ -75,8 +78,6 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSyncWorkflowDraft,
|
|
||||||
|
|
||||||
handleNodeDragStart,
|
handleNodeDragStart,
|
||||||
handleNodeDrag,
|
handleNodeDrag,
|
||||||
handleNodeDragStop,
|
handleNodeDragStop,
|
||||||
@ -84,12 +85,13 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
handleNodeLeave,
|
handleNodeLeave,
|
||||||
handleNodeClick,
|
handleNodeClick,
|
||||||
handleNodeConnect,
|
handleNodeConnect,
|
||||||
|
} = useNodesInteractions()
|
||||||
|
const {
|
||||||
handleEdgeEnter,
|
handleEdgeEnter,
|
||||||
handleEdgeLeave,
|
handleEdgeLeave,
|
||||||
handleEdgeDelete,
|
handleEdgeDelete,
|
||||||
handleEdgesChange,
|
handleEdgesChange,
|
||||||
} = useWorkflow()
|
} = useEdgesInteractions()
|
||||||
|
|
||||||
useOnViewportChange({
|
useOnViewportChange({
|
||||||
onEnd: () => handleSyncWorkflowDraft(),
|
onEnd: () => handleSyncWorkflowDraft(),
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import {
|
|||||||
useCallback,
|
useCallback,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useWorkflow } from '@/app/components/workflow/hooks'
|
import { useNodesInteractions } from '@/app/components/workflow/hooks'
|
||||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||||
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
||||||
@ -19,7 +19,7 @@ const Add = ({
|
|||||||
branchName,
|
branchName,
|
||||||
}: AddProps) => {
|
}: AddProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { handleNodeAddNext } = useWorkflow()
|
const { handleNodeAddNext } = useNodesInteractions()
|
||||||
|
|
||||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||||
handleNodeAddNext(nodeId, type, sourceHandle, toolDefaultValue)
|
handleNodeAddNext(nodeId, type, sourceHandle, toolDefaultValue)
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import type {
|
|||||||
} from '@/app/components/workflow/types'
|
} from '@/app/components/workflow/types'
|
||||||
import BlockIcon from '@/app/components/workflow/block-icon'
|
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||||
import { useWorkflow } from '@/app/components/workflow/hooks'
|
import { useNodesInteractions } from '@/app/components/workflow/hooks'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
|
|
||||||
type ItemProps = {
|
type ItemProps = {
|
||||||
@ -25,7 +25,7 @@ const Item = ({
|
|||||||
data,
|
data,
|
||||||
}: ItemProps) => {
|
}: ItemProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { handleNodeChange } = useWorkflow()
|
const { handleNodeChange } = useNodesInteractions()
|
||||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||||
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
||||||
}, [nodeId, sourceHandle, handleNodeChange])
|
}, [nodeId, sourceHandle, handleNodeChange])
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useWorkflow } from '../../../hooks'
|
import { useNodeDataUpdate } from '../../../hooks'
|
||||||
import type { Node } from '../../../types'
|
import type { Node } from '../../../types'
|
||||||
import { canRunBySingle } from '../../../utils'
|
import { canRunBySingle } from '../../../utils'
|
||||||
import PanelOperator from './panel-operator'
|
import PanelOperator from './panel-operator'
|
||||||
@ -22,7 +22,7 @@ const NodeControl: FC<NodeControlProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const { handleNodeDataUpdate } = useWorkflow()
|
const { handleNodeDataUpdate } = useNodeDataUpdate()
|
||||||
|
|
||||||
const handleOpenChange = useCallback((newOpen: boolean) => {
|
const handleOpenChange = useCallback((newOpen: boolean) => {
|
||||||
setOpen(newOpen)
|
setOpen(newOpen)
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { BlockEnum } from '../../../types'
|
|||||||
import type { Node } from '../../../types'
|
import type { Node } from '../../../types'
|
||||||
import BlockSelector from '../../../block-selector'
|
import BlockSelector from '../../../block-selector'
|
||||||
import type { ToolDefaultValue } from '../../../block-selector/types'
|
import type { ToolDefaultValue } from '../../../block-selector/types'
|
||||||
import { useWorkflow } from '../../../hooks'
|
import { useNodesInteractions } from '../../../hooks'
|
||||||
|
|
||||||
type NodeHandleProps = {
|
type NodeHandleProps = {
|
||||||
handleId: string
|
handleId: string
|
||||||
@ -30,7 +30,7 @@ export const NodeTargetHandle = ({
|
|||||||
nodeSelectorClassName,
|
nodeSelectorClassName,
|
||||||
}: NodeHandleProps) => {
|
}: NodeHandleProps) => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const { handleNodeAddPrev } = useWorkflow()
|
const { handleNodeAddPrev } = useNodesInteractions()
|
||||||
const edges = useEdges()
|
const edges = useEdges()
|
||||||
const connectedEdges = getConnectedEdges([{ id } as Node], edges)
|
const connectedEdges = getConnectedEdges([{ id } as Node], edges)
|
||||||
const connected = connectedEdges.find(edge => edge.targetHandle === handleId && edge.target === id)
|
const connected = connectedEdges.find(edge => edge.targetHandle === handleId && edge.target === id)
|
||||||
@ -92,7 +92,7 @@ export const NodeSourceHandle = ({
|
|||||||
nodeSelectorClassName,
|
nodeSelectorClassName,
|
||||||
}: NodeHandleProps) => {
|
}: NodeHandleProps) => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const { handleNodeAddNext } = useWorkflow()
|
const { handleNodeAddNext } = useNodesInteractions()
|
||||||
const edges = useEdges()
|
const edges = useEdges()
|
||||||
const connectedEdges = getConnectedEdges([{ id } as Node], edges)
|
const connectedEdges = getConnectedEdges([{ id } as Node], edges)
|
||||||
const connected = connectedEdges.find(edge => edge.sourceHandle === handleId && edge.source === id)
|
const connected = connectedEdges.find(edge => edge.sourceHandle === handleId && edge.source === id)
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {
|
|||||||
} from 'react'
|
} from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||||
import { useWorkflow } from '@/app/components/workflow/hooks'
|
import { useNodesInteractions } from '@/app/components/workflow/hooks'
|
||||||
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
type ChangeBlockProps = {
|
type ChangeBlockProps = {
|
||||||
@ -16,7 +16,7 @@ const ChangeBlock = ({
|
|||||||
sourceHandle,
|
sourceHandle,
|
||||||
}: ChangeBlockProps) => {
|
}: ChangeBlockProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { handleNodeChange } = useWorkflow()
|
const { handleNodeChange } = useNodesInteractions()
|
||||||
|
|
||||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||||
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import ChangeBlock from './change-block'
|
|||||||
import { useStore } from '@/app/components/workflow/store'
|
import { useStore } from '@/app/components/workflow/store'
|
||||||
import {
|
import {
|
||||||
useNodesExtraData,
|
useNodesExtraData,
|
||||||
useWorkflow,
|
useNodesInteractions,
|
||||||
} from '@/app/components/workflow/hooks'
|
} from '@/app/components/workflow/hooks'
|
||||||
import { DotsHorizontal } from '@/app/components/base/icons/src/vender/line/general'
|
import { DotsHorizontal } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
import {
|
import {
|
||||||
@ -52,7 +52,7 @@ const PanelOperator = ({
|
|||||||
const { locale } = useContext(I18n)
|
const { locale } = useContext(I18n)
|
||||||
const language = getLanguage(locale)
|
const language = getLanguage(locale)
|
||||||
const edges = useEdges()
|
const edges = useEdges()
|
||||||
const { handleNodeDelete } = useWorkflow()
|
const { handleNodeDelete } = useNodesInteractions()
|
||||||
const nodesExtraData = useNodesExtraData()
|
const nodesExtraData = useNodesExtraData()
|
||||||
const toolsets = useStore(s => s.toolsets)
|
const toolsets = useStore(s => s.toolsets)
|
||||||
const toolsMap = useStore(s => s.toolsMap)
|
const toolsMap = useStore(s => s.toolsMap)
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { useWorkflow } from '@/app/components/workflow/hooks'
|
import { useNodeDataUpdate } from '@/app/components/workflow/hooks'
|
||||||
import type { CommonNodeType } from '@/app/components/workflow/types'
|
import type { CommonNodeType } from '@/app/components/workflow/types'
|
||||||
const useNodeCrud = <T>(id: string, data: CommonNodeType<T>) => {
|
const useNodeCrud = <T>(id: string, data: CommonNodeType<T>) => {
|
||||||
const { handleNodeDataUpdate } = useWorkflow()
|
const { handleNodeDataUpdateWithSyncDraft } = useNodeDataUpdate()
|
||||||
|
|
||||||
const setInputs = (newInputs: CommonNodeType<T>) => {
|
const setInputs = (newInputs: CommonNodeType<T>) => {
|
||||||
handleNodeDataUpdate({
|
handleNodeDataUpdateWithSyncDraft({
|
||||||
id,
|
id,
|
||||||
data: newInputs,
|
data: newInputs,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useWorkflow } from '@/app/components/workflow/hooks'
|
import { useNodeDataUpdate } from '@/app/components/workflow/hooks'
|
||||||
import type { CommonNodeType, InputVar, Variable } from '@/app/components/workflow/types'
|
import type { CommonNodeType, InputVar, Variable } from '@/app/components/workflow/types'
|
||||||
import { InputVarType, NodeRunningStatus } from '@/app/components/workflow/types'
|
import { InputVarType, NodeRunningStatus } from '@/app/components/workflow/types'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
@ -21,7 +21,7 @@ const useOneStepRun = <T>({ id, data, defaultRunInputData, isInvalid = () => tru
|
|||||||
const [runInputData, setRunInputData] = useState<Record<string, any>>(defaultRunInputData || {})
|
const [runInputData, setRunInputData] = useState<Record<string, any>>(defaultRunInputData || {})
|
||||||
const [runResult, setRunResult] = useState<any>(null)
|
const [runResult, setRunResult] = useState<any>(null)
|
||||||
|
|
||||||
const { handleNodeDataUpdate }: { handleNodeDataUpdate: (data: any) => void } = useWorkflow()
|
const { handleNodeDataUpdate }: { handleNodeDataUpdate: (data: any) => void } = useNodeDataUpdate()
|
||||||
const isShowSingleRun = data._isSingleRun
|
const isShowSingleRun = data._isSingleRun
|
||||||
const hideSingleRun = () => {
|
const hideSingleRun = () => {
|
||||||
handleNodeDataUpdate({
|
handleNodeDataUpdate({
|
||||||
|
|||||||
@ -18,7 +18,10 @@ import {
|
|||||||
XClose,
|
XClose,
|
||||||
} from '@/app/components/base/icons/src/vender/line/general'
|
} from '@/app/components/base/icons/src/vender/line/general'
|
||||||
import BlockIcon from '@/app/components/workflow/block-icon'
|
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||||
import { useWorkflow } from '@/app/components/workflow/hooks'
|
import {
|
||||||
|
useNodeDataUpdate,
|
||||||
|
useNodesInteractions,
|
||||||
|
} from '@/app/components/workflow/hooks'
|
||||||
import { canRunBySingle } from '@/app/components/workflow/utils'
|
import { canRunBySingle } from '@/app/components/workflow/utils'
|
||||||
import { GitBranch01 } from '@/app/components/base/icons/src/vender/line/development'
|
import { GitBranch01 } from '@/app/components/base/icons/src/vender/line/development'
|
||||||
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||||
@ -36,18 +39,20 @@ const BasePanel: FC<BasePanelProps> = ({
|
|||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const { handleNodeSelect } = useNodesInteractions()
|
||||||
const {
|
const {
|
||||||
handleNodeSelect,
|
|
||||||
handleNodeDataUpdate,
|
handleNodeDataUpdate,
|
||||||
} = useWorkflow()
|
handleNodeDataUpdateWithSyncDraft,
|
||||||
|
} = useNodeDataUpdate()
|
||||||
|
|
||||||
const handleTitleChange = useCallback((title: string) => {
|
const handleTitleChange = useCallback((title: string) => {
|
||||||
if (!title)
|
if (!title)
|
||||||
return
|
return
|
||||||
handleNodeDataUpdate({ id, data: { ...data, title } })
|
handleNodeDataUpdateWithSyncDraft({ id, data: { ...data, title } })
|
||||||
}, [handleNodeDataUpdate, id, data])
|
}, [handleNodeDataUpdateWithSyncDraft, id, data])
|
||||||
const handleDescriptionChange = useCallback((desc: string) => {
|
const handleDescriptionChange = useCallback((desc: string) => {
|
||||||
handleNodeDataUpdate({ id, data: { ...data, desc } })
|
handleNodeDataUpdateWithSyncDraft({ id, data: { ...data, desc } })
|
||||||
}, [handleNodeDataUpdate, id, data])
|
}, [handleNodeDataUpdateWithSyncDraft, id, data])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-[420px] h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto'>
|
<div className='w-[420px] h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto'>
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import type { FC } from 'react'
|
|||||||
import React, { useCallback } from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useWorkflow } from '../../../hooks'
|
import { useEdgesInteractions } from '../../../hooks'
|
||||||
import AddButton from '../../_base/components/add-button'
|
import AddButton from '../../_base/components/add-button'
|
||||||
import Item from './class-item'
|
import Item from './class-item'
|
||||||
import type { Topic } from '@/app/components/workflow/nodes/question-classifier/types'
|
import type { Topic } from '@/app/components/workflow/nodes/question-classifier/types'
|
||||||
@ -22,7 +22,7 @@ const ClassList: FC<Props> = ({
|
|||||||
onChange,
|
onChange,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { handleEdgeDeleteByDeleteBranch } = useWorkflow()
|
const { handleEdgeDeleteByDeleteBranch } = useEdgesInteractions()
|
||||||
|
|
||||||
const handleClassChange = useCallback((index: number) => {
|
const handleClassChange = useCallback((index: number) => {
|
||||||
return (value: Topic) => {
|
return (value: Topic) => {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
useReactFlow,
|
useReactFlow,
|
||||||
useViewport,
|
useViewport,
|
||||||
} from 'reactflow'
|
} from 'reactflow'
|
||||||
import { useWorkflow } from '../hooks'
|
import { useNodesSyncDraft } from '../hooks'
|
||||||
import { useStore } from '../store'
|
import { useStore } from '../store'
|
||||||
import {
|
import {
|
||||||
PortalToFollowElem,
|
PortalToFollowElem,
|
||||||
@ -29,7 +29,7 @@ const ZoomInOut: FC = () => {
|
|||||||
fitView,
|
fitView,
|
||||||
} = useReactFlow()
|
} = useReactFlow()
|
||||||
const { zoom } = useViewport()
|
const { zoom } = useViewport()
|
||||||
const { handleSyncWorkflowDraft } = useWorkflow()
|
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const runningStatus = useStore(s => s.runningStatus)
|
const runningStatus = useStore(s => s.runningStatus)
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export const useChat = (
|
|||||||
) => {
|
) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { notify } = useToastContext()
|
const { notify } = useToastContext()
|
||||||
const run = useWorkflowRun()
|
const { handleRun } = useWorkflowRun()
|
||||||
const hasStopResponded = useRef(false)
|
const hasStopResponded = useRef(false)
|
||||||
const connversationId = useRef('')
|
const connversationId = useRef('')
|
||||||
const taskIdRef = useRef('')
|
const taskIdRef = useRef('')
|
||||||
@ -126,7 +126,7 @@ export const useChat = (
|
|||||||
|
|
||||||
let hasSetResponseId = false
|
let hasSetResponseId = false
|
||||||
|
|
||||||
run(
|
handleRun(
|
||||||
params,
|
params,
|
||||||
{
|
{
|
||||||
onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => {
|
onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => {
|
||||||
@ -179,7 +179,7 @@ export const useChat = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}, [run, handleResponding, handleUpdateChatList, notify, t, updateCurrentQA])
|
}, [handleRun, handleResponding, handleUpdateChatList, notify, t, updateCurrentQA])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
conversationId: connversationId.current,
|
conversationId: connversationId.current,
|
||||||
|
|||||||
@ -7,10 +7,7 @@ import { useNodes } from 'reactflow'
|
|||||||
import FormItem from '../nodes/_base/components/before-run-form/form-item'
|
import FormItem from '../nodes/_base/components/before-run-form/form-item'
|
||||||
import { BlockEnum } from '../types'
|
import { BlockEnum } from '../types'
|
||||||
import { useStore } from '../store'
|
import { useStore } from '../store'
|
||||||
import {
|
import { useWorkflowRun } from '../hooks'
|
||||||
useWorkflow,
|
|
||||||
useWorkflowRun,
|
|
||||||
} from '../hooks'
|
|
||||||
import type { StartNodeType } from '../nodes/start/types'
|
import type { StartNodeType } from '../nodes/start/types'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
|
|
||||||
@ -18,8 +15,10 @@ const InputsPanel = () => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const nodes = useNodes<StartNodeType>()
|
const nodes = useNodes<StartNodeType>()
|
||||||
const inputs = useStore(s => s.inputs)
|
const inputs = useStore(s => s.inputs)
|
||||||
const run = useWorkflowRun()
|
const {
|
||||||
const { handleRunInit } = useWorkflow()
|
handleRun,
|
||||||
|
handleRunSetting,
|
||||||
|
} = useWorkflowRun()
|
||||||
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
|
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
|
||||||
const variables = startNode?.data.variables || []
|
const variables = startNode?.data.variables || []
|
||||||
|
|
||||||
@ -34,10 +33,10 @@ const InputsPanel = () => {
|
|||||||
useStore.setState({ showInputsPanel: false })
|
useStore.setState({ showInputsPanel: false })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleRun = () => {
|
const doRun = () => {
|
||||||
handleCancel()
|
handleCancel()
|
||||||
handleRunInit()
|
handleRunSetting()
|
||||||
run({ inputs })
|
handleRun({ inputs })
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -72,7 +71,7 @@ const InputsPanel = () => {
|
|||||||
<Button
|
<Button
|
||||||
type='primary'
|
type='primary'
|
||||||
className='py-0 w-[190px] h-8 rounded-lg text-[13px] font-medium'
|
className='py-0 w-[190px] h-8 rounded-lg text-[13px] font-medium'
|
||||||
onClick={handleRun}
|
onClick={doRun}
|
||||||
>
|
>
|
||||||
{t('workflow.singleRun.startRun')}
|
{t('workflow.singleRun.startRun')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user