diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d2882f35d60..b0284b179f6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -367,6 +367,7 @@ class ApplicationController < ActionController::Base enhanced_rubrics multiselect_gradebook_filters assignment_edit_placement_not_on_announcements + platform_service_speedgrader ].freeze JS_ENV_ROOT_ACCOUNT_FEATURES = %i[ product_tours diff --git a/app/controllers/gradebooks_controller.rb b/app/controllers/gradebooks_controller.rb index 36a5e167561..3fc9794e97f 100644 --- a/app/controllers/gradebooks_controller.rb +++ b/app/controllers/gradebooks_controller.rb @@ -1162,12 +1162,25 @@ class GradebooksController < ApplicationController ) end - append_sis_data(env) - js_env(env) + if Account.site_admin.feature_enabled?(:platform_service_speedgrader) && params[:platform_sg].present? - render :speed_grader, locals: { - anonymize_students: @assignment.anonymize_students? - } + @page_title = t("SpeedGrader") + @body_classes << "full-width padless-content" + + remote_env(speedgrader: Services::PlatformServiceSpeedgrader.launch_url) + + js_env(env) + deferred_js_bundle :platform_speedgrader + + render html: "".html_safe, layout: "bare" + else + append_sis_data(env) + js_env(env) + + render :speed_grader, locals: { + anonymize_students: @assignment.anonymize_students? + } + end end format.json do diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index b8faa613bb3..529cf9629b3 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -516,6 +516,13 @@ module ApplicationHelper global_inst_object end + def remote_env(hash = nil) + @remote_env ||= {} + @remote_env.merge!(hash) if hash + + @remote_env + end + def editor_buttons # called outside of Lti::ContextToolFinder to make sure that # @context is non-nil and also a type of Context that would have diff --git a/app/views/layouts/_head.html.erb b/app/views/layouts/_head.html.erb index dd36de61615..c3d36b17b28 100644 --- a/app/views/layouts/_head.html.erb +++ b/app/views/layouts/_head.html.erb @@ -47,6 +47,7 @@ INST = <%= benchmark("rendering INST") { raw(inst_env.to_json) } %>; ENV = <%= benchmark("rendering ENV") { raw(render_js_env) } %>; BRANDABLE_CSS_HANDLEBARS_INDEX = <%= benchmark("rendering BRANDABLE_CSS_HANDLEBARS_INDEX") { raw(BrandableCSS.handlebars_index_json) } %> + REMOTES = <%= benchmark("rendering REMOTES") { raw(remote_env.to_json) } %>; <%= benchmark("include_head_js") { include_head_js } %> <% @xhrs_to_prefetch_from_controller&.each do |(args, kwargs)| -%> @@ -57,4 +58,4 @@ <%= render :partial => "shared/fullstory_snippet" %> <% if load_heap? %><%= render :partial => "shared/heap_js" %><% end %> <% if load_hotjar? %><%= render :partial => "shared/hotjar_js" %><% end %> - \ No newline at end of file + diff --git a/spec/controllers/gradebooks_controller_spec.rb b/spec/controllers/gradebooks_controller_spec.rb index cd1419786b4..9c4d4da78f5 100644 --- a/spec/controllers/gradebooks_controller_spec.rb +++ b/spec/controllers/gradebooks_controller_spec.rb @@ -3111,6 +3111,13 @@ describe GradebooksController do expect(response).not_to be_redirect end + it "loads the platform speedgreader when the feature flag is on and the platform_sg flag is passed" do + @assignment.publish + Account.site_admin.enable_feature!(:platform_service_speedgrader) + get "speed_grader", params: { course_id: @course, assignment_id: @assignment.id, platform_sg: true } + expect(response).to render_template(:bare, locals: { anonymous_grading: false }) + end + describe "js_env" do let(:js_env) { assigns[:js_env] } diff --git a/ui/featureBundles.ts b/ui/featureBundles.ts index 880d215bb06..ab3a3bbefab 100644 --- a/ui/featureBundles.ts +++ b/ui/featureBundles.ts @@ -155,6 +155,7 @@ const featureBundles: { past_global_alert: () => import('./features/past_global_alert/index'), past_global_announcements: () => import('./features/past_global_announcements/index'), permissions: () => import('./features/permissions/index'), + platform_speedgrader: () => import('./features/speed_grader/index'), plugins: () => import('./features/plugins/index'), prerequisites_lookup: () => import('./features/prerequisites_lookup/index'), profile_show: () => import('./features/profile_show/index'), diff --git a/ui/features/speed_grader/index.jsx b/ui/features/speed_grader/index.jsx index d30b4088b92..ce3dd01dfae 100644 --- a/ui/features/speed_grader/index.jsx +++ b/ui/features/speed_grader/index.jsx @@ -28,9 +28,10 @@ import {captureException} from '@sentry/browser' const I18n = useI18nScope('speed_grader') ready(() => { - if (window.ENV.FEATURES.platform_service_speedgrader) { + // The feature must be enabled AND we must be handed the speedgrader platform URL + if (window.ENV.FEATURES.platform_service_speedgrader && window.REMOTES?.speedgrader) { const theme = getCurrentTheme() - const mountPoint = document.querySelector('#content') + const mountPoint = document.querySelector('#react-router-portals') import('speedgrader/appInjector') .then(module => { module.render(mountPoint, theme) diff --git a/ui/global.d.ts b/ui/global.d.ts index b43d0402a1c..7d195a11ed8 100644 --- a/ui/global.d.ts +++ b/ui/global.d.ts @@ -19,6 +19,7 @@ import {sendMessageStudentsWho} from './shared/grading/messageStudentsWhoHelper' import type {GlobalEnv} from '@canvas/global/env/GlobalEnv.d' import {GlobalInst} from '@canvas/global/inst/GlobalInst' +import {GlobalRemotes} from '@canvas/global/remotes/GlobalRemotes' declare global { interface Global { @@ -32,6 +33,11 @@ declare global { * some by client code. */ readonly INST?: GlobalInst + + /** + * Remote locations for various pure front-end functionality. + */ + readonly REMOTES?: GlobalRemotes } interface Window { @@ -70,6 +76,11 @@ declare global { */ const INST: GlobalInst + /** + * Remote locations for various pure front-end functionality. + */ + const REMOTES: GlobalRemotes + type ShowIf = { (bool?: boolean): JQuery /** diff --git a/ui/shared/global/remotes/GlobalRemotes.d.ts b/ui/shared/global/remotes/GlobalRemotes.d.ts new file mode 100644 index 00000000000..587709831c6 --- /dev/null +++ b/ui/shared/global/remotes/GlobalRemotes.d.ts @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This file is part of Canvas. + * + * Canvas is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, version 3 of the License. + * + * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along + * with this program. If not, see . + */ + +export type GlobalRemotes = Partial<{ + speedgrader: string +}>