@@ -7,17 +7,18 @@ import type { IFileAction } from '@nextcloud/files'
77import type { PropType } from 'vue'
88import type { FileSource } from '../types.ts'
99
10- import { showError } from '@nextcloud/dialogs'
10+ import { openConflictPicker } from '@nextcloud/dialogs'
1111import { FileType , Folder , File as NcFile , Node , NodeStatus , Permission } from '@nextcloud/files'
1212import { t } from '@nextcloud/l10n'
1313import { generateUrl } from '@nextcloud/router'
1414import { isPublicShare } from '@nextcloud/sharing/public'
15+ import { getConflicts , getUploader } from '@nextcloud/upload'
1516import { vOnClickOutside } from '@vueuse/components'
1617import { extname } from 'path'
1718import Vue , { computed , defineComponent } from 'vue'
1819import { action as sidebarAction } from '../actions/sidebarAction.ts'
1920import logger from '../logger.ts'
20- import { dataTransferToFileTree , onDropExternalFiles , onDropInternalFiles } from '../services/DropService.ts'
21+ import { onDropInternalFiles } from '../services/DropService.ts'
2122import { getDragAndDropPreview } from '../utils/dragUtils.ts'
2223import { hashCode } from '../utils/hashUtils.ts'
2324import { isDownloadable } from '../utils/permissions.ts'
@@ -476,42 +477,69 @@ export default defineComponent({
476477 event . preventDefault ( )
477478 event . stopPropagation ( )
478479
479- // Caching the selection
480- const selection = this . draggingFiles
481- const items = [ ...event . dataTransfer ?. items || [ ] ] as DataTransferItem [ ]
482-
483- // We need to process the dataTransfer ASAP before the
484- // browser clears it. This is why we cache the items too.
485- const fileTree = await dataTransferToFileTree ( items )
486-
487- // We might not have the target directory fetched yet
488- const contents = await this . activeView ?. getContents ( this . source . path )
489- const folder = contents ?. folder
490- if ( ! folder ) {
491- showError ( this . t ( 'files' , 'Target folder does not exist any more' ) )
492- return
493- }
494-
495480 // If another button is pressed, cancel it. This
496481 // allows cancelling the drag with the right click.
497482 if ( ! this . canDrop || event . button ) {
498483 return
499484 }
500485
486+ // Caching the selection
487+ const selection = this . draggingFiles
488+ const items = Array . from ( event . dataTransfer ?. items || [ ] )
489+
490+ if ( selection . length === 0 && items . some ( ( item ) => item . kind === 'file' ) ) {
491+ const uploader = getUploader ( )
492+ await uploader . batchUpload (
493+ this . source . path ,
494+ items . filter ( ( item ) => item . kind === 'file' )
495+ . map ( ( item ) => 'webkitGetAsEntry' in item ? item . webkitGetAsEntry ( ) : item . getAsFile ( ) )
496+ . filter ( Boolean ) as ( FileSystemEntry | File ) [ ] ,
497+ async ( nodes , path ) => {
498+ try {
499+ const { contents, folder } = await this . activeView ! . getContents ( path )
500+ const conflicts = getConflicts ( nodes , contents )
501+ if ( conflicts . length === 0 ) {
502+ return nodes
503+ }
504+
505+ const result = await openConflictPicker (
506+ folder . displayname ,
507+ conflicts ,
508+ ( contents as Node [ ] ) . filter ( ( node ) => conflicts . some ( ( conflict ) => conflict . name === node . basename ) ) ,
509+ {
510+ recursive : true ,
511+ } ,
512+ )
513+ if ( result === null ) {
514+ return false
515+ }
516+ return [
517+ ...nodes . filter ( ( node ) => ! conflicts . some ( ( conflict ) => conflict . name === node . name ) ) ,
518+ ...result . selected ,
519+ ...result . renamed ,
520+ ]
521+ } catch {
522+ return nodes
523+ }
524+ } ,
525+ )
526+ this . dragover = false
527+ return
528+ }
529+
530+ // We might not have the target directory fetched yet
531+ const cachedContents = this . filesStore . getNodesByPath ( this . activeView . id , this . source . path )
532+ const contents = cachedContents . length === 0
533+ ? ( await this . activeView ! . getContents ( this . source . path ) ) . contents
534+ : cachedContents
535+
501536 const isCopy = event . ctrlKey
502537 this . dragover = false
503538
504- logger . debug ( 'Dropped' , { event, folder, selection, fileTree } )
505-
506- // Check whether we're uploading files
507- if ( selection . length === 0 && fileTree . contents . length > 0 ) {
508- await onDropExternalFiles ( fileTree , folder , contents . contents )
509- return
510- }
539+ logger . debug ( 'Dropped' , { event, folder : this . source , selection, fileTree } )
511540
512- // Else we're moving/copying files
513541 const nodes = selection . map ( ( source ) => this . filesStore . getNode ( source ) ) as Node [ ]
514- await onDropInternalFiles ( nodes , folder , contents . contents , isCopy )
542+ await onDropInternalFiles ( nodes , this . source , contents , isCopy )
515543
516544 // Reset selection after we dropped the files
517545 // if the dropped files are within the selection
0 commit comments