use-workflow-interactions.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import {
  2. useCallback,
  3. useState,
  4. } from 'react'
  5. import { useTranslation } from 'react-i18next'
  6. import { useReactFlow } from 'reactflow'
  7. import { useWorkflowStore } from '../store'
  8. import { DSL_EXPORT_CHECK, WORKFLOW_DATA_UPDATE } from '../constants'
  9. import type { WorkflowDataUpdator } from '../types'
  10. import {
  11. initialEdges,
  12. initialNodes,
  13. } from '../utils'
  14. import { useEdgesInteractions } from './use-edges-interactions'
  15. import { useNodesInteractions } from './use-nodes-interactions'
  16. import { useNodesSyncDraft } from './use-nodes-sync-draft'
  17. import { useEventEmitterContextContext } from '@/context/event-emitter'
  18. import { fetchWorkflowDraft } from '@/service/workflow'
  19. import { exportAppConfig } from '@/service/apps'
  20. import { useToastContext } from '@/app/components/base/toast'
  21. import { useStore as useAppStore } from '@/app/components/app/store'
  22. export const useWorkflowInteractions = () => {
  23. const workflowStore = useWorkflowStore()
  24. const { handleNodeCancelRunningStatus } = useNodesInteractions()
  25. const { handleEdgeCancelRunningStatus } = useEdgesInteractions()
  26. const handleCancelDebugAndPreviewPanel = useCallback(() => {
  27. workflowStore.setState({
  28. showDebugAndPreviewPanel: false,
  29. workflowRunningData: undefined,
  30. })
  31. handleNodeCancelRunningStatus()
  32. handleEdgeCancelRunningStatus()
  33. }, [workflowStore, handleNodeCancelRunningStatus, handleEdgeCancelRunningStatus])
  34. return {
  35. handleCancelDebugAndPreviewPanel,
  36. }
  37. }
  38. export const useWorkflowUpdate = () => {
  39. const reactflow = useReactFlow()
  40. const workflowStore = useWorkflowStore()
  41. const { eventEmitter } = useEventEmitterContextContext()
  42. const handleUpdateWorkflowCanvas = useCallback((payload: WorkflowDataUpdator) => {
  43. const {
  44. nodes,
  45. edges,
  46. viewport,
  47. } = payload
  48. const { setViewport } = reactflow
  49. eventEmitter?.emit({
  50. type: WORKFLOW_DATA_UPDATE,
  51. payload: {
  52. nodes: initialNodes(nodes, edges),
  53. edges: initialEdges(edges, nodes),
  54. },
  55. } as any)
  56. setViewport(viewport)
  57. }, [eventEmitter, reactflow])
  58. const handleRefreshWorkflowDraft = useCallback(() => {
  59. const {
  60. appId,
  61. setSyncWorkflowDraftHash,
  62. setIsSyncingWorkflowDraft,
  63. setEnvironmentVariables,
  64. setEnvSecrets,
  65. } = workflowStore.getState()
  66. setIsSyncingWorkflowDraft(true)
  67. fetchWorkflowDraft(`/apps/${appId}/workflows/draft`).then((response) => {
  68. handleUpdateWorkflowCanvas(response.graph as WorkflowDataUpdator)
  69. setSyncWorkflowDraftHash(response.hash)
  70. setEnvSecrets((response.environment_variables || []).filter(env => env.value_type === 'secret').reduce((acc, env) => {
  71. acc[env.id] = env.value
  72. return acc
  73. }, {} as Record<string, string>))
  74. setEnvironmentVariables(response.environment_variables?.map(env => env.value_type === 'secret' ? { ...env, value: '[__HIDDEN__]' } : env) || [])
  75. }).finally(() => setIsSyncingWorkflowDraft(false))
  76. }, [handleUpdateWorkflowCanvas, workflowStore])
  77. return {
  78. handleUpdateWorkflowCanvas,
  79. handleRefreshWorkflowDraft,
  80. }
  81. }
  82. export const useDSL = () => {
  83. const { t } = useTranslation()
  84. const { notify } = useToastContext()
  85. const { eventEmitter } = useEventEmitterContextContext()
  86. const [exporting, setExporting] = useState(false)
  87. const { doSyncWorkflowDraft } = useNodesSyncDraft()
  88. const appDetail = useAppStore(s => s.appDetail)
  89. const handleExportDSL = useCallback(async (include = false) => {
  90. if (!appDetail)
  91. return
  92. if (exporting)
  93. return
  94. try {
  95. setExporting(true)
  96. await doSyncWorkflowDraft()
  97. const { data } = await exportAppConfig({
  98. appID: appDetail.id,
  99. include,
  100. })
  101. const a = document.createElement('a')
  102. const file = new Blob([data], { type: 'application/yaml' })
  103. a.href = URL.createObjectURL(file)
  104. a.download = `${appDetail.name}.yml`
  105. a.click()
  106. }
  107. catch (e) {
  108. notify({ type: 'error', message: t('app.exportFailed') })
  109. }
  110. finally {
  111. setExporting(false)
  112. }
  113. }, [appDetail, notify, t, doSyncWorkflowDraft, exporting])
  114. const exportCheck = useCallback(async () => {
  115. if (!appDetail)
  116. return
  117. try {
  118. const workflowDraft = await fetchWorkflowDraft(`/apps/${appDetail?.id}/workflows/draft`)
  119. const list = (workflowDraft.environment_variables || []).filter(env => env.value_type === 'secret')
  120. if (list.length === 0) {
  121. handleExportDSL()
  122. return
  123. }
  124. eventEmitter?.emit({
  125. type: DSL_EXPORT_CHECK,
  126. payload: {
  127. data: list,
  128. },
  129. } as any)
  130. }
  131. catch (e) {
  132. notify({ type: 'error', message: t('app.exportFailed') })
  133. }
  134. }, [appDetail, eventEmitter, handleExportDSL, notify, t])
  135. return {
  136. exportCheck,
  137. handleExportDSL,
  138. }
  139. }