mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-01 21:31:36 +02:00
Upload files dropped onto the file tree (#8064)
GitOrigin-RevId: 97043661e344b72ff742326c9dc2809e46d0bb9c
This commit is contained in:
18
package-lock.json
generated
18
package-lock.json
generated
@@ -34542,6 +34542,7 @@
|
||||
"@uppy/core": "^1.15.0",
|
||||
"@uppy/dashboard": "^1.11.0",
|
||||
"@uppy/react": "^1.11.0",
|
||||
"@uppy/utils": "^4.0.7",
|
||||
"@uppy/xhr-upload": "^1.6.8",
|
||||
"abort-controller": "^3.0.0",
|
||||
"accepts": "^1.3.7",
|
||||
@@ -34819,6 +34820,14 @@
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/@uppy/utils": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.0.7.tgz",
|
||||
"integrity": "sha512-nKViMT8XchKy+NWpb3DtVKuzZBmW7au26LrMq89EsvTwIOT6UR9+7bmz/+zr3+lc7UC7vMgNChIC6G+/Ya9wWQ==",
|
||||
"dependencies": {
|
||||
"lodash.throttle": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
@@ -42084,6 +42093,7 @@
|
||||
"@uppy/core": "^1.15.0",
|
||||
"@uppy/dashboard": "^1.11.0",
|
||||
"@uppy/react": "^1.11.0",
|
||||
"@uppy/utils": "^4.0.7",
|
||||
"@uppy/xhr-upload": "^1.6.8",
|
||||
"abort-controller": "^3.0.0",
|
||||
"accepts": "^1.3.7",
|
||||
@@ -42330,6 +42340,14 @@
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"@uppy/utils": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.0.7.tgz",
|
||||
"integrity": "sha512-nKViMT8XchKy+NWpb3DtVKuzZBmW7au26LrMq89EsvTwIOT6UR9+7bmz/+zr3+lc7UC7vMgNChIC6G+/Ya9wWQ==",
|
||||
"requires": {
|
||||
"lodash.throttle": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Trans } from 'react-i18next'
|
||||
import { Alert, Button } from 'react-bootstrap'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Uppy from '@uppy/core'
|
||||
import XHRUpload from '@uppy/xhr-upload'
|
||||
@@ -14,7 +14,8 @@ import { refreshProjectMetadata } from '../../../util/api'
|
||||
import ErrorMessage from '../error-message'
|
||||
|
||||
export default function FileTreeUploadDoc() {
|
||||
const { parentFolderId, cancel, isDuplicate } = useFileTreeActionable()
|
||||
const { parentFolderId, cancel, isDuplicate, droppedFiles, setDroppedFiles } =
|
||||
useFileTreeActionable()
|
||||
const { _id: projectId } = useProjectContext(projectContextPropTypes)
|
||||
|
||||
const [error, setError] = useState()
|
||||
@@ -28,16 +29,22 @@ export default function FileTreeUploadDoc() {
|
||||
// calculate conflicts
|
||||
const buildConflicts = files =>
|
||||
Object.values(files).filter(file =>
|
||||
isDuplicate(parentFolderId, file.meta.name)
|
||||
isDuplicate(file.meta.targetFolderId ?? parentFolderId, file.meta.name)
|
||||
)
|
||||
|
||||
const buildEndpoint = (projectId, targetFolderId) => {
|
||||
let endpoint = `/project/${projectId}/upload`
|
||||
|
||||
if (targetFolderId) {
|
||||
endpoint += `?folder_id=${targetFolderId}`
|
||||
}
|
||||
|
||||
return endpoint
|
||||
}
|
||||
|
||||
// initialise the Uppy object
|
||||
const uppy = useUppy(() => {
|
||||
let endpoint = `/project/${projectId}/upload`
|
||||
|
||||
if (parentFolderId) {
|
||||
endpoint += `?folder_id=${parentFolderId}`
|
||||
}
|
||||
const endpoint = buildEndpoint(projectId, parentFolderId)
|
||||
|
||||
return (
|
||||
new Uppy({
|
||||
@@ -113,6 +120,37 @@ export default function FileTreeUploadDoc() {
|
||||
)
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (uppy && droppedFiles) {
|
||||
uppy.setOptions({
|
||||
autoProceed: false,
|
||||
})
|
||||
for (const file of droppedFiles.files) {
|
||||
const fileId = uppy.addFile({
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
data: file,
|
||||
source: 'Local',
|
||||
isRemote: false,
|
||||
meta: {
|
||||
targetFolderId: droppedFiles.targetFolderId,
|
||||
},
|
||||
})
|
||||
const uppyFile = uppy.getFile(fileId)
|
||||
uppy.setFileState(fileId, {
|
||||
xhrUpload: {
|
||||
...uppyFile.xhrUpload,
|
||||
endpoint: buildEndpoint(projectId, droppedFiles.targetFolderId),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
setDroppedFiles(null)
|
||||
}
|
||||
}, [uppy, droppedFiles, setDroppedFiles, projectId])
|
||||
|
||||
// handle forced overwriting of conflicting files
|
||||
const handleOverwrite = useCallback(() => {
|
||||
setOverwrite(true)
|
||||
|
||||
@@ -20,7 +20,7 @@ function FileTreeDraggablePreviewLayer({ isOver }) {
|
||||
? ref.current.getBoundingClientRect()
|
||||
: null
|
||||
|
||||
if (!isDragging) {
|
||||
if (!isDragging || !item.title) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
useReducer,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
@@ -132,6 +133,8 @@ export function FileTreeActionableProvider({ children }) {
|
||||
const { fileTreeData, dispatchRename, dispatchMove } = useFileTreeData()
|
||||
const { selectedEntityIds } = useFileTreeSelectable()
|
||||
|
||||
const [droppedFiles, setDroppedFiles] = useState(null)
|
||||
|
||||
const startRenaming = useCallback(() => {
|
||||
dispatch({ type: ACTION_TYPES.START_RENAME })
|
||||
}, [])
|
||||
@@ -363,6 +366,8 @@ export function FileTreeActionableProvider({ children }) {
|
||||
finishCreatingDoc,
|
||||
finishCreatingLinkedFile,
|
||||
cancel,
|
||||
droppedFiles,
|
||||
setDroppedFiles,
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { useRef, useEffect, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import getDroppedFiles from '@uppy/utils/lib/getDroppedFiles'
|
||||
|
||||
import { DndProvider, createDndContext, useDrag, useDrop } from 'react-dnd'
|
||||
import { HTML5Backend, getEmptyImage } from 'react-dnd-html5-backend'
|
||||
import {
|
||||
HTML5Backend,
|
||||
getEmptyImage,
|
||||
NativeTypes,
|
||||
} from 'react-dnd-html5-backend'
|
||||
|
||||
import {
|
||||
findAllInTreeOrThrow,
|
||||
@@ -119,20 +124,32 @@ const editorContextPropTypes = {
|
||||
}
|
||||
|
||||
export function useDroppable(droppedEntityId) {
|
||||
const { finishMoving } = useFileTreeActionable()
|
||||
const { finishMoving, setDroppedFiles, startUploadingDocOrFile } =
|
||||
useFileTreeActionable()
|
||||
|
||||
const [{ isOver }, dropRef] = useDrop({
|
||||
accept: DRAGGABLE_TYPE,
|
||||
accept: [DRAGGABLE_TYPE, NativeTypes.FILE],
|
||||
canDrop: (item, monitor) => {
|
||||
const isOver = monitor.isOver({ shallow: true })
|
||||
if (!isOver) return false
|
||||
if (item.forbiddenFolderIds.has(droppedEntityId)) return false
|
||||
if (
|
||||
item.type === DRAGGABLE_TYPE &&
|
||||
item.forbiddenFolderIds.has(droppedEntityId)
|
||||
)
|
||||
return false
|
||||
return true
|
||||
},
|
||||
drop: (item, monitor) => {
|
||||
const didDropInChild = monitor.didDrop()
|
||||
if (didDropInChild) return
|
||||
finishMoving(droppedEntityId, item.draggedEntityIds)
|
||||
if (item.type === DRAGGABLE_TYPE) {
|
||||
finishMoving(droppedEntityId, item.draggedEntityIds)
|
||||
} else {
|
||||
getDroppedFiles(item).then(files => {
|
||||
setDroppedFiles({ files, targetFolderId: droppedEntityId })
|
||||
startUploadingDocOrFile()
|
||||
})
|
||||
}
|
||||
},
|
||||
collect: monitor => ({
|
||||
isOver: monitor.canDrop(),
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
"@uppy/core": "^1.15.0",
|
||||
"@uppy/dashboard": "^1.11.0",
|
||||
"@uppy/react": "^1.11.0",
|
||||
"@uppy/utils": "^4.0.7",
|
||||
"@uppy/xhr-upload": "^1.6.8",
|
||||
"abort-controller": "^3.0.0",
|
||||
"accepts": "^1.3.7",
|
||||
|
||||
Reference in New Issue
Block a user