Просмотр исходного кода

Merge pull request #15444 from overleaf/td-remove-root-folder-scope-use

Remove use of root folder scope in figure modal

GitOrigin-RevId: d07247b644d312ef711f5601d3c10a3274e43416
Tim Down 2 лет назад
Родитель
Сommit
c34c95b46d

+ 2 - 2
services/web/frontend/js/features/source-editor/components/figure-modal/file-name-input.tsx

@@ -6,9 +6,9 @@ import {
   useState,
   useState,
 } from 'react'
 } from 'react'
 import { File, FileOrDirectory } from '../../utils/file'
 import { File, FileOrDirectory } from '../../utils/file'
-import useScopeValue from '../../../../shared/hooks/use-scope-value'
 import { Alert } from 'react-bootstrap'
 import { Alert } from 'react-bootstrap'
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
+import { useCurrentProjectFolders } from '@/features/source-editor/hooks/use-current-project-folders'
 
 
 type FileNameInputProps = Omit<
 type FileNameInputProps = Omit<
   DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
   DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
@@ -57,7 +57,7 @@ export const FileNameInput = ({
 }: FileNameInputProps) => {
 }: FileNameInputProps) => {
   const { t } = useTranslation()
   const { t } = useTranslation()
   const [overlap, setOverlap] = useState<boolean>(false)
   const [overlap, setOverlap] = useState<boolean>(false)
-  const [rootFolder] = useScopeValue<FileOrDirectory>('rootFolder')
+  const { rootFolder } = useCurrentProjectFolders()
   const { value } = props
   const { value } = props
 
 
   useEffect(() => {
   useEffect(() => {

+ 2 - 2
services/web/frontend/js/features/source-editor/components/figure-modal/file-relocator.tsx

@@ -2,7 +2,7 @@ import { useCallback } from 'react'
 import { FileNameInput } from './file-name-input'
 import { FileNameInput } from './file-name-input'
 import { File } from '../../utils/file'
 import { File } from '../../utils/file'
 import { Select } from '../../../../shared/components/select'
 import { Select } from '../../../../shared/components/select'
-import { useCurrentProjectFolders } from '../../hooks/useCurrentProjectFolders'
+import { useCurrentProjectFolders } from '../../hooks/use-current-project-folders'
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
 
 
 export const FileRelocator = ({
 export const FileRelocator = ({
@@ -25,7 +25,7 @@ export const FileRelocator = ({
   setNameDirty: (nameDirty: boolean) => void
   setNameDirty: (nameDirty: boolean) => void
 }) => {
 }) => {
   const { t } = useTranslation()
   const { t } = useTranslation()
-  const [folders, rootFile] = useCurrentProjectFolders()
+  const { folders, rootFile } = useCurrentProjectFolders()
 
 
   const nameChanged = useCallback(
   const nameChanged = useCallback(
     (e: React.ChangeEvent<HTMLInputElement>) => {
     (e: React.ChangeEvent<HTMLInputElement>) => {

+ 2 - 2
services/web/frontend/js/features/source-editor/components/figure-modal/file-sources/figure-modal-other-project-source.tsx

@@ -14,7 +14,7 @@ import {
   useProjectOutputFiles,
   useProjectOutputFiles,
 } from '../../../../file-tree/hooks/use-project-output-files'
 } from '../../../../file-tree/hooks/use-project-output-files'
 import { Button } from 'react-bootstrap'
 import { Button } from 'react-bootstrap'
-import { useCurrentProjectFolders } from '../../../hooks/useCurrentProjectFolders'
+import { useCurrentProjectFolders } from '../../../hooks/use-current-project-folders'
 import { File, isImageEntity } from '../../../utils/file'
 import { File, isImageEntity } from '../../../utils/file'
 import { postJSON } from '../../../../../infrastructure/fetch-json'
 import { postJSON } from '../../../../../infrastructure/fetch-json'
 import { useProjectContext } from '../../../../../shared/context/project-context'
 import { useProjectContext } from '../../../../../shared/context/project-context'
@@ -39,7 +39,7 @@ export const FigureModalOtherProjectSource: FC = () => {
   const [nameDirty, setNameDirty] = useState<boolean>(false)
   const [nameDirty, setNameDirty] = useState<boolean>(false)
   const [name, setName] = useState<string>('')
   const [name, setName] = useState<string>('')
   const [folder, setFolder] = useState<File | null>(null)
   const [folder, setFolder] = useState<File | null>(null)
-  const [, rootFile] = useCurrentProjectFolders()
+  const { rootFile } = useCurrentProjectFolders()
   const [file, setFile] = useState<OutputEntity | Entity | null>(null)
   const [file, setFile] = useState<OutputEntity | Entity | null>(null)
   const FileSelector = usingOutputFiles
   const FileSelector = usingOutputFiles
     ? SelectFromProjectOutputFiles
     ? SelectFromProjectOutputFiles

+ 3 - 3
services/web/frontend/js/features/source-editor/components/figure-modal/file-sources/figure-modal-project-source.tsx

@@ -1,13 +1,13 @@
 import { FC, useMemo } from 'react'
 import { FC, useMemo } from 'react'
-import useScopeValue from '../../../../../shared/hooks/use-scope-value'
 import { Select } from '../../../../../shared/components/select'
 import { Select } from '../../../../../shared/components/select'
 import { useFigureModalContext } from '../figure-modal-context'
 import { useFigureModalContext } from '../figure-modal-context'
-import { FileOrDirectory, filterFiles, isImageFile } from '../../../utils/file'
+import { filterFiles, isImageFile } from '../../../utils/file'
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
+import { useCurrentProjectFolders } from '@/features/source-editor/hooks/use-current-project-folders'
 
 
 export const FigureModalCurrentProjectSource: FC = () => {
 export const FigureModalCurrentProjectSource: FC = () => {
   const { t } = useTranslation()
   const { t } = useTranslation()
-  const [rootFolder] = useScopeValue<FileOrDirectory>('rootFolder')
+  const { rootFolder } = useCurrentProjectFolders()
   const files = useMemo(
   const files = useMemo(
     () => filterFiles(rootFolder)?.filter(isImageFile),
     () => filterFiles(rootFolder)?.filter(isImageFile),
     [rootFolder]
     [rootFolder]

+ 7 - 7
services/web/frontend/js/features/source-editor/components/figure-modal/file-sources/figure-modal-upload-source.tsx

@@ -1,6 +1,6 @@
 import { FC, useCallback, useEffect, useState } from 'react'
 import { FC, useCallback, useEffect, useState } from 'react'
 import { useFigureModalContext } from '../figure-modal-context'
 import { useFigureModalContext } from '../figure-modal-context'
-import { useCurrentProjectFolders } from '../../../hooks/useCurrentProjectFolders'
+import { useCurrentProjectFolders } from '../../../hooks/use-current-project-folders'
 import { File } from '../../../utils/file'
 import { File } from '../../../utils/file'
 import { Dashboard, useUppy } from '@uppy/react'
 import { Dashboard, useUppy } from '@uppy/react'
 import '@uppy/core/dist/style.css'
 import '@uppy/core/dist/style.css'
@@ -33,7 +33,7 @@ export const FigureModalUploadFileSource: FC = () => {
   const view = useCodeMirrorViewContext()
   const view = useCodeMirrorViewContext()
   const { dispatch, pastedImageData } = useFigureModalContext()
   const { dispatch, pastedImageData } = useFigureModalContext()
   const { _id: projectId } = useProjectContext()
   const { _id: projectId } = useProjectContext()
-  const [, rootFolder] = useCurrentProjectFolders()
+  const { rootFile } = useCurrentProjectFolders()
   const [folder, setFolder] = useState<File | null>(null)
   const [folder, setFolder] = useState<File | null>(null)
   const [nameDirty, setNameDirty] = useState<boolean>(false)
   const [nameDirty, setNameDirty] = useState<boolean>(false)
   // Files are immutable, so this will point to a (possibly) old version of the file
   // Files are immutable, so this will point to a (possibly) old version of the file
@@ -77,7 +77,7 @@ export const FigureModalUploadFileSource: FC = () => {
           if (!uploadResult.successful) {
           if (!uploadResult.successful) {
             throw new Error('Upload failed')
             throw new Error('Upload failed')
           }
           }
-          const uploadFolder = folder ?? rootFolder
+          const uploadFolder = folder ?? rootFile
           return uploadFolder.path === '' && uploadFolder.name === 'rootFolder'
           return uploadFolder.path === '' && uploadFolder.name === 'rootFolder'
             ? `${name}`
             ? `${name}`
             : `${uploadFolder.path ? uploadFolder.path + '/' : ''}${
             : `${uploadFolder.path ? uploadFolder.path + '/' : ''}${
@@ -86,7 +86,7 @@ export const FigureModalUploadFileSource: FC = () => {
         },
         },
       })
       })
     },
     },
-    [dispatch, rootFolder, uppy, view]
+    [dispatch, rootFile, uppy, view]
   )
   )
 
 
   useEffect(() => {
   useEffect(() => {
@@ -130,7 +130,7 @@ export const FigureModalUploadFileSource: FC = () => {
           xhrUpload: {
           xhrUpload: {
             ...(file as any).xhrUpload,
             ...(file as any).xhrUpload,
             endpoint: `/project/${projectId}/upload?folder_id=${
             endpoint: `/project/${projectId}/upload?folder_id=${
-              (folder ?? rootFolder).id
+              (folder ?? rootFile).id
             }`,
             }`,
           },
           },
         })
         })
@@ -179,7 +179,7 @@ export const FigureModalUploadFileSource: FC = () => {
   }, [
   }, [
     uppy,
     uppy,
     folder,
     folder,
-    rootFolder,
+    rootFile,
     name,
     name,
     nameDirty,
     nameDirty,
     dispatchUploadAction,
     dispatchUploadAction,
@@ -245,7 +245,7 @@ export const FigureModalUploadFileSource: FC = () => {
         name={name}
         name={name}
         nameDisabled={!file && !nameDirty}
         nameDisabled={!file && !nameDirty}
         onFolderChanged={item =>
         onFolderChanged={item =>
-          dispatchUploadAction(name, file, item ?? rootFolder)
+          dispatchUploadAction(name, file, item ?? rootFile)
         }
         }
         onNameChanged={name => dispatchUploadAction(name, file, folder)}
         onNameChanged={name => dispatchUploadAction(name, file, folder)}
         setFolder={setFolder}
         setFolder={setFolder}

+ 2 - 2
services/web/frontend/js/features/source-editor/components/figure-modal/file-sources/figure-modal-url-source.tsx

@@ -3,7 +3,7 @@ import { useFigureModalContext } from '../figure-modal-context'
 import { postJSON } from '../../../../../infrastructure/fetch-json'
 import { postJSON } from '../../../../../infrastructure/fetch-json'
 import { useProjectContext } from '../../../../../shared/context/project-context'
 import { useProjectContext } from '../../../../../shared/context/project-context'
 import { File } from '../../../utils/file'
 import { File } from '../../../utils/file'
-import { useCurrentProjectFolders } from '../../../hooks/useCurrentProjectFolders'
+import { useCurrentProjectFolders } from '../../../hooks/use-current-project-folders'
 import { FileRelocator } from '../file-relocator'
 import { FileRelocator } from '../file-relocator'
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
 import { useCodeMirrorViewContext } from '../../codemirror-editor'
 import { useCodeMirrorViewContext } from '../../codemirror-editor'
@@ -44,7 +44,7 @@ export const FigureModalUrlSource: FC = () => {
   const [nameDirty, setNameDirty] = useState<boolean>(false)
   const [nameDirty, setNameDirty] = useState<boolean>(false)
   const [name, setName] = useState<string>('')
   const [name, setName] = useState<string>('')
   const { _id: projectId } = useProjectContext()
   const { _id: projectId } = useProjectContext()
-  const [, rootFile] = useCurrentProjectFolders()
+  const { rootFile } = useCurrentProjectFolders()
   const [folder, setFolder] = useState<File>(rootFile)
   const [folder, setFolder] = useState<File>(rootFile)
 
 
   const { dispatch, getPath } = useFigureModalContext()
   const { dispatch, getPath } = useFigureModalContext()

+ 51 - 0
services/web/frontend/js/features/source-editor/hooks/use-current-project-folders.ts

@@ -0,0 +1,51 @@
+import { useMemo } from 'react'
+import { File, FileOrDirectory, filterFolders } from '../utils/file'
+import { useFileTreeData } from '@/shared/context/file-tree-data-context'
+import { Folder } from '../../../../../types/folder'
+import { Doc } from '../../../../../types/doc'
+import { FileRef } from '../../../../../types/file-ref'
+
+function docAdapter(doc: Doc): FileOrDirectory {
+  return {
+    id: doc._id,
+    name: doc.name,
+    type: 'doc',
+  }
+}
+
+function fileRefAdapter(fileRef: FileRef): FileOrDirectory {
+  return {
+    id: fileRef._id,
+    name: fileRef.name,
+    type: 'file',
+  }
+}
+
+function folderAdapter(folder: Folder): FileOrDirectory {
+  return {
+    id: folder._id,
+    name: folder.name,
+    type: 'folder',
+    children: folder.docs
+      .map(docAdapter)
+      .concat(
+        folder.fileRefs.map(fileRefAdapter),
+        folder.folders.map(folderAdapter)
+      ),
+  }
+}
+
+export const useCurrentProjectFolders: () => {
+  folders: File[] | undefined
+  rootFile: File
+  rootFolder: FileOrDirectory
+} = () => {
+  const { fileTreeData } = useFileTreeData()
+
+  return useMemo(() => {
+    const rootFolder = folderAdapter(fileTreeData)
+    const rootFile = { ...rootFolder, path: '' }
+    const folders = filterFolders(rootFolder)
+    return { folders, rootFile, rootFolder }
+  }, [fileTreeData])
+}

+ 0 - 13
services/web/frontend/js/features/source-editor/hooks/useCurrentProjectFolders.ts

@@ -1,13 +0,0 @@
-import { useMemo } from 'react'
-import useScopeValue from '../../../shared/hooks/use-scope-value'
-import { File, FileOrDirectory, filterFolders } from '../utils/file'
-
-export const useCurrentProjectFolders: () => [
-  File[] | undefined,
-  File
-] = () => {
-  const [rootFolder] = useScopeValue<FileOrDirectory>('rootFolder')
-  const rootFile = { ...rootFolder, path: '' }
-  const folders = useMemo(() => filterFolders(rootFolder), [rootFolder])
-  return [folders, rootFile]
-}

+ 32 - 35
services/web/test/frontend/features/source-editor/helpers/mock-scope.ts

@@ -1,45 +1,12 @@
 import { docId, mockDoc } from './mock-doc'
 import { docId, mockDoc } from './mock-doc'
-import { Folder } from '../../../../../types/folder'
 import { sleep } from '../../../helpers/sleep'
 import { sleep } from '../../../helpers/sleep'
+import { Folder } from '../../../../../types/folder'
 
 
 export const rootFolderId = '012345678901234567890123'
 export const rootFolderId = '012345678901234567890123'
 export const figuresFolderId = '123456789012345678901234'
 export const figuresFolderId = '123456789012345678901234'
 export const figureId = '234567890123456789012345'
 export const figureId = '234567890123456789012345'
 export const mockScope = (content?: string) => {
 export const mockScope = (content?: string) => {
   return {
   return {
-    rootFolder: {
-      id: rootFolderId,
-      name: 'rootFolder',
-      selected: false,
-      children: [
-        {
-          id: docId,
-          name: 'test.tex',
-          selected: false,
-          type: 'doc',
-        },
-        {
-          id: figuresFolderId,
-          name: 'figures',
-          selected: false,
-          type: 'folder',
-          children: [
-            {
-              id: figureId,
-              name: 'frog.jpg',
-              selected: false,
-              type: 'file',
-            },
-            {
-              id: 'fake-figure-id',
-              name: 'unicorn.png',
-              selected: false,
-              type: 'file',
-            },
-          ],
-        },
-      ],
-    },
     settings: {
     settings: {
       fontSize: 12,
       fontSize: 12,
       fontFamily: 'monaco',
       fontFamily: 'monaco',
@@ -66,7 +33,37 @@ export const mockScope = (content?: string) => {
       _id: 'test-project',
       _id: 'test-project',
       name: 'Test Project',
       name: 'Test Project',
       spellCheckLanguage: 'en',
       spellCheckLanguage: 'en',
-      rootFolder: [] as Folder[],
+      rootFolder: [
+        {
+          _id: rootFolderId,
+          name: 'rootFolder',
+          docs: [
+            {
+              _id: docId,
+              name: 'test.tex',
+            },
+          ],
+          folders: [
+            {
+              _id: figuresFolderId,
+              name: 'figures',
+              docs: [],
+              folders: [],
+              fileRefs: [
+                {
+                  _id: figureId,
+                  name: 'frog.jpg',
+                },
+                {
+                  _id: 'fake-figure-id',
+                  name: 'unicorn.png',
+                },
+              ],
+            },
+          ],
+          fileRefs: [],
+        },
+      ] as Folder[],
       features: {
       features: {
         trackChanges: true,
         trackChanges: true,
       },
       },