file-tree-root.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import React, { useEffect, useState } from 'react'
  2. import withErrorBoundary from '../../../infrastructure/error-boundary'
  3. import { useProjectContext } from '../../../shared/context/project-context'
  4. import { useFileTreeData } from '../../../shared/context/file-tree-data-context'
  5. import FileTreeContext from './file-tree-context'
  6. import FileTreeDraggablePreviewLayer from './file-tree-draggable-preview-layer'
  7. import FileTreeFolderList from './file-tree-folder-list'
  8. import FileTreeToolbar from './file-tree-toolbar'
  9. import FileTreeModalDelete from './modals/file-tree-modal-delete'
  10. import FileTreeModalCreateFolder from './modals/file-tree-modal-create-folder'
  11. import FileTreeModalError from './modals/file-tree-modal-error'
  12. import FileTreeContextMenu from './file-tree-context-menu'
  13. import FileTreeError from './file-tree-error'
  14. import { useDroppable } from '../contexts/file-tree-draggable'
  15. import { useFileTreeSocketListener } from '../hooks/file-tree-socket-listener'
  16. import FileTreeModalCreateFile from './modals/file-tree-modal-create-file'
  17. import FileTreeInner from './file-tree-inner'
  18. import { useDragLayer } from 'react-dnd'
  19. import classnames from 'classnames'
  20. const FileTreeRoot = React.memo<{
  21. onSelect: () => void
  22. onDelete: () => void
  23. onInit: () => void
  24. isConnected: boolean
  25. setRefProviderEnabled: () => void
  26. setStartedFreeTrial: () => void
  27. reindexReferences: () => void
  28. refProviders: Record<string, boolean>
  29. }>(function FileTreeRoot({
  30. refProviders,
  31. reindexReferences,
  32. setRefProviderEnabled,
  33. setStartedFreeTrial,
  34. onSelect,
  35. onInit,
  36. onDelete,
  37. isConnected,
  38. }) {
  39. const [fileTreeContainer, setFileTreeContainer] =
  40. useState<HTMLDivElement | null>(null)
  41. const { _id: projectId } = useProjectContext()
  42. const { fileTreeData } = useFileTreeData()
  43. const isReady = Boolean(projectId && fileTreeData)
  44. useEffect(() => {
  45. if (isReady) onInit()
  46. }, [isReady, onInit])
  47. if (!isReady) return null
  48. return (
  49. <div
  50. className="file-tree"
  51. data-testid="file-tree"
  52. ref={setFileTreeContainer}
  53. >
  54. {fileTreeContainer && (
  55. <FileTreeContext
  56. refProviders={refProviders}
  57. setRefProviderEnabled={setRefProviderEnabled}
  58. setStartedFreeTrial={setStartedFreeTrial}
  59. reindexReferences={reindexReferences}
  60. onSelect={onSelect}
  61. fileTreeContainer={fileTreeContainer}
  62. >
  63. {isConnected ? null : <div className="disconnected-overlay" />}
  64. <FileTreeToolbar />
  65. <FileTreeContextMenu />
  66. <FileTreeInner>
  67. <FileTreeRootFolder onDelete={onDelete} />
  68. </FileTreeInner>
  69. <FileTreeModalDelete />
  70. <FileTreeModalCreateFile />
  71. <FileTreeModalCreateFolder />
  72. <FileTreeModalError />
  73. </FileTreeContext>
  74. )}
  75. </div>
  76. )
  77. })
  78. function FileTreeRootFolder({ onDelete }: { onDelete: () => void }) {
  79. useFileTreeSocketListener(onDelete)
  80. const { fileTreeData } = useFileTreeData()
  81. const { isOver, dropRef } = useDroppable(fileTreeData._id)
  82. const dragLayer = useDragLayer(monitor => ({
  83. isDragging: monitor.isDragging(),
  84. item: monitor.getItem(),
  85. clientOffset: monitor.getClientOffset(),
  86. }))
  87. return (
  88. <>
  89. <FileTreeDraggablePreviewLayer isOver={isOver} {...dragLayer} />
  90. <FileTreeFolderList
  91. folders={fileTreeData.folders}
  92. docs={fileTreeData.docs}
  93. files={fileTreeData.fileRefs}
  94. classes={{
  95. root: classnames('file-tree-list', {
  96. 'file-tree-dragging': dragLayer.isDragging,
  97. }),
  98. }}
  99. dropRef={dropRef as any}
  100. dataTestId="file-tree-list-root"
  101. />
  102. </>
  103. )
  104. }
  105. export default withErrorBoundary(FileTreeRoot, FileTreeError)