Skip to content

Commit 131c2ad

Browse files
authored
Merge pull request #4959 from ozer550/add-survey-completion-option-for-assessments
Add survey completion option for exercise
2 parents 939b864 + 761e4fc commit 131c2ad

6 files changed

Lines changed: 69 additions & 11 deletions

File tree

contentcuration/contentcuration/frontend/shared/constants.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ export const FeatureFlagKeys = Object.keys(FeatureFlagsSchema.properties).reduce
202202

203203
export const ContentModalities = {
204204
QUIZ: 'QUIZ',
205+
SURVEY: 'SURVEY',
205206
};
206207

207208
export const AccessibilityCategoriesMap = {
@@ -223,6 +224,7 @@ export const CompletionDropdownMap = {
223224
goal: 'goal',
224225
practiceQuiz: 'practiceQuiz',
225226
reference: 'reference',
227+
survey: 'survey',
226228
};
227229

228230
export const DurationDropdownMap = {
@@ -284,7 +286,11 @@ export const CompletionOptionsDropdownMap = {
284286
CompletionDropdownMap.completeDuration,
285287
CompletionDropdownMap.reference,
286288
],
287-
[ContentKindsNames.EXERCISE]: [CompletionDropdownMap.goal, CompletionDropdownMap.practiceQuiz],
289+
[ContentKindsNames.EXERCISE]: [
290+
CompletionDropdownMap.goal,
291+
CompletionDropdownMap.practiceQuiz,
292+
CompletionDropdownMap.survey,
293+
],
288294
[ContentKindsNames.HTML5]: [
289295
CompletionDropdownMap.completeDuration,
290296
CompletionDropdownMap.determinedByResource,

contentcuration/contentcuration/frontend/shared/mixins.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ export const metadataStrings = createTranslator('CommonMetadataStrings', {
261261
context:
262262
'One of the completion criteria types specific to exercises. An exercise with this criteria represents a quiz.',
263263
},
264+
survey: {
265+
message: 'Survey',
266+
context:
267+
'One of the completion criteria types specific to exercises. An exercise with this criteria represents a survey.',
268+
},
264269

265270
// Learning Activities
266271
all: {

contentcuration/contentcuration/frontend/shared/views/contentNodeFields/CompletionOptions/index.vue

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
<script>
106106
107107
import get from 'lodash/get';
108+
import { mapGetters } from 'vuex/dist/vuex.common.js';
108109
import ActivityDuration from './ActivityDuration';
109110
import MasteryCriteriaGoal from './MasteryCriteriaGoal';
110111
import MasteryCriteriaMofNFields from './MasteryCriteriaMofNFields';
@@ -119,6 +120,7 @@
119120
completionCriteriaToDropdownMap,
120121
defaultCompletionCriteriaModels,
121122
defaultCompletionCriteriaThresholds,
123+
FeatureFlagKeys,
122124
} from 'shared/constants';
123125
import { MasteryModelsNames } from 'shared/leUtils/MasteryModels';
124126
import { ContentKindsNames } from 'shared/leUtils/ContentKinds';
@@ -172,6 +174,7 @@
172174
},
173175
},
174176
computed: {
177+
...mapGetters(['hasFeatureEnabled']),
175178
notUnique() {
176179
return this.value === nonUniqueValue;
177180
},
@@ -186,8 +189,16 @@
186189
},
187190
showMasteryCriteriaGoalDropdown() {
188191
if (this.kind === ContentKindsNames.EXERCISE) {
189-
//this ensures that anytime the completion dropdown is practice quiz
190-
return this.value.modality !== ContentModalities.QUIZ;
192+
//this ensures that anytime the completion dropdown is practice quiz or
193+
// survey we dont show the mastery criteria goal dropdown
194+
let showDropDown = true;
195+
if (
196+
this.value.modality === ContentModalities.QUIZ ||
197+
this.value.modality === ContentModalities.SURVEY
198+
) {
199+
showDropDown = false;
200+
}
201+
return showDropDown;
191202
}
192203
return false;
193204
},
@@ -220,11 +231,16 @@
220231
) {
221232
return CompletionDropdownMap.practiceQuiz;
222233
}
234+
if (
235+
this.value.modality === ContentModalities.SURVEY &&
236+
this.model === CompletionCriteriaModels.MASTERY
237+
) {
238+
return CompletionDropdownMap.survey;
239+
}
223240
return completionCriteriaToDropdownMap[this.model];
224241
},
225242
set(value) {
226243
const update = {};
227-
228244
if (value === CompletionDropdownMap.reference) {
229245
update.model = CompletionCriteriaModels.REFERENCE;
230246
update.durationType = null;
@@ -256,6 +272,9 @@
256272
} else if (value === CompletionDropdownMap.goal) {
257273
update.modality = null;
258274
update.model = CompletionCriteriaModels.MASTERY;
275+
} else if (value === CompletionDropdownMap.survey) {
276+
update.modality = ContentModalities.SURVEY;
277+
update.threshold = { mastery_model: MasteryModelsNames.DO_ALL };
259278
}
260279
this.handleInput(update);
261280
},
@@ -280,6 +299,9 @@
280299
if (this.value.modality === ContentModalities.QUIZ) {
281300
return false;
282301
}
302+
if (this.value.modality === ContentModalities.SURVEY) {
303+
return false;
304+
}
283305
return get(this, 'threshold.mastery_model') === MasteryModelsNames.M_OF_N;
284306
},
285307
mOfN: {
@@ -358,10 +380,15 @@
358380
},
359381
showCorrectCompletionOptions() {
360382
if (this.kind) {
361-
return CompletionOptionsDropdownMap[this.kind].map(model => ({
362-
text: this.translateMetadataString(model),
363-
value: CompletionDropdownMap[model],
364-
}));
383+
return CompletionOptionsDropdownMap[this.kind]
384+
.map(model => ({
385+
text: this.translateMetadataString(model),
386+
value: CompletionDropdownMap[model],
387+
}))
388+
.filter(
389+
option =>
390+
!(option.value === 'survey' && !this.hasFeatureEnabled(FeatureFlagKeys.survey))
391+
);
365392
}
366393
return [];
367394
},

contentcuration/contentcuration/frontend/shared/views/contentNodeFields/__tests__/completionOptions.spec.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
import Vue from 'vue';
22
import Vuetify from 'vuetify';
33
import { shallowMount, mount } from '@vue/test-utils';
4+
import Vuex from 'vuex';
45
import CompletionOptions from '../CompletionOptions';
56
import { CompletionCriteriaModels } from 'shared/constants';
67

78
Vue.use(Vuetify);
9+
Vue.use(Vuex);
10+
let store;
811

912
describe('CompletionOptions', () => {
13+
beforeEach(() => {
14+
store = new Vuex.Store({
15+
getters: {
16+
hasFeatureEnabled: () => () => true,
17+
},
18+
});
19+
});
1020
it('smoke test', () => {
11-
const wrapper = shallowMount(CompletionOptions);
21+
const wrapper = shallowMount(CompletionOptions, { store });
1222
expect(wrapper.isVueInstance()).toBe(true);
1323
});
1424
describe(`completion dropdown`, () => {
1525
it(`renders the completion dropdown`, () => {
16-
const wrapper = mount(CompletionOptions);
26+
const wrapper = mount(CompletionOptions, { store });
1727
const dropdown = wrapper.find({ ref: 'completion' });
1828
expect(dropdown.exists()).toBe(true);
1929
});
@@ -147,6 +157,7 @@ describe('CompletionOptions', () => {
147157
describe(`exercise`, () => {
148158
it(`'When goal is met' should be displayed by default`, () => {
149159
const wrapper = mount(CompletionOptions, {
160+
store,
150161
propsData: {
151162
kind: 'exercise',
152163
value: { model: null, threshold: { m: null, n: null } },
@@ -195,6 +206,7 @@ describe('CompletionOptions', () => {
195206
describe(`exercise`, () => {
196207
it(`Goal and MofN components should not be displayed when 'Practice Quiz' is selected`, async () => {
197208
const wrapper = mount(CompletionOptions, {
209+
store,
198210
propsData: {
199211
kind: 'exercise',
200212
value: { model: 'mastery', threshold: { m: 3, n: 5 }, modality: 'QUIZ' },
@@ -233,6 +245,7 @@ describe('CompletionOptions', () => {
233245
});
234246
it(`duration dropdown is hidden by default for documents`, () => {
235247
const wrapper = mount(CompletionOptions, {
248+
store,
236249
propsData: {
237250
kind: 'document',
238251
value: { suggested_duration: null },
@@ -243,6 +256,7 @@ describe('CompletionOptions', () => {
243256
});
244257
it(`duration dropdown is hidden by default for exercises`, () => {
245258
const wrapper = mount(CompletionOptions, {
259+
store,
246260
propsData: {
247261
kind: 'exercise',
248262
value: { model: 'mastery', threshold: { m: 3, n: 5 }, suggested_duration: null },
@@ -253,6 +267,7 @@ describe('CompletionOptions', () => {
253267
});
254268
it(`'Reference' is disabled for exercises`, async () => {
255269
const wrapper = mount(CompletionOptions, {
270+
store,
256271
propsData: {
257272
kind: 'exercise',
258273
value: { model: 'mastery', threshold: { m: 3, n: 5 } },

contentcuration/contentcuration/static/feature_flags.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
"type": "boolean",
1414
"title":"Test AI feature",
1515
"description": "Allow user access to AI features"
16+
},
17+
"survey":{
18+
"type": "boolean",
19+
"title":"Test Survey feature",
20+
"description": "Allow user access to Survey"
1621
}
1722
},
1823
"examples": [

contentcuration/contentcuration/viewsets/contentnode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ def update(self, instance, validated_data):
288288

289289

290290
class ExtraFieldsOptionsSerializer(JSONFieldDictSerializer):
291-
modality = ChoiceField(choices=(("QUIZ", "Quiz"),), allow_null=True, required=False)
291+
modality = ChoiceField(choices=(("QUIZ", "Quiz"),("SURVEY","Survey")), allow_null=True, required=False)
292292
completion_criteria = CompletionCriteriaSerializer(required=False)
293293

294294

0 commit comments

Comments
 (0)