From cd454bae51f40b1249e6fa6133c2949970eb3018 Mon Sep 17 00:00:00 2001
From: Ramires Viana <59319979+ramiresviana@users.noreply.github.com>
Date: Fri, 19 Jun 2020 04:46:33 -0300
Subject: [PATCH] feat: upload progress based on total size (#993)

---
 frontend/package-lock.json                |  5 ++
 frontend/package.json                     |  1 +
 frontend/src/components/files/Listing.vue | 67 +++++++++++++++++------
 3 files changed, 55 insertions(+), 18 deletions(-)

diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 543297d9..eb5f4b61 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -8802,6 +8802,11 @@
       "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
       "dev": true
     },
+    "lodash.throttle": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+      "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
+    },
     "lodash.transform": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/lodash.transform/-/lodash.transform-4.6.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 93865b95..e99c0643 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -13,6 +13,7 @@
     "clipboard": "^2.0.4",
     "js-base64": "^2.5.1",
     "lodash.clonedeep": "^4.5.0",
+    "lodash.throttle": "^4.1.1",
     "material-design-icons": "^3.0.1",
     "moment": "^2.24.0",
     "normalize.css": "^8.0.1",
diff --git a/frontend/src/components/files/Listing.vue b/frontend/src/components/files/Listing.vue
index ca9b7244..3e4c64c2 100644
--- a/frontend/src/components/files/Listing.vue
+++ b/frontend/src/components/files/Listing.vue
@@ -89,6 +89,7 @@
 
 <script>
 import { mapState, mapMutations } from 'vuex'
+import throttle from 'lodash.throttle'
 import Item from './ListingItem'
 import css from '@/utils/css'
 import { users, files as api } from '@/api'
@@ -100,7 +101,13 @@ export default {
   components: { Item },
   data: function () {
     return {
-      show: 50
+      show: 50,
+      uploading: {
+        id: 0,
+        count: 0,
+        size: 0,
+        progress: []
+      }
     }
   },
   computed: {
@@ -450,20 +457,24 @@ export default {
             }
         })
     },
+    setProgress: throttle(function() {
+      if (this.uploading.count == 0) {
+        return
+      }
+      
+      let sum = this.uploading.progress.reduce((acc, val) => acc + val)
+      this.$store.commit('setProgress', Math.ceil(sum / this.uploading.size * 100))
+    }, 100, {leading: false, trailing: true}),
     handleFiles (files, base, overwrite = false) {
-      buttons.loading('upload')
+      if (this.uploading.count == 0) {
+        buttons.loading('upload')
+      }
+
       let promises = []
-      let progress = new Array(files.length).fill(0)
 
       let onupload = (id) => (event) => {
-        progress[id] = (event.loaded / event.total) * 100
-
-        let sum = 0
-        for (let i = 0; i < progress.length; i++) {
-          sum += progress[i]
-        }
-
-        this.$store.commit('setProgress', Math.ceil(sum / progress.length))
+        this.uploading.progress[id] = event.loaded
+        this.setProgress()
       }
 
       for (let i = 0; i < files.length; i++) {
@@ -472,30 +483,50 @@ export default {
         if (!file.isDir) {
           let filename = (file.fullPath !== undefined) ? file.fullPath : file.name
           let filenameEncoded = url.encodeRFC5987ValueChars(filename)
-          promises.push(api.post(this.$route.path + base + filenameEncoded, file, overwrite, onupload(i)))
+
+          let id = this.uploading.id
+
+          this.uploading.size += file.size
+          this.uploading.id++
+          this.uploading.count++
+
+          let promise = api.post(this.$route.path + base + filenameEncoded, file, overwrite, throttle(onupload(id), 100)).finally(() => {            
+            this.uploading.count--
+          })
+
+          promises.push(promise)
         } else {
-          let uri = this.$route.path + base;
-          let folders = file.path.split("/");
+          let uri = this.$route.path + base
+          let folders = file.path.split("/")
 
           for (let i = 0; i < folders.length; i++) {
-            let folder = folders[i];
-            let folderEncoded = encodeURIComponent(folder);
+            let folder = folders[i]
+            let folderEncoded = encodeURIComponent(folder)
             uri += folderEncoded + "/"
           }
 
-          api.post(uri);
+          api.post(uri)
         }
       }
 
       let finish = () => {
+        if (this.uploading.count > 0) {
+          return
+        }
+
         buttons.success('upload')
+
         this.$store.commit('setProgress', 0)
+        this.$store.commit('setReload', true)
+
+        this.uploading.id = 0
+        this.uploading.sizes = []
+        this.uploading.progress = []        
       }
 
       Promise.all(promises)
         .then(() => {
           finish()
-          this.$store.commit('setReload', true)
         })
         .catch(error => {
           finish()