Skip to content

Commit 5efc04c

Browse files
authored
Merge pull request #12281 from nucleogenesis/fix--make-eqm-validations-good
EQM: Validation improvements
2 parents e2384dd + 9c36032 commit 5efc04c

File tree

5 files changed

+53
-6
lines changed

5 files changed

+53
-6
lines changed

kolibri/plugins/coach/assets/src/composables/useQuizCreation.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export default function useQuizCreation() {
4444
// Local state
4545
// -----------
4646

47+
const quizHasChanged = ref(false);
48+
4749
/** @type {ref<Quiz>}
4850
* The "source of truth" quiz object from which all reactive properties should derive
4951
* This will be validated and sent to the API when the user saves the quiz */
@@ -74,6 +76,7 @@ export default function useQuizCreation() {
7476
* @throws {TypeError} if section is not a valid QuizSection
7577
**/
7678
function updateSection({ section_id, ...updates }) {
79+
set(quizHasChanged, true);
7780
const targetSection = get(allSections).find(section => section.section_id === section_id);
7881
if (!targetSection) {
7982
throw new TypeError(`Section with id ${section_id} not found; cannot be updated.`);
@@ -300,6 +303,7 @@ export default function useQuizCreation() {
300303
setActiveSection(get(allSections)[0].section_id);
301304
}
302305
}
306+
set(quizHasChanged, false);
303307
}
304308

305309
/**
@@ -349,6 +353,7 @@ export default function useQuizCreation() {
349353
* @affects _quiz
350354
* Validates the input type and then updates _quiz with the given updates */
351355
function updateQuiz(updates) {
356+
set(quizHasChanged, true);
352357
if (!validateQuiz(updates)) {
353358
throw new TypeError(`Updates are not a valid Quiz object: ${JSON.stringify(updates)}`);
354359
}
@@ -583,6 +588,7 @@ export default function useQuizCreation() {
583588
removeQuestionFromSelection,
584589

585590
// Computed
591+
quizHasChanged,
586592
channels,
587593
replacements,
588594
quiz,

kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@
324324
@cancel="handleShowConfirmation"
325325
@submit="handleConfirmDelete"
326326
>
327+
<!-- TODO Use `displaySectionTitle` here once #12274 is merged as that PR
328+
changes how we handle section indexing, which is needed for displaySectionTitle -->
327329
{{ deleteConfirmation$({ section_title: activeSection.section_title }) }}
328330
</KModal>
329331

@@ -565,6 +567,8 @@
565567
this.$nextTick(() => {
566568
this.$store.dispatch(
567569
'createSnackbar',
570+
// TODO Use `displaySectionTitle` here once #12274 is merged as that PR
571+
// changes how we handle section indexing
568572
this.sectionDeletedNotification$({ section_title })
569573
);
570574
this.focusActiveSectionTab();

kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionEditor.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@
358358
const learners_see_fixed_order = ref(activeSection.value.learners_see_fixed_order);
359359
const question_count = ref(activeSection.value.question_count);
360360
const description = ref(activeSection.value.description);
361-
const section_title = ref(activeSection.value.section_title);
361+
const section_title = ref(activeSection.value.section_title.trim());
362362
363363
const sectionTitleInvalidText = computed(() => {
364364
if (section_title.value.trim() === '') {
@@ -370,7 +370,7 @@
370370
// Skip the current section
371371
return true;
372372
}
373-
return section.section_title !== section_title.value;
373+
return section.section_title.trim() !== section_title.value.trim();
374374
});
375375
if (!titleIsUnique) {
376376
return sectionTitleUniqueWarning$();
@@ -383,7 +383,7 @@
383383
learners_see_fixed_order: learners_see_fixed_order.value,
384384
question_count: question_count.value,
385385
description: description.value,
386-
section_title: section_title.value,
386+
section_title: section_title.value.trim(),
387387
},
388388
pick(activeSection.value, [
389389
'learners_see_fixed_order',

kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@
8787

8888
</KPageContainer>
8989

90+
<KModal
91+
v-if="closeConfirmationToRoute"
92+
:submitText="coreString('continueAction')"
93+
:cancelText="coreString('cancelAction')"
94+
:title="closeConfirmationTitle$()"
95+
@cancel="closeConfirmationToRoute = null"
96+
@submit="$router.push(closeConfirmationToRoute)"
97+
>
98+
{{ closeConfirmationMessage$() }}
99+
</KModal>
100+
101+
102+
90103
<router-view v-if="quizInitialized" />
91104

92105
</CoachImmersivePage>
@@ -121,14 +134,24 @@
121134
},
122135
mixins: [commonCoreStrings],
123136
setup() {
137+
const closeConfirmationToRoute = ref(null);
124138
const { classId, groups } = useCoreCoach();
125-
const { quiz, updateQuiz, saveQuiz, initializeQuiz, allSectionsEmpty } = useQuizCreation();
139+
const {
140+
quizHasChanged,
141+
quiz,
142+
updateQuiz,
143+
saveQuiz,
144+
initializeQuiz,
145+
allSectionsEmpty,
146+
} = useQuizCreation();
126147
const showError = ref(false);
127148
const quizInitialized = ref(false);
128149
129150
const {
130151
saveAndClose$,
131152
allSectionsEmptyWarning$,
153+
closeConfirmationTitle$,
154+
closeConfirmationMessage$,
132155
sectionOrderLabel$,
133156
randomizedLabel$,
134157
fixedLabel$,
@@ -137,10 +160,14 @@
137160
} = enhancedQuizManagementStrings;
138161
139162
return {
163+
closeConfirmationTitle$,
164+
closeConfirmationMessage$,
140165
classId,
141166
groups,
167+
closeConfirmationToRoute,
142168
showError,
143169
quiz,
170+
quizHasChanged,
144171
saveQuiz,
145172
updateQuiz,
146173
initializeQuiz,
@@ -202,6 +229,14 @@
202229
});
203230
},
204231
},
232+
beforeRouteLeave(to, from, next) {
233+
if (this.quizHasChanged && !this.closeConfirmationToRoute) {
234+
this.closeConfirmationToRoute = to;
235+
next(false);
236+
} else {
237+
next();
238+
}
239+
},
205240
mounted() {
206241
this.$store.dispatch('notLoading');
207242
},
@@ -234,7 +269,7 @@
234269
}
235270
})
236271
.catch(error => {
237-
const errors = CatchErrors(error, [ERROR_CONSTANTS.UNIQUE]);
272+
const errors = CatchErrors(error, [ERROR_CONSTANTS.UNIQUE, 'BLANK']);
238273
this.$refs.detailsModal.handleSubmitFailure();
239274
if (errors.length) {
240275
this.$refs.detailsModal.handleSubmitTitleFailure();

kolibri/plugins/coach/assets/src/views/plan/assignments/AssignmentDetailsModal.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@
302302
});
303303
} else {
304304
this.formIsSubmitted = false;
305-
this.$refs.titleField.focus();
306305
}
307306
},
308307
/**
@@ -318,6 +317,9 @@
318317
handleSubmitTitleFailure() {
319318
this.formIsSubmitted = false;
320319
this.showTitleError = true;
320+
this.$refs.titleField.focus();
321+
// Scroll to the title field in case focus() didn't do that immediately
322+
this.window.scrollTo({ top: 0, behavior: 'smooth' });
321323
},
322324
},
323325
};

0 commit comments

Comments
 (0)