diff --git a/packages/dashboard/src/appUtils.js b/packages/dashboard/src/appUtils.js index 6c0d603..7c3e846 100644 --- a/packages/dashboard/src/appUtils.js +++ b/packages/dashboard/src/appUtils.js @@ -70,6 +70,10 @@ export const bytesToMegabytes = (bytes) => { }; export const encode = (key) => { + if (key && key !== '/' && key.startsWith('/')) { + // File keys should never start with / + key = key.slice(1) + } return btoa(unescape(encodeURIComponent(key))); }; diff --git a/packages/dashboard/src/components/files/FileOptions.vue b/packages/dashboard/src/components/files/FileOptions.vue index 05ffd84..c2029e6 100644 --- a/packages/dashboard/src/components/files/FileOptions.vue +++ b/packages/dashboard/src/components/files/FileOptions.vue @@ -86,9 +86,14 @@ export default defineComponent({ }) }, deleteConfirm: async function() { - this.deleteModal = false - if (this.row.type === 'folder') { + // When deleting folders, first must copy the objects, because the popup close forces a reset on properties + const originalFolder = { ...this.row } + const folderContents = [...this.deleteFolderContents] + const folderContentsCount = this.deleteFolderInnerFilesCount + + this.deleteModal = false + const notif = this.q.notify({ group: false, spinner: true, @@ -97,16 +102,16 @@ export default defineComponent({ timeout: 0 }) - // console.log(this.deleteFolderContents) - for (const [i, innerFile] of this.deleteFolderContents.entries()) { + for (const [i, innerFile] of folderContents.entries()) { if (innerFile.key) { await apiHandler.deleteObject(innerFile.key, this.selectedBucket) } notif({ - caption: `${parseInt(i*100/(this.deleteFolderInnerFilesCount+1))}%` // +1 because still needs to delete the folder + caption: `${parseInt(i*100/(folderContentsCount+1))}%` // +1 because still needs to delete the folder }) } - await apiHandler.deleteObject(this.row.key, this.selectedBucket) + + await apiHandler.deleteObject(originalFolder.key, this.selectedBucket) notif({ icon: 'done', // we add an icon @@ -116,6 +121,7 @@ export default defineComponent({ timeout: 2500 // we will timeout it in 2.5s }) } else { + this.deleteModal = false await apiHandler.deleteObject(this.row.key, this.selectedBucket) this.q.notify({ group: false, diff --git a/packages/dashboard/src/components/utils/DragAndDrop.vue b/packages/dashboard/src/components/utils/DragAndDrop.vue index 5e0fc90..920cdac 100644 --- a/packages/dashboard/src/components/utils/DragAndDrop.vue +++ b/packages/dashboard/src/components/utils/DragAndDrop.vue @@ -110,6 +110,7 @@ export default { }, async uploadFiles (folders) { let totalFiles = 0 + let totalSize = 0 const filenames = [] // Create folders and count files @@ -119,13 +120,16 @@ export default { // } if (folder !== '') { - await apiHandler.createFolder(this.selectedFolder + folder + '/', this.selectedBucket) + let folderKey = this.selectedFolder + folder + '/' + + await apiHandler.createFolder(folderKey, this.selectedBucket) } totalFiles += files.length for (const file of files) { filenames.push(file.name) + totalSize += file.size } } @@ -142,6 +146,7 @@ export default { // Upload files let uploadCount = 0 + let uploadSize = 0 for (const [folder, files] of Object.entries(folders)) { notif({ message: `Uploading files ${uploadCount+1}/${filenames.length}...`, @@ -164,7 +169,7 @@ export default { const chunkSize = 95 * 1024 * 1024 // Files bigger than 100MB require multipart upload if (file.size > chunkSize) { - const { uploadId, key } = (await apiHandler.multipartCreate(file, key, this.selectedBucket)).data + const { uploadId } = (await apiHandler.multipartCreate(file, key, this.selectedBucket)).data let partNumber = 1 const parts = [] @@ -178,6 +183,9 @@ export default { const { data } = await apiHandler.multipartUpload(uploadId, partNumber, this.selectedBucket, key, chunk, (progressEvent) => { //console.log((start + progressEvent.loaded) * 100 / file.size) + notif({ + caption: `${parseInt((uploadSize+start + progressEvent.loaded)*100/(totalSize))}%` + }) // self.$store.dispatch('setUploadProgress', { // filename: file.name, // progress: (start + progressEvent.loaded) * 100 / file.size @@ -192,12 +200,17 @@ export default { } else { await apiHandler.uploadObjects(file, key, this.selectedBucket, (progressEvent) => { //console.log(progressEvent.loaded * 100 / file.size) + notif({ + caption: `${parseInt((uploadSize+progressEvent.loaded)*100/(totalSize))}%` + }) // self.$store.dispatch('setUploadProgress', { // filename: file.name, // progress: progressEvent.loaded * 100 / file.size // }) // TODO }) } + + uploadSize += file.size } }