mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 01:48:04 +08:00
refactor workflow
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
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'
|
||||
@ -16,3 +15,5 @@ export * from './use-shortcuts'
|
||||
export * from './use-workflow-interactions'
|
||||
export * from './use-workflow-mode'
|
||||
export * from './use-format-time-from-now'
|
||||
export * from './use-nodes-meta-data'
|
||||
export * from './use-available-blocks'
|
||||
|
||||
58
web/app/components/workflow/hooks/use-available-blocks.ts
Normal file
58
web/app/components/workflow/hooks/use-available-blocks.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import {
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { BlockEnum } from '../types'
|
||||
import { useNodesMetaData } from './use-nodes-meta-data'
|
||||
|
||||
const availableBlocksFilter = (nodeType: BlockEnum, inContainer?: boolean) => {
|
||||
if (inContainer && (nodeType === BlockEnum.Iteration || nodeType === BlockEnum.Loop || nodeType === BlockEnum.End))
|
||||
return false
|
||||
|
||||
if (!inContainer && nodeType === BlockEnum.LoopEnd)
|
||||
return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export const useAvailableBlocks = (nodeType?: BlockEnum, inContainer?: boolean) => {
|
||||
const {
|
||||
nodes: availableNodes,
|
||||
} = useNodesMetaData()
|
||||
const availableNodesType = useMemo(() => availableNodes.map(node => node.type), [availableNodes])
|
||||
const availablePrevBlocks = useMemo(() => {
|
||||
if (!nodeType || nodeType === BlockEnum.Start)
|
||||
return []
|
||||
|
||||
return availableNodesType
|
||||
}, [availableNodesType, nodeType])
|
||||
const availableNextBlocks = useMemo(() => {
|
||||
if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd)
|
||||
return []
|
||||
|
||||
return availableNodesType
|
||||
}, [availableNodesType, nodeType])
|
||||
|
||||
const getAvailableBlocks = useCallback((nodeType?: BlockEnum, inContainer?: boolean) => {
|
||||
let availablePrevBlocks = availableNodesType
|
||||
if (!nodeType || nodeType === BlockEnum.Start)
|
||||
availablePrevBlocks = []
|
||||
|
||||
let availableNextBlocks = availableNodesType
|
||||
if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd)
|
||||
availableNextBlocks = []
|
||||
|
||||
return {
|
||||
availablePrevBlocks: availablePrevBlocks.filter(nType => availableBlocksFilter(nType, inContainer)),
|
||||
availableNextBlocks: availableNextBlocks.filter(nType => availableBlocksFilter(nType, inContainer)),
|
||||
}
|
||||
}, [availableNodesType])
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
getAvailableBlocks,
|
||||
availablePrevBlocks: availablePrevBlocks.filter(nType => availableBlocksFilter(nType, inContainer)),
|
||||
availableNextBlocks: availableNextBlocks.filter(nType => availableBlocksFilter(nType, inContainer)),
|
||||
}
|
||||
}, [getAvailableBlocks, availablePrevBlocks, availableNextBlocks, inContainer])
|
||||
}
|
||||
@ -22,7 +22,7 @@ import {
|
||||
} from '../constants'
|
||||
import type { ToolNodeType } from '../nodes/tool/types'
|
||||
import { useIsChatMode } from './use-workflow'
|
||||
import { useNodesExtraData } from './use-nodes-data'
|
||||
import { useNodesMetaData } from './use-nodes-meta-data'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
@ -37,7 +37,7 @@ import { fetchDatasets } from '@/service/datasets'
|
||||
export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
||||
const { t } = useTranslation()
|
||||
const language = useGetLanguage()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const { nodesMap: nodesExtraData } = useNodesMetaData()
|
||||
const isChatMode = useIsChatMode()
|
||||
const buildInTools = useStore(s => s.buildInTools)
|
||||
const customTools = useStore(s => s.customTools)
|
||||
@ -100,7 +100,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
||||
|
||||
if (node.type === CUSTOM_NODE) {
|
||||
const checkData = getCheckData(node.data)
|
||||
const { errorMessage } = nodesExtraData[node.data.type].checkValid(checkData, t, moreDataForCheckValid)
|
||||
const { errorMessage } = nodesExtraData![node.data.type].checkValid(checkData, t, moreDataForCheckValid)
|
||||
|
||||
if (errorMessage || !validNodes.find(n => n.id === node.id)) {
|
||||
list.push({
|
||||
@ -148,7 +148,7 @@ export const useChecklistBeforePublish = () => {
|
||||
const { notify } = useToastContext()
|
||||
const isChatMode = useIsChatMode()
|
||||
const store = useStoreApi()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const { nodesMap: nodesExtraData } = useNodesMetaData()
|
||||
const { data: strategyProviders } = useStrategyProviders()
|
||||
const updateDatasetsDetail = useDatasetsDetailStore(s => s.updateDatasetsDetail)
|
||||
const updateTime = useRef(0)
|
||||
@ -228,7 +228,7 @@ export const useChecklistBeforePublish = () => {
|
||||
}
|
||||
|
||||
const checkData = getCheckData(node.data, datasets)
|
||||
const { errorMessage } = nodesExtraData[node.data.type as BlockEnum].checkValid(checkData, t, moreDataForCheckValid)
|
||||
const { errorMessage } = nodesExtraData![node.data.type as BlockEnum].checkValid(checkData, t, moreDataForCheckValid)
|
||||
|
||||
if (errorMessage) {
|
||||
notify({ type: 'error', message: `[${node.data.title}] ${errorMessage}` })
|
||||
|
||||
@ -1,77 +0,0 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import produce from 'immer'
|
||||
import { BlockEnum } from '../types'
|
||||
import {
|
||||
NODES_EXTRA_DATA,
|
||||
NODES_INITIAL_DATA,
|
||||
} from '../constants'
|
||||
import { useIsChatMode } from './use-workflow'
|
||||
|
||||
export const useNodesInitialData = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return useMemo(() => produce(NODES_INITIAL_DATA, (draft) => {
|
||||
Object.keys(draft).forEach((key) => {
|
||||
draft[key as BlockEnum].title = t(`workflow.blocks.${key}`)
|
||||
})
|
||||
}), [t])
|
||||
}
|
||||
|
||||
export const useNodesExtraData = () => {
|
||||
const { t } = useTranslation()
|
||||
const isChatMode = useIsChatMode()
|
||||
|
||||
return useMemo(() => produce(NODES_EXTRA_DATA, (draft) => {
|
||||
Object.keys(draft).forEach((key) => {
|
||||
draft[key as BlockEnum].about = t(`workflow.blocksAbout.${key}`)
|
||||
draft[key as BlockEnum].availablePrevNodes = draft[key as BlockEnum].getAvailablePrevNodes(isChatMode)
|
||||
draft[key as BlockEnum].availableNextNodes = draft[key as BlockEnum].getAvailableNextNodes(isChatMode)
|
||||
})
|
||||
}), [t, isChatMode])
|
||||
}
|
||||
|
||||
export const useAvailableBlocks = (nodeType?: BlockEnum, isInIteration?: boolean, isInLoop?: boolean) => {
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const availablePrevBlocks = useMemo(() => {
|
||||
if (!nodeType)
|
||||
return []
|
||||
return nodesExtraData[nodeType].availablePrevNodes || []
|
||||
}, [nodeType, nodesExtraData])
|
||||
|
||||
const availableNextBlocks = useMemo(() => {
|
||||
if (!nodeType)
|
||||
return []
|
||||
|
||||
return nodesExtraData[nodeType].availableNextNodes || []
|
||||
}, [nodeType, nodesExtraData])
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
availablePrevBlocks: availablePrevBlocks.filter((nType) => {
|
||||
if (isInIteration && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
|
||||
return false
|
||||
|
||||
if (isInLoop && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
|
||||
return false
|
||||
|
||||
if (!isInLoop && nType === BlockEnum.LoopEnd)
|
||||
return false
|
||||
|
||||
return true
|
||||
}),
|
||||
availableNextBlocks: availableNextBlocks.filter((nType) => {
|
||||
if (isInIteration && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
|
||||
return false
|
||||
|
||||
if (isInLoop && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
|
||||
return false
|
||||
|
||||
if (!isInLoop && nType === BlockEnum.LoopEnd)
|
||||
return false
|
||||
|
||||
return true
|
||||
}),
|
||||
}
|
||||
}, [isInIteration, availablePrevBlocks, availableNextBlocks, isInLoop])
|
||||
}
|
||||
@ -31,7 +31,6 @@ import {
|
||||
ITERATION_PADDING,
|
||||
LOOP_CHILDREN_Z_INDEX,
|
||||
LOOP_PADDING,
|
||||
NODES_INITIAL_DATA,
|
||||
NODE_WIDTH_X_OFFSET,
|
||||
X_OFFSET,
|
||||
Y_OFFSET,
|
||||
@ -60,6 +59,7 @@ import {
|
||||
useWorkflowReadOnly,
|
||||
} from './use-workflow'
|
||||
import { WorkflowHistoryEvent, useWorkflowHistory } from './use-workflow-history'
|
||||
import { useNodesMetaData } from './use-nodes-meta-data'
|
||||
|
||||
export const useNodesInteractions = () => {
|
||||
const { t } = useTranslation()
|
||||
@ -84,6 +84,7 @@ export const useNodesInteractions = () => {
|
||||
handleNodeLoopChildrenCopy,
|
||||
} = useNodeLoopInteractions()
|
||||
const dragNodeStartPosition = useRef({ x: 0, y: 0 } as { x: number; y: number })
|
||||
const { nodesMap: nodesMetaDataMap } = useNodesMetaData()
|
||||
|
||||
const { saveStateToHistory, undo, redo } = useWorkflowHistory()
|
||||
|
||||
@ -682,6 +683,10 @@ export const useNodesInteractions = () => {
|
||||
} = store.getState()
|
||||
const nodes = getNodes()
|
||||
const nodesWithSameType = nodes.filter(node => node.data.type === nodeType)
|
||||
const {
|
||||
defaultValue,
|
||||
title,
|
||||
} = nodesMetaDataMap![nodeType]
|
||||
const {
|
||||
newNode,
|
||||
newIterationStartNode,
|
||||
@ -689,8 +694,8 @@ export const useNodesInteractions = () => {
|
||||
} = generateNewNode({
|
||||
type: getNodeCustomTypeByNodeDataType(nodeType),
|
||||
data: {
|
||||
...NODES_INITIAL_DATA[nodeType],
|
||||
title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${nodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${nodeType}`),
|
||||
...(defaultValue as any),
|
||||
title: nodesWithSameType.length > 0 ? `${title} ${nodesWithSameType.length + 1}` : title,
|
||||
...(toolDefaultValue || {}),
|
||||
selected: true,
|
||||
_showAddVariablePopup: (nodeType === BlockEnum.VariableAssigner || nodeType === BlockEnum.VariableAggregator) && !!prevNodeId,
|
||||
@ -1093,7 +1098,7 @@ export const useNodesInteractions = () => {
|
||||
}
|
||||
handleSyncWorkflowDraft()
|
||||
saveStateToHistory(WorkflowHistoryEvent.NodeAdd)
|
||||
}, [getNodesReadOnly, store, t, handleSyncWorkflowDraft, saveStateToHistory, workflowStore, getAfterNodesInSameBranch, checkNestedParallelLimit])
|
||||
}, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory, workflowStore, getAfterNodesInSameBranch, checkNestedParallelLimit, nodesMetaDataMap])
|
||||
|
||||
const handleNodeChange = useCallback((
|
||||
currentNodeId: string,
|
||||
@ -1114,6 +1119,10 @@ export const useNodesInteractions = () => {
|
||||
const currentNode = nodes.find(node => node.id === currentNodeId)!
|
||||
const connectedEdges = getConnectedEdges([currentNode], edges)
|
||||
const nodesWithSameType = nodes.filter(node => node.data.type === nodeType)
|
||||
const {
|
||||
defaultValue,
|
||||
title,
|
||||
} = nodesMetaDataMap![nodeType]
|
||||
const {
|
||||
newNode: newCurrentNode,
|
||||
newIterationStartNode,
|
||||
@ -1121,8 +1130,8 @@ export const useNodesInteractions = () => {
|
||||
} = generateNewNode({
|
||||
type: getNodeCustomTypeByNodeDataType(nodeType),
|
||||
data: {
|
||||
...NODES_INITIAL_DATA[nodeType],
|
||||
title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${nodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${nodeType}`),
|
||||
...(defaultValue as any),
|
||||
title: nodesWithSameType.length > 0 ? `${title} ${nodesWithSameType.length + 1}` : title,
|
||||
...(toolDefaultValue || {}),
|
||||
_connectedSourceHandleIds: [],
|
||||
_connectedTargetHandleIds: [],
|
||||
@ -1175,7 +1184,7 @@ export const useNodesInteractions = () => {
|
||||
handleSyncWorkflowDraft()
|
||||
|
||||
saveStateToHistory(WorkflowHistoryEvent.NodeChange)
|
||||
}, [getNodesReadOnly, store, t, handleSyncWorkflowDraft, saveStateToHistory])
|
||||
}, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory, nodesMetaDataMap])
|
||||
|
||||
const handleNodesCancelSelected = useCallback(() => {
|
||||
const {
|
||||
@ -1285,7 +1294,7 @@ export const useNodesInteractions = () => {
|
||||
} = generateNewNode({
|
||||
type: nodeToPaste.type,
|
||||
data: {
|
||||
...NODES_INITIAL_DATA[nodeType],
|
||||
...nodesMetaDataMap![nodeType].defaultValue,
|
||||
...nodeToPaste.data,
|
||||
selected: false,
|
||||
_isBundled: false,
|
||||
@ -1361,7 +1370,7 @@ export const useNodesInteractions = () => {
|
||||
saveStateToHistory(WorkflowHistoryEvent.NodePaste)
|
||||
handleSyncWorkflowDraft()
|
||||
}
|
||||
}, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy, handleNodeLoopChildrenCopy])
|
||||
}, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy, handleNodeLoopChildrenCopy, nodesMetaDataMap])
|
||||
|
||||
const handleNodesDuplicate = useCallback((nodeId?: string) => {
|
||||
if (getNodesReadOnly())
|
||||
|
||||
14
web/app/components/workflow/hooks/use-nodes-meta-data.ts
Normal file
14
web/app/components/workflow/hooks/use-nodes-meta-data.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { useMemo } from 'react'
|
||||
import type { AvailableNodesMetaData } from '@/app/components/workflow/hooks-store'
|
||||
import { useHooksStore } from '@/app/components/workflow/hooks-store'
|
||||
|
||||
export const useNodesMetaData = () => {
|
||||
const availableNodesMetaData = useHooksStore(s => s.availableNodesMetaData)
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
nodes: availableNodesMetaData?.nodes || [],
|
||||
nodesMap: availableNodesMetaData?.nodesMap || {},
|
||||
} as AvailableNodesMetaData
|
||||
}, [availableNodesMetaData])
|
||||
}
|
||||
@ -32,7 +32,7 @@ import {
|
||||
} from '../constants'
|
||||
import { CUSTOM_NOTE_NODE } from '../note-node/constants'
|
||||
import { findUsedVarNodes, getNodeOutputVars, updateNodeVars } from '../nodes/_base/components/variable/utils'
|
||||
import { useNodesExtraData } from './use-nodes-data'
|
||||
import { useAvailableBlocks } from './use-available-blocks'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import {
|
||||
fetchAllBuiltInTools,
|
||||
@ -55,7 +55,7 @@ export const useWorkflow = () => {
|
||||
const { t } = useTranslation()
|
||||
const store = useStoreApi()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const { getAvailableBlocks } = useAvailableBlocks()
|
||||
const setPanelWidth = useCallback((width: number) => {
|
||||
localStorage.setItem('workflow-node-panel-width', `${width}`)
|
||||
workflowStore.setState({ panelWidth: width })
|
||||
@ -361,8 +361,8 @@ export const useWorkflow = () => {
|
||||
return false
|
||||
|
||||
if (sourceNode && targetNode) {
|
||||
const sourceNodeAvailableNextNodes = nodesExtraData[sourceNode.data.type].availableNextNodes
|
||||
const targetNodeAvailablePrevNodes = [...nodesExtraData[targetNode.data.type].availablePrevNodes, BlockEnum.Start]
|
||||
const sourceNodeAvailableNextNodes = getAvailableBlocks(sourceNode.data.type, !!sourceNode.parentId).availableNextBlocks
|
||||
const targetNodeAvailablePrevNodes = getAvailableBlocks(targetNode.data.type, !!targetNode.parentId).availablePrevBlocks
|
||||
|
||||
if (!sourceNodeAvailableNextNodes.includes(targetNode.data.type))
|
||||
return false
|
||||
@ -386,7 +386,7 @@ export const useWorkflow = () => {
|
||||
}
|
||||
|
||||
return !hasCycle(targetNode)
|
||||
}, [store, nodesExtraData, checkParallelLimit])
|
||||
}, [store, checkParallelLimit, getAvailableBlocks])
|
||||
|
||||
const getNode = useCallback((nodeId?: string) => {
|
||||
const { getNodes } = store.getState()
|
||||
|
||||
Reference in New Issue
Block a user