use-edges-interactions.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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 edgeWillBeDeleted = edges.filter(edge => edge.source === nodeId && edge.sourceHandle === branchId)
  58. if (!edgeWillBeDeleted.length)
  59. return
  60. const nodes = getNodes()
  61. const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
  62. edgeWillBeDeleted.map(edge => ({ type: 'remove', edge })),
  63. nodes,
  64. )
  65. const newNodes = produce(nodes, (draft: Node[]) => {
  66. draft.forEach((node) => {
  67. if (nodesConnectedSourceOrTargetHandleIdsMap[node.id]) {
  68. node.data = {
  69. ...node.data,
  70. ...nodesConnectedSourceOrTargetHandleIdsMap[node.id],
  71. }
  72. }
  73. })
  74. })
  75. setNodes(newNodes)
  76. const newEdges = produce(edges, (draft) => {
  77. return draft.filter(edge => !edgeWillBeDeleted.find(e => e.id === edge.id))
  78. })
  79. setEdges(newEdges)
  80. handleSyncWorkflowDraft()
  81. saveStateToHistory(WorkflowHistoryEvent.EdgeDeleteByDeleteBranch)
  82. }, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory])
  83. const handleEdgeDelete = useCallback(() => {
  84. if (getNodesReadOnly())
  85. return
  86. const {
  87. getNodes,
  88. setNodes,
  89. edges,
  90. setEdges,
  91. } = store.getState()
  92. const currentEdgeIndex = edges.findIndex(edge => edge.selected)
  93. if (currentEdgeIndex < 0)
  94. return
  95. const currentEdge = edges[currentEdgeIndex]
  96. const nodes = getNodes()
  97. const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
  98. [
  99. { type: 'remove', edge: currentEdge },
  100. ],
  101. nodes,
  102. )
  103. const newNodes = produce(nodes, (draft: Node[]) => {
  104. draft.forEach((node) => {
  105. if (nodesConnectedSourceOrTargetHandleIdsMap[node.id]) {
  106. node.data = {
  107. ...node.data,
  108. ...nodesConnectedSourceOrTargetHandleIdsMap[node.id],
  109. }
  110. }
  111. })
  112. })
  113. setNodes(newNodes)
  114. const newEdges = produce(edges, (draft) => {
  115. draft.splice(currentEdgeIndex, 1)
  116. })
  117. setEdges(newEdges)
  118. handleSyncWorkflowDraft()
  119. saveStateToHistory(WorkflowHistoryEvent.EdgeDelete)
  120. }, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory])
  121. const handleEdgesChange = useCallback<OnEdgesChange>((changes) => {
  122. if (getNodesReadOnly())
  123. return
  124. const {
  125. edges,
  126. setEdges,
  127. } = store.getState()
  128. const newEdges = produce(edges, (draft) => {
  129. changes.forEach((change) => {
  130. if (change.type === 'select')
  131. draft.find(edge => edge.id === change.id)!.selected = change.selected
  132. })
  133. })
  134. setEdges(newEdges)
  135. }, [store, getNodesReadOnly])
  136. const handleEdgeCancelRunningStatus = useCallback(() => {
  137. const {
  138. edges,
  139. setEdges,
  140. } = store.getState()
  141. const newEdges = produce(edges, (draft) => {
  142. draft.forEach((edge) => {
  143. edge.data._sourceRunningStatus = undefined
  144. edge.data._targetRunningStatus = undefined
  145. edge.data._waitingRun = false
  146. })
  147. })
  148. setEdges(newEdges)
  149. }, [store])
  150. return {
  151. handleEdgeEnter,
  152. handleEdgeLeave,
  153. handleEdgeDeleteByDeleteBranch,
  154. handleEdgeDelete,
  155. handleEdgesChange,
  156. handleEdgeCancelRunningStatus,
  157. }
  158. }