diff --git a/frontend/src/store/modules/upload.js b/frontend/src/store/modules/upload.js index c1378d9a..738edaf9 100644 --- a/frontend/src/store/modules/upload.js +++ b/frontend/src/store/modules/upload.js @@ -1,34 +1,95 @@ import Vue from 'vue' +import { files as api } from '@/api' +import throttle from 'lodash.throttle' +import buttons from '@/utils/buttons' + +const UPLOADS_LIMIT = 5; const state = { id: 0, - count: 0, size: 0, - progress: [] + progress: [], + queue: [], + uploads: {} } const mutations = { - incrementId: (state) => { - state.id = state.id + 1 - }, - incrementSize: (state, value) => { - state.size = state.size + value - }, - incrementCount: (state) => { - state.count = state.count + 1 - }, - decreaseCount: (state) => { - state.count = state.count - 1 - }, setProgress(state, { id, loaded }) { Vue.set(state.progress, id, loaded) }, reset: (state) => { state.id = 0 state.size = 0 - state.count = 0 state.progress = [] + }, + addJob: (state, item) => { + state.queue.push(item) + state.size += item.file.size + state.id++ + }, + moveJob(state) { + const item = state.queue[0] + state.queue.shift() + Vue.set(state.uploads, item.id, item) + }, + removeJob(state, id) { + delete state.uploads[id] } } -export default { state, mutations, namespaced: true } \ No newline at end of file +const actions = { + upload: (context, item) => { + let uploadsCount = Object.keys(context.state.uploads).length; + + let isQueueEmpty = context.state.queue.length == 0 + let isUploadsEmpty = uploadsCount == 0 + + if (isQueueEmpty && isUploadsEmpty) { + buttons.loading('upload') + } + + context.commit('addJob', item) + context.dispatch('processUploads') + }, + finishUpload: (context, item) => { + context.commit('setProgress', { id: item.id, loaded: item.file.size }) + context.commit('removeJob', item.id) + context.dispatch('processUploads') + }, + processUploads: async (context) => { + let uploadsCount = Object.keys(context.state.uploads).length; + + let isBellowLimit = uploadsCount < UPLOADS_LIMIT + let isQueueEmpty = context.state.queue.length == 0 + let isUploadsEmpty = uploadsCount == 0 + + let isFinished = isQueueEmpty && isUploadsEmpty + let canProcess = isBellowLimit && !isQueueEmpty + + if (isFinished) { + buttons.success('upload') + context.commit('reset') + context.commit('setReload', true, { root: true }) + } + + if (canProcess) { + const item = context.state.queue[0]; + context.commit('moveJob') + + if (item.file.isDir) { + await api.post(item.path).catch(Vue.prototype.$showError) + } else { + let onUpload = throttle( + (event) => context.commit('setProgress', { id: item.id, loaded: event.loaded }), + 100, { leading: true, trailing: false } + ) + + await api.post(item.path, item.file, item.overwrite, onUpload).catch(Vue.prototype.$showError) + } + + context.dispatch('finishUpload', item) + } + } +} + +export default { state, mutations, actions, namespaced: true } \ No newline at end of file diff --git a/frontend/src/utils/upload.js b/frontend/src/utils/upload.js index 32b32fa9..61e6a8e7 100644 --- a/frontend/src/utils/upload.js +++ b/frontend/src/utils/upload.js @@ -1,7 +1,4 @@ import store from '@/store' -import { files as api } from '@/api' -import throttle from 'lodash.throttle' -import buttons from '@/utils/buttons' import url from '@/utils/url' export function checkConflict(files, items) { @@ -71,6 +68,7 @@ export function scanFiles(dt) { } else if (entry.isDirectory) { const dir = { isDir: true, + size: 0, path: `${directory}${entry.name}` } @@ -102,67 +100,34 @@ export function scanFiles(dt) { } export function handleFiles(files, path, overwrite = false) { - if (store.state.upload.count == 0) { - buttons.loading('upload') - } - - let promises = [] - - let onupload = (id) => (event) => { - store.commit('upload/setProgress', { id, loaded: event.loaded }) - } - for (let i = 0; i < files.length; i++) { let file = files[i] - if (!file.isDir) { - let filename = (file.fullPath !== undefined) ? file.fullPath : file.name - let filenameEncoded = url.encodeRFC5987ValueChars(filename) + let filename = (file.fullPath !== undefined) ? file.fullPath : file.name + let filenameEncoded = url.encodeRFC5987ValueChars(filename) - let id = store.state.upload.id + let id = store.state.upload.id - store.commit('upload/incrementSize', file.size) - store.commit('upload/incrementId') - store.commit('upload/incrementCount') + let itemPath = path + filenameEncoded - let promise = api.post(path + filenameEncoded, file, overwrite, throttle(onupload(id), 100)).finally(() => { - store.commit('upload/decreaseCount') - }) - - promises.push(promise) - } else { - let uri = path + if (file.isDir) { + itemPath = path let folders = file.path.split("/") for (let i = 0; i < folders.length; i++) { let folder = folders[i] let folderEncoded = encodeURIComponent(folder) - uri += folderEncoded + "/" + itemPath += folderEncoded + "/" } - - api.post(uri) - } - } - - let finish = () => { - if (store.state.upload.count > 0) { - return } - buttons.success('upload') + const item = { + id, + path: itemPath, + file, + overwrite + } - store.commit('setReload', true) - store.commit('upload/reset') + store.dispatch('upload/upload', item); } - - Promise.all(promises) - .then(() => { - finish() - }) - .catch(error => { - finish() - this.$showError(error) - }) - - return false } \ No newline at end of file