mirror of https://github.com/langgenius/dify.git
split hooks
This commit is contained in:
parent
64fa343d16
commit
a55a7603dd
|
|
@ -4,7 +4,7 @@ import {
|
|||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStore } from './store'
|
||||
import { useWorkflow } from './hooks'
|
||||
import { useNodesSyncDraft } from './hooks'
|
||||
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import {
|
||||
FeaturesChoose,
|
||||
|
|
@ -14,7 +14,7 @@ import {
|
|||
const Features = () => {
|
||||
const { t } = useTranslation()
|
||||
const setShowFeaturesPanel = useStore(state => state.setShowFeaturesPanel)
|
||||
const { handleSyncWorkflowDraft } = useWorkflow()
|
||||
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
|
||||
const handleFeaturesChange = useCallback(() => {
|
||||
handleSyncWorkflowDraft()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
|
|||
import { useStore } from '../store'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useWorkflow,
|
||||
useWorkflowRun,
|
||||
} from '../hooks'
|
||||
import RunAndHistory from './run-and-history'
|
||||
import EditingTitle from './editing-title'
|
||||
|
|
@ -24,15 +24,15 @@ const Header: FC = () => {
|
|||
const appSidebarExpand = useAppStore(s => s.appSidebarExpand)
|
||||
const isChatMode = useIsChatMode()
|
||||
const runningStatus = useStore(s => s.runningStatus)
|
||||
const { handleRunInit } = useWorkflow()
|
||||
const { handleRunSetting } = useWorkflowRun()
|
||||
|
||||
const handleShowFeatures = useCallback(() => {
|
||||
useStore.setState({ showFeaturesPanel: true })
|
||||
}, [])
|
||||
|
||||
const handleGoBackToEdit = useCallback(() => {
|
||||
handleRunInit(true)
|
||||
}, [handleRunInit])
|
||||
handleRunSetting(true)
|
||||
}, [handleRunSetting])
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
|
|||
import { useStore } from '../store'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useWorkflow,
|
||||
useWorkflowRun,
|
||||
} from '../hooks'
|
||||
import { WorkflowRunningStatus } from '../types'
|
||||
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
|
|
@ -54,11 +54,11 @@ RunMode.displayName = 'RunMode'
|
|||
|
||||
const PreviewMode = memo(() => {
|
||||
const { t } = useTranslation()
|
||||
const { handleRunInit } = useWorkflow()
|
||||
const { handleRunSetting } = useWorkflowRun()
|
||||
const runningStatus = useStore(s => s.runningStatus)
|
||||
|
||||
const handleClick = () => {
|
||||
handleRunInit()
|
||||
handleRunSetting()
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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 { useTranslation } from 'react-i18next'
|
||||
import produce from 'immer'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
import type {
|
||||
EdgeMouseHandler,
|
||||
NodeDragHandler,
|
||||
NodeMouseHandler,
|
||||
OnConnect,
|
||||
OnEdgesChange,
|
||||
Viewport,
|
||||
} from 'reactflow'
|
||||
import {
|
||||
Position,
|
||||
getConnectedEdges,
|
||||
getIncomers,
|
||||
getOutgoers,
|
||||
useReactFlow,
|
||||
useStoreApi,
|
||||
} 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 {
|
||||
BlockEnum,
|
||||
NodeRunningStatus,
|
||||
WorkflowRunningStatus,
|
||||
} from './types'
|
||||
import {
|
||||
NODES_EXTRA_DATA,
|
||||
NODES_INITIAL_DATA,
|
||||
NODE_WIDTH_X_OFFSET,
|
||||
Y_OFFSET,
|
||||
} from './constants'
|
||||
import {
|
||||
getLayoutByDagre,
|
||||
} 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'
|
||||
} from '../constants'
|
||||
import { useNodesInitialData } from './use-nodes-data'
|
||||
import { useNodesSyncDraft } from './use-nodes-sync-draft'
|
||||
|
||||
export const useIsChatMode = () => {
|
||||
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 = () => {
|
||||
export const useNodesInteractions = () => {
|
||||
const store = useStoreApi()
|
||||
const reactFlow = useReactFlow()
|
||||
const nodesInitialData = useNodesInitialData()
|
||||
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) => {
|
||||
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 { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
|
||||
const handleNodeDragStart = useCallback<NodeDragHandler>(() => {
|
||||
const {
|
||||
|
|
@ -164,8 +36,10 @@ export const useWorkflow = () => {
|
|||
setIsDragging,
|
||||
} = useStore.getState()
|
||||
|
||||
if (!runningStatus)
|
||||
setIsDragging(true)
|
||||
if (runningStatus)
|
||||
return
|
||||
|
||||
setIsDragging(true)
|
||||
}, [])
|
||||
|
||||
const handleNodeDrag = useCallback<NodeDragHandler>((e, node: Node) => {
|
||||
|
|
@ -433,25 +307,6 @@ export const useWorkflow = () => {
|
|||
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((
|
||||
currentNodeId: string,
|
||||
nodeType: BlockEnum,
|
||||
|
|
@ -636,196 +491,7 @@ export const useWorkflow = () => {
|
|||
}
|
||||
}, [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 {
|
||||
handleSyncWorkflowDraft,
|
||||
handleLayout,
|
||||
handleSetViewport,
|
||||
|
||||
handleNodeDragStart,
|
||||
handleNodeDrag,
|
||||
handleNodeDragStop,
|
||||
|
|
@ -835,94 +501,8 @@ export const useWorkflow = () => {
|
|||
handleNodeClick,
|
||||
handleNodeConnect,
|
||||
handleNodeDelete,
|
||||
handleNodeDataUpdate,
|
||||
handleNodeAddNext,
|
||||
handleNodeAddPrev,
|
||||
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
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
} from './types'
|
||||
import {
|
||||
useEdgesInteractions,
|
||||
useNodesInitialData,
|
||||
useWorkflow,
|
||||
useNodesInteractions,
|
||||
useNodesSyncDraft,
|
||||
} from './hooks'
|
||||
import Header from './header'
|
||||
import CustomNode from './nodes'
|
||||
|
|
@ -65,6 +67,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
}) => {
|
||||
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
|
||||
const runningStatus = useStore(s => s.runningStatus)
|
||||
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
|
||||
useEffect(() => {
|
||||
setAutoFreeze(false)
|
||||
|
|
@ -75,8 +78,6 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
}, [])
|
||||
|
||||
const {
|
||||
handleSyncWorkflowDraft,
|
||||
|
||||
handleNodeDragStart,
|
||||
handleNodeDrag,
|
||||
handleNodeDragStop,
|
||||
|
|
@ -84,12 +85,13 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
handleNodeLeave,
|
||||
handleNodeClick,
|
||||
handleNodeConnect,
|
||||
|
||||
} = useNodesInteractions()
|
||||
const {
|
||||
handleEdgeEnter,
|
||||
handleEdgeLeave,
|
||||
handleEdgeDelete,
|
||||
handleEdgesChange,
|
||||
} = useWorkflow()
|
||||
} = useEdgesInteractions()
|
||||
|
||||
useOnViewportChange({
|
||||
onEnd: () => handleSyncWorkflowDraft(),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
useCallback,
|
||||
} from 'react'
|
||||
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 { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
||||
|
|
@ -19,7 +19,7 @@ const Add = ({
|
|||
branchName,
|
||||
}: AddProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleNodeAddNext } = useWorkflow()
|
||||
const { handleNodeAddNext } = useNodesInteractions()
|
||||
|
||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||
handleNodeAddNext(nodeId, type, sourceHandle, toolDefaultValue)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import type {
|
|||
} from '@/app/components/workflow/types'
|
||||
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||
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'
|
||||
|
||||
type ItemProps = {
|
||||
|
|
@ -25,7 +25,7 @@ const Item = ({
|
|||
data,
|
||||
}: ItemProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleNodeChange } = useWorkflow()
|
||||
const { handleNodeChange } = useNodesInteractions()
|
||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
||||
}, [nodeId, sourceHandle, handleNodeChange])
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useWorkflow } from '../../../hooks'
|
||||
import { useNodeDataUpdate } from '../../../hooks'
|
||||
import type { Node } from '../../../types'
|
||||
import { canRunBySingle } from '../../../utils'
|
||||
import PanelOperator from './panel-operator'
|
||||
|
|
@ -22,7 +22,7 @@ const NodeControl: FC<NodeControlProps> = ({
|
|||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
const { handleNodeDataUpdate } = useWorkflow()
|
||||
const { handleNodeDataUpdate } = useNodeDataUpdate()
|
||||
|
||||
const handleOpenChange = useCallback((newOpen: boolean) => {
|
||||
setOpen(newOpen)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { BlockEnum } from '../../../types'
|
|||
import type { Node } from '../../../types'
|
||||
import BlockSelector from '../../../block-selector'
|
||||
import type { ToolDefaultValue } from '../../../block-selector/types'
|
||||
import { useWorkflow } from '../../../hooks'
|
||||
import { useNodesInteractions } from '../../../hooks'
|
||||
|
||||
type NodeHandleProps = {
|
||||
handleId: string
|
||||
|
|
@ -30,7 +30,7 @@ export const NodeTargetHandle = ({
|
|||
nodeSelectorClassName,
|
||||
}: NodeHandleProps) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
const { handleNodeAddPrev } = useWorkflow()
|
||||
const { handleNodeAddPrev } = useNodesInteractions()
|
||||
const edges = useEdges()
|
||||
const connectedEdges = getConnectedEdges([{ id } as Node], edges)
|
||||
const connected = connectedEdges.find(edge => edge.targetHandle === handleId && edge.target === id)
|
||||
|
|
@ -92,7 +92,7 @@ export const NodeSourceHandle = ({
|
|||
nodeSelectorClassName,
|
||||
}: NodeHandleProps) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
const { handleNodeAddNext } = useWorkflow()
|
||||
const { handleNodeAddNext } = useNodesInteractions()
|
||||
const edges = useEdges()
|
||||
const connectedEdges = getConnectedEdges([{ id } as Node], edges)
|
||||
const connected = connectedEdges.find(edge => edge.sourceHandle === handleId && edge.source === id)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
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'
|
||||
|
||||
type ChangeBlockProps = {
|
||||
|
|
@ -16,7 +16,7 @@ const ChangeBlock = ({
|
|||
sourceHandle,
|
||||
}: ChangeBlockProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleNodeChange } = useWorkflow()
|
||||
const { handleNodeChange } = useNodesInteractions()
|
||||
|
||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import ChangeBlock from './change-block'
|
|||
import { useStore } from '@/app/components/workflow/store'
|
||||
import {
|
||||
useNodesExtraData,
|
||||
useWorkflow,
|
||||
useNodesInteractions,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { DotsHorizontal } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import {
|
||||
|
|
@ -52,7 +52,7 @@ const PanelOperator = ({
|
|||
const { locale } = useContext(I18n)
|
||||
const language = getLanguage(locale)
|
||||
const edges = useEdges()
|
||||
const { handleNodeDelete } = useWorkflow()
|
||||
const { handleNodeDelete } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
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'
|
||||
const useNodeCrud = <T>(id: string, data: CommonNodeType<T>) => {
|
||||
const { handleNodeDataUpdate } = useWorkflow()
|
||||
const { handleNodeDataUpdateWithSyncDraft } = useNodeDataUpdate()
|
||||
|
||||
const setInputs = (newInputs: CommonNodeType<T>) => {
|
||||
handleNodeDataUpdate({
|
||||
handleNodeDataUpdateWithSyncDraft({
|
||||
id,
|
||||
data: newInputs,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState } from 'react'
|
||||
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 { InputVarType, NodeRunningStatus } from '@/app/components/workflow/types'
|
||||
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 [runResult, setRunResult] = useState<any>(null)
|
||||
|
||||
const { handleNodeDataUpdate }: { handleNodeDataUpdate: (data: any) => void } = useWorkflow()
|
||||
const { handleNodeDataUpdate }: { handleNodeDataUpdate: (data: any) => void } = useNodeDataUpdate()
|
||||
const isShowSingleRun = data._isSingleRun
|
||||
const hideSingleRun = () => {
|
||||
handleNodeDataUpdate({
|
||||
|
|
|
|||
|
|
@ -18,7 +18,10 @@ import {
|
|||
XClose,
|
||||
} from '@/app/components/base/icons/src/vender/line/general'
|
||||
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 { GitBranch01 } from '@/app/components/base/icons/src/vender/line/development'
|
||||
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
|
|
@ -36,18 +39,20 @@ const BasePanel: FC<BasePanelProps> = ({
|
|||
children,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleNodeSelect } = useNodesInteractions()
|
||||
const {
|
||||
handleNodeSelect,
|
||||
handleNodeDataUpdate,
|
||||
} = useWorkflow()
|
||||
handleNodeDataUpdateWithSyncDraft,
|
||||
} = useNodeDataUpdate()
|
||||
|
||||
const handleTitleChange = useCallback((title: string) => {
|
||||
if (!title)
|
||||
return
|
||||
handleNodeDataUpdate({ id, data: { ...data, title } })
|
||||
}, [handleNodeDataUpdate, id, data])
|
||||
handleNodeDataUpdateWithSyncDraft({ id, data: { ...data, title } })
|
||||
}, [handleNodeDataUpdateWithSyncDraft, id, data])
|
||||
const handleDescriptionChange = useCallback((desc: string) => {
|
||||
handleNodeDataUpdate({ id, data: { ...data, desc } })
|
||||
}, [handleNodeDataUpdate, id, data])
|
||||
handleNodeDataUpdateWithSyncDraft({ id, data: { ...data, desc } })
|
||||
}, [handleNodeDataUpdateWithSyncDraft, id, data])
|
||||
|
||||
return (
|
||||
<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 produce from 'immer'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useWorkflow } from '../../../hooks'
|
||||
import { useEdgesInteractions } from '../../../hooks'
|
||||
import AddButton from '../../_base/components/add-button'
|
||||
import Item from './class-item'
|
||||
import type { Topic } from '@/app/components/workflow/nodes/question-classifier/types'
|
||||
|
|
@ -22,7 +22,7 @@ const ClassList: FC<Props> = ({
|
|||
onChange,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleEdgeDeleteByDeleteBranch } = useWorkflow()
|
||||
const { handleEdgeDeleteByDeleteBranch } = useEdgesInteractions()
|
||||
|
||||
const handleClassChange = useCallback((index: number) => {
|
||||
return (value: Topic) => {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
useReactFlow,
|
||||
useViewport,
|
||||
} from 'reactflow'
|
||||
import { useWorkflow } from '../hooks'
|
||||
import { useNodesSyncDraft } from '../hooks'
|
||||
import { useStore } from '../store'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
|
|
@ -29,7 +29,7 @@ const ZoomInOut: FC = () => {
|
|||
fitView,
|
||||
} = useReactFlow()
|
||||
const { zoom } = useViewport()
|
||||
const { handleSyncWorkflowDraft } = useWorkflow()
|
||||
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
const [open, setOpen] = useState(false)
|
||||
const runningStatus = useStore(s => s.runningStatus)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export const useChat = (
|
|||
) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const run = useWorkflowRun()
|
||||
const { handleRun } = useWorkflowRun()
|
||||
const hasStopResponded = useRef(false)
|
||||
const connversationId = useRef('')
|
||||
const taskIdRef = useRef('')
|
||||
|
|
@ -126,7 +126,7 @@ export const useChat = (
|
|||
|
||||
let hasSetResponseId = false
|
||||
|
||||
run(
|
||||
handleRun(
|
||||
params,
|
||||
{
|
||||
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 {
|
||||
conversationId: connversationId.current,
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@ import { useNodes } from 'reactflow'
|
|||
import FormItem from '../nodes/_base/components/before-run-form/form-item'
|
||||
import { BlockEnum } from '../types'
|
||||
import { useStore } from '../store'
|
||||
import {
|
||||
useWorkflow,
|
||||
useWorkflowRun,
|
||||
} from '../hooks'
|
||||
import { useWorkflowRun } from '../hooks'
|
||||
import type { StartNodeType } from '../nodes/start/types'
|
||||
import Button from '@/app/components/base/button'
|
||||
|
||||
|
|
@ -18,8 +15,10 @@ const InputsPanel = () => {
|
|||
const { t } = useTranslation()
|
||||
const nodes = useNodes<StartNodeType>()
|
||||
const inputs = useStore(s => s.inputs)
|
||||
const run = useWorkflowRun()
|
||||
const { handleRunInit } = useWorkflow()
|
||||
const {
|
||||
handleRun,
|
||||
handleRunSetting,
|
||||
} = useWorkflowRun()
|
||||
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
|
||||
const variables = startNode?.data.variables || []
|
||||
|
||||
|
|
@ -34,10 +33,10 @@ const InputsPanel = () => {
|
|||
useStore.setState({ showInputsPanel: false })
|
||||
}, [])
|
||||
|
||||
const handleRun = () => {
|
||||
const doRun = () => {
|
||||
handleCancel()
|
||||
handleRunInit()
|
||||
run({ inputs })
|
||||
handleRunSetting()
|
||||
handleRun({ inputs })
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -72,7 +71,7 @@ const InputsPanel = () => {
|
|||
<Button
|
||||
type='primary'
|
||||
className='py-0 w-[190px] h-8 rounded-lg text-[13px] font-medium'
|
||||
onClick={handleRun}
|
||||
onClick={doRun}
|
||||
>
|
||||
{t('workflow.singleRun.startRun')}
|
||||
</Button>
|
||||
|
|
|
|||
Loading…
Reference in New Issue