use-nodes-sync-draft.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { useCallback } from 'react'
  2. import produce from 'immer'
  3. import { useStoreApi } from 'reactflow'
  4. import { useParams } from 'next/navigation'
  5. import {
  6. useStore,
  7. useWorkflowStore,
  8. } from '../store'
  9. import { BlockEnum } from '../types'
  10. import { useNodesReadOnly } from './use-workflow'
  11. import { syncWorkflowDraft } from '@/service/workflow'
  12. import { useFeaturesStore } from '@/app/components/base/features/hooks'
  13. import { API_PREFIX } from '@/config'
  14. export const useNodesSyncDraft = () => {
  15. const store = useStoreApi()
  16. const workflowStore = useWorkflowStore()
  17. const featuresStore = useFeaturesStore()
  18. const { getNodesReadOnly } = useNodesReadOnly()
  19. const debouncedSyncWorkflowDraft = useStore(s => s.debouncedSyncWorkflowDraft)
  20. const params = useParams()
  21. const getPostParams = useCallback((appIdParams?: string) => {
  22. const {
  23. getNodes,
  24. edges,
  25. transform,
  26. } = store.getState()
  27. const [x, y, zoom] = transform
  28. const appId = workflowStore.getState().appId
  29. if (appId || appIdParams) {
  30. const nodes = getNodes()
  31. const hasStartNode = nodes.find(node => node.data.type === BlockEnum.Start)
  32. if (!hasStartNode)
  33. return
  34. const features = featuresStore!.getState().features
  35. const producedNodes = produce(nodes, (draft) => {
  36. draft.forEach((node) => {
  37. Object.keys(node.data).forEach((key) => {
  38. if (key.startsWith('_'))
  39. delete node.data[key]
  40. })
  41. })
  42. })
  43. const producedEdges = produce(edges, (draft) => {
  44. draft.forEach((edge) => {
  45. Object.keys(edge.data).forEach((key) => {
  46. if (key.startsWith('_'))
  47. delete edge.data[key]
  48. })
  49. })
  50. })
  51. return {
  52. url: `/apps/${appId || appIdParams}/workflows/draft`,
  53. params: {
  54. graph: {
  55. nodes: producedNodes,
  56. edges: producedEdges,
  57. viewport: {
  58. x,
  59. y,
  60. zoom,
  61. },
  62. },
  63. features: {
  64. opening_statement: features.opening?.opening_statement || '',
  65. suggested_questions: features.opening?.suggested_questions || [],
  66. suggested_questions_after_answer: features.suggested,
  67. text_to_speech: features.text2speech,
  68. speech_to_text: features.speech2text,
  69. retriever_resource: features.citation,
  70. sensitive_word_avoidance: features.moderation,
  71. file_upload: features.file,
  72. },
  73. },
  74. }
  75. }
  76. }, [store, featuresStore, workflowStore])
  77. const syncWorkflowDraftWhenPageClose = useCallback(() => {
  78. const postParams = getPostParams()
  79. if (postParams) {
  80. navigator.sendBeacon(
  81. `${API_PREFIX}/apps/${params.appId}/workflows/draft?_token=${localStorage.getItem('console_token')}`,
  82. JSON.stringify(postParams.params),
  83. )
  84. }
  85. }, [getPostParams, params.appId])
  86. const doSyncWorkflowDraft = useCallback(async (appId?: string) => {
  87. const postParams = getPostParams(appId)
  88. if (postParams) {
  89. const res = await syncWorkflowDraft(postParams)
  90. workflowStore.getState().setDraftUpdatedAt(res.updated_at)
  91. }
  92. }, [workflowStore, getPostParams])
  93. const handleSyncWorkflowDraft = useCallback((sync?: boolean, appId?: string) => {
  94. if (getNodesReadOnly())
  95. return
  96. if (sync)
  97. doSyncWorkflowDraft(appId)
  98. else
  99. debouncedSyncWorkflowDraft(doSyncWorkflowDraft)
  100. }, [debouncedSyncWorkflowDraft, doSyncWorkflowDraft, getNodesReadOnly])
  101. return {
  102. doSyncWorkflowDraft,
  103. handleSyncWorkflowDraft,
  104. syncWorkflowDraftWhenPageClose,
  105. }
  106. }