Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion contentcuration/contentcuration/frontend/shared/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ export const FeatureFlagKeys = Object.keys(FeatureFlagsSchema.properties).reduce

export const ContentModalities = {
QUIZ: 'QUIZ',
SURVEY: 'SURVEY',
};

export const AccessibilityCategoriesMap = {
Expand All @@ -223,6 +224,7 @@ export const CompletionDropdownMap = {
goal: 'goal',
practiceQuiz: 'practiceQuiz',
reference: 'reference',
survey: 'survey',
};

export const DurationDropdownMap = {
Expand Down Expand Up @@ -284,7 +286,11 @@ export const CompletionOptionsDropdownMap = {
CompletionDropdownMap.completeDuration,
CompletionDropdownMap.reference,
],
[ContentKindsNames.EXERCISE]: [CompletionDropdownMap.goal, CompletionDropdownMap.practiceQuiz],
[ContentKindsNames.EXERCISE]: [
CompletionDropdownMap.goal,
CompletionDropdownMap.practiceQuiz,
CompletionDropdownMap.survey,
],
[ContentKindsNames.HTML5]: [
CompletionDropdownMap.completeDuration,
CompletionDropdownMap.determinedByResource,
Expand Down
5 changes: 5 additions & 0 deletions contentcuration/contentcuration/frontend/shared/mixins.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,11 @@ export const metadataStrings = createTranslator('CommonMetadataStrings', {
context:
'One of the completion criteria types specific to exercises. An exercise with this criteria represents a quiz.',
},
survey: {
message: 'Survey',
context:
'One of the completion criteria types specific to exercises. An exercise with this criteria represents a survey.',
},

// Learning Activities
all: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
<script>

import get from 'lodash/get';
import { mapGetters } from 'vuex/dist/vuex.common.js';
import ActivityDuration from './ActivityDuration';
import MasteryCriteriaGoal from './MasteryCriteriaGoal';
import MasteryCriteriaMofNFields from './MasteryCriteriaMofNFields';
Expand All @@ -119,6 +120,7 @@
completionCriteriaToDropdownMap,
defaultCompletionCriteriaModels,
defaultCompletionCriteriaThresholds,
FeatureFlagKeys,
} from 'shared/constants';
import { MasteryModelsNames } from 'shared/leUtils/MasteryModels';
import { ContentKindsNames } from 'shared/leUtils/ContentKinds';
Expand Down Expand Up @@ -172,6 +174,7 @@
},
},
computed: {
...mapGetters(['hasFeatureEnabled']),
notUnique() {
return this.value === nonUniqueValue;
},
Expand All @@ -186,8 +189,16 @@
},
showMasteryCriteriaGoalDropdown() {
if (this.kind === ContentKindsNames.EXERCISE) {
//this ensures that anytime the completion dropdown is practice quiz
return this.value.modality !== ContentModalities.QUIZ;
//this ensures that anytime the completion dropdown is practice quiz or
// survey we dont show the mastery criteria goal dropdown
let showDropDown = true;
if (
this.value.modality === ContentModalities.QUIZ ||
this.value.modality === ContentModalities.SURVEY
) {
showDropDown = false;
}
return showDropDown;
}
return false;
},
Expand Down Expand Up @@ -220,11 +231,16 @@
) {
return CompletionDropdownMap.practiceQuiz;
}
if (
this.value.modality === ContentModalities.SURVEY &&
this.model === CompletionCriteriaModels.MASTERY
) {
return CompletionDropdownMap.survey;
}
return completionCriteriaToDropdownMap[this.model];
},
set(value) {
const update = {};

if (value === CompletionDropdownMap.reference) {
update.model = CompletionCriteriaModels.REFERENCE;
update.durationType = null;
Expand Down Expand Up @@ -256,6 +272,9 @@
} else if (value === CompletionDropdownMap.goal) {
update.modality = null;
update.model = CompletionCriteriaModels.MASTERY;
} else if (value === CompletionDropdownMap.survey) {
update.modality = ContentModalities.SURVEY;
update.threshold = { mastery_model: MasteryModelsNames.DO_ALL };
}
this.handleInput(update);
},
Expand All @@ -280,6 +299,9 @@
if (this.value.modality === ContentModalities.QUIZ) {
return false;
}
if (this.value.modality === ContentModalities.SURVEY) {
return false;
}
return get(this, 'threshold.mastery_model') === MasteryModelsNames.M_OF_N;
},
mOfN: {
Expand Down Expand Up @@ -358,10 +380,15 @@
},
showCorrectCompletionOptions() {
if (this.kind) {
return CompletionOptionsDropdownMap[this.kind].map(model => ({
text: this.translateMetadataString(model),
value: CompletionDropdownMap[model],
}));
return CompletionOptionsDropdownMap[this.kind]
.map(model => ({
text: this.translateMetadataString(model),
value: CompletionDropdownMap[model],
}))
.filter(
option =>
!(option.value === 'survey' && !this.hasFeatureEnabled(FeatureFlagKeys.survey))
);
}
return [];
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import Vue from 'vue';
import Vuetify from 'vuetify';
import { shallowMount, mount } from '@vue/test-utils';
import Vuex from 'vuex';
import CompletionOptions from '../CompletionOptions';
import { CompletionCriteriaModels } from 'shared/constants';

Vue.use(Vuetify);
Vue.use(Vuex);
let store;

describe('CompletionOptions', () => {
beforeEach(() => {
store = new Vuex.Store({
getters: {
hasFeatureEnabled: () => () => true,
},
});
});
it('smoke test', () => {
const wrapper = shallowMount(CompletionOptions);
const wrapper = shallowMount(CompletionOptions, { store });
expect(wrapper.isVueInstance()).toBe(true);
});
describe(`completion dropdown`, () => {
it(`renders the completion dropdown`, () => {
const wrapper = mount(CompletionOptions);
const wrapper = mount(CompletionOptions, { store });
const dropdown = wrapper.find({ ref: 'completion' });
expect(dropdown.exists()).toBe(true);
});
Expand Down Expand Up @@ -147,6 +157,7 @@ describe('CompletionOptions', () => {
describe(`exercise`, () => {
it(`'When goal is met' should be displayed by default`, () => {
const wrapper = mount(CompletionOptions, {
store,
propsData: {
kind: 'exercise',
value: { model: null, threshold: { m: null, n: null } },
Expand Down Expand Up @@ -195,6 +206,7 @@ describe('CompletionOptions', () => {
describe(`exercise`, () => {
it(`Goal and MofN components should not be displayed when 'Practice Quiz' is selected`, async () => {
const wrapper = mount(CompletionOptions, {
store,
propsData: {
kind: 'exercise',
value: { model: 'mastery', threshold: { m: 3, n: 5 }, modality: 'QUIZ' },
Expand Down Expand Up @@ -233,6 +245,7 @@ describe('CompletionOptions', () => {
});
it(`duration dropdown is hidden by default for documents`, () => {
const wrapper = mount(CompletionOptions, {
store,
propsData: {
kind: 'document',
value: { suggested_duration: null },
Expand All @@ -243,6 +256,7 @@ describe('CompletionOptions', () => {
});
it(`duration dropdown is hidden by default for exercises`, () => {
const wrapper = mount(CompletionOptions, {
store,
propsData: {
kind: 'exercise',
value: { model: 'mastery', threshold: { m: 3, n: 5 }, suggested_duration: null },
Expand All @@ -253,6 +267,7 @@ describe('CompletionOptions', () => {
});
it(`'Reference' is disabled for exercises`, async () => {
const wrapper = mount(CompletionOptions, {
store,
propsData: {
kind: 'exercise',
value: { model: 'mastery', threshold: { m: 3, n: 5 } },
Expand Down
5 changes: 5 additions & 0 deletions contentcuration/contentcuration/static/feature_flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
"type": "boolean",
"title":"Test AI feature",
"description": "Allow user access to AI features"
},
"survey":{
"type": "boolean",
"title":"Test Survey feature",
"description": "Allow user access to Survey"
}
},
"examples": [
Expand Down
2 changes: 1 addition & 1 deletion contentcuration/contentcuration/viewsets/contentnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ def update(self, instance, validated_data):


class ExtraFieldsOptionsSerializer(JSONFieldDictSerializer):
modality = ChoiceField(choices=(("QUIZ", "Quiz"),), allow_null=True, required=False)
modality = ChoiceField(choices=(("QUIZ", "Quiz"),("SURVEY","Survey")), allow_null=True, required=False)
completion_criteria = CompletionCriteriaSerializer(required=False)


Expand Down