Merge remote-tracking branch 'origin/upload-fix'

# Conflicts:
#	public/mix-manifest.json
This commit is contained in:
Peter Papp
2021-02-25 15:23:09 +01:00
8 changed files with 372 additions and 273 deletions

View File

@@ -110,7 +110,7 @@ export default {
},
computed: {
...mapGetters([
'isLogged', 'isGuest', 'config'
'isLogged', 'isGuest', 'config', 'fileQueue'
]),
isGuestLayout() {
return (includes([

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': filesInQueueTotal > 0, 'is-dragging': isDragging }"
@dragover.prevent
@drop.stop.prevent="dropUpload($event)"
@dragover="dragEnter"
@@ -119,7 +119,7 @@
},
computed: {
...mapGetters([
'uploadingFilesCount',
'filesInQueueTotal',
'fileInfoVisible',
'fileInfoDetail',
'currentFolder',

View File

@@ -1,20 +1,21 @@
<template>
<transition name="info-panel">
<div v-if="uploadingFilesCount" class="upload-progress">
<div v-if="fileQueue.length > 0" class="upload-progress">
<div class="progress-title">
<!--Is processing-->
<span v-if="isProcessingFile">
<refresh-cw-icon size="12" class="sync-alt"></refresh-cw-icon>
{{ $t('uploading.processing_file') }}
</span>
<span v-if="!isProcessingFile && uploadingFilesCount.total === 1">
{{ $t('uploading.progress_single_upload', {progress: uploadingFileProgress}) }}
</span>
<span v-if="!isProcessingFile && uploadingFilesCount.total > 1">
{{ $t('uploading.progress', {current:uploadingFilesCount.current, total: uploadingFilesCount.total, progress: uploadingFileProgress}) }}
<!--Multi file upload-->
<span v-if="!isProcessingFile && fileQueue.length > 0">
{{ $t('uploading.progress', {current:filesInQueueUploaded, total: filesInQueueTotal, progress: uploadingProgress}) }}
</span>
</div>
<div class="progress-wrapper">
<ProgressBar :progress="uploadingFileProgress" />
<ProgressBar :progress="uploadingProgress" />
<span @click="cancelUpload" :title="$t('uploading.cancel')" class="cancel-icon">
<x-icon size="16" @click="cancelUpload"></x-icon>
</span>
@@ -38,9 +39,11 @@
},
computed: {
...mapGetters([
'uploadingFileProgress',
'uploadingFilesCount',
'filesInQueueUploaded',
'filesInQueueTotal',
'uploadingProgress',
'isProcessingFile',
'fileQueue',
])
},
methods: {

View File

@@ -76,123 +76,106 @@ const Helpers = {
this.$store.dispatch('createFolder', folderName)
}
Vue.prototype.$handleUploading = async function (files, parent_id) {
let fileBuffer = []
// Append the file list to fileBuffer array
Array.prototype.push.apply(fileBuffer, files);
let fileSucceed = 0
// Update files count in progressbar
store.commit('UPDATE_FILE_COUNT_PROGRESS', {
current: fileSucceed,
total: files.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
let rootFolder = parent_id ? parent_id : parentFolder
// Upload files
do {
let file = fileBuffer.shift(),
chunks = []
// Calculate ceils
let size = this.$store.getters.config.chunkSize,
chunksCeil = Math.ceil(file.size / size);
// Create chunks
for (let i = 0; i < chunksCeil; i++) {
chunks.push(file.slice(
i * size, Math.min(i * size + size, file.size), file.type
));
}
// Set Data
let formData = new FormData(),
uploadedSize = 0,
isNotGeneralError = true,
striped_name = 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', rootFolder)
formData.set('is_last', isLast);
// Upload chunks
do {
await store.dispatch('uploadFiles', {
form: formData,
fileSize: 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: files.length
})
} while (fileBuffer.length !== 0)
store.commit('UPDATE_FILE_COUNT_PROGRESS', undefined)
}
Vue.prototype.$uploadFiles = async function (files) {
if (files.length == 0) return
if (files.length == 0) return
if (!this.$checkFileMimetype(files) || !this.$checkUploadLimit(files)) return
this.$handleUploading(files, undefined)
// Push items to file queue
[...files].map(item => {
this.$store.commit('ADD_FILES_TO_QUEUE', {
parent_id: store.getters.currentFolder.unique_id,
file: item,
})
});
// Start uploading if uploading process isn't running
if (this.$store.getters.filesInQueueTotal == 0)
this.$handleUploading(store.getters.fileQueue[0])
// Increase total files in upload bar
this.$store.commit('INCREASE_FILES_IN_QUEUES_TOTAL', files.length)
}
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
// Get files
let files = [...event.dataTransfer.items].map(item => item.getAsFile());
// Push items to file queue
[...event.dataTransfer.items].map(item => {
this.$store.commit('ADD_FILES_TO_QUEUE', {
parent_id: parent_id,
file: item.getAsFile(),
})
});
this.$handleUploading(files, parent_id)
// Start uploading if uploading process isn't running
if (this.$store.getters.filesInQueueTotal == 0)
this.$handleUploading(this.$store.getters.fileQueue[0])
// Increase total files in upload bar
this.$store.commit('INCREASE_FILES_IN_QUEUES_TOTAL', [...event.dataTransfer.items].length)
}
Vue.prototype.$handleUploading = async function (item) {
// Create ceil
let size = store.getters.config.chunkSize,
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')
@@ -281,6 +264,7 @@ const Helpers = {
message: i18n.t('popup_error.message')
})
}
Vue.prototype.$checkFileMimetype = function(files) {
let validated = true
let mimetypesBlacklist = store.getters.config.mimetypesBlacklist
@@ -345,6 +329,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,17 +4,24 @@ import { events } from '@/bus'
import { last } from 'lodash'
import axios from 'axios'
import Vue from 'vue'
import store from '../index'
const defaultState = {
processingPopup: undefined,
fileQueue: [],
filesInQueueTotal: 0,
filesInQueueUploaded: 0,
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
@@ -23,15 +30,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 }) => {
@@ -126,7 +133,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')
@@ -172,9 +179,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, {
@@ -183,62 +190,72 @@ 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)
// Remove first file from file queue
commit('SHIFT_FROM_FILE_QUEUE')
// 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)
resolve(response)
})
.catch(error => {
commit('PROCESSING_FILE', false)
// Reset file progress
commit('UPLOADING_FILE_PROGRESS', 0)
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
// Increase count in files in queue uploaded for 1
commit('INCREASE_FILES_IN_QUEUE_UPLOADED')
}
// Reset uploader
commit('UPDATE_FILE_COUNT_PROGRESS', undefined)
// Start uploading next file if file queue is not empty
if (getters.fileQueue.length) {
Vue.prototype.$handleUploading(getters.fileQueue[0])
}
// Reset upload process
if (! getters.fileQueue.length)
commit('CLEAR_UPLOAD_PROGRESS')
})
.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('CLEAR_UPLOAD_PROGRESS')
})
// Cancel the upload request
@@ -247,7 +264,7 @@ const actions = {
// Hide upload progress bar
commit('PROCESSING_FILE', false)
commit('UPDATE_FILE_COUNT_PROGRESS', undefined)
commit('CLEAR_UPLOAD_PROGRESS')
})
})
},
@@ -260,28 +277,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())
},
@@ -387,11 +403,39 @@ const actions = {
const mutations = {
PROCESSING_POPUP(state, status) {
state.processingPopup = status
},
ADD_FILES_TO_QUEUE(state, file) {
state.fileQueue.push(file)
},
SHIFT_FROM_FILE_QUEUE(state) {
state.fileQueue.shift()
},
PROCESSING_FILE(state, status) {
state.isProcessingFile = status
},
UPLOADING_FILE_PROGRESS(state, percentage) {
state.uploadingProgress = percentage
},
INCREASE_FILES_IN_QUEUES_TOTAL(state, count) {
state.filesInQueueTotal += count
},
INCREASE_FILES_IN_QUEUE_UPLOADED(state) {
state.filesInQueueUploaded++
},
CLEAR_UPLOAD_PROGRESS(state) {
state.filesInQueueUploaded = 0
state.filesInQueueTotal = 0
state.fileQueue = []
}
}
const getters = {
processingPopup: state => state.processingPopup
filesInQueueUploaded: state => state.filesInQueueUploaded,
filesInQueueTotal: state => state.filesInQueueTotal,
uploadingProgress: state => state.uploadingProgress,
isProcessingFile: state => state.isProcessingFile,
processingPopup: state => state.processingPopup,
fileQueue: state => state.fileQueue
}
export default {