Skip to content

Commit

Permalink
Merge pull request #12278 from rtibbles/randomize_sections
Browse files Browse the repository at this point in the history
Update to allow and implement randomization of sections.
  • Loading branch information
rtibbles authored Jun 14, 2024
2 parents 660d003 + 44a4e10 commit 5b207a0
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,9 @@ export const Quiz = {
type: Number,
default: getRandomInt(),
},
// Default to sections being shown in a fixed order
learners_see_fixed_order: {
type: Boolean,
default: true,
},
};
28 changes: 20 additions & 8 deletions kolibri/plugins/coach/assets/src/composables/useQuizCreation.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ function validateQuiz(quiz) {
return validateObject(quiz, Quiz);
}

const fieldsToSave = [
'title',
'assignments',
'learner_ids',
'collection',
'learners_see_fixed_order',
'draft',
'active',
'archive',
];

/**
* Composable function presenting primary interface for Quiz Creation
*/
Expand Down Expand Up @@ -299,16 +310,17 @@ export default function useQuizCreation() {
return Promise.reject(`Quiz is not valid: ${JSON.stringify(get(_quiz))}`);
}

const id = get(_quiz).id;
const quizData = get(_quiz);

const id = quizData.id;

const finalQuiz = {
title: get(_quiz).title,
assignments: get(_quiz).assignments,
learner_ids: get(_quiz).learner_ids,
collection: get(_quiz).collection,
};
const finalQuiz = {};

for (const field of fieldsToSave) {
finalQuiz[field] = quizData[field];
}

if (get(_quiz).draft) {
if (finalQuiz.draft) {
// Here we update each section's `resource_pool` to only be the IDs of the resources
const questionSourcesWithoutResourcePool = get(allSections).map(section => {
const sectionToSave = { ...section };
Expand Down
11 changes: 6 additions & 5 deletions kolibri/plugins/coach/assets/src/views/common/QuizStatus.vue
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
:layout8="{ span: 4 }"
:layout12="{ span: 12 }"
>
{{ $tr('questionOrderLabel') }}
{{ sectionOrderLabel$() }}
</KGridItem>
<KGridItem
:layout4="{ span: 4 }"
Expand Down Expand Up @@ -265,6 +265,7 @@
import Lockr from 'lockr';
import { QUIZ_REPORT_VISIBILITY_MODAL_DISMISSED } from 'kolibri.coreVue.vuex.constants';
import { mapActions } from 'vuex';
import { enhancedQuizManagementStrings } from 'kolibri-common/strings/enhancedQuizManagementStrings';
import { coachStringsMixin } from './commonCoachStrings';
import Score from './Score';
import Recipients from './Recipients';
Expand All @@ -275,6 +276,10 @@
name: 'QuizStatus',
components: { Score, Recipients, ElapsedTime, StatusElapsedTime, AverageScoreTooltip },
mixins: [coachStringsMixin, commonCoreStrings],
setup() {
const { sectionOrderLabel$ } = enhancedQuizManagementStrings;
return { sectionOrderLabel$ };
},
props: {
className: {
type: String,
Expand Down Expand Up @@ -454,10 +459,6 @@
context:
'The label for a switch that will toggle whether or not learners can view their quiz report.',
},
questionOrderLabel: {
message: 'Question order',
context: 'A label for the place where the question order is shown.',
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
<KRadioButton
v-model="learners_see_fixed_order"
:label="randomizedLabel$()"
:buttonValue="true"
:buttonValue="false"
:description="randomizedOptionDescription$()"
/>
</KGridItem>
Expand All @@ -101,7 +101,7 @@
<KRadioButton
v-model="learners_see_fixed_order"
:label="fixedLabel$()"
:buttonValue="false"
:buttonValue="true"
:description="fixedOptionDescription$()"
/>
</KGridItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,40 @@
@update="updateQuiz"
/>

<div v-if="quizInitialized">
<h5 class="section-order-header">
{{ sectionOrderLabel$() }}
</h5>
<KGrid>
<KGridItem
:layout12="{ span: 6 }"
:layout8="{ span: 4 }"
:layout4="{ span: 2 }"
>
<KRadioButton
:currentValue="quiz.learners_see_fixed_order"
:label="randomizedLabel$()"
:buttonValue="false"
:description="randomizedSectionOptionDescription$()"
@input="value => updateQuiz({ learners_see_fixed_order: value })"
/>
</KGridItem>
<KGridItem
:layout12="{ span: 6 }"
:layout8="{ span: 4 }"
:layout4="{ span: 2 }"
>
<KRadioButton
:currentValue="quiz.learners_see_fixed_order"
:label="fixedLabel$()"
:buttonValue="true"
:description="fixedSectionOptionDescription$()"
@input="value => updateQuiz({ learners_see_fixed_order: value })"
/>
</KGridItem>
</KGrid>
</div>

<CreateQuizSection v-if="quizInitialized && quiz.draft" />

<BottomAppBar>
Expand Down Expand Up @@ -92,7 +126,15 @@
const showError = ref(false);
const quizInitialized = ref(false);
const { saveAndClose$, allSectionsEmptyWarning$ } = enhancedQuizManagementStrings;
const {
saveAndClose$,
allSectionsEmptyWarning$,
sectionOrderLabel$,
randomizedLabel$,
fixedLabel$,
randomizedSectionOptionDescription$,
fixedSectionOptionDescription$,
} = enhancedQuizManagementStrings;
return {
classId,
Expand All @@ -106,6 +148,11 @@
allSectionsEmpty,
allSectionsEmptyWarning$,
saveAndClose$,
sectionOrderLabel$,
randomizedLabel$,
fixedLabel$,
randomizedSectionOptionDescription$,
fixedSectionOptionDescription$,
};
},
provide() {
Expand Down Expand Up @@ -212,4 +259,9 @@
margin-right: 8px;
}
.section-order-header {
margin-top: 0;
margin-bottom: 0.5em;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import CatchErrors from 'kolibri.utils.CatchErrors';
import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';
import { ExamResource } from 'kolibri.resources';
import { enhancedQuizManagementStrings } from 'kolibri-common/strings/enhancedQuizManagementStrings';
import { PageNames } from '../../../constants';
import commonCoach from '../../common';
import CoachAppBarPage from '../../CoachAppBarPage';
Expand All @@ -97,6 +98,16 @@
QuizOptionsDropdownMenu,
},
mixins: [commonCoach, coachStringsMixin, commonCoreStrings],
setup() {
const {
randomizedSectionOptionDescription$,
fixedSectionOptionDescription$,
} = enhancedQuizManagementStrings;
return {
randomizedSectionOptionDescription$,
fixedSectionOptionDescription$,
};
},
data() {
return {
quiz: {
Expand Down Expand Up @@ -133,8 +144,8 @@
},
orderDescriptionString() {
return this.quizIsRandomized
? this.coachString('orderRandomDescription')
: this.coachString('orderFixedDescription');
? this.randomizedSectionOptionDescription$()
: this.fixedSectionOptionDescription$();
},
classId() {
return this.$route.params.classId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<script>
import fromPairs from 'lodash/fromPairs';
import { enhancedQuizManagementStrings } from 'kolibri-common/strings/enhancedQuizManagementStrings';
import commonCoach from '../common';
import CoachImmersivePage from '../CoachImmersivePage';
import QuestionListPreview from '../plan/CreateExamPage/QuestionListPreview';
Expand All @@ -46,6 +47,16 @@
QuestionListPreview,
},
mixins: [commonCoach],
setup() {
const {
randomizedSectionOptionDescription$,
fixedSectionOptionDescription$,
} = enhancedQuizManagementStrings;
return {
randomizedSectionOptionDescription$,
fixedSectionOptionDescription$,
};
},
data() {
return {
quiz: {
Expand All @@ -60,15 +71,18 @@
},
computed: {
selectedQuestions() {
return this.quiz.question_sources;
return this.quiz.question_sources.reduce((acc, section) => {
acc = [...acc, ...section.questions];
return acc;
}, []);
},
quizIsRandomized() {
return !this.quiz.learners_see_fixed_order;
},
orderDescriptionString() {
return this.quizIsRandomized
? this.coachString('orderRandomDescription')
: this.coachString('orderFixedDescription');
? this.randomizedSectionOptionDescription$()
: this.fixedSectionOptionDescription$();
},
title() {
return this.$tr('pageTitle', { title: this.quiz.title });
Expand Down
11 changes: 8 additions & 3 deletions kolibri/plugins/learn/assets/src/modules/examViewer/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,20 @@ export function showExam(store, params, alreadyOnQuiz) {
store.commit('classAssignments/SET_CURRENT_CLASSROOM', classroom);
fetchExamWithContent(exam).then(({ exam: converted, exercises: contentNodes }) => {
if (shouldResolve()) {
const { question_sources } = converted;
let { question_sources } = converted;

// When necessary, randomize the questions for the learner.
// Seed based on the user ID so they see a consistent order each time.
question_sources.forEach(section => {
for (const section of question_sources) {
if (!section.learners_see_fixed_order) {
section.questions = shuffled(section.questions, store.state.core.session.user_id);
}
});
}
// When necessary randomize the order of the sections
// Seed based on the user ID so they see a consistent order each time.
if (!converted.learners_see_fixed_order) {
question_sources = shuffled(question_sources, store.state.core.session.user_id);
}
// If necessary, convert the question source info
const allQuestions = question_sources.reduce((acc, section) => {
acc = [...acc, ...section.questions];
Expand Down
10 changes: 10 additions & 0 deletions packages/kolibri-common/strings/enhancedQuizManagementStrings.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ export const enhancedQuizManagementStrings = createTranslator('EnhancedQuizManag
message:
'Please choose a different resource or decrease the number of questions to be replaced.',
},
sectionOrderLabel: {
message: 'Section order',
context: 'A label for the place where the section order option is shown.',
},
questionOrder: {
message: 'Question order',
},
Expand All @@ -130,12 +134,18 @@ export const enhancedQuizManagementStrings = createTranslator('EnhancedQuizManag
randomizedOptionDescription: {
message: 'Each learner sees a different question order',
},
randomizedSectionOptionDescription: {
message: 'Each learner sees a different section order',
},
fixedLabel: {
message: 'Fixed',
},
fixedOptionDescription: {
message: 'Each learner sees the same question order',
},
fixedSectionOptionDescription: {
message: 'Each learner sees the same section order',
},
questionEditedSuccessfully: {
message: 'Question edited successfully',
},
Expand Down

0 comments on commit 5b207a0

Please sign in to comment.