123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- import { useCallback } from 'react'
- import {
- useEdges,
- useNodes,
- useStoreApi,
- } from 'reactflow'
- import { useTranslation } from 'react-i18next'
- import { uniqBy } from 'lodash-es'
- import produce from 'immer'
- import {
- useIsChatMode,
- useNodeDataUpdate,
- useWorkflow,
- } from '../../hooks'
- import { getNodesConnectedSourceOrTargetHandleIdsMap } from '../../utils'
- import type {
- Edge,
- Node,
- ValueSelector,
- Var,
- } from '../../types'
- import { useWorkflowStore } from '../../store'
- import type {
- VarGroupItem,
- VariableAssignerNodeType,
- } from './types'
- import { toNodeAvailableVars } from '@/app/components/workflow/nodes/_base/components/variable/utils'
- export const useVariableAssigner = () => {
- const store = useStoreApi()
- const workflowStore = useWorkflowStore()
- const { handleNodeDataUpdate } = useNodeDataUpdate()
- const handleAssignVariableValueChange = useCallback((nodeId: string, value: ValueSelector, varDetail: Var, groupId?: string) => {
- const { getNodes } = store.getState()
- const nodes = getNodes()
- const node: Node<VariableAssignerNodeType> = nodes.find(node => node.id === nodeId)!
- let payload
- if (groupId && groupId !== 'target') {
- payload = {
- advanced_settings: {
- ...node.data.advanced_settings,
- groups: node.data.advanced_settings?.groups.map((group: VarGroupItem & { groupId: string }) => {
- if (group.groupId === groupId && !group.variables.some(item => item.join('.') === (value as ValueSelector).join('.'))) {
- return {
- ...group,
- variables: [...group.variables, value],
- output_type: varDetail.type,
- }
- }
- return group
- }),
- },
- }
- }
- else {
- if (node.data.variables.some(item => item.join('.') === (value as ValueSelector).join('.')))
- return
- payload = {
- variables: [...node.data.variables, value],
- output_type: varDetail.type,
- }
- }
- handleNodeDataUpdate({
- id: nodeId,
- data: payload,
- })
- }, [store, handleNodeDataUpdate])
- const handleAddVariableInAddVariablePopupWithPosition = useCallback((
- nodeId: string,
- variableAssignerNodeId: string,
- variableAssignerNodeHandleId: string,
- value: ValueSelector,
- varDetail: Var,
- ) => {
- const {
- getNodes,
- setNodes,
- } = store.getState()
- const {
- setShowAssignVariablePopup,
- } = workflowStore.getState()
- const newNodes = produce(getNodes(), (draft) => {
- draft.forEach((node) => {
- if (node.id === nodeId || node.id === variableAssignerNodeId) {
- node.data = {
- ...node.data,
- _showAddVariablePopup: false,
- _holdAddVariablePopup: false,
- }
- }
- })
- })
- setNodes(newNodes)
- setShowAssignVariablePopup(undefined)
- handleAssignVariableValueChange(variableAssignerNodeId, value, varDetail, variableAssignerNodeHandleId)
- }, [store, workflowStore, handleAssignVariableValueChange])
- const handleRemoveEdges = useCallback((nodeId: string, enabled: boolean) => {
- const {
- getNodes,
- setNodes,
- edges,
- setEdges,
- } = store.getState()
- const nodes = getNodes()
- const needDeleteEdges = edges.filter(edge => edge.target === nodeId)
- if (!needDeleteEdges.length)
- return
- const currentNode = nodes.find(node => node.id === nodeId)!
- const groups = currentNode.data.advanced_settings?.groups || []
- let shouldKeepEdges: Edge[] = []
- if (enabled) {
- shouldKeepEdges = edges.filter((edge) => {
- return edge.target === nodeId && edge.targetHandle === 'target'
- }).map((edge) => {
- return {
- ...edge,
- targetHandle: groups[0].groupId,
- }
- })
- }
- else {
- shouldKeepEdges = edges.filter((edge) => {
- return edge.target === nodeId && edge.targetHandle === groups[0].groupId
- }).map((edge) => {
- return {
- ...edge,
- targetHandle: 'target',
- }
- })
- }
- const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
- [
- ...needDeleteEdges.map((needDeleteEdge) => {
- return {
- type: 'remove',
- edge: needDeleteEdge,
- }
- }),
- ...shouldKeepEdges.map((shouldKeepEdge) => {
- return {
- type: 'add',
- edge: shouldKeepEdge,
- }
- }),
- ],
- nodes,
- )
- const newNodes = produce(nodes, (draft) => {
- draft.forEach((node) => {
- if (nodesConnectedSourceOrTargetHandleIdsMap[node.id]) {
- node.data = {
- ...node.data,
- ...nodesConnectedSourceOrTargetHandleIdsMap[node.id],
- }
- }
- })
- })
- setNodes(newNodes)
- const newEdges = produce(edges, (draft) => {
- draft = draft.filter(edge => edge.target !== nodeId)
- draft.push(...shouldKeepEdges)
- return draft
- })
- setEdges(newEdges)
- }, [store])
- const handleGroupItemMouseEnter = useCallback((groupId: string) => {
- const {
- setHoveringAssignVariableGroupId,
- } = workflowStore.getState()
- setHoveringAssignVariableGroupId(groupId)
- }, [workflowStore])
- const handleGroupItemMouseLeave = useCallback(() => {
- const {
- connectingNodePayload,
- setHoveringAssignVariableGroupId,
- } = workflowStore.getState()
- if (connectingNodePayload)
- setHoveringAssignVariableGroupId(undefined)
- }, [workflowStore])
- return {
- handleAddVariableInAddVariablePopupWithPosition,
- handleRemoveEdges,
- handleGroupItemMouseEnter,
- handleGroupItemMouseLeave,
- handleAssignVariableValueChange,
- }
- }
- export const useGetAvailableVars = () => {
- const { t } = useTranslation()
- const nodes: Node[] = useNodes()
- const edges: Edge[] = useEdges()
- const { getBeforeNodesInSameBranch } = useWorkflow()
- const isChatMode = useIsChatMode()
- const getAvailableVars = useCallback((nodeId: string, handleId: string, filterVar: (v: Var) => boolean) => {
- const availableNodes: Node[] = []
- const currentNode = nodes.find(node => node.id === nodeId)!
- if (!currentNode)
- return []
- const parentNode = nodes.find(node => node.id === currentNode.parentId)
- const connectedEdges = edges.filter(edge => edge.target === nodeId && edge.targetHandle === handleId)
- if (parentNode && !connectedEdges.length) {
- const beforeNodes = getBeforeNodesInSameBranch(parentNode.id)
- availableNodes.push(...beforeNodes)
- }
- else {
- connectedEdges.forEach((connectedEdge) => {
- const beforeNodes = getBeforeNodesInSameBranch(connectedEdge.source)
- const connectedNode = nodes.find(node => node.id === connectedEdge.source)!
- availableNodes.push(connectedNode, ...beforeNodes)
- })
- }
- return toNodeAvailableVars({
- parentNode,
- t,
- beforeNodes: uniqBy(availableNodes, 'id').filter(node => node.id !== nodeId),
- isChatMode,
- filterVar,
- })
- }, [nodes, edges, t, isChatMode, getBeforeNodesInSameBranch])
- return getAvailableVars
- }
|