hide blueprint lock icons on child courses

A front-end performance hack on courses with large numbers of modules.
If this feature flag is on we hide the lock icons on child courses and
instead append a lock emoji to the title when there are restrictions.
This is a performance hack that should be sparingly used.

flag=modules_page_hide_blueprint_lock_icon_for_children

test plan:
  - turn on the feature flag
  - Create a blueprint parent course with an assignment that has some
    restrictions
  - Create a child course from the blueprint
  - Go to the modules page in the child course and verify that the lock
    icon is not added via javascript (on the right side of the page) but
    is an emoji added from the ERB near the title

Change-Id: I968d92396d0b099d121f71360a1ea97c3dd4c9cf
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/356281
Reviewed-by: Spencer Olson <solson@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
QA-Review: Keith Garner <kgarner@instructure.com>
Product-Review: Keith Garner <kgarner@instructure.com>
This commit is contained in:
Keith T. Garner 2024-08-29 10:35:03 -05:00 committed by SaltNPepa
parent 5e5029a920
commit 24748d0459
7 changed files with 91 additions and 12 deletions

View File

@ -145,14 +145,18 @@ class ContextModulesController < ApplicationController
} }
is_master_course = MasterCourses::MasterTemplate.is_master_course?(@context) is_master_course = MasterCourses::MasterTemplate.is_master_course?(@context)
is_child_course = MasterCourses::ChildSubscription.is_child_course?(@context) @is_child_course = MasterCourses::ChildSubscription.is_child_course?(@context)
if is_master_course || is_child_course if is_master_course || @is_child_course
hash[:MASTER_COURSE_SETTINGS] = { hash[:MASTER_COURSE_SETTINGS] = {
IS_MASTER_COURSE: is_master_course, IS_MASTER_COURSE: is_master_course,
IS_CHILD_COURSE: is_child_course, IS_CHILD_COURSE: @is_child_course,
MASTER_COURSE_DATA_URL: context_url(@context, :context_context_modules_master_course_info_url) MASTER_COURSE_DATA_URL: context_url(@context, :context_context_modules_master_course_info_url)
} }
end end
if !@is_student && @is_child_course &&
@context.account.feature_enabled?(:modules_page_hide_blueprint_lock_icon_for_children)
hash[:HIDE_BLUEPRINT_LOCK_ICON_FOR_CHILDREN] = true
end
append_default_due_time_js_env(@context, hash) append_default_due_time_js_env(@context, hash)
js_env(hash) js_env(hash)

View File

@ -154,6 +154,13 @@ module ContextModulesHelper
end end
module_data[:items_data] = items_data module_data[:items_data] = items_data
if @is_child_course && !is_student &&
@context.account.feature_enabled?(:modules_page_hide_blueprint_lock_icon_for_children)
module_data[:items_restrictions] =
MasterCourses::MasterContentTag.fetch_module_item_restrictions_for_child(module_data[:items].map(&:id))
module_data[:items_restrictions].transform_values!(&:any?)
end
module_data module_data
end end

View File

@ -241,9 +241,10 @@
<% <%
item_data = module_data[:items_data][item.id] item_data = module_data[:items_data][item.id]
locals = { locals = {
:completion_criteria => context_module.completion_requirements, item_restrictions: module_data.dig(:items_restrictions, item.id),
:item_data => item_data, completion_criteria: context_module.completion_requirements,
:viewable => @can_view, item_data: item_data,
viewable: @can_view,
} }
%> %>
<%= render :partial => 'context_modules/module_item_next', :object => item, :as => :module_item, :locals => locals %> <%= render :partial => 'context_modules/module_item_next', :object => item, :as => :module_item, :locals => locals %>

View File

@ -24,6 +24,7 @@
can_direct_share = can_do(@context, @current_user, :direct_share) can_direct_share = can_do(@context, @current_user, :direct_share)
criterion = completion_criteria && completion_criteria.find{|c| c[:id] == module_item.id} criterion = completion_criteria && completion_criteria.find{|c| c[:id] == module_item.id}
show_checkpoints = @context.root_account.feature_enabled?(:discussion_checkpoints) && module_item && module_item.content_type == 'DiscussionTopic' && module_item.content.checkpoints? show_checkpoints = @context.root_account.feature_enabled?(:discussion_checkpoints) && module_item && module_item.content_type == 'DiscussionTopic' && module_item.content.checkpoints?
item_restrictions ||= nil
@module_item_image_tags ||= { @module_item_image_tags ||= {
'indent' => "<i class='icon-arrow-right'></i>".html_safe, 'indent' => "<i class='icon-arrow-right'></i>".html_safe,
@ -101,30 +102,35 @@
<div class="ig-info"> <div class="ig-info">
<div class="module-item-title"> <div class="module-item-title">
<span class="item_name"> <span class="item_name">
<% title = module_item&.title %>
<% if module_item && module_item.content_type == 'ExternalUrl' && module_item.new_tab %> <% if module_item && module_item.content_type == 'ExternalUrl' && module_item.new_tab %>
<% # FYI, this link gets opened via context_modules_helper.externalUrlLinkClick %> <% # FYI, this link gets opened via context_modules_helper.externalUrlLinkClick %>
<a <a
title="<%= module_item && module_item.title %>" title="<%= title %>"
class="title external_url_link" class="title external_url_link"
target="_blank" target="_blank"
href="<%= module_item.url %>" href="<%= module_item.url %>"
data-item-href="<%= context_url(@context, :context_url) %>/modules/items/<%= module_item.id %>" data-item-href="<%= context_url(@context, :context_url) %>/modules/items/<%= module_item.id %>"
> >
<%= module_item.title %> <%= title %>
</a> </a>
<% elsif !(module_item && module_item.content_type == 'ContextModuleSubHeader') %> <% elsif !(module_item && module_item.content_type == 'ContextModuleSubHeader') %>
<a <a
title="<%= module_item && module_item.title %>" title="<%= title %>"
class="ig-title title item_link" class="ig-title title item_link"
href="<%= context_url(@context, :context_url) %>/modules/items/<%= module_item ? module_item.id : "{{ id }}" %>" href="<%= context_url(@context, :context_url) %>/modules/items/<%= module_item ? module_item.id : "{{ id }}" %>"
<% if item_data[:mastery_paths] && item_data[:mastery_paths][:locked] %> <% if item_data[:mastery_paths] && item_data[:mastery_paths][:locked] %>
aria-describedby="module-item-locked-<%= module_item && module_item.id %>" aria-describedby="module-item-locked-<%= module_item && module_item.id %>"
<% end %> <% end %>
> >
<%= module_item && module_item.title %> <%= title %>
</a> </a>
<% if title && item_restrictions %>
🔒
<% end %>
<% end %> <% end %>
<span title="<%= module_item && module_item.title %>" class="title locked_title"><%= module_item && module_item.title %></span>
<span title="<%= title %>" class="title locked_title"><%= title %></span>
<span class="points_possible" style="display: none;"><%= round_if_whole(module_item.try_rescue(:assignment).try_rescue(:points_possible)) || nbsp %></span> <span class="points_possible" style="display: none;"><%= round_if_whole(module_item.try_rescue(:assignment).try_rescue(:points_possible)) || nbsp %></span>
<span class="requirement" style="display: none;">&nbsp;</span> <span class="requirement" style="display: none;">&nbsp;</span>
<span class="completion_requirement" style="display: none;">&nbsp;</span> <span class="completion_requirement" style="display: none;">&nbsp;</span>

View File

@ -215,3 +215,12 @@ dashboard_graphql_integration:
Integrate GraphQL queries and mutations for the Dashboard to improve loading speed Integrate GraphQL queries and mutations for the Dashboard to improve loading speed
and simplify data fetching logic. and simplify data fetching logic.
applies_to: SiteAdmin applies_to: SiteAdmin
modules_page_hide_blueprint_lock_icon_for_children:
state: hidden
display_name: Hide Blueprint Lock Icon on child course Modules Page
description: |-
If enabled, the blueprint lock icon will be hidden on the modules page. This is a performance hack and should only
be used for customers with a large number of content items (2000+) in a course.
applies_to: Account

View File

@ -253,6 +253,51 @@ describe ContextModulesHelper do
expect(module_data[:items]).to be_empty expect(module_data[:items]).to be_empty
end end
context "feature flag modules_page_hide_blueprint_lock_icon_for_children" do
context "is on" do
before(:once) do
t_course.account.feature_flags.create!(feature: "modules_page_hide_blueprint_lock_icon_for_children", state: "on")
end
it "returns blueprinit item restrictions for a teacher in a child course" do
@is_child_course = true
module_data = process_module_data(t_module, false, @teacher, @session)
expect(module_data[:items_restrictions]).not_to be_nil
end
it "does not return blueprinit item restrictions for a student in a child course" do
@is_child_course = true
module_data = process_module_data(t_module, true, @student, @session)
expect(module_data[:items_restrictions]).to be_nil
end
it "does not return blueprinit item restrictions for a teacher if not a blueprint child" do
@is_child_course = nil
module_data = process_module_data(t_module, false, @teacher, @session)
expect(module_data[:items_restrictions]).to be_nil
end
end
context "is off" do
it "does not return blueprinit item restrictions for a teacher in a child course" do
@is_child_course = true
module_data = process_module_data(t_module, false, @teacher, @session)
expect(module_data[:items_restrictions]).to be_nil
end
it "does not return blueprinit item restrictions for a student in a child course" do
@is_child_course = true
module_data = process_module_data(t_module, true, @student, @session)
expect(module_data[:items_restrictions]).to be_nil
end
end
end
end end
describe "add_mastery_paths_to_cache_key" do describe "add_mastery_paths_to_cache_key" do

View File

@ -369,7 +369,14 @@ window.modules = (function () {
item.setAttribute('data-master_course_restrictions', JSON.stringify(restriction)) item.setAttribute('data-master_course_restrictions', JSON.stringify(restriction))
} }
this.initMasterCourseLockButton(item, restriction) if (
!(
ENV.MASTER_COURSE_SETTINGS.IS_CHILD_COURSE &&
ENV.HIDE_BLUEPRINT_LOCK_ICON_FOR_CHILDREN
)
) {
this.initMasterCourseLockButton(item, restriction)
}
} }
}) })
} }