Skip to content

Commit db3d81a

Browse files
authored
Merge pull request #42409 from nextcloud/backport/42366/stable28
2 parents 72a5a20 + 4f3eb7c commit db3d81a

File tree

6 files changed

+107
-18
lines changed

6 files changed

+107
-18
lines changed

apps/files/src/components/DragAndDropNotice.vue

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,33 @@
2525
class="files-list__drag-drop-notice"
2626
@drop="onDrop">
2727
<div class="files-list__drag-drop-notice-wrapper">
28-
<TrayArrowDownIcon :size="48" />
29-
<h3 class="files-list-drag-drop-notice__title">
30-
{{ t('files', 'Drag and drop files here to upload') }}
31-
</h3>
28+
<template v-if="canUpload && !isQuotaExceeded">
29+
<TrayArrowDownIcon :size="48" />
30+
<h3 class="files-list-drag-drop-notice__title">
31+
{{ t('files', 'Drag and drop files here to upload') }}
32+
</h3>
33+
</template>
34+
35+
<!-- Not permitted to drop files here -->
36+
<template v-else>
37+
<h3 class="files-list-drag-drop-notice__title">
38+
{{ cantUploadLabel }}
39+
</h3>
40+
</template>
3241
</div>
3342
</div>
3443
</template>
3544

3645
<script lang="ts">
37-
import { translate as t } from '@nextcloud/l10n'
3846
import { defineComponent } from 'vue'
47+
import { Folder, Permission } from '@nextcloud/files'
48+
import { showError, showSuccess } from '@nextcloud/dialogs'
49+
import { translate as t } from '@nextcloud/l10n'
3950
4051
import TrayArrowDownIcon from 'vue-material-design-icons/TrayArrowDown.vue'
4152
4253
import logger from '../logger.js'
4354
import { handleDrop } from '../services/DropService'
44-
import { showSuccess } from '@nextcloud/dialogs'
4555
4656
export default defineComponent({
4757
name: 'DragAndDropNotice',
@@ -52,7 +62,7 @@ export default defineComponent({
5262
5363
props: {
5464
currentFolder: {
55-
type: Object,
65+
type: Folder,
5666
required: true,
5767
},
5868
},
@@ -63,35 +73,86 @@ export default defineComponent({
6373
}
6474
},
6575
76+
computed: {
77+
/**
78+
* Check if the current folder has create permissions
79+
*/
80+
canUpload() {
81+
return this.currentFolder && (this.currentFolder.permissions & Permission.CREATE) !== 0
82+
},
83+
isQuotaExceeded() {
84+
return this.currentFolder?.attributes?.['quota-available-bytes'] === 0
85+
},
86+
87+
cantUploadLabel() {
88+
if (this.isQuotaExceeded) {
89+
return this.t('files', 'Your have used your space quota and cannot upload files anymore')
90+
} else if (!this.canUpload) {
91+
return this.t('files', 'You don’t have permission to upload or create files here')
92+
}
93+
return null
94+
},
95+
},
96+
6697
mounted() {
6798
// Add events on parent to cover both the table and DragAndDrop notice
6899
const mainContent = window.document.querySelector('main.app-content') as HTMLElement
69100
mainContent.addEventListener('dragover', this.onDragOver)
70101
mainContent.addEventListener('dragleave', this.onDragLeave)
102+
mainContent.addEventListener('drop', this.onContentDrop)
71103
},
72104
73105
beforeDestroy() {
74106
const mainContent = window.document.querySelector('main.app-content') as HTMLElement
75107
mainContent.removeEventListener('dragover', this.onDragOver)
76108
mainContent.removeEventListener('dragleave', this.onDragLeave)
109+
mainContent.removeEventListener('drop', this.onContentDrop)
77110
},
78111
79112
methods: {
80113
onDragOver(event: DragEvent) {
114+
// Needed to keep the drag/drop events chain working
115+
event.preventDefault()
116+
81117
const isForeignFile = event.dataTransfer?.types.includes('Files')
118+
119+
logger.debug('Drag over DragAndDropNotice', { isForeignFile, event })
82120
if (isForeignFile) {
83-
// Only handle uploading
121+
// Only handle uploading of outside files (not Nextcloud files)
84122
this.dragover = true
85123
}
86124
},
87125
88-
onDragLeave(/* event: DragEvent */) {
126+
onDragLeave(event: DragEvent) {
127+
// Counter bubbling, make sure we're ending the drag
128+
// only when we're leaving the current element
129+
// Avoid flickering
130+
const currentTarget = event.currentTarget as HTMLElement
131+
if (currentTarget?.contains(event.relatedTarget as HTMLElement)) {
132+
return
133+
}
134+
135+
if (this.dragover) {
136+
this.dragover = false
137+
}
138+
},
139+
140+
onContentDrop(event: DragEvent) {
141+
logger.debug('Drag and drop cancelled, dropped on empty space', { event })
142+
event.preventDefault()
89143
if (this.dragover) {
90144
this.dragover = false
91145
}
92146
},
93147
94148
onDrop(event: DragEvent) {
149+
logger.debug('Dropped on DragAndDropNotice', { event, error: this.cantUploadLabel })
150+
151+
if (!this.canUpload || this.isQuotaExceeded) {
152+
showError(this.cantUploadLabel)
153+
return
154+
}
155+
95156
if (this.$el.querySelector('tbody')?.contains(event.target as Node)) {
96157
return
97158
}

apps/files/src/components/FilesListVirtual.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ export default defineComponent({
128128
FileEntryGrid,
129129
headers: getFileListHeaders(),
130130
scrollToIndex: 0,
131-
dndNoticeHeight: 0,
132131
}
133132
},
134133
@@ -259,7 +258,10 @@ export default defineComponent({
259258
onDragOver(event: DragEvent) {
260259
// Detect if we're only dragging existing files or not
261260
const isForeignFile = event.dataTransfer?.types.includes('Files')
261+
262262
if (isForeignFile) {
263+
// Only handle uploading of existing Nextcloud files
264+
// See DragAndDropNotice for handling of foreign files
263265
return
264266
}
265267

apps/files/src/services/DropService.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323
import type { Upload } from '@nextcloud/upload'
2424
import type { FileStat, ResponseDataDetailed } from 'webdav'
2525

26-
import { showError } from '@nextcloud/dialogs'
27-
import { emit } from '@nextcloud/event-bus'
2826
import { davGetClient, davGetDefaultPropfind, davResultToNode, davRootPath } from '@nextcloud/files'
29-
import { translate as t } from '@nextcloud/l10n'
27+
import { emit } from '@nextcloud/event-bus'
3028
import { getUploader } from '@nextcloud/upload'
29+
import { joinPaths } from '@nextcloud/paths'
30+
import { showError } from '@nextcloud/dialogs'
31+
import { translate as t } from '@nextcloud/l10n'
32+
3133
import logger from '../logger.js'
3234

3335
export const handleDrop = async (data: DataTransfer) => {
@@ -85,10 +87,12 @@ const handleRecursiveUpload = async (entry: FileSystemEntry, path: string = ''):
8587
]
8688
} else {
8789
const directory = entry as FileSystemDirectoryEntry
88-
logger.debug('Handle directory recursivly', { name: directory.name })
8990

9091
// TODO: Implement this on `@nextcloud/upload`
91-
const absolutPath = `${davRootPath}${getUploader().destination.path}${path}${directory.name}`
92+
const absolutPath = joinPaths(davRootPath, getUploader().destination.path, path, directory.name)
93+
94+
logger.debug('Handle directory recursively', { name: directory.name, absolutPath })
95+
9296
const davClient = davGetClient()
9397
const dirExists = await davClient.exists(absolutPath)
9498
if (!dirExists) {

dist/files-main.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files-main.js.LICENSE.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,28 @@
166166
*
167167
*/
168168

169+
/**
170+
* @copyright Copyright (c) 2023 Ferdinand Thiessen <[email protected]>
171+
*
172+
* @author Ferdinand Thiessen <[email protected]>
173+
*
174+
* @license AGPL-3.0-or-later
175+
*
176+
* This program is free software: you can redistribute it and/or modify
177+
* it under the terms of the GNU Affero General Public License as
178+
* published by the Free Software Foundation, either version 3 of the
179+
* License, or (at your option) any later version.
180+
*
181+
* This program is distributed in the hope that it will be useful,
182+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
183+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
184+
* GNU Affero General Public License for more details.
185+
*
186+
* You should have received a copy of the GNU Affero General Public License
187+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
188+
*
189+
*/
190+
169191
/**
170192
* @copyright Copyright (c) 2023 John Molakvoæ <[email protected]>
171193
*

dist/files-main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)