From 6e7e14ae249ea2fde9b43a9fd3c3acf7713ebf44 Mon Sep 17 00:00:00 2001
From: Felix Eckhofer <felix@eckhofer.com>
Date: Sat, 21 Dec 2024 01:38:12 +0100
Subject: [PATCH] Render list of users once and re-use template for every
 session

This dramatically speeds up rendering with many translators.
---
 .../controllers/filteredlist_controller.js        | 15 +++++++++++++++
 app/views/assignments/_filteredlist.html.erb      |  4 ++--
 .../assignments/_filteredlist_option.html.erb     |  2 +-
 app/views/assignments/_user_add.html.erb          |  2 +-
 app/views/conferences/show.html.erb               |  5 +++++
 app/views/sessions/_session.html.erb              |  3 ++-
 6 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/app/javascript/controllers/filteredlist_controller.js b/app/javascript/controllers/filteredlist_controller.js
index c658117..2cabbaf 100644
--- a/app/javascript/controllers/filteredlist_controller.js
+++ b/app/javascript/controllers/filteredlist_controller.js
@@ -16,6 +16,21 @@ export default class extends Controller {
   }
 
   expand() {
+    if(this.listTarget.children.length == 0) {
+      const conference = this.element.dataset.conference;
+      const session = this.element.dataset.session;
+      const url = `/conferences/${conference}/sessions/${session}/assignments`;
+
+      const template = document.getElementById("template_filteredlist_options").content;
+      const clone = document.importNode(template, true);
+      clone.querySelectorAll("a.add_button").forEach(el => {
+        el.setAttribute("href", `${url}?user_id=${el.dataset.user}`);
+        el.setAttribute("data-turbo-frame",
+          this.element.closest('turbo-frame[data-controller="session"]').id);
+      });
+      this.listTarget.appendChild(clone);
+    }
+
     this.listTarget.classList.remove("hidden");
     this.inputTarget.classList.remove("rounded-b-md");
     this.filter_nodebounce();
diff --git a/app/views/assignments/_filteredlist.html.erb b/app/views/assignments/_filteredlist.html.erb
index e4e5f2f..be2746c 100644
--- a/app/views/assignments/_filteredlist.html.erb
+++ b/app/views/assignments/_filteredlist.html.erb
@@ -1,4 +1,4 @@
-<div data-controller="filteredlist">
+<div data-controller="filteredlist" data-conference="<%= session.conference.slug %>" data-session="<%= session.ref_id %>">
   <div class="relative">
     <input
       type="text"
@@ -16,7 +16,7 @@
   </div>
   <ul data-filteredlist-target="list" class="hidden max-h-32 overflow-scroll flex flex-row flex-wrap gap-1 my-1 mt-0 flex-shrink-0 bg-black/10 rounded-b-md p-2">
     <% users.each do |user| %>
-      <%= render partial: 'assignments/filteredlist_option', locals: { session: session, user: user } %>
+      <%= render partial: 'assignments/filteredlist_option', locals: { user: } %>
     <% end %>
   </ul>
 </div>
diff --git a/app/views/assignments/_filteredlist_option.html.erb b/app/views/assignments/_filteredlist_option.html.erb
index 6579860..a6f49e9 100644
--- a/app/views/assignments/_filteredlist_option.html.erb
+++ b/app/views/assignments/_filteredlist_option.html.erb
@@ -2,5 +2,5 @@
   data-filteredlist-match="<%= user.name.downcase %>"
   data-turbo-track="dynamic"
 >
-  <%= render partial: 'assignments/user_add', locals: { user: user, session: session } %>
+  <%= render partial: 'assignments/user_add', locals: { user: } %>
 </li>
diff --git a/app/views/assignments/_user_add.html.erb b/app/views/assignments/_user_add.html.erb
index 191b07f..3a5516b 100644
--- a/app/views/assignments/_user_add.html.erb
+++ b/app/views/assignments/_user_add.html.erb
@@ -4,7 +4,7 @@
 <span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10" style="background-color: <%= user.avatar_color %>" title="<%= user.name %>">
   <span style="color: <%= user.text_color %>"><%= user.name %></span>
   <button type="button" class="group relative -mr-1 size-3.5 rounded-sm hover:bg-gray-500/20">
-    <%= link_to conference_session_assignments_path(session.conference, session, user_id: user.id), data: { turbo_method: :post, turbo_frame: dom_id(session), action: "filteredlist#contract" } do %>
+    <%= link_to "", class: "add_button", data: { turbo_method: :post, user: user.id } do %>
       <span class="sr-only">Add</span>
       <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16" stroke-width="1" class="size-3.5 stroke-gray-600/50 group-hover:stroke-gray-600/75 fill-gray-600/50" style="stroke: <%= user.text_color %>; fill: <%= user.text_color %>">
         <path d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z" />
diff --git a/app/views/conferences/show.html.erb b/app/views/conferences/show.html.erb
index c72964c..e5d5434 100644
--- a/app/views/conferences/show.html.erb
+++ b/app/views/conferences/show.html.erb
@@ -8,6 +8,11 @@ current_time = Time.zone.now.in_time_zone(@conference.time_zone)
 #current_time = @sessions_by_date[@conference.days.first].first.starts_at.advance(minutes: 5)
 %>
 <%= turbo_stream_from @conference %>
+<template class="hidden" id="template_filteredlist_options">
+  <% @users.each do |user| %>
+    <%= render partial: 'assignments/filteredlist_option', locals: { user: } %>
+  <% end %>
+</template>
 <div>
   <div>
     <a href="#now" onclick="document.querySelector('#now')?.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' }); return false" class="underline text-blue-500">Jump to current time</a>
diff --git a/app/views/sessions/_session.html.erb b/app/views/sessions/_session.html.erb
index b2ab250..c220a44 100644
--- a/app/views/sessions/_session.html.erb
+++ b/app/views/sessions/_session.html.erb
@@ -85,6 +85,7 @@
     </div>
     <hr>
     <small>unassigned (<%= unassigned_users.length %>)</small>
-    <%= render partial: 'assignments/filteredlist', locals: { session: session, users: unassigned_users } %>
+    <%= render partial: 'assignments/filteredlist', locals: { session: session, users: [] } %>
+    </div>
   </div>
 <% end %>
-- 
GitLab