diff --git a/kolibri/plugins/coach/assets/src/constants/index.js b/kolibri/plugins/coach/assets/src/constants/index.js index b38f0f7c756..6cdd0045e3a 100644 --- a/kolibri/plugins/coach/assets/src/constants/index.js +++ b/kolibri/plugins/coach/assets/src/constants/index.js @@ -25,6 +25,7 @@ export const PageNames = { EXAM_CREATION_PREVIEW: 'EXAM_CREATION_PREVIEW', EXAM_CREATION_SEARCH: 'EXAM_CREATION_SEARCH', EXAM_CREATION_QUESTION_SELECTION: 'EXAM_CREATION_QUESTION_SELECTION', + EXAM_SIDE_PANEL: 'EXAM_SIDE_PANEL', EXAM_PREVIEW: 'EXAM_PREVIEW', EXAM_REPORT: 'EXAM_REPORT', EXAM_REPORT_DETAIL: 'EXAM_REPORT_DETAIL', diff --git a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js index 5d2f629c50b..ff95e2c181d 100644 --- a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js @@ -14,6 +14,10 @@ import { import CreatePracticeQuizPage from '../views/plan/CreateExamPage/CreatePracticeQuizPage.vue'; import CreateExamPage from '../views/plan/CreateExamPage'; import CreateExamPreview from '../views/plan/CreateExamPage/CreateExamPreview.vue'; +import SectionSidePanel from '../views/plan/CreateExamPage/SectionSidePanel.vue'; +import SectionEditor from '../views/plan/CreateExamPage/SectionEditor.vue'; +import ResourceSelection from '../views/plan/CreateExamPage/ResourceSelection.vue'; +import ReplaceQuestions from '../views/plan/CreateExamPage/ReplaceQuestions.vue'; import PlanQuizPreviewPage from '../views/plan/PlanQuizPreviewPage'; import CoachExamsPage from '../views/plan/CoachExamsPage'; import { showExamsPage } from '../modules/examsRoot/handlers'; @@ -37,26 +41,30 @@ export default [ name: PageNames.EXAM_CREATION_ROOT, path: '/:classId/plan/quizzes/new', component: CreateExamPage, - }, - { - name: PageNames.QUIZ_SECTION_EDITOR, - path: '/:classId/plan/quizzes/new/:section_id/edit', - component: CreateExamPage, - }, - { - name: PageNames.QUIZ_REPLACE_QUESTIONS, - path: '/:classId/plan/quizzes/new/:section_id/replace-questions', - component: CreateExamPage, - }, - { - name: PageNames.QUIZ_SELECT_RESOURCES, - path: '/:classId/plan/quizzes/new/:section_id/select-resources/:topic_id?', - component: CreateExamPage, - }, - { - name: PageNames.BOOK_MARKED_RESOURCES, - path: '/:classId/plan/quizzes/new/:section_id/select-resources/bookmarks', - component: CreateExamPage, + children: [ + { + name: PageNames.EXAM_SIDE_PANEL, + path: ':section_id', + component: SectionSidePanel, + children: [ + { + name: PageNames.QUIZ_SECTION_EDITOR, + path: 'edit', + component: SectionEditor, + }, + { + name: PageNames.QUIZ_REPLACE_QUESTIONS, + path: 'replace-questions', + component: ReplaceQuestions, + }, + { + name: PageNames.QUIZ_SELECT_RESOURCES, + path: 'select-resources/:topic_id?', + component: ResourceSelection, + }, + ], + }, + ], }, { name: PageNames.EXAM_CREATION_PRACTICE_QUIZ, diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ConfirmCancellationModal.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ConfirmCancellationModal.vue index 38497c9b061..e60e3640bb0 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ConfirmCancellationModal.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ConfirmCancellationModal.vue @@ -48,16 +48,9 @@ export default { name: 'ConfirmCancellationModal', mixins: [commonCoreStrings], - props: { - closePanelRoute: { - type: Object, - required: true, - }, - }, methods: { handleContinueAction() { this.$emit('continue'); - this.$router.replace(this.closePanelRoute); }, closeModal() { this.$emit('cancel'); diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue index f3edc5cbba3..0e028cca79d 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue @@ -313,8 +313,6 @@ - - @@ -334,7 +332,7 @@ import Draggable from 'kolibri.coreVue.components.Draggable'; import { injectQuizCreation } from '../../../composables/useQuizCreation'; import commonCoach from '../../common'; - import SectionSidePanel from './SectionSidePanel'; + import { PageNames } from '../../../constants'; import TabsWithOverflow from './TabsWithOverflow'; import AccordionContainer from './AccordionContainer'; import AccordionItem from './AccordionItem'; @@ -351,7 +349,6 @@ DragSortWidget, DragHandle, TabsWithOverflow, - SectionSidePanel, }, mixins: [commonCoreStrings, commonCoach], setup() { @@ -509,13 +506,15 @@ methods: { handleReplaceSelection() { const section_id = get(this.activeSection).section_id; - this.$router.replace({ path: 'new/' + section_id + '/replace-questions' }); + const route = this.$router.getRoute(PageNames.QUIZ_REPLACE_QUESTIONS, { section_id }); + this.$router.push(route); }, handleActiveSectionAction(opt) { const section_id = this.activeSection.section_id; + const editRoute = this.$router.getRoute(PageNames.QUIZ_SECTION_EDITOR, { section_id }); switch (opt.label) { case this.editSectionLabel$(): - this.$router.replace({ path: 'new/' + section_id + '/edit' }); + this.$router.push(editRoute); break; case this.deleteSectionLabel$(): this.removeSection(this.activeSection.section_id); @@ -573,7 +572,8 @@ set(this.dragActive, true); }, openSelectResources(section_id) { - this.$router.replace({ path: 'new/' + section_id + '/select-resources' }); + const route = this.$router.getRoute(PageNames.QUIZ_SELECT_RESOURCES, { section_id }); + this.$router.push(route); }, }, }; diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue index d11589743bb..80315507f76 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue @@ -105,13 +105,18 @@ style="float: right;" :text="coreString('saveChangesAction')" :primary="true" - :disabled="!hasTopicId() && !showBookmarks" + :disabled="!workingPoolHasChanged" @click="saveSelectedResource" /> + @@ -133,6 +138,7 @@ import { injectQuizCreation } from '../../../composables/useQuizCreation'; import LessonsSearchBox from '../LessonResourceSelectionPage/SearchTools/LessonsSearchBox.vue'; import ContentCardList from './../LessonResourceSelectionPage/ContentCardList.vue'; + import ConfirmCancellationModal from './ConfirmCancellationModal.vue'; import ResourceSelectionBreadcrumbs from './../LessonResourceSelectionPage/SearchTools/ResourceSelectionBreadcrumbs.vue'; export default { @@ -142,9 +148,10 @@ BookmarkIcon, LessonsSearchBox, ResourceSelectionBreadcrumbs, + ConfirmCancellationModal, }, mixins: [commonCoreStrings], - setup() { + setup(_, context) { const store = getCurrentInstance().proxy.$store; const route = computed(() => store.state.route); const topicId = computed(() => route.value.params.topic_id); @@ -154,6 +161,9 @@ const showBookmarks = computed(() => route.value.query.showBookmarks); const searchQuery = computed(() => route.value.query.search); const { updateSection, activeResourcePool, selectAllQuestions } = injectQuizCreation(); + const showConfirmationModal = ref(false); + + const prevRoute = ref({ name: PageNames.EXAM_CREATION_ROOT }); const { sectionSettings$, @@ -377,6 +387,7 @@ // call this annotateTopicsWithDescendantCounts method to ensure that the channels are // annotated with their num_assessments and those without assessments are filtered out annotateTopicsWithDescendantCounts(resources.value.map(c => c.id)).then(() => { + channels.value = resources.value; _loading.value = false; }); }); @@ -408,6 +419,10 @@ return searchResults.value; } + if (!topicId.value) { + return channels.value; + } + return resources.value; }); @@ -432,16 +447,36 @@ return fetchMoreQuizResources(); } + function handleCancelClose() { + showConfirmationModal.value = false; + } + + function handleConfirmClose() { + context.emit('closePanel'); + } + + const workingPoolHasChanged = computed(() => { + return ( + workingResourcePool.value.length != activeResourcePool.value.length || + !isEqual(workingResourcePool.value.sort(), activeResourcePool.value.sort()) + ); + }); + return { selectAllChecked, selectAllIndeterminate, showSelectAll, handleSelectAll, toggleSelected, + prevRoute, + workingPoolHasChanged, + handleConfirmClose, + handleCancelClose, topic, topicId, contentList, resources, + showConfirmationModal, hasCheckbox, loading, hasMore, @@ -464,18 +499,13 @@ updateSection, selectAllQuestions, workingResourcePool, + activeResourcePool, addToWorkingResourcePool, removeFromWorkingResourcePool, showBookmarks, selectedResourcesInformation$, }; }, - props: { - closePanelRoute: { - type: Object, - required: true, - }, - }, computed: { isTopicIdSet() { return this.$route.params.topic_id; @@ -506,6 +536,19 @@ this.bookmarksCount = newVal.length; }, }, + beforeRouteEnter(_, from, next) { + next(vm => { + vm.prevRoute = from; + }); + }, + beforeRouteLeave(_, __, next) { + if (!this.showConfirmationModal && this.workingPoolHasChanged) { + this.showConfirmationModal = true; + next(false); + } else { + next(); + } + }, methods: { showTopicSizeWarningCard(content) { return !this.hasCheckbox(content) && content.kind === ContentNodeKinds.TOPIC; @@ -547,9 +590,6 @@ topicsLink(topicId) { return this.topicListingLink({ ...this.$route.params, topicId }); }, - hasTopicId() { - return Boolean(this.$route.params.topic_id); - }, saveSelectedResource() { this.updateSection({ section_id: this.$route.params.section_id, @@ -559,7 +599,7 @@ //Also reset workingResourcePool this.resetWorkingResourcePool(); - this.$router.replace(this.closePanelRoute); + this.$router.replace(this.prevRoute); }, selectionMetadata(content) { if (content.kind === ContentNodeKinds.TOPIC) { diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionEditor.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionEditor.vue index f3c76ca92a9..57042cc5d68 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionEditor.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionEditor.vue @@ -15,7 +15,7 @@ :layout4="{ span: 2 }" > @@ -29,7 +29,7 @@
@@ -43,8 +43,8 @@ icon="minus" aria-hidden="true" class="number-btn" - :disabled="numberOfQuestions === 1" - @click="numberOfQuestions -= 1" + :disabled="question_count === 1" + @click="question_count -= 1" />
@@ -62,7 +62,7 @@ + @@ -222,23 +227,69 @@