file-tree-upload-conflicts.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import { FileTreeEntity } from '../../../../../../types/file-tree-entity'
  2. import { useTranslation } from 'react-i18next'
  3. import { useProjectContext } from '@/shared/context/project-context'
  4. import { useCallback } from 'react'
  5. import { syncDelete } from '@/features/file-tree/util/sync-mutation'
  6. import { TFunction } from 'i18next'
  7. import OLButton from '@/shared/components/ol/ol-button'
  8. export type Conflict = {
  9. entity: FileTreeEntity
  10. type: 'file' | 'folder'
  11. }
  12. const getConflictText = (conflicts: Conflict[], t: TFunction) => {
  13. const hasFolderConflict = conflicts.some(
  14. conflict => conflict.type === 'folder'
  15. )
  16. const hasFileConflict = conflicts.some(conflict => conflict.type === 'file')
  17. if (hasFolderConflict && hasFileConflict) {
  18. return t('the_following_files_and_folders_already_exist_in_this_project')
  19. }
  20. if (hasFolderConflict) {
  21. return t('the_following_folder_already_exists_in_this_project', {
  22. count: conflicts.length,
  23. })
  24. }
  25. return t('the_following_files_already_exist_in_this_project')
  26. }
  27. export function FileUploadConflicts({
  28. cancel,
  29. conflicts,
  30. handleOverwrite,
  31. }: {
  32. cancel: () => void
  33. conflicts: Conflict[]
  34. handleOverwrite: () => void
  35. }) {
  36. const { t } = useTranslation()
  37. // Don't allow overwriting folders with files
  38. const hasFolderConflict = conflicts.some(
  39. conflict => conflict.type === 'folder'
  40. )
  41. return (
  42. <div className="small modal-new-file-body-conflict">
  43. {conflicts.length > 0 && (
  44. <>
  45. <p className="text-center mb-0">{getConflictText(conflicts, t)}</p>
  46. <ul className="text-center list-unstyled row-spaced-small mt-1">
  47. {conflicts.map((conflict, index) => (
  48. <li key={index}>
  49. <strong>{conflict.entity.name}</strong>
  50. </li>
  51. ))}
  52. </ul>
  53. </>
  54. )}
  55. {!hasFolderConflict && (
  56. <p className="text-center row-spaced-small">
  57. {t('do_you_want_to_overwrite_them')}
  58. </p>
  59. )}
  60. <p className="text-center">
  61. <OLButton variant="secondary" onClick={cancel}>
  62. {t('cancel')}
  63. </OLButton>
  64. &nbsp;
  65. {!hasFolderConflict && (
  66. <OLButton variant="danger" onClick={handleOverwrite}>
  67. {t('overwrite')}
  68. </OLButton>
  69. )}
  70. </p>
  71. </div>
  72. )
  73. }
  74. export function FolderUploadConflicts({
  75. cancel,
  76. handleOverwrite,
  77. conflicts,
  78. setError,
  79. }: {
  80. cancel: () => void
  81. handleOverwrite: () => void
  82. conflicts: Conflict[]
  83. setError: (error: string) => void
  84. }) {
  85. const { t } = useTranslation()
  86. const { projectId } = useProjectContext()
  87. // Don't allow overwriting files with a folder
  88. const hasFileConflict = conflicts.some(conflict => conflict.type === 'file')
  89. const deleteAndRetry = useCallback(async () => {
  90. // TODO: confirm deletion?
  91. try {
  92. await Promise.all(
  93. conflicts.map(conflict =>
  94. syncDelete(projectId, 'folder', conflict.entity._id)
  95. )
  96. )
  97. handleOverwrite()
  98. } catch (error: any) {
  99. setError(error.message)
  100. }
  101. }, [setError, conflicts, handleOverwrite, projectId])
  102. return (
  103. <div className="small modal-new-file-body-conflict">
  104. <p className="text-center mb-0">{getConflictText(conflicts, t)}</p>
  105. <ul className="text-center list-unstyled row-spaced-small mt-1">
  106. {conflicts.map((conflict, index) => (
  107. <li key={index}>
  108. <strong>{conflict.entity.name}</strong>
  109. </li>
  110. ))}
  111. </ul>
  112. {!hasFileConflict && (
  113. <p className="text-center row-spaced-small">
  114. {t('overwriting_the_original_folder')}
  115. <br />
  116. {t('do_you_want_to_overwrite_it', {
  117. count: conflicts.length,
  118. })}
  119. </p>
  120. )}
  121. <p className="text-center">
  122. <OLButton variant="secondary" onClick={cancel}>
  123. {t('cancel')}
  124. </OLButton>
  125. &nbsp;
  126. {!hasFileConflict && (
  127. <OLButton variant="danger" onClick={deleteAndRetry}>
  128. {t('overwrite')}
  129. </OLButton>
  130. )}
  131. </p>
  132. </div>
  133. )
  134. }