use-edges-interactions.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { useCallback } from 'react'
  2. import produce from 'immer'
  3. import type {
  4. EdgeMouseHandler,
  5. OnEdgesChange,
  6. } from 'reactflow'
  7. import {
  8. useStoreApi,
  9. } from 'reactflow'
  10. import type {
  11. Node,
  12. } from '../types'
  13. import { getNodesConnectedSourceOrTargetHandleIdsMap } from '../utils'
  14. import { useNodesSyncDraft } from './use-nodes-sync-draft'
  15. import { useNodesReadOnly } from './use-workflow'
  16. import { WorkflowHistoryEvent, useWorkflowHistory } from './use-workflow-history'
  17. export const useEdgesInteractions = () => {
  18. const store = useStoreApi()
  19. const { handleSyncWorkflowDraft } = useNodesSyncDraft()
  20. const { getNodesReadOnly } = useNodesReadOnly()
  21. const { saveStateToHistory } = useWorkflowHistory()
  22. const handleEdgeEnter = useCallback<EdgeMouseHandler>((_, edge) => {
  23. if (getNodesReadOnly())
  24. return
  25. const {
  26. edges,
  27. setEdges,
  28. } = store.getState()
  29. const newEdges = produce(edges, (draft) => {
  30. const currentEdge = draft.find(e => e.id === edge.id)!
  31. currentEdge.data._hovering = true
  32. })
  33. setEdges(newEdges)
  34. }, [store, getNodesReadOnly])
  35. const handleEdgeLeave = useCallback<EdgeMouseHandler>((_, edge) => {
  36. if (getNodesReadOnly())
  37. return
  38. const {
  39. edges,
  40. setEdges,
  41. } = store.getState()
  42. const newEdges = produce(edges, (draft) => {
  43. const currentEdge = draft.find(e => e.id === edge.id)!
  44. currentEdge.data._hovering = false
  45. })
  46. setEdges(newEdges)
  47. }, [store, getNodesReadOnly])
  48. const handleEdgeDeleteByDeleteBranch = useCallback((nodeId: string, branchId: string) => {
  49. if (getNodesReadOnly())
  50. return
  51. const {
  52. getNodes,
  53. setNodes,
  54. edges,
  55. setEdges,
  56. } = store.getState()
  57. const currentEdgeIndex = edges.findIndex(edge => edge.source === nodeId && edge.sourceHandle === branchId)
  58. if (currentEdgeIndex < 0)
  59. return
  60. const currentEdge = edges[currentEdgeIndex]
  61. const newNodes = produce(getNodes(), (draft: Node[]) => {
  62. const sourceNode = draft.find(node => node.id === currentEdge.source)
  63. const targetNode = draft.find(node => node.id === currentEdge.target)
  64. if (sourceNode)
  65. sourceNode.data._connectedSourceHandleIds = sourceNode.data._connectedSourceHandleIds?.filter(handleId => handleId !== currentEdge.sourceHandle)
  66. if (targetNode)
  67. targetNode.data._connectedTargetHandleIds = targetNode.data._connectedTargetHandleIds?.filter(handleId => handleId !== currentEdge.targetHandle)
  68. })
  69. setNodes(newNodes)
  70. const newEdges = produce(edges, (draft) => {
  71. draft.splice(currentEdgeIndex, 1)
  72. })
  73. setEdges(newEdges)
  74. handleSyncWorkflowDraft()
  75. saveStateToHistory(WorkflowHistoryEvent.EdgeDeleteByDeleteBranch)
  76. }, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory])
  77. const handleEdgeDelete = useCallback(() => {
  78. if (getNodesReadOnly())
  79. return
  80. const {
  81. getNodes,
  82. setNodes,
  83. edges,
  84. setEdges,
  85. } = store.getState()
  86. const currentEdgeIndex = edges.findIndex(edge => edge.selected)
  87. if (currentEdgeIndex < 0)
  88. return
  89. const currentEdge = edges[currentEdgeIndex]
  90. const nodes = getNodes()
  91. const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
  92. [
  93. { type: 'remove', edge: currentEdge },
  94. ],
  95. nodes,
  96. )
  97. const newNodes = produce(nodes, (draft: Node[]) => {
  98. draft.forEach((node) => {
  99. if (nodesConnectedSourceOrTargetHandleIdsMap[node.id]) {
  100. node.data = {
  101. ...node.data,
  102. ...nodesConnectedSourceOrTargetHandleIdsMap[node.id],
  103. }
  104. }
  105. })
  106. })
  107. setNodes(newNodes)
  108. const newEdges = produce(edges, (draft) => {
  109. draft.splice(currentEdgeIndex, 1)
  110. })
  111. setEdges(newEdges)
  112. handleSyncWorkflowDraft()
  113. saveStateToHistory(WorkflowHistoryEvent.EdgeDelete)
  114. }, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory])
  115. const handleEdgesChange = useCallback<OnEdgesChange>((changes) => {
  116. if (getNodesReadOnly())
  117. return
  118. const {
  119. edges,
  120. setEdges,
  121. } = store.getState()
  122. const newEdges = produce(edges, (draft) => {
  123. changes.forEach((change) => {
  124. if (change.type === 'select')
  125. draft.find(edge => edge.id === change.id)!.selected = change.selected
  126. })
  127. })
  128. setEdges(newEdges)
  129. }, [store, getNodesReadOnly])
  130. const handleEdgeCancelRunningStatus = useCallback(() => {
  131. const {
  132. edges,
  133. setEdges,
  134. } = store.getState()
  135. const newEdges = produce(edges, (draft) => {
  136. draft.forEach((edge) => {
  137. edge.data._run = false
  138. })
  139. })
  140. setEdges(newEdges)
  141. }, [store])
  142. return {
  143. handleEdgeEnter,
  144. handleEdgeLeave,
  145. handleEdgeDeleteByDeleteBranch,
  146. handleEdgeDelete,
  147. handleEdgesChange,
  148. handleEdgeCancelRunningStatus,
  149. }
  150. }