- uploading via files queue

This commit is contained in:
Peter Papp
2021-02-21 19:56:03 +01:00
parent d92bb50a03
commit b8790a964b
7 changed files with 244 additions and 371 deletions

View File

@@ -112,7 +112,7 @@ export default {
'shared',
'public'
]
return !this.$isThisLocation(locations) || this.fileInfoDetail.length === 0
return !this.$isThisLocation(locations) || this.fileInfoDetail.length === 0
},
canUploadInView() {
return !this.$isThisLocation(['base', 'public'])
@@ -125,7 +125,7 @@ export default {
'shared',
'public'
]
return !this.$isThisLocation(locations) || this.fileInfoDetail.length === 0
return !this.$isThisLocation(locations) || this.fileInfoDetail.length === 0
},
canShareInView() {
@@ -137,7 +137,7 @@ export default {
'public'
]
return !this.$isThisLocation(locations) || this.fileInfoDetail.length > 1 || this.fileInfoDetail.length === 0
return !this.$isThisLocation(locations) || this.fileInfoDetail.length > 1 || this.fileInfoDetail.length === 0
}
},
data() {
@@ -183,14 +183,14 @@ export default {
events.$emit('folder:actions', this.currentFolder)
},
deleteItem() {
if(this.fileInfoDetail.length > 0)
if (this.fileInfoDetail.length > 0)
this.$store.dispatch('deleteItem')
},
createFolder() {
this.$store.dispatch('createFolder', this.$t('popup_create_folder.folder_default_name'))
},
moveItem() {
if(this.fileInfoDetail.length > 0)
if (this.fileInfoDetail.length > 0)
events.$emit('popup:open', { name: 'move', item: this.fileInfoDetail })
},
shareItem() {
@@ -215,9 +215,9 @@ export default {
// this.sortingAndPreview = state
// })
events.$on('unClick', () => {
this.sortingAndPreview = false
})
events.$on('unClick', () => {
this.sortingAndPreview = false
})
}
}
</script>
@@ -225,15 +225,18 @@ export default {
<style scoped lang="scss">
@import "@assets/vue-file-manager/_variables";
@import "@assets/vue-file-manager/_mixins";
.preview-sorting {
.preview-sorting {
/deep/ .label {
color: $text !important;
}
/deep/ .preview-sorting {
path, line, polyline, rect, circle {
stroke: $text !important;
}
path, line, polyline, rect, circle {
stroke: $text !important;
}
}
&:hover {
/deep/ .preview-sorting {
path, line, polyline, rect, circle {
@@ -358,6 +361,7 @@ export default {
&.preview-sorting {
background: $light_background;
/deep/ .preview-sorting {
path, line, polyline, rect, circle {
stroke: $theme !important;
@@ -423,14 +427,15 @@ export default {
background: $dark_mode_foreground !important;
}
}
.preview-sorting {
.preview-sorting {
/deep/ .label {
color: $text !important;
}
/deep/ .preview-sorting {
path, line, polyline, rect, circle {
stroke: $dark_mode_text_primary !important;
}
path, line, polyline, rect, circle {
stroke: $dark_mode_text_primary !important;
}
}
}
}

View File

@@ -1,5 +1,5 @@
<template>
<div class="file-content" id="file-content-id" :class="{ 'is-offset': uploadingFilesCount, 'is-dragging': isDragging }"
<div class="file-content" id="file-content-id" :class="{ 'is-offset': filesQueue > 0, 'is-dragging': isDragging }"
@dragover.prevent
@drop.stop.prevent="dropUpload($event)"
@dragover="dragEnter"
@@ -119,7 +119,7 @@
},
computed: {
...mapGetters([
'uploadingFilesCount',
'filesQueue',
'fileInfoVisible',
'fileInfoDetail',
'currentFolder',

View File

@@ -1,6 +1,7 @@
<template>
<transition name="info-panel">
<div v-if="filesQueue.length > 0" class="upload-progress">
<!--<div v-if="filesQueue.length > 0" class="upload-progress">-->
<div class="upload-progress">
<div class="progress-title">
<!--Is processing-->
@@ -11,16 +12,16 @@
<!--Single file upload-->
<span v-if="!isProcessingFile && filesQueue.length === 1">
{{ $t('uploading.progress_single_upload', {progress: 80}) }}
{{ $t('uploading.progress_single_upload', {progress: uploadingProgress}) }}
</span>
<!--Multi file upload-->
<span v-if="!isProcessingFile && filesQueue.length > 1">
{{ $t('uploading.progress', {current:'x', total: filesQueue.length, progress: 80}) }}
{{ $t('uploading.progress', {current:'x', total: filesQueue.length, progress: uploadingProgress}) }}
</span>
</div>
<div class="progress-wrapper">
<ProgressBar :progress="80" />
<ProgressBar :progress="uploadingProgress" />
<span @click="cancelUpload" :title="$t('uploading.cancel')" class="cancel-icon">
<x-icon size="16" @click="cancelUpload"></x-icon>
</span>
@@ -44,6 +45,7 @@
},
computed: {
...mapGetters([
'uploadingProgress',
'isProcessingFile',
'filesQueue',
])

View File

@@ -76,103 +76,6 @@ const Helpers = {
this.$store.dispatch('createFolder', folderName)
}
Vue.prototype.$handleUploading = async function () {
//let files = this.$store.getters.filesQueue
let fileBuffer = []
// Append the file list to fileBuffer array
Array.prototype.push.apply(fileBuffer, this.$store.getters.filesQueue);
let fileSucceed = 0
// Update files count in progressbar
store.commit('UPDATE_FILE_COUNT_PROGRESS', {
current: fileSucceed,
total: this.$store.getters.filesQueue.length
})
// Reset upload progress to 0
store.commit('UPLOADING_FILE_PROGRESS', 0)
// Get parent id
let parentFolder = this.$store.getters.currentFolder ? this.$store.getters.currentFolder.unique_id : 0
// Upload files
do {
let onQueue = fileBuffer.shift(),
chunks = []
// Calculate ceils
let size = this.$store.getters.config.chunkSize,
chunksCeil = Math.ceil(onQueue.file.size / size);
// Create chunks
for (let i = 0; i < chunksCeil; i++) {
chunks.push(onQueue.file.slice(
i * size, Math.min(i * size + size, onQueue.file.size), onQueue.file.type
));
}
// Set Data
let formData = new FormData(),
uploadedSize = 0,
isNotGeneralError = true,
striped_name = onQueue.file.name.replace(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g, ''),
filename = Array(16).fill(0).map(x => Math.random().toString(36).charAt(2)).join('') + '-' + striped_name + '.part'
do {
let isLast = chunks.length === 1,
chunk = chunks.shift(),
attempts = 0
// Set form data
formData.set('file', chunk, filename);
formData.set('parent_id', onQueue.parent_id)
formData.set('is_last', isLast);
// Upload chunks
do {
await store.dispatch('uploadFiles', {
form: formData,
fileSize: onQueue.file.size,
totalUploadedSize: uploadedSize
}).then(() => {
uploadedSize = uploadedSize + chunk.size
}).catch((error) => {
// Count attempts
attempts++
// Break uploading proccess
if (error.response.status === 500)
isNotGeneralError = false
//Break if mimetype of file is in blacklist
if(error.response.status === 415)
isNotGeneralError = false
// Show Error
if (attempts === 3)
this.$isSomethingWrong()
})
} while (isNotGeneralError && attempts !== 0 && attempts !== 3)
} while (isNotGeneralError && chunks.length !== 0)
fileSucceed++
// Progress file log
store.commit('UPDATE_FILE_COUNT_PROGRESS', {
current: fileSucceed,
total: this.$store.getters.filesQueue.length
})
} while (fileBuffer.length !== 0)
store.commit('UPDATE_FILE_COUNT_PROGRESS', undefined)
}
Vue.prototype.$uploadFiles = async function (files) {
if (files.length == 0) return
@@ -185,7 +88,7 @@ const Helpers = {
Vue.prototype.$uploadExternalFiles = async function (event, parent_id) {
// Prevent submit empty files
if (event.dataTransfer.items.length == 0) return
if (event.dataTransfer.items.length === 0) return
// Push files to queue
[...event.dataTransfer.items].map(item => {
@@ -195,11 +98,70 @@ const Helpers = {
})
});
if (! this.$store.getters.uploadingFilesCount) {
this.$handleUploading()
if (! this.$store.getters.uploadingProgress > 0) {
this.$handleUploading(
this.$store.getters.filesQueue.shift()
)
}
}
Vue.prototype.$handleUploading = async function (item) {
// Create ceil
let size = 128000000, // todo: chunksize doriesit
chunksCeil = Math.ceil(item.file.size / size),
chunks = []
// Create chunks
for (let i = 0; i < chunksCeil; i++) {
chunks.push(item.file.slice(
i * size, Math.min(i * size + size, item.file.size), item.file.type
));
}
// Set Data
let formData = new FormData(),
uploadedSize = 0,
isNotGeneralError = true,
striped_name = item.file.name.replace(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g, ''),
filename = Array(16).fill(0).map(x => Math.random().toString(36).charAt(2)).join('') + '-' + striped_name + '.part'
do {
let isLast = chunks.length === 1,
chunk = chunks.shift(),
attempts = 0
// Set form data
formData.set('file', chunk, filename);
formData.set('parent_id', item.parent_id)
formData.set('is_last', isLast);
// Upload chunks
do {
await store.dispatch('uploadFiles', {
form: formData,
fileSize: item.file.size,
totalUploadedSize: uploadedSize
}).then(() => {
uploadedSize = uploadedSize + chunk.size
}).catch((error) => {
// Count attempts
attempts++
// Show Error
if (attempts === 3)
this.$isSomethingWrong()
// Break uploading process
if ([500, 415].includes(error.response.status))
isNotGeneralError = false
})
} while (isNotGeneralError && attempts !== 0 && attempts !== 3)
} while (isNotGeneralError && chunks.length !== 0)
}
Vue.prototype.$downloadFile = function (url, filename) {
var anchor = document.createElement('a')
@@ -288,6 +250,7 @@ const Helpers = {
message: i18n.t('popup_error.message')
})
}
Vue.prototype.$checkFileMimetype = function(files) {
let validated = true
let mimetypesBlacklist = store.getters.config.mimetypesBlacklist
@@ -352,6 +315,7 @@ const Helpers = {
// Get data of Navigator tree
this.$store.dispatch('getFolderTree')
}
Vue.prototype.$checkOS = function() {
// Handle styled scrollbar for Windows
if (navigator.userAgent.indexOf('Windows') != -1) {

View File

@@ -5,11 +5,8 @@ import router from '@/router'
import i18n from '@/i18n/index'
const defaultState = {
uploadingFilesCount: undefined,
fileInfoDetail: [],
currentFolder: undefined,
uploadingFileProgress: 0,
isProcessingFile: false,
navigation: undefined,
isSearching: false,
browseHistory: [],
@@ -264,12 +261,6 @@ const mutations = {
CHANGE_SEARCHING_STATE(state, searchState) {
state.isSearching = searchState
},
UPLOADING_FILE_PROGRESS(state, percentage) {
state.uploadingFileProgress = percentage
},
UPDATE_FILE_COUNT_PROGRESS(state, data) {
state.uploadingFilesCount = data
},
UPDATE_SHARED_ITEM(state, data) {
state.data.find(item => {
if (item.unique_id == data.item_id) item.shared = data
@@ -292,15 +283,9 @@ const mutations = {
STORE_CURRENT_FOLDER(state, folder) {
state.currentFolder = folder
},
PROCESSING_FILE(state, status) {
state.isProcessingFile = status
}
}
const getters = {
uploadingFileProgress: state => state.uploadingFileProgress,
uploadingFilesCount: state => state.uploadingFilesCount,
isProcessingFile: state => state.isProcessingFile,
fileInfoDetail: state => state.fileInfoDetail,
currentFolder: state => state.currentFolder,
browseHistory: state => state.browseHistory,

View File

@@ -4,18 +4,22 @@ import { events } from '@/bus'
import { last } from 'lodash'
import axios from 'axios'
import Vue from 'vue'
import store from '../index'
const defaultState = {
processingPopup: undefined,
filesQueue: [],
isProcessingFile: false,
uploadingProgress: 0
}
const actions = {
downloadFolder: ({commit, getters}, folder) => {
downloadFolder: ({ commit, getters }, folder) => {
commit('PROCESSING_POPUP', {
title: i18n.t('popup_zipping.title'),
message: i18n.t('popup_zipping.message'),
message: i18n.t('popup_zipping.message')
})
// Get route
@@ -24,15 +28,15 @@ const actions = {
: '/api/zip-folder/' + folder.unique_id
axios.get(route)
.then(response => {
Vue.prototype.$downloadFile(response.data.url, response.data.name)
})
.catch(() => {
Vue.prototype.$isSomethingWrong()
})
.finally(() => {
commit('PROCESSING_POPUP', undefined)
})
.then(response => {
Vue.prototype.$downloadFile(response.data.url, response.data.name)
})
.catch(() => {
Vue.prototype.$isSomethingWrong()
})
.finally(() => {
commit('PROCESSING_POPUP', undefined)
})
},
downloadFiles: ({ commit, getters }) => {
@@ -124,7 +128,7 @@ const actions = {
//Set focus on new folder name
setTimeout(() => {
events.$emit('newFolder:focus', response.data.unique_id)
}, 10);
}, 10)
if (getters.currentFolder.location !== 'public')
dispatch('getAppData')
@@ -170,9 +174,9 @@ const actions = {
? '/api/upload/public/' + router.currentRoute.params.token
: '/api/upload'
// Create cancel token for axios cancelation
const CancelToken = axios.CancelToken
const source = CancelToken.source()
// Create cancel token for axios cancellation
const CancelToken = axios.CancelToken,
source = CancelToken.source()
axios
.post(route, form, {
@@ -181,63 +185,63 @@ const actions = {
'Content-Type': 'application/octet-stream'
},
onUploadProgress: event => {
var percentCompleted = Math.floor(((totalUploadedSize + event.loaded) / fileSize) * 100)
commit('UPLOADING_FILE_PROGRESS', percentCompleted >= 100 ? 100 : percentCompleted)
if (percentCompleted >= 100) {
// Set processing file
if (percentCompleted >= 100)
commit('PROCESSING_FILE', true)
}
}
})
.then(response => {
resolve(response)
commit('PROCESSING_FILE', false)
// Check if user is in uploading folder, if yes, than show new file
if (response.data.folder_id == getters.currentFolder.unique_id)
if (response.data.folder_id == getters.currentFolder.unique_id) {
// Add uploaded item into view
commit('ADD_NEW_ITEMS', response.data)
// TODO: handle new uploads if exist
resolve(response)
})
.catch(error => {
commit('PROCESSING_FILE', false)
reject(error)
switch (error.response.status) {
case 423:
events.$emit('alert:open', {
emoji: '😬😬😬',
title: i18n.t('popup_exceed_limit.title'),
message: i18n.t('popup_exceed_limit.message')
})
break
case 415:
events.$emit('alert:open', {
emoji: '😬😬😬',
title: i18n.t('popup_mimetypes_blacklist.title'),
message: i18n.t('popup_mimetypes_blacklist.message')
})
break
case 413:
events.$emit('alert:open', {
emoji: '😟😟😟',
title: i18n.t('popup_paylod_error.title'),
message: i18n.t('popup_paylod_error.message')
})
break
default:
events.$emit('alert:open', {
title: i18n.t('popup_error.title'),
message: i18n.t('popup_error.message')
})
break
// Reset file progress
commit('UPLOADING_FILE_PROGRESS', 0)
}
// Reset uploader
// TODO: handle new uploads if exist
if (getters.filesQueue.length > 0) {
Vue.prototype.$handleUploading(getters.filesQueue[0])
commit('SHIFT_FILE_FROM_QUEUE')
// todo: doriesit uploading ffile statistiky na frontende
}
})
.catch(error => {
reject(error)
let messages = {
'423': {
title: i18n.t('popup_exceed_limit.title'),
message: i18n.t('popup_exceed_limit.message')
},
'415': {
title: i18n.t('popup_mimetypes_blacklist.title'),
message: i18n.t('popup_mimetypes_blacklist.message')
},
'413': {
title: i18n.t('popup_paylod_error.title'),
message: i18n.t('popup_paylod_error.message')
}
}
events.$emit('alert:open', {
emoji: '😬😬😬',
title: messages[error.response.status]['title'],
message: messages[error.response.status]['message']
})
commit('PROCESSING_FILE', false)
commit('UPDATE_FILE_COUNT_PROGRESS', undefined)
})
@@ -260,28 +264,27 @@ const actions = {
// If coming no selected item dont get items to restore from fileInfoDetail
if (!item)
items = getters.fileInfoDetail
// Check if file can be restored to home directory
if (getters.currentFolder.location === 'trash')
restoreToHome = true
items.forEach(data => itemToRestore.push({
'type': data.type,
'unique_id': data.unique_id,
'unique_id': data.unique_id
}))
// Remove file preview
commit('CLEAR_FILEINFO_DETAIL')
axios
.post(getters.api + '/restore-items' ,{
.post(getters.api + '/restore-items', {
to_home: restoreToHome,
data: itemToRestore,
data: itemToRestore
})
.then(
// Remove file
items.forEach( data => commit('REMOVE_ITEM', data.unique_id) )
items.forEach(data => commit('REMOVE_ITEM', data.unique_id))
)
.catch(() => Vue.prototype.$isSomethingWrong())
},
@@ -390,12 +393,23 @@ const mutations = {
},
ADD_FILES_TO_QUEUE(state, file) {
state.filesQueue.push(file)
},
SHIFT_FILE_FROM_QUEUE(state) {
state.filesQueue.shift()
},
PROCESSING_FILE(state, status) {
state.isProcessingFile = status
},
UPLOADING_FILE_PROGRESS(state, percentage) {
state.uploadingProgress = percentage
}
}
const getters = {
uploadingProgress: state => state.uploadingProgress,
isProcessingFile: state => state.isProcessingFile,
processingPopup: state => state.processingPopup,
filesQueue: state => state.filesQueue,
filesQueue: state => state.filesQueue
}
export default {