summaryrefslogtreecommitdiffstats
path: root/apps/files
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@protonmail.com>2024-02-01 18:59:58 +0100
committerbackportbot[bot] <backportbot[bot]@users.noreply.github.com>2024-02-07 08:53:32 +0000
commitc48edcb2be0815ec549fdedaf957711412e3e2f8 (patch)
treec50daba43445b57545574868421a3f00bf5330a6 /apps/files
parent5dc2200ca02d4461ac61dd0e68bcbfa76068435c (diff)
downloadnextcloud-server-c48edcb2be0815ec549fdedaf957711412e3e2f8.tar.gz
nextcloud-server-c48edcb2be0815ec549fdedaf957711412e3e2f8.zip
fix(files): drop to folder path and user feedback
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
Diffstat (limited to 'apps/files')
-rw-r--r--apps/files/src/components/DragAndDropNotice.vue50
-rw-r--r--apps/files/src/components/FileEntry.vue35
-rw-r--r--apps/files/src/components/FileEntryGrid.vue42
3 files changed, 96 insertions, 31 deletions
diff --git a/apps/files/src/components/DragAndDropNotice.vue b/apps/files/src/components/DragAndDropNotice.vue
index 3f7126fac67..a9c1d8e99ad 100644
--- a/apps/files/src/components/DragAndDropNotice.vue
+++ b/apps/files/src/components/DragAndDropNotice.vue
@@ -47,6 +47,7 @@ import { defineComponent } from 'vue'
import { Folder, Permission } from '@nextcloud/files'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
+import { UploadStatus } from '@nextcloud/upload'
import TrayArrowDownIcon from 'vue-material-design-icons/TrayArrowDown.vue'
@@ -143,10 +144,11 @@ export default defineComponent({
}
},
- onDrop(event: DragEvent) {
- logger.debug('Dropped on DragAndDropNotice', { event, error: this.cantUploadLabel })
+ async onDrop(event: DragEvent) {
+ logger.debug('Dropped on DragAndDropNotice', { event })
- if (!this.canUpload || this.isQuotaExceeded) {
+ // cantUploadLabel is null if we can upload
+ if (this.cantUploadLabel) {
showError(this.cantUploadLabel)
return
}
@@ -162,23 +164,31 @@ export default defineComponent({
// Start upload
logger.debug(`Uploading files to ${this.currentFolder.path}`)
// Process finished uploads
- handleDrop(event.dataTransfer).then((uploads) => {
- logger.debug('Upload terminated', { uploads })
- showSuccess(t('files', 'Upload successful'))
-
- // Scroll to last upload in current directory if terminated
- const lastUpload = uploads.findLast((upload) => !upload.file.webkitRelativePath.includes('/') && upload.response?.headers?.['oc-fileid'])
- if (lastUpload !== undefined) {
- this.$router.push({
- ...this.$route,
- params: {
- view: this.$route.params?.view ?? 'files',
- // Remove instanceid from header response
- fileid: parseInt(lastUpload.response!.headers['oc-fileid']),
- },
- })
- }
- })
+ const uploads = await handleDrop(event.dataTransfer)
+ logger.debug('Upload terminated', { uploads })
+
+ if (uploads.some((upload) => upload.status === UploadStatus.FAILED)) {
+ showError(t('files', 'Some files could not be uploaded'))
+ const failedUploads = uploads.filter((upload) => upload.status === UploadStatus.FAILED)
+ logger.debug('Some files could not be uploaded', { failedUploads })
+ } else {
+ showSuccess(t('files', 'Files uploaded successfully'))
+ }
+
+ // Scroll to last successful upload in current directory if terminated
+ const lastUpload = uploads.findLast((upload) => upload.status !== UploadStatus.FAILED
+ && !upload.file.webkitRelativePath.includes('/')
+ && upload.response?.headers?.['oc-fileid'])
+
+ if (lastUpload !== undefined) {
+ this.$router.push({
+ ...this.$route,
+ params: {
+ view: this.$route.params?.view ?? 'files',
+ fileid: parseInt(lastUpload.response!.headers['oc-fileid']),
+ },
+ })
+ }
}
this.dragover = false
},
diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue
index 8b4c7b71ef9..8243dc1199c 100644
--- a/apps/files/src/components/FileEntry.vue
+++ b/apps/files/src/components/FileEntry.vue
@@ -101,7 +101,7 @@ import type { PropType } from 'vue'
import { extname, join } from 'path'
import { FileType, formatFileSize, Permission, Folder, File as NcFile, NodeStatus, Node, View } from '@nextcloud/files'
import { getUploader } from '@nextcloud/upload'
-import { showError } from '@nextcloud/dialogs'
+import { showError, showSuccess } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import { vOnClickOutside } from '@vueuse/components'
import moment from '@nextcloud/moment'
@@ -515,12 +515,37 @@ export default defineComponent({
logger.debug('Dropped', { event, selection: this.draggingFiles })
// Check whether we're uploading files
- if (event.dataTransfer?.files?.length > 0) {
+ if (event.dataTransfer?.files
+ && event.dataTransfer.files.length > 0) {
const uploader = getUploader()
- event.dataTransfer.files.forEach((file: File) => {
- uploader.upload(join(this.source.path, file.name), file)
- })
+
+ // Check whether the uploader is in the same folder
+ // This should never happen™
+ if (!uploader.destination.path.startsWith(uploader.destination.path)) {
+ logger.error('The current uploader destination is not the same as the current folder')
+ showError(t('files', 'An error occurred while uploading. Please try again later.'))
+ return
+ }
+
logger.debug(`Uploading files to ${this.source.path}`)
+ const queue = [] as Promise<Upload>[]
+ for (const file of event.dataTransfer.files) {
+ // Because the uploader destination is properly set to the current folder
+ // we can just use the basename as the relative path.
+ queue.push(uploader.upload(join(this.source.basename, file.name), file))
+ }
+
+ const results = await Promise.allSettled(queue)
+ const errors = results.filter(result => result.status === 'rejected')
+ if (errors.length > 0) {
+ logger.error('Error while uploading files', { errors })
+ showError(t('files', 'Some files could not be uploaded'))
+ return
+ }
+
+ logger.debug('Files uploaded successfully')
+ showSuccess(t('files', 'Files uploaded successfully'))
+
return
}
diff --git a/apps/files/src/components/FileEntryGrid.vue b/apps/files/src/components/FileEntryGrid.vue
index 99fd45813ed..d42da54431c 100644
--- a/apps/files/src/components/FileEntryGrid.vue
+++ b/apps/files/src/components/FileEntryGrid.vue
@@ -78,7 +78,7 @@ import type { PropType } from 'vue'
import { extname, join } from 'path'
import { FileType, Permission, Folder, File as NcFile, NodeStatus, Node, View } from '@nextcloud/files'
import { getUploader } from '@nextcloud/upload'
-import { showError } from '@nextcloud/dialogs'
+import { showError, showSuccess } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import { generateUrl } from '@nextcloud/router'
import { vOnClickOutside } from '@vueuse/components'
@@ -358,7 +358,12 @@ export default Vue.extend({
logger.debug('Drag ended')
},
- async onDrop(event) {
+ async onDrop(event: DragEvent) {
+ // skip if native drop like text drag and drop from files names
+ if (!this.draggingFiles && !event.dataTransfer?.files?.length) {
+ return
+ }
+
event.preventDefault()
event.stopPropagation()
@@ -374,12 +379,37 @@ export default Vue.extend({
logger.debug('Dropped', { event, selection: this.draggingFiles })
// Check whether we're uploading files
- if (event.dataTransfer?.files?.length > 0) {
+ if (event.dataTransfer?.files
+ && event.dataTransfer.files.length > 0) {
const uploader = getUploader()
- event.dataTransfer.files.forEach((file: File) => {
- uploader.upload(join(this.source.path, file.name), file)
- })
+
+ // Check whether the uploader is in the same folder
+ // This should never happen™
+ if (!uploader.destination.path.startsWith(uploader.destination.path)) {
+ logger.error('The current uploader destination is not the same as the current folder')
+ showError(t('files', 'An error occurred while uploading. Please try again later.'))
+ return
+ }
+
logger.debug(`Uploading files to ${this.source.path}`)
+ const queue = [] as Promise<Upload>[]
+ for (const file of event.dataTransfer.files) {
+ // Because the uploader destination is properly set to the current folder
+ // we can just use the basename as the relative path.
+ queue.push(uploader.upload(join(this.source.basename, file.name), file))
+ }
+
+ const results = await Promise.allSettled(queue)
+ const errors = results.filter(result => result.status === 'rejected')
+ if (errors.length > 0) {
+ logger.error('Error while uploading files', { errors })
+ showError(t('files', 'Some files could not be uploaded'))
+ return
+ }
+
+ logger.debug('Files uploaded successfully')
+ showSuccess(t('files', 'Files uploaded successfully'))
+
return
}