launch the platform speedgrader

When the feature flag is enabled, and when the param platform_sg is
passed in the URL, launch the platform speedgrader instead of default
speedgrader. This will allow for easily testing between classic
speedgrader and platform speedgrader.

flag=platform_service_speedgrader

test plan:
 - Have a course with some students and an assignment
 - Enable the feature flag
 - Either have a local module federation server running or supply a URL
   to dynamic configuration for the launch url
 - Go to the assignment and click on speedgrader
 - Note that classic sg loads
 - add "&platform_sg=true" to the URL and refresh
 - Note the new hotness

Change-Id: I6341406f563256c54cc009589a22b93019600373
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/340885
Reviewed-by: Cameron Ray <cameron.ray@instructure.com>
Reviewed-by: Aaron Shafovaloff <ashafovaloff@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
QA-Review: Aaron Shafovaloff <ashafovaloff@instructure.com>
Product-Review: Aaron Shafovaloff <ashafovaloff@instructure.com>
This commit is contained in:
Keith T. Garner 2024-02-20 11:03:59 -06:00 committed by Keith Garner
parent f59d0736c7
commit 6629e7c1ed
9 changed files with 71 additions and 8 deletions

View File

@ -367,6 +367,7 @@ class ApplicationController < ActionController::Base
enhanced_rubrics enhanced_rubrics
multiselect_gradebook_filters multiselect_gradebook_filters
assignment_edit_placement_not_on_announcements assignment_edit_placement_not_on_announcements
platform_service_speedgrader
].freeze ].freeze
JS_ENV_ROOT_ACCOUNT_FEATURES = %i[ JS_ENV_ROOT_ACCOUNT_FEATURES = %i[
product_tours product_tours

View File

@ -1162,6 +1162,18 @@ class GradebooksController < ApplicationController
) )
end end
if Account.site_admin.feature_enabled?(:platform_service_speedgrader) && params[:platform_sg].present?
@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) append_sis_data(env)
js_env(env) js_env(env)
@ -1169,6 +1181,7 @@ class GradebooksController < ApplicationController
anonymize_students: @assignment.anonymize_students? anonymize_students: @assignment.anonymize_students?
} }
end end
end
format.json do format.json do
render json: SpeedGrader::Assignment.new( render json: SpeedGrader::Assignment.new(

View File

@ -516,6 +516,13 @@ module ApplicationHelper
global_inst_object global_inst_object
end end
def remote_env(hash = nil)
@remote_env ||= {}
@remote_env.merge!(hash) if hash
@remote_env
end
def editor_buttons def editor_buttons
# called outside of Lti::ContextToolFinder to make sure that # called outside of Lti::ContextToolFinder to make sure that
# @context is non-nil and also a type of Context that would have # @context is non-nil and also a type of Context that would have

View File

@ -47,6 +47,7 @@
INST = <%= benchmark("rendering INST") { raw(inst_env.to_json) } %>; INST = <%= benchmark("rendering INST") { raw(inst_env.to_json) } %>;
ENV = <%= benchmark("rendering ENV") { raw(render_js_env) } %>; ENV = <%= benchmark("rendering ENV") { raw(render_js_env) } %>;
BRANDABLE_CSS_HANDLEBARS_INDEX = <%= benchmark("rendering BRANDABLE_CSS_HANDLEBARS_INDEX") { raw(BrandableCSS.handlebars_index_json) } %> BRANDABLE_CSS_HANDLEBARS_INDEX = <%= benchmark("rendering BRANDABLE_CSS_HANDLEBARS_INDEX") { raw(BrandableCSS.handlebars_index_json) } %>
REMOTES = <%= benchmark("rendering REMOTES") { raw(remote_env.to_json) } %>;
</script> </script>
<%= benchmark("include_head_js") { include_head_js } %> <%= benchmark("include_head_js") { include_head_js } %>
<% @xhrs_to_prefetch_from_controller&.each do |(args, kwargs)| -%> <% @xhrs_to_prefetch_from_controller&.each do |(args, kwargs)| -%>

View File

@ -3111,6 +3111,13 @@ describe GradebooksController do
expect(response).not_to be_redirect expect(response).not_to be_redirect
end 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 describe "js_env" do
let(:js_env) { assigns[:js_env] } let(:js_env) { assigns[:js_env] }

View File

@ -155,6 +155,7 @@ const featureBundles: {
past_global_alert: () => import('./features/past_global_alert/index'), past_global_alert: () => import('./features/past_global_alert/index'),
past_global_announcements: () => import('./features/past_global_announcements/index'), past_global_announcements: () => import('./features/past_global_announcements/index'),
permissions: () => import('./features/permissions/index'), permissions: () => import('./features/permissions/index'),
platform_speedgrader: () => import('./features/speed_grader/index'),
plugins: () => import('./features/plugins/index'), plugins: () => import('./features/plugins/index'),
prerequisites_lookup: () => import('./features/prerequisites_lookup/index'), prerequisites_lookup: () => import('./features/prerequisites_lookup/index'),
profile_show: () => import('./features/profile_show/index'), profile_show: () => import('./features/profile_show/index'),

View File

@ -28,9 +28,10 @@ import {captureException} from '@sentry/browser'
const I18n = useI18nScope('speed_grader') const I18n = useI18nScope('speed_grader')
ready(() => { 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 theme = getCurrentTheme()
const mountPoint = document.querySelector('#content') const mountPoint = document.querySelector('#react-router-portals')
import('speedgrader/appInjector') import('speedgrader/appInjector')
.then(module => { .then(module => {
module.render(mountPoint, theme) module.render(mountPoint, theme)

11
ui/global.d.ts vendored
View File

@ -19,6 +19,7 @@
import {sendMessageStudentsWho} from './shared/grading/messageStudentsWhoHelper' import {sendMessageStudentsWho} from './shared/grading/messageStudentsWhoHelper'
import type {GlobalEnv} from '@canvas/global/env/GlobalEnv.d' import type {GlobalEnv} from '@canvas/global/env/GlobalEnv.d'
import {GlobalInst} from '@canvas/global/inst/GlobalInst' import {GlobalInst} from '@canvas/global/inst/GlobalInst'
import {GlobalRemotes} from '@canvas/global/remotes/GlobalRemotes'
declare global { declare global {
interface Global { interface Global {
@ -32,6 +33,11 @@ declare global {
* some by client code. * some by client code.
*/ */
readonly INST?: GlobalInst readonly INST?: GlobalInst
/**
* Remote locations for various pure front-end functionality.
*/
readonly REMOTES?: GlobalRemotes
} }
interface Window { interface Window {
@ -70,6 +76,11 @@ declare global {
*/ */
const INST: GlobalInst const INST: GlobalInst
/**
* Remote locations for various pure front-end functionality.
*/
const REMOTES: GlobalRemotes
type ShowIf = { type ShowIf = {
(bool?: boolean): JQuery<HTMLElement> (bool?: boolean): JQuery<HTMLElement>
/** /**

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
export type GlobalRemotes = Partial<{
speedgrader: string
}>