Remove IORCM FF from backend and frontend code

closes OUT-5002, OUT-5003
flag=individual_outcome_rating_and_calculation

Test plan:
- Enable Improved Outcomes Management FF
- Disable Individual Outcome Rating and Calculation FF
- Disable Account Level Mastery Scales FF
- Go to Account > Outcomes
- Verify that you can see the Improved Management UI
with only the Manage tab
- Click Create button and verify that the Create modal
includes individual ratings and calculation fields
- Enter information in the form, click Create button
and verify that new outcome is created properly
- Select the outcome and click kebab menu -> Edit
- Verify that the Edit modal includes individual
ratings and calculation method fields
- Make changes to the ratings and calculation fields, click
Save button and verify that the outcome is properly updated
- Enable Account Level Mastery Scales FF
- Go to Account > Outcomes
- Verify that you can see the Improved Management UI
with Manage, Mastery and Calculation tabs
- Open Create modal and verify that it does not include
individual ratings and calculation fields
- Enter information in the form, click Create button
and verify that new outcome is created properly
- Select the outcome and click kebab menu -> Edit
- Verify that the Edit modal does not include individual
ratings and calculation method field
- Make changes to the ratings and calculation fields, click
Save button and verify that the outcome is properly updateds
- Disable Improved Outcomes Management FF
- Disable Account Level Mastery Scales FF
- Go to Account > Outcomes and verify that you see the legacy UI
- Select any of the outcomes created previously and verify that
you can see the individual ratings and calculation method
- Click Edit button, change the ratings and calculation method,
click Save and verify that the outcome is properly updated

Change-Id: I97c2e056caf6692115c9ace9bcbc1aba667796d1
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/287498
QA-Review: Marcus Pompeu <marcus.pompeu@instructure.com>
Product-Review: Ben Friedman <ben.friedman@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Marcus Pompeu <marcus.pompeu@instructure.com>
This commit is contained in:
Martin Yosifov 2022-04-06 09:54:42 -07:00
parent 7153fa35b0
commit 8472c3c3ae
30 changed files with 155 additions and 268 deletions

View File

@ -61,7 +61,7 @@ class OutcomesController < ApplicationController
set_tutorial_js_env
mastery_scales_js_env
proficiency_roles_js_env
individual_outcome_rating_and_calculation_js_env
improved_outcomes_management_js_env
end
def show

View File

@ -45,7 +45,6 @@ module Mutations
return {} unless ratings_input.count.positive? && context
raise GraphQL::ExecutionError, I18n.t("individual ratings data input with invidual_outcome_rating_and_calculation FF disabled") unless context.root_account.feature_enabled?(:individual_outcome_rating_and_calculation)
raise GraphQL::ExecutionError, I18n.t("individual ratings data input with acount_level_mastery_scale FF enabled") if context.root_account.feature_enabled?(:account_level_mastery_scales)
updated_ratings_attrs = {}

View File

@ -31,7 +31,7 @@ class Mutations::UpdateLearningOutcome < Mutations::BaseLearningOutcomeMutation
outcome_input = attrs(input, record.context)
if individual_outcome_rating_and_calculation_enabled?(record.context)
unless account_level_mastery_scales_enabled?(record.context)
update_rubric_criterion(record, outcome_input)
outcome_input.delete(:rubric_criterion)
end

View File

@ -20,6 +20,8 @@
module Types
class LearningOutcomeType < ApplicationObjectType
include OutcomesFeaturesHelper
class AssessedLoader < GraphQL::Batch::Loader
def perform(outcomes)
assessed_ids = LearningOutcomeResult.active.where(learning_outcome_id: outcomes).distinct.pluck(:learning_outcome_id)
@ -65,27 +67,27 @@ module Types
field :calculation_method, String, null: true
def calculation_method
outcome.calculation_method if individual_outcome_rating_and_calculation_enabled?
outcome.calculation_method unless account_level_mastery_scales_enabled?(outcome.context)
end
field :calculation_int, Integer, null: true
def calculation_int
outcome.calculation_int if individual_outcome_rating_and_calculation_enabled?
outcome.calculation_int unless account_level_mastery_scales_enabled?(outcome.context)
end
field :mastery_points, Float, null: true
def mastery_points
outcome.mastery_points if individual_outcome_rating_and_calculation_enabled?
outcome.mastery_points unless account_level_mastery_scales_enabled?(outcome.context)
end
field :points_possible, Float, null: true
def points_possible
outcome.points_possible if individual_outcome_rating_and_calculation_enabled?
outcome.points_possible unless account_level_mastery_scales_enabled?(outcome.context)
end
field :ratings, [Types::ProficiencyRatingType], null: true
def ratings
outcome.rubric_criterion[:ratings] if individual_outcome_rating_and_calculation_enabled?
outcome.rubric_criterion[:ratings] unless account_level_mastery_scales_enabled?(outcome.context)
end
field :can_edit, Boolean, null: false
@ -129,11 +131,5 @@ module Types
def outcome_context_promise
Loaders::AssociationLoader.for(LearningOutcome, :context).load(outcome)
end
def individual_outcome_rating_and_calculation_enabled?
@individual_outcome_rating_and_calculation_enabled ||= domain_root_account.feature_enabled?(:individual_outcome_rating_and_calculation) &&
domain_root_account.feature_enabled?(:improved_outcomes_management) &&
!domain_root_account.feature_enabled?(:account_level_mastery_scales)
end
end
end

View File

@ -1438,8 +1438,6 @@ module ApplicationHelper
if @domain_root_account.feature_enabled?(:account_level_mastery_scales)
js_env(
ACCOUNT_LEVEL_MASTERY_SCALES: true,
IMPROVED_OUTCOMES_MANAGEMENT:
@domain_root_account.feature_enabled?(:improved_outcomes_management),
MASTERY_SCALE: {
outcome_proficiency: @context.resolved_outcome_proficiency&.as_json,
outcome_calculation_method: @context.resolved_outcome_calculation_method&.as_json
@ -1454,14 +1452,10 @@ module ApplicationHelper
!@current_user.fake_student? && !@current_user.used_feature?(:cc_prefs) && !k5_student
end
def individual_outcome_rating_and_calculation_js_env
if @domain_root_account.feature_enabled?(:individual_outcome_rating_and_calculation) && !@domain_root_account.feature_enabled?(:account_level_mastery_scales)
js_env(
INDIVIDUAL_OUTCOME_RATING_AND_CALCULATION: true,
IMPROVED_OUTCOMES_MANAGEMENT:
@domain_root_account.feature_enabled?(:improved_outcomes_management)
)
end
def improved_outcomes_management_js_env
js_env(
IMPROVED_OUTCOMES_MANAGEMENT: @domain_root_account.feature_enabled?(:improved_outcomes_management)
)
end
def append_default_due_time_js_env(context, hash)

View File

@ -19,9 +19,7 @@
#
module OutcomesFeaturesHelper
def individual_outcome_rating_and_calculation_enabled?(context)
context.root_account.feature_enabled?(:improved_outcomes_management) &&
context.root_account.feature_enabled?(:individual_outcome_rating_and_calculation) &&
!context.root_account.feature_enabled?(:account_level_mastery_scales)
def account_level_mastery_scales_enabled?(context)
context&.root_account&.feature_enabled?(:account_level_mastery_scales)
end
end

View File

@ -17,21 +17,25 @@
%>
<%
css_bundle :learning_outcomes, :tinymce
js_bundle :learning_outcomes
css_bundle :tinymce
provide :page_title, t("#titles.learning_outcomes", "Learning Outcomes")
%>
<h1 class="screenreader-only"><%= t("#titles.learning_outcomes", "Learning Outcomes") %></h1>
<%
if @domain_root_account.feature_enabled?(:improved_outcomes_management)
css_bundle :improved_outcomes_management
else
css_bundle :learning_outcomes
js_bundle :learning_outcomes
end
%>
<% if (@domain_root_account.feature_enabled?(:account_level_mastery_scales) || @domain_root_account.feature_enabled?(:individual_outcome_rating_and_calculation)) %>
<% if @domain_root_account.feature_enabled?(:improved_outcomes_management) || @domain_root_account.feature_enabled?(:account_level_mastery_scales) %>
<%
js_bundle :outcome_management
css_bundle :proficiency_table
js_bundle :outcome_management
%>
<div id="outcome_management"></div>
<div id="outcomes" style="display: none;"></div>

View File

@ -131,8 +131,6 @@ describe Mutations::CreateLearningOutcome do
end
it "creates a learning outcome with individual ratings and calculation method" do
@domain_root_account.enable_feature!(:individual_outcome_rating_and_calculation)
@domain_root_account.enable_feature!(:improved_outcomes_management)
@domain_root_account.disable_feature!(:account_level_mastery_scales)
calculation_method = default_rating_variables[:calculation_method]
@ -221,16 +219,7 @@ describe Mutations::CreateLearningOutcome do
expect_error(result, "Argument 'groupId' on InputObject 'CreateLearningOutcomeInput' is required.")
end
it "raises error when data includes individual ratings with IORC FF disabled" do
@course.root_account.disable_feature!(:individual_outcome_rating_and_calculation)
@course.root_account.disable_feature!(:account_level_mastery_scales)
result = execute_with_input "#{variables},#{rating_variables}"
expect_error(result, "individual ratings data input with invidual_outcome_rating_and_calculation FF disabled")
end
it "raises error when data includes individual ratings with both IORC and ALMS FFs enabled" do
@course.root_account.enable_feature!(:individual_outcome_rating_and_calculation)
it "raises error when data includes individual ratings with account_level_mastery_scales FF enabled" do
@course.root_account.enable_feature!(:account_level_mastery_scales)
result = execute_with_input "#{variables},#{rating_variables}"

View File

@ -121,7 +121,7 @@ describe Mutations::UpdateLearningOutcome do
expect(result["vendorGuid"]).to eq "vg--1"
end
context "individual ratings and calculation method feature flag enabled" do
context "account_level_mastery_scales feature flag disabled" do
def expect_result(rating_vars, calculation_method, calculation_int, mastery_points, ratings)
result = execute_with_input "#{variables},#{rating_vars}"
expect(result["errors"]).to be_nil
@ -144,8 +144,6 @@ describe Mutations::UpdateLearningOutcome do
end
before do
@domain_root_account.enable_feature!(:individual_outcome_rating_and_calculation)
@domain_root_account.enable_feature!(:improved_outcomes_management)
@domain_root_account.disable_feature!(:account_level_mastery_scales)
end
@ -260,16 +258,7 @@ describe Mutations::UpdateLearningOutcome do
expect_error(result, "can't be blank")
end
it "raises error when data includes individual ratings with IORC FF disabled" do
@course.root_account.disable_feature!(:individual_outcome_rating_and_calculation)
@course.root_account.disable_feature!(:account_level_mastery_scales)
result = execute_with_input "#{variables},#{rating_variables}"
expect_error(result, "individual ratings data input with invidual_outcome_rating_and_calculation FF disabled")
end
it "raises error when data includes individual ratings with both IORC and ALMS FFs enabled" do
@course.root_account.enable_feature!(:individual_outcome_rating_and_calculation)
it "raises error when data includes individual ratings with account_level_mastery_scales FF enabled" do
@course.root_account.enable_feature!(:account_level_mastery_scales)
result = execute_with_input "#{variables},#{rating_variables}"

View File

@ -37,14 +37,9 @@ describe Types::LearningOutcomeType do
outcome_type_raw
end
context "with IOM and IORC enabled and ALMS disabled" do
before(:once) do
@domain_root_account.enable_feature! :improved_outcomes_management
@domain_root_account.enable_feature! :individual_outcome_rating_and_calculation
context "Account Level Mastery Scales Feature Flag" do
it "returns outcome with individual ratings and calculation method if FF disabled" do
@domain_root_account.disable_feature! :account_level_mastery_scales
end
it "returns outcome with ratings and calculation" do
expect(outcome_type.resolve("_id")).to eq @outcome.id.to_s
expect(outcome_type.resolve("contextId")).to eq @outcome.context_id.to_s
expect(outcome_type.resolve("contextType")).to eq @outcome.context_type
@ -64,31 +59,15 @@ describe Types::LearningOutcomeType do
expect(outcome_type.resolve("canEdit")).to eq true
end
end
context "with any other combination of FF" do
def set_feature_flag_by_bit(feature_flag, bit_value)
@domain_root_account.set_feature_flag!(feature_flag, bit_value == 1 ? Feature::STATE_ON : Feature::STATE_OFF)
end
it "returns outcome without individual ratings and calculation method if FF enabled" do
@domain_root_account.enable_feature! :account_level_mastery_scales
(0..7).each do |mask|
next if mask == 6
ff_iom = (mask >> 2) & 1
ff_iorc = (mask >> 1) & 1
ff_alms = mask & 1
it "returns no ratings and calculation (IOM: #{ff_iom}, IORC: #{ff_iorc}, ALMS: #{ff_alms})" do
set_feature_flag_by_bit :improved_outcomes_management, ff_iom
set_feature_flag_by_bit :individual_outcome_rating_and_calculation, ff_iorc
set_feature_flag_by_bit :account_level_mastery_scales, ff_alms
expect(outcome_type.resolve("calculationMethod")).to be_nil
expect(outcome_type.resolve("calculationInt")).to be_nil
expect(outcome_type.resolve("pointsPossible")).to be_nil
expect(outcome_type.resolve("masteryPoints")).to be_nil
expect(outcome_type.resolve("ratings { points }")).to be_nil
end
expect(outcome_type.resolve("calculationMethod")).to be_nil
expect(outcome_type.resolve("calculationInt")).to be_nil
expect(outcome_type.resolve("pointsPossible")).to be_nil
expect(outcome_type.resolve("masteryPoints")).to be_nil
expect(outcome_type.resolve("ratings { points }")).to be_nil
end
end

View File

@ -1303,19 +1303,6 @@ describe ApplicationHelper do
expect(mastery_scale[:outcome_proficiency]).to eq @proficiency.as_json
expect(mastery_scale[:outcome_calculation_method]).to eq @calculation_method.as_json
end
it "includes improved outcomes management FF" do
helper.mastery_scales_js_env
expect(js_env[:IMPROVED_OUTCOMES_MANAGEMENT]).to be(false)
end
context "when improved_outcomes_management enabled" do
it "includes improved outcomes management FF" do
@course.root_account.enable_feature! :improved_outcomes_management
helper.mastery_scales_js_env
expect(js_env[:IMPROVED_OUTCOMES_MANAGEMENT]).to be(true)
end
end
end
end
@ -1404,7 +1391,7 @@ describe ApplicationHelper do
end
end
describe "individual_outcome_rating_and_calculation_js_env" do
describe "improved_outcomes_management_js_env" do
before(:once) do
course_model
@context = @course
@ -1417,52 +1404,21 @@ describe ApplicationHelper do
allow(helper).to receive(:js_env) { |env| js_env.merge!(env) }
end
context "when individual_outcome_rating_and_calculation FF is disabled" do
before(:once) do
@course.root_account.disable_feature! :individual_outcome_rating_and_calculation
end
it "does not include in js_env individual outcome rating and calculation key" do
helper.individual_outcome_rating_and_calculation_js_env
expect(js_env).not_to have_key :INDIVIDUAL_OUTCOME_RATING_AND_CALCULATION
end
it "does not include in js_env improved outcomes management key" do
helper.individual_outcome_rating_and_calculation_js_env
expect(js_env).not_to have_key :IMPROVED_OUTCOMES_MANAGEMENT
context "when improved_outcomes_management FF is enabled" do
it "sets improved_outcomes_management key in js_env to true" do
@course.root_account.enable_feature! :improved_outcomes_management
helper.improved_outcomes_management_js_env
expect(js_env).to have_key :IMPROVED_OUTCOMES_MANAGEMENT
expect(js_env[:IMPROVED_OUTCOMES_MANAGEMENT]).to be(true)
end
end
context "when individual_outcome_rating_and_calculation FF is enabled" do
before(:once) do
@course.root_account.enable_feature! :individual_outcome_rating_and_calculation
end
context "when account_level_mastery_scales FF is disabled" do
before(:once) do
@course.root_account.disable_feature! :account_level_mastery_scales
end
it "includes in js_env individual outcome rating and calculation key" do
helper.individual_outcome_rating_and_calculation_js_env
expect(js_env).to have_key :INDIVIDUAL_OUTCOME_RATING_AND_CALCULATION
end
it "includes in js_env improved outcomes management key" do
helper.individual_outcome_rating_and_calculation_js_env
expect(js_env).to have_key :IMPROVED_OUTCOMES_MANAGEMENT
end
end
context "when account_level_mastery_scales FF is enabled" do
before(:once) do
@course.root_account.enable_feature! :account_level_mastery_scales
end
it "does not include in js_env individual outcome rating and calculation key" do
helper.individual_outcome_rating_and_calculation_js_env
expect(js_env).not_to have_key :INDIVIDUAL_OUTCOME_RATING_AND_CALCULATION
end
context "when improved_outcomes_management FF is disabled" do
it "sets improved_outcomes_management key in js_env to false" do
@course.root_account.disable_feature! :improved_outcomes_management
helper.improved_outcomes_management_js_env
expect(js_env).to have_key :IMPROVED_OUTCOMES_MANAGEMENT
expect(js_env[:IMPROVED_OUTCOMES_MANAGEMENT]).to be(false)
end
end
end

View File

@ -24,33 +24,41 @@ describe OutcomesFeaturesHelper do
before :once do
@account = Account.default
@context = @course = @account.courses.create!
outcome_model(context: @course)
@global_outcome = outcome_model(global: true, title: "Global outcome")
@account_outcome = outcome_model(context: @account)
@course_outcome = outcome_model(context: @course)
end
describe "#individual_outcome_rating_and_calculation_enabled?" do
describe "#account_level_mastery_scales_enabled?" do
before do
@context.root_account.enable_feature!(:improved_outcomes_management)
@context.root_account.enable_feature!(:individual_outcome_rating_and_calculation)
@context.root_account.disable_feature!(:account_level_mastery_scales)
end
it "is true when IOM and IORCM are enabled and ALMS is disabled" do
expect(individual_outcome_rating_and_calculation_enabled?(@outcome.context)).to eq true
end
it "is false when improved outcomes management (IOM) is disabled" do
@context.root_account.disable_feature!(:improved_outcomes_management)
expect(individual_outcome_rating_and_calculation_enabled?(@outcome.context)).to eq false
end
it "is false when individual outcome rating and calculation (IORCM) is disabled" do
@context.root_account.disable_feature!(:individual_outcome_rating_and_calculation)
expect(individual_outcome_rating_and_calculation_enabled?(@outcome.context)).to eq false
end
it "is false when account level mastery scales (ALMS) is enabled" do
@context.root_account.enable_feature!(:account_level_mastery_scales)
expect(individual_outcome_rating_and_calculation_enabled?(@outcome.context)).to eq false
end
it "returns true when account_level_mastery_scales FF is enabled" do
expect(account_level_mastery_scales_enabled?(@course_outcome.context)).to eq true
end
it "returns false when account_level_mastery_scales FF is disabled" do
@context.root_account.disable_feature!(:account_level_mastery_scales)
expect(account_level_mastery_scales_enabled?(@course_outcome.context)).to eq false
end
it "works properly when arg is course outcome" do
expect(account_level_mastery_scales_enabled?(@course_outcome.context)).to eq true
@context.root_account.disable_feature!(:account_level_mastery_scales)
expect(account_level_mastery_scales_enabled?(@course_outcome.context)).to eq false
end
it "works properly when arg is account outcome" do
expect(account_level_mastery_scales_enabled?(@account_outcome.context)).to eq true
@context.root_account.disable_feature!(:account_level_mastery_scales)
expect(account_level_mastery_scales_enabled?(@account_outcome.context)).to eq false
end
it "works properly when arg is global outcome" do
expect(account_level_mastery_scales_enabled?(@global_outcome.context)).to eq nil
@context.root_account.disable_feature!(:account_level_mastery_scales)
expect(account_level_mastery_scales_enabled?(@global_outcome.context)).to eq nil
end
end
end

View File

@ -437,13 +437,13 @@ describe "outcome gradebook" do
end
end
context "with individual outcome rating and calculation method" do
context "Account Level Mastery Scales" do
before(:once) do
outcome_criterion = LearningOutcome.default_rubric_criterion
outcome_criterion[:ratings][1][:points] = 4
outcome_criterion[:mastery_points] = 4
outcome = LearningOutcome.create!(context: @course, title: "Outcome with IORCM", rubric_criterion: outcome_criterion)
outcome = LearningOutcome.create!(context: @course, title: "Outcome with individual ratings", rubric_criterion: outcome_criterion)
proficiency = OutcomeProficiency.new(context: @course)
proficiency.replace_ratings(OutcomeProficiency.default_ratings)
@ -463,10 +463,9 @@ describe "outcome gradebook" do
result(@student_1, alignment, 3)
end
it "Displays mastery achieved if IORCM is disabled" do
it "Displays mastery achieved if Account Level Mastery Scales FF is enabled" do
Account.default.set_feature_flag!("account_level_mastery_scales", "on")
Account.default.set_feature_flag!("improved_outcomes_management", "on")
Account.default.set_feature_flag!("individual_outcome_rating_and_calculation", "off")
get "/courses/#{@course.id}/gradebook"
select_learning_mastery
@ -475,10 +474,9 @@ describe "outcome gradebook" do
expect(selected_values_colors).to contain_exactly("#0B874B")
end
it "Displays mastery not achieved if IORCM is enabled" do
it "Displays mastery not achieved if Account Level Mastery Scales FF is disabled" do
Account.default.set_feature_flag!("account_level_mastery_scales", "off")
Account.default.set_feature_flag!("improved_outcomes_management", "on")
Account.default.set_feature_flag!("individual_outcome_rating_and_calculation", "on")
get "/courses/#{@course.id}/gradebook"
select_learning_mastery

View File

@ -364,9 +364,10 @@ describe "outcomes" do
end
end
describe "with individual_ratings_and_calculation_method enabled" do
describe "with account_level_mastery_scales disabled" do
before do
enable_improved_outcomes_management_with_individual_ratings(Account.default)
enable_improved_outcomes_management(Account.default)
disable_account_level_mastery_scales(Account.default)
end
it "creates an outcome with default ratings and calculation method" do

View File

@ -331,9 +331,7 @@ module ImprovedOutcomeManagementPage
drilldown_outcome_groups.find { |group| group.text.split("\n")[0] == text }
end
def enable_improved_outcomes_management_with_individual_ratings(account)
account.enable_feature!(:improved_outcomes_management)
account.enable_feature!(:individual_outcome_rating_and_calculation)
def disable_account_level_mastery_scales(account)
account.disable_feature!(:account_level_mastery_scales)
end

View File

@ -55,13 +55,8 @@ import Ratings from './Management/Ratings'
const I18n = useI18nScope('OutcomeManagement')
const CreateOutcomeModal = ({isOpen, onCloseHandler, onSuccess, starterGroupId}) => {
const {
contextType,
contextId,
friendlyDescriptionFF,
isMobileView,
individualOutcomeRatingAndCalculationFF
} = useCanvasContext()
const {contextType, contextId, friendlyDescriptionFF, isMobileView, accountLevelMasteryScalesFF} =
useCanvasContext()
const [title, titleChangeHandler] = useInput()
const [displayName, displayNameChangeHandler] = useInput()
const [friendlyDescription, friendlyDescriptionChangeHandler] = useInput()
@ -157,7 +152,7 @@ const CreateOutcomeModal = ({isOpen, onCloseHandler, onSuccess, starterGroupId})
displayName,
description
}
if (individualOutcomeRatingAndCalculationFF) {
if (!accountLevelMasteryScalesFF) {
input.calculationMethod = proficiencyCalculation.calculationMethod
input.calculationInt = proficiencyCalculation.calculationInt
const {masteryPoints: inputMasteryPoints, ratings: inputRatings} =
@ -286,7 +281,7 @@ const CreateOutcomeModal = ({isOpen, onCloseHandler, onSuccess, starterGroupId})
/>
</View>
)}
{individualOutcomeRatingAndCalculationFF && (
{!accountLevelMasteryScalesFF && (
<View as="div" padding="small 0 0">
<Ratings
ratings={ratings}

View File

@ -58,9 +58,8 @@ const FindOutcomeItem = ({
friendlyDescription
}) => {
const [truncated, setTruncated] = useState(true)
const {isMobileView, individualOutcomeRatingAndCalculationFF} = useCanvasContext()
const shouldShowDescription =
description || friendlyDescription || individualOutcomeRatingAndCalculationFF
const {isMobileView, accountLevelMasteryScalesFF} = useCanvasContext()
const shouldShowDescription = description || friendlyDescription || !accountLevelMasteryScalesFF
const onClickHandler = () => shouldShowDescription && setTruncated(prevState => !prevState)
const IconArrowOpenEnd = isMobileView ? IconArrowOpenEndSolid : IconArrowOpenEndLine
const IconArrowOpenDown = isMobileView ? IconArrowOpenDownSolid : IconArrowOpenDownLine

View File

@ -54,7 +54,7 @@ const ManageOutcomeItem = ({
contextType,
contextId,
friendlyDescriptionFF,
individualOutcomeRatingAndCalculationFF,
accountLevelMasteryScalesFF,
canManage,
isAdmin,
isCourse
@ -71,8 +71,7 @@ const ManageOutcomeItem = ({
friendlyDescriptionFF ||
(outcomeContextType === contextType && outcomeContextId === contextId) ||
allowAdminEdit
const shouldShowDescription =
description || friendlyDescription || individualOutcomeRatingAndCalculationFF
const shouldShowDescription = description || friendlyDescription || !accountLevelMasteryScalesFF
if (!title) return null

View File

@ -40,8 +40,7 @@ const OutcomeDescription = ({
masteryPoints,
ratings
}) => {
const {friendlyDescriptionFF, isStudent, individualOutcomeRatingAndCalculationFF} =
useCanvasContext()
const {friendlyDescriptionFF, isStudent, accountLevelMasteryScalesFF} = useCanvasContext()
const shouldShowFriendlyDescription = friendlyDescriptionFF && friendlyDescription
let fullDescription = description
let truncatedDescription = stripHtmlTags(fullDescription || '')
@ -56,7 +55,7 @@ const OutcomeDescription = ({
!isStudent &&
truncatedDescription !== friendlyDescription
if (!description && !friendlyDescription && !individualOutcomeRatingAndCalculationFF) return null
if (!description && !friendlyDescription && accountLevelMasteryScalesFF) return null
return (
<View>
@ -114,7 +113,7 @@ const OutcomeDescription = ({
</View>
)}
{!truncated && individualOutcomeRatingAndCalculationFF && (
{!truncated && !accountLevelMasteryScalesFF && (
<View>
<Ratings
ratings={prepareRatings(ratings)}

View File

@ -56,7 +56,7 @@ const OutcomeEditModal = ({outcome, isOpen, onCloseHandler, onEditLearningOutcom
const [description, setDescription, descriptionChanged] = useInput(outcome.description || '')
const [friendlyDescription, friendlyDescriptionChangeHandler, friendlyDescriptionChanged] =
useInput(outcome.friendlyDescription?.description || '')
const {contextType, contextId, friendlyDescriptionFF, individualOutcomeRatingAndCalculationFF} =
const {contextType, contextId, friendlyDescriptionFF, accountLevelMasteryScalesFF} =
useCanvasContext()
const {
ratings,
@ -145,7 +145,7 @@ const OutcomeEditModal = ({outcome, isOpen, onCloseHandler, onEditLearningOutcom
if (displayName && displayNameChanged) input.displayName = displayName
// description can be null/empty. no need to check if it is available only if it has changed
if (descriptionChanged) input.description = description
if (individualOutcomeRatingAndCalculationFF) {
if (!accountLevelMasteryScalesFF) {
if (proficiencyCalculationMethodChanged || proficiencyCalculationIntChanged) {
input.calculationMethod = proficiencyCalculationMethod
input.calculationInt = calculationInt
@ -289,7 +289,7 @@ const OutcomeEditModal = ({outcome, isOpen, onCloseHandler, onEditLearningOutcom
/>
</View>
)}
{individualOutcomeRatingAndCalculationFF && (
{!accountLevelMasteryScalesFF && (
<View as="div" padding="small 0 0">
<Ratings
ratings={ratings}

View File

@ -31,7 +31,7 @@ const render = (
contextId = '2',
contextType = 'Account',
friendlyDescriptionFF = true,
individualOutcomeRatingAndCalculationFF = false,
accountLevelMasteryScalesFF = true,
renderer = rtlRender
} = {}
) => {
@ -44,7 +44,7 @@ const render = (
contextId,
contextType,
friendlyDescriptionFF,
individualOutcomeRatingAndCalculationFF
accountLevelMasteryScalesFF
}
}}
>
@ -139,9 +139,9 @@ describe('ManageOutcomeItem', () => {
)
})
it('displays enabled caret button if no description but individualOutcomeRatingAndCalculationFF on', () => {
it('displays enabled caret button if no description and accountLevelMasteryScales is disabled', () => {
const {queryByTestId} = render(<ManageOutcomeItem {...defaultProps({description: null})} />, {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
})
expect(queryByTestId('icon-arrow-right').closest('button')).toBeEnabled()
})
@ -218,20 +218,20 @@ describe('ManageOutcomeItem', () => {
})
})
describe('individual outcome rating and calculation FF', () => {
describe('when feature flag enabled', () => {
describe('account level mastery scales FF', () => {
describe('when feature flag disabled', () => {
it('enables caret button even if no description', () => {
const {queryByTestId} = render(
<ManageOutcomeItem {...defaultProps({description: null})} />,
{
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
)
expect(queryByTestId('icon-arrow-right').closest('button')).toBeEnabled()
})
})
describe('when feature flag disabled', () => {
describe('when feature flag enabled', () => {
it('disables caret button and changes cursor to "not-allowed" if no description', () => {
const {queryByTestId} = render(<ManageOutcomeItem {...defaultProps({description: null})} />)
expect(queryByTestId('icon-arrow-right').closest('button')).toBeDisabled()

View File

@ -45,15 +45,11 @@ describe('OutcomeDescription', () => {
const render = (
children,
{
friendlyDescriptionFF = false,
individualOutcomeRatingAndCalculationFF = false,
isStudent = false
} = {}
{friendlyDescriptionFF = false, accountLevelMasteryScalesFF = true, isStudent = false} = {}
) => {
return rtlRender(
<OutcomesContext.Provider
value={{env: {friendlyDescriptionFF, individualOutcomeRatingAndCalculationFF, isStudent}}}
value={{env: {friendlyDescriptionFF, accountLevelMasteryScalesFF, isStudent}}}
>
{children}
</OutcomesContext.Provider>
@ -166,13 +162,13 @@ describe('OutcomeDescription', () => {
})
})
describe('individual outcome rating and calculation FF', () => {
describe('when feature flag enabled', () => {
describe('account level mastery scales FF', () => {
describe('when feature flag disabled', () => {
it('renders ratings when description prop not provided/null and expanded', () => {
const {queryByTestId} = render(
<OutcomeDescription {...defaultProps({description: null, truncated: false})} />,
{
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
)
expect(queryByTestId(ratingsTestId)).toBeInTheDocument()
@ -180,20 +176,20 @@ describe('OutcomeDescription', () => {
it('displays calculation method if description expanded', () => {
const {getByText} = render(<OutcomeDescription {...defaultProps({truncated: false})} />, {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
})
expect(getByText('Proficiency Calculation:')).toBeInTheDocument()
})
it('hides calculation method if description truncated', () => {
const {queryByText} = render(<OutcomeDescription {...defaultProps()} />, {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
})
expect(queryByText('Proficiency Calculation:')).not.toBeInTheDocument()
})
})
describe('when feature flag disabled', () => {
describe('when feature flag enabled', () => {
it('hides calculation method', () => {
const {queryByText} = render(<OutcomeDescription {...defaultProps({truncated: false})} />)
expect(queryByText('Proficiency Calculation:')).not.toBeInTheDocument()

View File

@ -72,7 +72,7 @@ describe('OutcomeEditModal', () => {
contextType: 'Account',
contextId: '1',
friendlyDescriptionFF: true,
individualOutcomeRatingAndCalculationFF: false
accountLevelMasteryScalesFF: true
},
mockOverrides = []
} = {}) => {
@ -347,14 +347,14 @@ describe('OutcomeEditModal', () => {
})
})
describe('Individual Outcome Proficiency and Calculation Feature Flag', () => {
describe('when feature flag enabled', () => {
describe('account level mastery scales FF', () => {
describe('when feature flag disabled', () => {
it('displays calculation method selection form if outcome is created in same context', async () => {
const {getByLabelText} = renderWithProvider({
env: {
contextType: 'Account',
contextId: '1',
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
})
expect(getByLabelText('Calculation Method')).toBeInTheDocument()
@ -365,7 +365,7 @@ describe('OutcomeEditModal', () => {
env: {
contextType: 'Course',
contextId: '2',
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
})
expect(getByTestId('read-only-calculation-method')).toBeInTheDocument()
@ -376,7 +376,7 @@ describe('OutcomeEditModal', () => {
env: {
contextType: 'Account',
contextId: '1',
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
})
expect(getByTestId('outcome-management-ratings')).toBeInTheDocument()
@ -388,7 +388,7 @@ describe('OutcomeEditModal', () => {
env: {
contextType: 'Course',
contextId: '2',
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
})
expect(getByTestId('outcome-management-ratings')).toBeInTheDocument()
@ -407,7 +407,7 @@ describe('OutcomeEditModal', () => {
env: {
contextType: 'Account',
contextId: '1',
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
},
mockOverrides: mocks
})
@ -442,7 +442,7 @@ describe('OutcomeEditModal', () => {
env: {
contextType: 'Account',
contextId: '1',
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
},
mockOverrides: mocks
})
@ -469,7 +469,7 @@ describe('OutcomeEditModal', () => {
env: {
contextType: 'Account',
contextId: '1',
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
})
expect(getByTestId('outcome-edit-modal-horizontal-divider')).toBeInTheDocument()
@ -480,7 +480,7 @@ describe('OutcomeEditModal', () => {
env: {
contextType: 'Account',
contextId: '1',
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
})
const ratingDescription = getByLabelText('Change description for mastery level 2')
@ -499,7 +499,7 @@ describe('OutcomeEditModal', () => {
env: {
contextType: 'Account',
contextId: '1',
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
})
const masteryPoints = getByLabelText('Change mastery points')
@ -514,7 +514,7 @@ describe('OutcomeEditModal', () => {
})
})
describe('when feature flag disabled', () => {
describe('when feature flag enabled', () => {
it('does not display Calculation Method selection form', async () => {
const {queryByLabelText} = renderWithProvider()
expect(queryByLabelText('Calculation Method')).not.toBeInTheDocument()

View File

@ -50,7 +50,7 @@ describe('CreateOutcomeModal', () => {
contextType = 'Account',
contextId = '1',
friendlyDescriptionFF = true,
individualOutcomeRatingAndCalculationFF = false,
accountLevelMasteryScalesFF = true,
mocks = accountMocks({childGroupsCount: 0}),
isMobileView = false,
renderer = rtlRender,
@ -64,7 +64,7 @@ describe('CreateOutcomeModal', () => {
contextType,
contextId,
friendlyDescriptionFF,
individualOutcomeRatingAndCalculationFF,
accountLevelMasteryScalesFF,
isMobileView,
treeBrowserRootGroupId
}
@ -473,11 +473,11 @@ describe('CreateOutcomeModal', () => {
})
})
describe('Invidiual Outcome Proficiency and Calculation Feature Flag', () => {
describe('when feature flag enabled', () => {
describe('Account Level Mastery Scales Feature Flag', () => {
describe('when feature flag disabled', () => {
it('displays Calculation Method selection form', async () => {
const {getByLabelText} = render(<CreateOutcomeModal {...defaultProps()} />, {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
})
await act(async () => jest.runOnlyPendingTimers())
expect(getByLabelText('Calculation Method')).toBeInTheDocument()
@ -485,7 +485,7 @@ describe('CreateOutcomeModal', () => {
it('displays Proficiency Ratings selection form', async () => {
const {getByTestId} = render(<CreateOutcomeModal {...defaultProps()} />, {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
})
await act(async () => jest.runOnlyPendingTimers())
expect(getByTestId('outcome-management-ratings')).toBeInTheDocument()
@ -496,7 +496,7 @@ describe('CreateOutcomeModal', () => {
const {getByText, getByLabelText, getByDisplayValue} = render(
<CreateOutcomeModal {...defaultProps()} />,
{
individualOutcomeRatingAndCalculationFF: true,
accountLevelMasteryScalesFF: false,
mocks: [
...smallOutcomeTree(),
createLearningOutcomeMock({
@ -531,7 +531,7 @@ describe('CreateOutcomeModal', () => {
it('displays horizontal divider between ratings and calculation method which is hidden from screen readers', async () => {
const {getByTestId} = render(<CreateOutcomeModal {...defaultProps()} />, {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
})
await act(async () => jest.runOnlyPendingTimers())
expect(getByTestId('outcome-create-modal-horizontal-divider')).toBeInTheDocument()
@ -539,7 +539,7 @@ describe('CreateOutcomeModal', () => {
it('sets focus on rating description if error in both description and points and click on Create button', () => {
const {getByText, getByLabelText} = render(<CreateOutcomeModal {...defaultProps()} />, {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
})
fireEvent.change(getByLabelText('Name'), {target: {value: 'Outcome 123'}})
const ratingDescription = getByLabelText('Change description for mastery level 2')
@ -555,7 +555,7 @@ describe('CreateOutcomeModal', () => {
it('sets focus on mastery points if error in mastery points and calculation method and click on Create button', () => {
const {getByText, getByLabelText} = render(<CreateOutcomeModal {...defaultProps()} />, {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
})
fireEvent.change(getByLabelText('Name'), {target: {value: 'Outcome 123'}})
const masteryPoints = getByLabelText('Change mastery points')
@ -570,7 +570,7 @@ describe('CreateOutcomeModal', () => {
})
})
describe('when feature flag disabled', () => {
describe('when feature flag enabled', () => {
it('does not display Calculation Method selection form', async () => {
const {queryByLabelText} = render(<CreateOutcomeModal {...defaultProps()} />)
await act(async () => jest.runOnlyPendingTimers())

View File

@ -52,18 +52,14 @@ describe('FindOutcomeItem', () => {
const render = (
children,
{
friendlyDescriptionFF = true,
individualOutcomeRatingAndCalculationFF = false,
renderer = rtlRender
} = {}
{friendlyDescriptionFF = true, accountLevelMasteryScalesFF = true, renderer = rtlRender} = {}
) => {
return renderer(
<OutcomesContext.Provider
value={{
env: {
friendlyDescriptionFF,
individualOutcomeRatingAndCalculationFF
accountLevelMasteryScalesFF
}
}}
>
@ -202,17 +198,17 @@ describe('FindOutcomeItem', () => {
expect(queryByText('test friendly description')).not.toBeInTheDocument()
})
describe('individual outcome rating and calculation FF', () => {
describe('when feature flag enabled', () => {
describe('account level mastery scales FF', () => {
describe('when feature flag disabled', () => {
it('enables caret button even if no description', () => {
const {queryByTestId} = render(<FindOutcomeItem {...defaultProps({description: null})} />, {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
})
expect(queryByTestId('icon-arrow-right').closest('button')).toBeEnabled()
})
})
describe('when feature flag disabled', () => {
describe('when feature flag enabled', () => {
it('disables caret button if no description', () => {
const {queryByTestId} = render(<FindOutcomeItem {...defaultProps({description: null})} />)
expect(queryByTestId('icon-arrow-right').closest('button')).toBeDisabled()

View File

@ -149,9 +149,8 @@ describe('OutcomeManagement', () => {
expect(getByText('Calculation')).toBeInTheDocument()
})
it('renders only Manage tab when Individual Outcome Rating and Calculation FF is enabled', async () => {
delete window.ENV.ACCOUNT_LEVEL_MASTERY_SCALES
window.ENV.INDIVIDUAL_OUTCOME_RATING_AND_CALCULATION = true
it('renders only Manage tab when Account Level Mastery Scales FF is disabled', async () => {
window.ENV.ACCOUNT_LEVEL_MASTERY_SCALES = false
const {getByText, queryByText} = render(
<MockedProvider cache={cache} mocks={[...outcomeGroupsMocks]}>
<OutcomeManagement />

View File

@ -36,7 +36,6 @@ export const getContext = isMobileView => {
const treeBrowserRootGroupId = ROOT_GROUP_ID
const treeBrowserAccountGroupId = ACCOUNT_GROUP_ID
const rootIds = [globalRootId, treeBrowserAccountGroupId, treeBrowserRootGroupId]
const individualOutcomeRatingAndCalculationFF = ENV.INDIVIDUAL_OUTCOME_RATING_AND_CALCULATION
const accountLevelMasteryScalesFF = ENV.ACCOUNT_LEVEL_MASTERY_SCALES
return {
@ -54,7 +53,6 @@ export const getContext = isMobileView => {
treeBrowserRootGroupId,
treeBrowserAccountGroupId,
rootIds,
individualOutcomeRatingAndCalculationFF,
accountLevelMasteryScalesFF
}
}

View File

@ -137,12 +137,12 @@ describe('useOutcomeFormValidate', () => {
expect(result.current.fieldWithError).toBe('friendly_description')
})
it('validates ratings, mastery points and calculation method for errors if individual ratings and calculation FF is enabled', () => {
it('validates ratings, mastery points and calculation method for errors if account level mastery scales FF is disabled', () => {
const wrapper = ({children}) => (
<OutcomesContext.Provider
value={{
env: {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
}}
>
@ -183,7 +183,7 @@ describe('useOutcomeFormValidate', () => {
<OutcomesContext.Provider
value={{
env: {
individualOutcomeRatingAndCalculationFF: true
accountLevelMasteryScalesFF: false
}
}}
>

View File

@ -35,8 +35,6 @@ const useCanvasContext = () => {
const treeBrowserRootGroupId = context?.env?.treeBrowserRootGroupId
const treeBrowserAccountGroupId = context?.env?.treeBrowserAccountGroupId
const rootIds = context?.env?.rootIds
const individualOutcomeRatingAndCalculationFF =
context?.env?.individualOutcomeRatingAndCalculationFF
const accountLevelMasteryScalesFF = context?.env?.accountLevelMasteryScalesFF
return {
@ -54,7 +52,6 @@ const useCanvasContext = () => {
treeBrowserRootGroupId,
treeBrowserAccountGroupId,
rootIds,
individualOutcomeRatingAndCalculationFF,
accountLevelMasteryScalesFF
}
}

View File

@ -21,14 +21,14 @@ import useInputFocus from './useInputFocus'
import useCanvasContext from './useCanvasContext'
const useOutcomeFormValidate = ({focusOnRatingsError, clearRatingsFocus}) => {
const {friendlyDescriptionFF, individualOutcomeRatingAndCalculationFF} = useCanvasContext()
const {friendlyDescriptionFF, accountLevelMasteryScalesFF} = useCanvasContext()
const [focusOnErrorField, setFocusOnErrorField] = useState(false)
const [fieldWithError, setFieldWithError] = useState(null)
const fields = ['title', 'display_name']
if (friendlyDescriptionFF) {
fields.push('friendly_description')
}
if (individualOutcomeRatingAndCalculationFF) {
if (!accountLevelMasteryScalesFF) {
fields.push('mastery_points', 'individual_calculation_method')
}
const {inputElRefs, setInputElRef} = useInputFocus(fields)
@ -50,7 +50,7 @@ const useOutcomeFormValidate = ({focusOnRatingsError, clearRatingsFocus}) => {
typeof clearRatingsFocus === 'function' && clearRatingsFocus()
// validate form fields in reverse order to focus on first field with error
if (individualOutcomeRatingAndCalculationFF) {
if (!accountLevelMasteryScalesFF) {
if (proficiencyCalculationError) errField = 'individual_calculation_method'
if (masteryPointsError) errField = 'mastery_points'
if (ratingsError) errField = 'individual_ratings'