update-dsl-modal.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. 'use client'
  2. import type { MouseEventHandler } from 'react'
  3. import {
  4. memo,
  5. useCallback,
  6. useRef,
  7. useState,
  8. } from 'react'
  9. import { useContext } from 'use-context-selector'
  10. import { useTranslation } from 'react-i18next'
  11. import {
  12. RiAlertLine,
  13. RiCloseLine,
  14. } from '@remixicon/react'
  15. import { WORKFLOW_DATA_UPDATE } from './constants'
  16. import {
  17. initialEdges,
  18. initialNodes,
  19. } from './utils'
  20. import Uploader from '@/app/components/app/create-from-dsl-modal/uploader'
  21. import Button from '@/app/components/base/button'
  22. import Modal from '@/app/components/base/modal'
  23. import { ToastContext } from '@/app/components/base/toast'
  24. import { updateWorkflowDraftFromDSL } from '@/service/workflow'
  25. import { useEventEmitterContextContext } from '@/context/event-emitter'
  26. import { useStore as useAppStore } from '@/app/components/app/store'
  27. type UpdateDSLModalProps = {
  28. onCancel: () => void
  29. onBackup: () => void
  30. onImport?: () => void
  31. }
  32. const UpdateDSLModal = ({
  33. onCancel,
  34. onBackup,
  35. onImport,
  36. }: UpdateDSLModalProps) => {
  37. const { t } = useTranslation()
  38. const { notify } = useContext(ToastContext)
  39. const appDetail = useAppStore(s => s.appDetail)
  40. const [currentFile, setDSLFile] = useState<File>()
  41. const [fileContent, setFileContent] = useState<string>()
  42. const [loading, setLoading] = useState(false)
  43. const { eventEmitter } = useEventEmitterContextContext()
  44. const readFile = (file: File) => {
  45. const reader = new FileReader()
  46. reader.onload = function (event) {
  47. const content = event.target?.result
  48. setFileContent(content as string)
  49. }
  50. reader.readAsText(file)
  51. }
  52. const handleFile = (file?: File) => {
  53. setDSLFile(file)
  54. if (file)
  55. readFile(file)
  56. if (!file)
  57. setFileContent('')
  58. }
  59. const isCreatingRef = useRef(false)
  60. const handleImport: MouseEventHandler = useCallback(async () => {
  61. if (isCreatingRef.current)
  62. return
  63. isCreatingRef.current = true
  64. if (!currentFile)
  65. return
  66. try {
  67. if (appDetail && fileContent) {
  68. setLoading(true)
  69. const {
  70. graph,
  71. features,
  72. hash,
  73. } = await updateWorkflowDraftFromDSL(appDetail.id, fileContent)
  74. const { nodes, edges, viewport } = graph
  75. eventEmitter?.emit({
  76. type: WORKFLOW_DATA_UPDATE,
  77. payload: {
  78. nodes: initialNodes(nodes, edges),
  79. edges: initialEdges(edges, nodes),
  80. viewport,
  81. features,
  82. hash,
  83. },
  84. } as any)
  85. if (onImport)
  86. onImport()
  87. notify({ type: 'success', message: t('workflow.common.importSuccess') })
  88. setLoading(false)
  89. onCancel()
  90. }
  91. }
  92. catch (e) {
  93. setLoading(false)
  94. notify({ type: 'error', message: t('workflow.common.importFailure') })
  95. }
  96. isCreatingRef.current = false
  97. }, [currentFile, fileContent, onCancel, notify, t, eventEmitter, appDetail, onImport])
  98. return (
  99. <Modal
  100. className='p-6 w-[520px] rounded-2xl'
  101. isShow={true}
  102. onClose={() => {}}
  103. >
  104. <div className='flex items-center justify-between mb-6'>
  105. <div className='text-2xl font-semibold text-[#101828]'>{t('workflow.common.importDSL')}</div>
  106. <div className='flex items-center justify-center w-[22px] h-[22px] cursor-pointer' onClick={onCancel}>
  107. <RiCloseLine className='w-5 h-5 text-gray-500' />
  108. </div>
  109. </div>
  110. <div className='flex mb-4 px-4 py-3 bg-[#FFFAEB] rounded-xl border border-[#FEDF89]'>
  111. <RiAlertLine className='shrink-0 mt-0.5 mr-2 w-4 h-4 text-[#F79009]' />
  112. <div>
  113. <div className='mb-2 text-sm font-medium text-[#354052]'>{t('workflow.common.importDSLTip')}</div>
  114. <Button
  115. variant='secondary-accent'
  116. onClick={onBackup}
  117. >
  118. {t('workflow.common.backupCurrentDraft')}
  119. </Button>
  120. </div>
  121. </div>
  122. <div className='mb-8'>
  123. <div className='mb-1 text-[13px] font-semibold text-[#354052]'>
  124. {t('workflow.common.chooseDSL')}
  125. </div>
  126. <Uploader
  127. file={currentFile}
  128. updateFile={handleFile}
  129. className='!mt-0'
  130. />
  131. </div>
  132. <div className='flex justify-end'>
  133. <Button className='mr-2' onClick={onCancel}>{t('app.newApp.Cancel')}</Button>
  134. <Button
  135. disabled={!currentFile || loading}
  136. variant='warning'
  137. onClick={handleImport}
  138. loading={loading}
  139. >
  140. {t('workflow.common.overwriteAndImport')}
  141. </Button>
  142. </div>
  143. </Modal>
  144. )
  145. }
  146. export default memo(UpdateDSLModal)