From 16a8c4be0c8b9810ba4233236324e7dd8851e08c Mon Sep 17 00:00:00 2001 From: Mariam A Date: Wed, 13 Nov 2024 15:06:03 -0500 Subject: [PATCH] LTI-410: implement pagination to improve performance (#364) This feature was implemented by calling all recordings first and counting them, then only displaying a portion at a time. It will have to be updated once the LB/BBB start sending back the totalElements field. --- app/controllers/concerns/bbb_helper.rb | 32 ++++++++++- app/controllers/rooms_controller.rb | 22 +++++--- app/javascript/packs/rename.js | 6 +- app/javascript/packs/rooms.js | 46 ++++++++++++++++ app/views/shared/_room.html.erb | 76 +++++++++++++++++++++++++- 5 files changed, 167 insertions(+), 15 deletions(-) diff --git a/app/controllers/concerns/bbb_helper.rb b/app/controllers/concerns/bbb_helper.rb index e13d640f..ed3cefcb 100644 --- a/app/controllers/concerns/bbb_helper.rb +++ b/app/controllers/concerns/bbb_helper.rb @@ -22,6 +22,7 @@ module BbbHelper attr_writer :cache, :cache_enabled # Rails.cache store is assumed. # Enabled by default. RECORDINGS_KEY = :recordings + RECORDINGS_PER_PAGE = 8 include RoomsError include BrokerHelper @@ -123,12 +124,39 @@ def meeting_running? end # Fetches all recordings for a room. - def recordings + def recordings(page = 1) res = Rails.cache.fetch("rooms/#{@chosen_room.handler}/#{RECORDINGS_KEY}", expires_in: Rails.configuration.cache_expires_in_minutes.minutes) if Rails.configuration.cache_enabled - res ||= bbb.get_recordings(meetingID: @chosen_room.handler) + offset = (page.to_i - 1) * RECORDINGS_PER_PAGE # The offset is an index that starts at 0. + res ||= bbb.get_recordings(meetingID: @chosen_room.handler, offset: offset, limit: RECORDINGS_PER_PAGE) # offset and limit are for pagination purposes recordings_formatted(res) end + def recordings_count + res = Rails.cache.fetch("rooms/#{@chosen_room.handler}/#{RECORDINGS_KEY}", expires_in: Rails.configuration.cache_expires_in_minutes.minutes) if Rails.configuration.cache_enabled + res ||= bbb.get_recordings(meetingID: @chosen_room.handler) + res[:recordings].length + end + + def paginate? + recordings_count > RECORDINGS_PER_PAGE + end + + # returns the amount of pages for recordings + def pages_count + (recordings_count.to_f / RECORDINGS_PER_PAGE).ceil + end + + # on the last page, we don't want recordings that were in the second-to-last page to show + def recordings_limit(page) + page_int = page.to_i + num_of_recs = recordings_count + recordings_overflow = num_of_recs - page_int * RECORDINGS_PER_PAGE + # if offset is > 0 and there are less recordings than the current page * recordings per page, then we'll need to pass a limit that's less than what's defined in RECORDINGS_PER_PAGE + return recordings_overflow if page_int.positive? && recordings_overflow < RECORDINGS_PER_PAGE + + RECORDINGS_PER_PAGE + end + # Fetch an individual recording def recording(record_id) r = bbb.get_recordings(meetingID: @chosen_room.handler, recordID: record_id) diff --git a/app/controllers/rooms_controller.rb b/app/controllers/rooms_controller.rb index b7fc87c6..2eb66642 100644 --- a/app/controllers/rooms_controller.rb +++ b/app/controllers/rooms_controller.rb @@ -47,10 +47,13 @@ class RoomsController < ApplicationController # GET /rooms/1 # GET /rooms/1.json def show + # page offset is equal to the page number minus 1 + @page = params[:page] || 1 + session[:page] = @page respond_to do |format| if @room && @chosen_room begin - @recordings = recordings + @recordings = recordings(@page) @meeting_info = meeting_info @meeting_running = @meeting_info[:returncode] == true rescue BigBlueButton::BigBlueButtonException => e @@ -185,25 +188,29 @@ def meeting_close # POST /rooms/:id/recording/:record_id/unpublish def recording_unpublish unpublish_recording(params[:record_id]) - redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce])) + @page_num = session[:page] || 1 + redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce], page: @page_num)) end # POST /rooms/:id/recording/:record_id/publish def recording_publish publish_recording(params[:record_id]) - redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce])) + @page_num = session[:page] || 1 + redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce], page: @page_num)) end # POST /rooms/:id/recording/:record_id/protect def recording_protect update_recording(params[:record_id], protect: true) - redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce])) + @page_num = session[:page] || 1 + redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce], page: @page_num)) end # POST /rooms/:id/recording/:record_id/unprotect def recording_unprotect update_recording(params[:record_id], protect: false) - redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce])) + @page_num = session[:page] || 1 + redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce], page: @page_num)) end # POST /rooms/:id/recording/:record_id/update @@ -219,7 +226,8 @@ def recording_update # POST /rooms/:id/recording/:record_id/delete def recording_delete delete_recording(params[:record_id]) - redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce])) + @page_num = session[:page] || 1 + redirect_to(room_path(params[:id], launch_nonce: params[:launch_nonce], page: @page_num)) end # POST /rooms/:id/recording/:record_id/:format/recording @@ -237,7 +245,7 @@ def individual_recording redirect_to(errors_path(401)) end - helper_method :recording_date, :recording_length, :meeting_running?, :bigbluebutton_moderator_roles, + helper_method :recording_date, :recording_length, :meeting_running?, :bigbluebutton_moderator_roles, :paginate?, :recordings_count, :pages_count, :bigbluebutton_recording_public_formats, :meeting_info, :bigbluebutton_recording_enabled, :server_running? private diff --git a/app/javascript/packs/rename.js b/app/javascript/packs/rename.js index 703cb4eb..a8c7e550 100644 --- a/app/javascript/packs/rename.js +++ b/app/javascript/packs/rename.js @@ -16,7 +16,7 @@ * with BigBlueButton; if not, see . */ -function func() { +$(document).on('turbolinks:load', function () { var controller = $("body").data('controller'); var action = $("body").data('action'); @@ -135,6 +135,4 @@ function func() { configure_recording_row(recording_description, 'recording-description-text'); }); } -}; - -$(func) // run when the DOM is ready +}); diff --git a/app/javascript/packs/rooms.js b/app/javascript/packs/rooms.js index 63aff254..c769cb8e 100644 --- a/app/javascript/packs/rooms.js +++ b/app/javascript/packs/rooms.js @@ -47,4 +47,50 @@ $(document).on('turbolinks:load', function () { } }); } + + /** PAGINATION STUFF */ + /** disable previous or next buttons if user is on first or last page */ + const $paginationContainer = $("#pagination-container"); + + if ($paginationContainer.length) { + const currentPage = parseInt($paginationContainer.data("current-page")); + const totalPages = parseInt($paginationContainer.data("total-pages")); + + const $previousButton = $("#backbtn"); + const $nextButton = $("#nextbtn"); + + // Disable Previous button if on the first page + if (currentPage <= 1) { + $previousButton.addClass("cursor-not-allowed opacity-50") + .attr("aria-disabled", "true") + .attr("href", "javascript:void(0)"); + } else { + $previousButton.removeClass("cursor-not-allowed opacity-50") + .removeAttr("aria-disabled") + .attr("href", $previousButton.data("pageNum")); + } + + // Disable Next button if on the last page + if (currentPage >= totalPages) { + $nextButton.addClass("cursor-not-allowed opacity-50") + .attr("aria-disabled", "true") + .attr("href", "javascript:void(0)"); + } else { + $nextButton.removeClass("cursor-not-allowed opacity-50") + .removeAttr("aria-disabled") + .attr("href", $nextButton.data("pageNum")); + } + } + + /** change the colour of the page buttons */ + // Get the current page number from the container + const currentPage = $("#pagination-container").data("current-page"); + + // Define the classes + const activeClasses = "text-blue-600 border border-blue-300 bg-blue-50 hover:bg-blue-100 hover:text-blue-700"; + const nonActiveClasses = "text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700"; + + // Remove active styling from all buttons, then apply to the current button + $("[id^='pg-']").removeClass(activeClasses).addClass(nonActiveClasses); + $(`#pg-${currentPage}-btn`).removeClass(nonActiveClasses).addClass(activeClasses); }); diff --git a/app/views/shared/_room.html.erb b/app/views/shared/_room.html.erb index bd4a3831..7b6ebd60 100644 --- a/app/views/shared/_room.html.erb +++ b/app/views/shared/_room.html.erb @@ -154,10 +154,10 @@ <% if bigbluebutton_recording_enabled %> -
+
<%= render "shared/components/search_bar", subtitle: t("default.room.recordings")%> -
+
@@ -194,5 +194,77 @@
+ + + <% numOfPages = pages_count %> + <% if paginate? %> +
+ +
+ <% end %>
<% end %>