From 411ec8fc758dd552ea6a5414a346994b54a149dc Mon Sep 17 00:00:00 2001
From: Simon Mayer <simon.mayer@onb.ac.at>
Date: Mon, 10 Oct 2022 17:38:07 +0200
Subject: [PATCH] Fully implement progress bar for all notifications

---
 app/controllers/dataset_controller.rb         | 22 +++++++----
 .../channels/notification_channel.js          |  8 +++-
 app/views/dataset/add_documents.js.erb        |  3 +-
 app/views/dataset/set_working_dataset.js.erb  |  3 +-
 app/views/shared/_notification.html.erb       |  2 +-
 app/workers/export_dataset_worker.rb          | 37 ++++++++++++-------
 app/workers/search_to_dataset_worker.rb       |  5 ++-
 7 files changed, 52 insertions(+), 28 deletions(-)

diff --git a/app/controllers/dataset_controller.rb b/app/controllers/dataset_controller.rb
index 5360107..e3d41a1 100644
--- a/app/controllers/dataset_controller.rb
+++ b/app/controllers/dataset_controller.rb
@@ -130,7 +130,7 @@ class DatasetController < ApplicationController
     message = "<p> #{@nb_added_docs} document#{@nb_added_docs > 1 ? "s were" : " was"} added to your dataset.</p>"
     message.concat "<p>#{existing.size} document#{existing.size > 1 ? "s" : ""} already exist in this dataset.</p>" unless existing.empty?
     # render partial: "shared/notification", locals: {notif_title: title, notif_content: message.html_safe}
-    out["notif"] = render_to_string layout: false, partial: "shared/notification", locals: { notif_title: title, notif_content: message.html_safe }
+    out["notif"] = render_to_string layout: false, partial: "shared/notification", locals: { notif_title: title, notif_content: message.html_safe, notif_autohide: "true" }
     out["nbissues"] = dataset.documents.select { |d| d["type"] == "issue" }.size
     out["nbarticles"] = dataset.documents.select { |d| d["type"] == "article" }.size
     out["nbdocs"] = out["nbissues"] + out["nbarticles"]
@@ -145,7 +145,7 @@ class DatasetController < ApplicationController
     existing = dataset.add_compound params[:compound_id]  # Add docs and return existing ids
     title = dataset.title
     message = "<p> The compound article was added to your dataset.</p>"
-    out["notif"] = render_to_string layout: false, partial: "shared/notification", locals: { notif_title: title, notif_content: message.html_safe }
+    out["notif"] = render_to_string layout: false, partial: "shared/notification", locals: { notif_title: title, notif_content: message.html_safe, notif_autohide: "true" }
     out["nbissues"] = dataset.documents.select { |d| d["type"] == "issue" }.size
     out["nbarticles"] = dataset.documents.select { |d| d["type"] == "article" }.size
     out["nbcompounds"] = dataset.documents.select { |d| d["type"] == "compound" }.size
@@ -164,21 +164,27 @@ class DatasetController < ApplicationController
   end
 
   def add_all_documents
-    SearchToDatasetWorker.perform_async(current_user.id, session[:working_dataset], params[:search_params].to_unsafe_h)
+    time = Time.now.to_i
+    SearchToDatasetWorker.perform_async(current_user.id, session[:working_dataset], params[:search_params].to_unsafe_h, time)
     title = Dataset.find(session[:working_dataset]).title
     message = "<p>Documents are being added to your dataset.</p><div class=\"completion-rate mt-2\">
-        <div class=\"progress\" id=\"progress-#{session[:working_dataset]}\">
+        <div class=\"progress\" id=\"progress-#{session[:working_dataset]}#{time}\">
             <div class=\"progress-bar progress-bar-striped\" role=\"progressbar\" style=\"width: 0%;\" aria-valuenow=\"0\" aria-valuemin=\"0\" aria-valuemax=\"100\">0%</div>
         </div>
 </div>"
-    render partial: "shared/notification", locals: { notif_title: title, notif_content: message.html_safe }
+    render partial: "shared/notification", locals: { notif_title: title, notif_content: message.html_safe, notif_autohide: "false" }
   end
 
   def export_dataset
-    ExportDatasetWorker.perform_async(current_user.id, params[:dataset_id], params[:export_type])
+    time = Time.now.to_i
+    ExportDatasetWorker.perform_async(current_user.id, params[:dataset_id], params[:export_type], time)
     title = Dataset.find(params[:dataset_id]).title
-    message = "<p>The export is being prepared. You will be notified when the operation is done.</p>"
-    render partial: "shared/notification", locals: { notif_title: title, notif_content: message.html_safe }
+    message = "<p>The export is being prepared.</p><div class=\"completion-rate mt-2\">
+    <div class=\"progress\" id=\"progress-#{session[:working_dataset]}#{time}\">
+        <div class=\"progress-bar progress-bar-striped\" role=\"progressbar\" style=\"width: 0%;\" aria-valuenow=\"0\" aria-valuemin=\"0\" aria-valuemax=\"100\">0%</div>
+    </div>
+</div>"
+    render partial: "shared/notification", locals: { notif_title: title, notif_content: message.html_safe, notif_autohide: "false" }
   end
 
   def toggle_sharing_status
diff --git a/app/javascript/channels/notification_channel.js b/app/javascript/channels/notification_channel.js
index 7b32a09..031fd2e 100644
--- a/app/javascript/channels/notification_channel.js
+++ b/app/javascript/channels/notification_channel.js
@@ -41,11 +41,15 @@ consumer.subscriptions.create("NotificationChannel", {
                     progress_bar.attr("aria-valuenow", data.completion)
                     progress_bar.html(`${data.completion}%`)
                 }
-                if(window.location.pathname.endsWith("/search")) {
-                    const progress_bar = $("#progress-".concat(data.dataset_id)).find('.progress-bar')
+                if(window.location.pathname.endsWith("/search") || window.location.pathname.endsWith("/dataset/".concat(data.dataset_id))) {
+                    const progress_bar = $("#progress-".concat(data.dataset_id).concat(data.time)).find('.progress-bar')
                     progress_bar.attr("style", `width: ${data.completion}%;`)
                     progress_bar.attr("aria-valuenow", data.completion)
                     progress_bar.html(`${data.completion}%`)
+                    
+                    if(data.completion == 100) {
+                        progress_bar.closest(".toast").hide(2000);
+                    }
                 }
                 break
             case "experiment_finished":
diff --git a/app/views/dataset/add_documents.js.erb b/app/views/dataset/add_documents.js.erb
index de326e7..6bfb328 100644
--- a/app/views/dataset/add_documents.js.erb
+++ b/app/views/dataset/add_documents.js.erb
@@ -2,7 +2,8 @@
 $("#notifications").append("<%= j render(partial: "shared/notification",
                                          locals: {
                                             notif_title: "Dataset modified",
-                                            notif_content: content
+                                            notif_content: content,
+                                            notif_autohide: "true"
                                          }) %>")
 
 for(const notif of $('.toast')) {
diff --git a/app/views/dataset/set_working_dataset.js.erb b/app/views/dataset/set_working_dataset.js.erb
index 877d6fb..b0a2f4e 100644
--- a/app/views/dataset/set_working_dataset.js.erb
+++ b/app/views/dataset/set_working_dataset.js.erb
@@ -2,7 +2,8 @@
 $("#notifications").append("<%= j render(partial: "shared/notification",
                                          locals: {
                                             notif_title: "Working dataset",
-                                            notif_content: content
+                                            notif_content: content,
+                                            notif_autohide: "true"
                                          }) %>")
 
 for(let notif of $('.toast')) {
diff --git a/app/views/shared/_notification.html.erb b/app/views/shared/_notification.html.erb
index 00ff707..9bdd00d 100644
--- a/app/views/shared/_notification.html.erb
+++ b/app/views/shared/_notification.html.erb
@@ -1,4 +1,4 @@
-<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
+<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide=<%= notif_autohide %>>
     <div class="toast-header">
         <strong class="me-auto"><%= notif_title %></strong>
         <small class="text-muted">just now</small>
diff --git a/app/workers/export_dataset_worker.rb b/app/workers/export_dataset_worker.rb
index 9ef8beb..e6fc2f0 100644
--- a/app/workers/export_dataset_worker.rb
+++ b/app/workers/export_dataset_worker.rb
@@ -4,14 +4,25 @@ class ExportDatasetWorker
   include Sidekiq::Worker
   include ActionView::Helpers::FormOptionsHelper
 
-  def perform(user_id, dataset_id, export_type)
+  def perform(user_id, dataset_id, export_type, time)
     dataset = Dataset.find(dataset_id)
     file = Tempfile.new(["export_#{dataset.title.parameterize(separator: "_")}_", ".#{export_type}"], "tmp")
     to_write = []
     named_entities = dataset.named_entities
     named_entities = named_entities.values.map { |h| h.values }.flatten
     documents = dataset.fetch_paginated_documents(1, 100, "default", "asc", "all", recursive = true)
-    documents[:docs].map do |doc|
+    numDocuments = documents[:docs].size
+    documents[:docs].map.with_index do |doc, idx|
+      increase = (100 * (idx + 1) / numDocuments).to_i - (100 * idx / numDocuments).to_i
+      if increase > 0
+        completion = (100 * (idx + 1) / numDocuments).to_i
+        ActionCable.server.broadcast("notifications.#{user_id}", {
+          type: "completion_rate",
+          dataset_id: dataset_id,
+          completion: completion,
+          time: time,
+        })
+      end
       case export_type
       when "json"
         lang = doc.language
@@ -28,16 +39,16 @@ class ExportDatasetWorker
         end
         entities = entities.map do |ne|
           {
-                      mention: ne["mention_ssi"],
-                      indexStart: ne["article_index_start_isi"],
-                      indexEnd: ne["article_index_end_isi"],
-                      stance: if ne["stance_fsi"] == 0
-                        "neutral"
-                      else
-                        ne["stance_fsi"] > 0 ? "positive" : "negative"
-                      end,
-                      linked_entity_url: ne["linked_entity_ssi"] == "" || ne["linked_entity_ssi"].nil? ? nil : "https://www.wikidata.org/wiki/#{ne["linked_entity_ssi"].split("_")[-1]}",
-                    }
+            mention: ne["mention_ssi"],
+            indexStart: ne["article_index_start_isi"],
+            indexEnd: ne["article_index_end_isi"],
+            stance: if ne["stance_fsi"] == 0
+              "neutral"
+            else
+              ne["stance_fsi"] > 0 ? "positive" : "negative"
+            end,
+            linked_entity_url: ne["linked_entity_ssi"] == "" || ne["linked_entity_ssi"].nil? ? nil : "https://www.wikidata.org/wiki/#{ne["linked_entity_ssi"].split("_")[-1]}",
+          }
         end
         unless under_copyright(lang, doc.date_created, User.find(user_id))
           to_write << { id: doc.id,
@@ -76,7 +87,7 @@ class ExportDatasetWorker
     content = "<p>Your dataset is ready. <a target=\"_blank\" href=\"/en/tool/newspapers-platform/send?filename=#{File.basename(file.path)}\">Click here</a> to download it.</p>"
     ActionCable.server.broadcast("notifications.#{user_id}", {
       type: "notify",
-      html: ApplicationController.render(partial: "shared/notification", locals: { notif_title: dataset.title, notif_content: content }),
+      html: ApplicationController.render(partial: "shared/notification", locals: { notif_title: dataset.title, notif_content: content, notif_autohide: "false" }),
     })
   end
 
diff --git a/app/workers/search_to_dataset_worker.rb b/app/workers/search_to_dataset_worker.rb
index f1126cf..cc1bc1a 100644
--- a/app/workers/search_to_dataset_worker.rb
+++ b/app/workers/search_to_dataset_worker.rb
@@ -2,7 +2,7 @@ class SearchToDatasetWorker
   include Sidekiq::Worker
   include ActionView::Helpers::FormOptionsHelper
 
-  def perform(user_id, dataset_id, search_params)
+  def perform(user_id, dataset_id, search_params, time)
     puts "### #{search_params}"
     dataset = Dataset.find(dataset_id)
     search_params["fl"] = "id"
@@ -22,6 +22,7 @@ class SearchToDatasetWorker
       ActionCable.server.broadcast("notifications.#{user_id}", {
         type: "completion_rate",
         dataset_id: dataset_id,
+        time: time,
         completion: completion,
       })
     end
@@ -33,7 +34,7 @@ class SearchToDatasetWorker
     dataset_options = options_for_select(User.find(user_id).datasets.map { |d| ["#{d.title} (#{d.documents.size} docs)", d.id] })
     ActionCable.server.broadcast("notifications.#{user_id}", {
       type: "notify",
-      html: ApplicationController.render(partial: "shared/notification", locals: { notif_title: dataset.title, notif_content: content }),
+      html: ApplicationController.render(partial: "shared/notification", locals: { notif_title: dataset.title, notif_content: content, notif_autohide: "true" }),
       dataset_options: dataset_options,
     })
   end
-- 
GitLab