mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #15444 from overleaf/td-remove-root-folder-scope-use
Remove use of root folder scope in figure modal GitOrigin-RevId: d07247b644d312ef711f5601d3c10a3274e43416
This commit is contained in:
parent
13f246a85e
commit
c34c95b46d
9 changed files with 101 additions and 66 deletions
|
@ -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,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>) => {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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])
|
||||||
|
}
|
|
@ -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]
|
|
||||||
}
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue