file-tree-root.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import React, { useEffect, useState } from 'react'
  2. import PropTypes from 'prop-types'
  3. import withErrorBoundary from '../../../infrastructure/error-boundary'
  4. import { useProjectContext } from '../../../shared/context/project-context'
  5. import { useFileTreeData } from '../../../shared/context/file-tree-data-context'
  6. import FileTreeContext from './file-tree-context'
  7. import FileTreeDraggablePreviewLayer from './file-tree-draggable-preview-layer'
  8. import FileTreeFolderList from './file-tree-folder-list'
  9. import FileTreeToolbar from './file-tree-toolbar'
  10. import FileTreeModalDelete from './modals/file-tree-modal-delete'
  11. import FileTreeModalCreateFolder from './modals/file-tree-modal-create-folder'
  12. import FileTreeModalError from './modals/file-tree-modal-error'
  13. import FileTreeContextMenu from './file-tree-context-menu'
  14. import FileTreeError from './file-tree-error'
  15. import { useDroppable } from '../contexts/file-tree-draggable'
  16. import { useFileTreeSocketListener } from '../hooks/file-tree-socket-listener'
  17. import FileTreeModalCreateFile from './modals/file-tree-modal-create-file'
  18. const FileTreeRoot = React.memo(function FileTreeRoot({
  19. refProviders,
  20. reindexReferences,
  21. setRefProviderEnabled,
  22. setStartedFreeTrial,
  23. onSelect,
  24. onInit,
  25. isConnected,
  26. }) {
  27. const { _id: projectId } = useProjectContext(projectContextPropTypes)
  28. const { fileTreeData } = useFileTreeData()
  29. const isReady = projectId && fileTreeData
  30. const [shouldShowVisualSelection, setShouldShowVisualSelection] =
  31. useState(true)
  32. const handleFileTreeClick = e => {
  33. if (e.target.classList.contains('bottom-buffer')) {
  34. setShouldShowVisualSelection(false)
  35. return
  36. }
  37. setShouldShowVisualSelection(e.target !== e.currentTarget)
  38. }
  39. useEffect(() => {
  40. if (isReady) onInit()
  41. }, [isReady, onInit])
  42. if (!isReady) return null
  43. return (
  44. <FileTreeContext
  45. refProviders={refProviders}
  46. setRefProviderEnabled={setRefProviderEnabled}
  47. setStartedFreeTrial={setStartedFreeTrial}
  48. reindexReferences={reindexReferences}
  49. onSelect={onSelect}
  50. >
  51. {isConnected ? null : <div className="disconnected-overlay" />}
  52. <FileTreeToolbar />
  53. <FileTreeContextMenu />
  54. {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
  55. <div
  56. className="file-tree-inner"
  57. onClick={handleFileTreeClick}
  58. data-testid="file-tree-inner"
  59. >
  60. <FileTreeRootFolder
  61. shouldShowVisualSelection={shouldShowVisualSelection}
  62. />
  63. </div>
  64. <FileTreeModalDelete />
  65. <FileTreeModalCreateFile />
  66. <FileTreeModalCreateFolder />
  67. <FileTreeModalError />
  68. </FileTreeContext>
  69. )
  70. })
  71. function FileTreeRootFolder({ shouldShowVisualSelection }) {
  72. useFileTreeSocketListener()
  73. const { fileTreeData } = useFileTreeData()
  74. const { isOver, dropRef } = useDroppable(fileTreeData._id)
  75. return (
  76. <>
  77. <FileTreeDraggablePreviewLayer isOver={isOver} />
  78. <FileTreeFolderList
  79. folders={fileTreeData.folders}
  80. docs={fileTreeData.docs}
  81. files={fileTreeData.fileRefs}
  82. classes={{ root: 'file-tree-list' }}
  83. dropRef={dropRef}
  84. isOver={isOver}
  85. shouldShowVisualSelection={shouldShowVisualSelection}
  86. >
  87. <li className="bottom-buffer" />
  88. </FileTreeFolderList>
  89. </>
  90. )
  91. }
  92. FileTreeRootFolder.propTypes = {
  93. shouldShowVisualSelection: PropTypes.bool,
  94. }
  95. FileTreeRoot.propTypes = {
  96. onSelect: PropTypes.func.isRequired,
  97. onInit: PropTypes.func.isRequired,
  98. isConnected: PropTypes.bool.isRequired,
  99. setRefProviderEnabled: PropTypes.func.isRequired,
  100. setStartedFreeTrial: PropTypes.func.isRequired,
  101. reindexReferences: PropTypes.func.isRequired,
  102. refProviders: PropTypes.object.isRequired,
  103. }
  104. const projectContextPropTypes = {
  105. _id: PropTypes.string.isRequired,
  106. }
  107. export default withErrorBoundary(FileTreeRoot, FileTreeError)