From 73d8dd9a453510272e442d5cc815c2cce0b792be Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Wed, 2 Jan 2019 15:19:45 +0100
Subject: [PATCH] Fixed UX/autoreload issues in import screen

---
 front/src/components/common/ActionTable.vue   | 26 ++++++++++--
 front/src/components/library/FileUpload.vue   | 42 +++----------------
 front/src/store/ui.js                         |  2 +-
 front/src/views/admin/users/UsersDetail.vue   |  1 -
 .../views/content/libraries/FilesTable.vue    |  9 +++-
 5 files changed, 37 insertions(+), 43 deletions(-)

diff --git a/front/src/components/common/ActionTable.vue b/front/src/components/common/ActionTable.vue
index 5b138a3c6f..5b04d3caba 100644
--- a/front/src/components/common/ActionTable.vue
+++ b/front/src/components/common/ActionTable.vue
@@ -1,9 +1,22 @@
 <template>
   <table class="ui compact very basic single line unstackable table">
     <thead>
-      <tr v-if="actionUrl && actions.length > 0">
+      <tr>
         <th colspan="1000">
-          <div class="ui small form">
+          <div v-if="refreshable" class="right floated">
+            <span v-if="needsRefresh">
+              <translate>Content have been updated, click refresh to see up-to-date content</translate>
+            </span>
+            <button
+              @click="$emit('refresh')"
+              class="ui basic icon button"
+              :title="labels.refresh"
+              :aria-label="labels.refresh">
+              <i class="refresh icon"></i>
+            </button>
+          </div>
+
+          <div class="ui small left floated form" v-if="actionUrl && actions.length > 0">
             <div class="ui inline fields">
               <div class="field">
                 <label><translate>Actions</translate></label>
@@ -132,6 +145,8 @@ export default {
   props: {
     actionUrl: {type: String, required: false, default: null},
     idField: {type: String, required: false, default: 'id'},
+    refreshable: {type: Boolean, required: false, default: false},
+    needsRefresh: {type: Boolean, required: false, default: false},
     objectsData: {type: Object, required: true},
     actions: {type: Array, required: true, default: () => { return [] }},
     filters: {type: Object, required: false, default: () => { return {} }},
@@ -244,13 +259,18 @@ export default {
       let self = this
       return this.objectsData.results.map((o) => {
         let custom = self.customObjects.filter((co) => {
-          return self.getId(co) == self.getId(o)
+          return self.getId(co) === self.getId(o)
         })[0]
         if (custom) {
           return custom
         }
         return o
       })
+    },
+    labels () {
+      return {
+        refresh: this.$gettext('Refresh table content')
+      }
     }
   },
   watch: {
diff --git a/front/src/components/library/FileUpload.vue b/front/src/components/library/FileUpload.vue
index d2c93202f6..fbc6428a23 100644
--- a/front/src/components/library/FileUpload.vue
+++ b/front/src/components/library/FileUpload.vue
@@ -115,7 +115,8 @@
     </div>
     <div :class="['ui', 'bottom', 'attached', 'segment', {hidden: currentTab != 'processing'}]">
       <library-files-table
-        :key="String(processTimestamp)"
+        :needs-refresh="needsRefresh"
+        @fetch-start="needsRefresh = false"
         :filters="{import_reference: importReference}"
         :custom-objects="Object.values(uploads.objects)"></library-files-table>
     </div>
@@ -142,6 +143,7 @@ export default {
     this.$router.replace({ query: { import: importReference } });
     return {
       files: [],
+      needsRefresh: false,
       currentTab: "summary",
       uploadUrl: "/api/v1/uploads/",
       importReference,
@@ -199,31 +201,6 @@ export default {
           value: this.uploadedFilesCount + this.finishedJobs
         });
     },
-    disconnect() {
-      if (!this.bridge) {
-        return;
-      }
-      this.bridge.socket.close(1000, "goodbye", { keepClosed: true });
-    },
-    openWebsocket() {
-      this.disconnect();
-      let self = this;
-      let token = this.$store.state.auth.token;
-      const bridge = new WebSocketBridge();
-      this.bridge = bridge;
-      let url = this.$store.getters["instance/absoluteUrl"](
-        `api/v1/activity?token=${token}`
-      );
-      url = url.replace("http://", "ws://");
-      url = url.replace("https://", "wss://");
-      bridge.connect(url);
-      bridge.listen(function(event) {
-        self.handleEvent(event);
-      });
-      bridge.socket.addEventListener("open", function() {
-        console.log("Connected to WebSocket");
-      });
-    },
     handleImportEvent(event) {
       let self = this;
       if (event.upload.import_reference != self.importReference) {
@@ -232,17 +209,10 @@ export default {
       this.$nextTick(() => {
         self.uploads[event.old_status] -= 1;
         self.uploads[event.new_status] += 1;
-        self.uploads.objects[event.upload.uuid] = event.track_file;
-        self.triggerReload();
+        self.uploads.objects[event.upload.uuid] = event.upload;
+        self.needsRefresh = true
       });
-    },
-    triggerReload: _.throttle(
-      function() {
-        this.processTimestamp = new Date();
-      },
-      10000,
-      { leading: true }
-    )
+    }
   },
   computed: {
     labels() {
diff --git a/front/src/store/ui.js b/front/src/store/ui.js
index da08754962..b366f233d8 100644
--- a/front/src/store/ui.js
+++ b/front/src/store/ui.js
@@ -49,8 +49,8 @@ export default {
       })
     },
     websocketEvent ({state}, event) {
-      console.log('Dispatching websocket event', event)
       let handlers = state.websocketEventsHandlers[event.type]
+      console.log('Dispatching websocket event', event, handlers)
       if (!handlers) {
         return
       }
diff --git a/front/src/views/admin/users/UsersDetail.vue b/front/src/views/admin/users/UsersDetail.vue
index b347f814a2..7eaafb6cb7 100644
--- a/front/src/views/admin/users/UsersDetail.vue
+++ b/front/src/views/admin/users/UsersDetail.vue
@@ -145,7 +145,6 @@ export default {
       if (toNull && !newValue) {
         newValue = null
       }
-      console.log(newValue, typeof newValue)
       let params = {}
       if (attr === "permissions") {
         params["permissions"] = {}
diff --git a/front/src/views/content/libraries/FilesTable.vue b/front/src/views/content/libraries/FilesTable.vue
index 1f176d8cbb..130a1a207c 100644
--- a/front/src/views/content/libraries/FilesTable.vue
+++ b/front/src/views/content/libraries/FilesTable.vue
@@ -46,7 +46,10 @@
         :objects-data="result"
         :custom-objects="customObjects"
         :actions="actions"
+        :refreshable="true"
+        :needs-refresh="needsRefresh"
         :action-url="'uploads/action/'"
+        @refresh="fetchData"
         :filters="actionFilters">
         <template slot="header-cells">
           <th><translate>Title</translate></th>
@@ -133,6 +136,7 @@ export default {
   mixins: [OrderingMixin, TranslationsMixin],
   props: {
     filters: {type: Object, required: false},
+    needsRefresh: {type: Boolean, required: false, default: false},
     defaultQuery: {type: String, default: ''},
     customObjects: {type: Array, required: false, default: () => { return [] }}
   },
@@ -199,12 +203,13 @@ export default {
       }
     },
     fetchData () {
+      this.$emit('fetch-start')
       let params = _.merge({
         'page': this.page,
         'page_size': this.paginateBy,
         'ordering': this.getOrderingAsString(),
         'q': this.search.query
-      }, {})
+      }, this.filters || {})
       let self = this
       self.isLoading = true
       self.checked = []
@@ -302,7 +307,7 @@ export default {
     search (newValue) {
       this.page = 1
       this.fetchData()
-    },
+    }
   }
 }
 </script>
-- 
GitLab