From b0ea7d226d4aa11783a4d7cc81e2d6d78a1b7afe Mon Sep 17 00:00:00 2001 From: thanksameeelian Date: Tue, 12 Sep 2023 09:47:04 -0500 Subject: [PATCH 1/5] add ability to retain and apply selected subtopic after facility is selected --- kolibri/plugins/coach/assets/src/app.js | 3 +- .../coach/assets/src/routes/baseRoutes.js | 8 ++--- .../plugins/coach/assets/src/routes/index.js | 33 ++++++++++++++----- .../assets/src/routes/planLessonsRoutes.js | 16 ++++++++- .../coach/assets/src/routes/planRoutes.js | 4 +-- .../coach/assets/src/routes/reportRoutes.js | 21 ++++++++++-- .../assets/src/views/AllFacilitiesPage.vue | 20 +++++++---- .../assets/src/views/CoachClassListPage.vue | 17 ++++++++-- .../src/views/home/HomePage/OverviewBlock.vue | 2 +- .../assets/src/views/plan/PlanHeader.vue | 2 +- .../src/views/reports/ReportsHeader.vue | 2 +- 11 files changed, 97 insertions(+), 31 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/app.js b/kolibri/plugins/coach/assets/src/app.js index 272a2403352..dccabe36f07 100644 --- a/kolibri/plugins/coach/assets/src/app.js +++ b/kolibri/plugins/coach/assets/src/app.js @@ -41,7 +41,8 @@ class CoachToolsModule extends KolibriApp { to.name ) ) { - promises.push(this.store.dispatch('initClassInfo', to.params.classId)); + if (to.params.classId) + promises.push(this.store.dispatch('initClassInfo', to.params.classId)); } else { this.store.dispatch('coachNotifications/stopPolling'); } diff --git a/kolibri/plugins/coach/assets/src/routes/baseRoutes.js b/kolibri/plugins/coach/assets/src/routes/baseRoutes.js index 6a47df31237..aad97436e8c 100644 --- a/kolibri/plugins/coach/assets/src/routes/baseRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/baseRoutes.js @@ -7,15 +7,15 @@ export default { }, classHome: { name: PageNames.HOME_PAGE, - path: '/:classId/home', + path: '/:classId?/home', }, plan: { name: PageNames.PLAN_PAGE, - path: '/:classId/plan', - redirect: '/:classId/plan/lessons', + path: '/:classId?/plan', + redirect: '/:classId?/plan/lessons', }, reports: { name: PageNames.REPORTS_PAGE, - path: '/:classId/reports', + path: '/:classId?/reports', }, }; diff --git a/kolibri/plugins/coach/assets/src/routes/index.js b/kolibri/plugins/coach/assets/src/routes/index.js index 0c76b1a2301..3f2f6654e3f 100644 --- a/kolibri/plugins/coach/assets/src/routes/index.js +++ b/kolibri/plugins/coach/assets/src/routes/index.js @@ -12,31 +12,44 @@ import { PageNames } from '../constants'; import reportRoutes from './reportRoutes'; import planRoutes from './planRoutes'; +function classIdParamRequiredGuard(toRoute, subtopicName) { + if (store.getters.userIsMultiFacilityAdmin && !toRoute.params.classId) { + router.replace({ + name: 'AllFacilitiesPage', + params: { subtopicName }, + }); + return true; + } +} + export default [ ...planRoutes, ...reportRoutes, { - path: '/facilities', + name: 'AllFacilitiesPage', + path: '/:subtopicName?/facilities', component: AllFacilitiesPage, + props: true, handler() { store.dispatch('notLoading'); }, }, { - path: '/classes', + path: '/:facility_id?/classes', component: CoachClassListPage, + props: true, handler(toRoute) { store.dispatch('loading'); // if user only has access to one facility, facility_id will not be accessible from URL, // but always defaulting to userFacilityId would cause problems for multi-facility admins - const facilityId = toRoute.query.facility_id || store.getters.userFacilityId; + const facilityId = toRoute.params.facility_id || store.getters.userFacilityId; store.dispatch('setClassList', facilityId).then( () => { if (!store.getters.classListPageEnabled) { - // If no class list page, redirect to - // the first (and only) class. + // If no class list page, redirect to the first (and only) class and + // to the originally-selected subtopic, if available router.replace({ - name: HomePage.name, + name: toRoute.params.subtopicName || HomePage.name, params: { classId: store.state.classList[0].id }, }); return; @@ -52,9 +65,12 @@ export default [ }, { name: PageNames.HOME_PAGE, - path: '/:classId/home', + path: '/:classId?/home', component: HomePage, - handler() { + handler: toRoute => { + if (classIdParamRequiredGuard(toRoute, HomePage.name)) { + return; + } store.dispatch('notLoading'); }, meta: { @@ -71,7 +87,6 @@ export default [ titleParts: ['activityLabel', 'CLASS_NAME'], }, }, - { name: ClassesPageNames.CLASS_LEARNERS_LIST_VIEWER, path: '/:classId/learners', diff --git a/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js b/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js index 5bb0a742c38..410eee2ec15 100644 --- a/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js @@ -1,4 +1,5 @@ import store from 'kolibri.coreVue.vuex.store'; +import router from 'kolibri.coreVue.router'; import { showLessonResourceContentPreview, showLessonResourceSelectionRootPage, @@ -20,7 +21,7 @@ import PlanLessonSelectionContentPreview from '../views/plan/PlanLessonSelection import LessonEditDetailsPage from '../views/plan/LessonEditDetailsPage'; import LessonCreationPage from '../views/plan/LessonCreationPage'; -const CLASS = '/:classId/plan'; +const CLASS = '/:classId?/plan'; const LESSON = '/lessons/:lessonId'; const ALL_LESSONS = '/lessons'; const SELECTION = '/selection'; @@ -34,12 +35,25 @@ function path(...args) { const { showLessonsRootPage } = useLessons(); +function classIdParamRequiredGuard(toRoute, subtopicName) { + if (store.getters.userIsMultiFacilityAdmin && !toRoute.params.classId) { + router.replace({ + name: 'AllFacilitiesPage', + params: { subtopicName }, + }); + return true; + } +} + export default [ { name: LessonsPageNames.PLAN_LESSONS_ROOT, path: path(CLASS, ALL_LESSONS), component: LessonsRootPage, handler(toRoute) { + if (classIdParamRequiredGuard(toRoute, 'PLAN_PAGE')) { + return; + } showLessonsRootPage(store, toRoute.params.classId); }, meta: { diff --git a/kolibri/plugins/coach/assets/src/routes/planRoutes.js b/kolibri/plugins/coach/assets/src/routes/planRoutes.js index 05f1b5a2c3d..96e0b0cf1a2 100644 --- a/kolibri/plugins/coach/assets/src/routes/planRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/planRoutes.js @@ -14,8 +14,8 @@ export default [ ...planExamRoutes, { name: PageNames.PLAN_PAGE, - path: '/:classId/plan', - redirect: '/:classId/plan/lessons', + path: '/:classId?/plan', + redirect: '/:classId?/plan/lessons', }, { name: GroupsPage.name, diff --git a/kolibri/plugins/coach/assets/src/routes/reportRoutes.js b/kolibri/plugins/coach/assets/src/routes/reportRoutes.js index 1c2317d7ccd..c47ca8f34a4 100644 --- a/kolibri/plugins/coach/assets/src/routes/reportRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/reportRoutes.js @@ -1,4 +1,5 @@ import store from 'kolibri.coreVue.vuex.store'; +import router from 'kolibri.coreVue.router'; import { PageNames } from '../constants'; import pages from '../views/reports/allReportsPages'; import { @@ -16,7 +17,7 @@ import LessonEditDetailsPage from '../views/plan/LessonEditDetailsPage'; import QuizEditDetailsPage from '../views/plan/QuizEditDetailsPage'; const ACTIVITY = '/activity'; -const CLASS = '/:classId/reports'; +const CLASS = '/:classId?/reports'; const GROUPS = '/groups'; const GROUP = '/groups/:groupId'; const LEARNERS = '/learners'; @@ -41,6 +42,16 @@ function defaultHandler() { store.dispatch('notLoading'); } +function classIdParamRequiredGuard(toRoute, subtopicName) { + if (store.getters.userIsMultiFacilityAdmin && !toRoute.params.classId) { + router.replace({ + name: 'AllFacilitiesPage', + params: { subtopicName }, + }); + return true; + } +} + export default [ { name: PageNames.REPORTS_PAGE, @@ -445,7 +456,13 @@ export default [ { path: path(CLASS, LESSONS), component: pages.ReportsLessonListPage, - handler: defaultHandler, + handler: toRoute => { + if (classIdParamRequiredGuard(toRoute, 'ReportsLessonListPage')) { + return; + } + defaultHandler(); + }, + meta: { titleParts: ['lessonsLabel', 'CLASS_NAME'], }, diff --git a/kolibri/plugins/coach/assets/src/views/AllFacilitiesPage.vue b/kolibri/plugins/coach/assets/src/views/AllFacilitiesPage.vue index 57a15684f68..ab9e41c03d1 100644 --- a/kolibri/plugins/coach/assets/src/views/AllFacilitiesPage.vue +++ b/kolibri/plugins/coach/assets/src/views/AllFacilitiesPage.vue @@ -53,27 +53,35 @@ CoreTable, }, mixins: [commonCoach, commonCoreStrings], + props: { + subtopicName: { + type: String, + required: false, + default: null, + }, + }, computed: { facilities() { return this.$store.state.core.facilities; }, }, beforeMount() { - // Redirect to single-facility landing page if user/device isn't supposed - // to manage multiple facilities if (!this.$store.getters.userIsMultiFacilityAdmin) { - this.$router.replace(this.coachClassListPageLink()); + const singleFacility = { id: this.$store.getters.userFacilityId }; + this.$router.replace(this.coachClassListPageLink(singleFacility)); } }, methods: { coachClassListPageLink(facility) { - const query = {}; + const params = {}; if (facility) { - query.facility_id = facility.id; + params.facility_id = facility.id; } + params.subtopicName = this.subtopicName; + return { name: 'CoachClassListPage', - query, + params, }; }, }, diff --git a/kolibri/plugins/coach/assets/src/views/CoachClassListPage.vue b/kolibri/plugins/coach/assets/src/views/CoachClassListPage.vue index 7926206df6b..6fa202ad5f8 100644 --- a/kolibri/plugins/coach/assets/src/views/CoachClassListPage.vue +++ b/kolibri/plugins/coach/assets/src/views/CoachClassListPage.vue @@ -43,7 +43,7 @@ @@ -78,6 +78,13 @@ CoachAppBarPage, }, mixins: [commonCoach, commonCoreStrings], + props: { + subtopicName: { + type: String, + required: false, + default: null, + }, + }, computed: { ...mapGetters(['isAdmin', 'isClassCoach', 'isFacilityCoach', 'userIsMultiFacilityAdmin']), ...mapState(['classList', 'dataLoading']), @@ -99,16 +106,20 @@ const facilityUrl = urls['kolibri:kolibri.plugins.facility:facility_management']; if (facilityUrl) { if (this.userIsMultiFacilityAdmin) { - return `${facilityUrl()}#/${this.$route.query.facility_id}/classes`; + return `${facilityUrl()}#/${this.$route.params.facility_id}/classes`; } return facilityUrl(); } return ''; }, + getNextPageName() { + return this.subtopicName || 'HomePage'; + }, appBarTitle() { let facilityName; - const { facility_id } = this.$route.query; + const { facility_id } = this.$route.params; + if (facility_id) { const match = find(this.$store.state.core.facilities, { id: facility_id }) || {}; facilityName = match.name; diff --git a/kolibri/plugins/coach/assets/src/views/home/HomePage/OverviewBlock.vue b/kolibri/plugins/coach/assets/src/views/home/HomePage/OverviewBlock.vue index 1e3cb631833..dcd4a3c0492 100644 --- a/kolibri/plugins/coach/assets/src/views/home/HomePage/OverviewBlock.vue +++ b/kolibri/plugins/coach/assets/src/views/home/HomePage/OverviewBlock.vue @@ -79,7 +79,7 @@ if (this.$store.getters.userIsMultiFacilityAdmin) { facility_id = this.$store.state.classSummary.facility_id; } - return this.$router.getRoute('CoachClassListPage', {}, { facility_id }); + return this.$router.getRoute('CoachClassListPage', { facility_id }); }, classLearnersListRoute() { const { query } = this.$route; diff --git a/kolibri/plugins/coach/assets/src/views/plan/PlanHeader.vue b/kolibri/plugins/coach/assets/src/views/plan/PlanHeader.vue index a3876ad96e9..89b849606c4 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/PlanHeader.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/PlanHeader.vue @@ -4,7 +4,7 @@

diff --git a/kolibri/plugins/coach/assets/src/views/reports/ReportsHeader.vue b/kolibri/plugins/coach/assets/src/views/reports/ReportsHeader.vue index 76bf7daa697..d86a8899811 100644 --- a/kolibri/plugins/coach/assets/src/views/reports/ReportsHeader.vue +++ b/kolibri/plugins/coach/assets/src/views/reports/ReportsHeader.vue @@ -4,7 +4,7 @@

From f4d91239033a99a6c159ce34362017dcfa74f3b2 Mon Sep 17 00:00:00 2001 From: thanksameeelian Date: Wed, 13 Sep 2023 17:34:08 -0500 Subject: [PATCH 2/5] move navigation guard to utils, add handling for single facility user --- .../plugins/coach/assets/src/routes/index.js | 11 +---------- .../assets/src/routes/planLessonsRoutes.js | 12 +----------- .../coach/assets/src/routes/reportRoutes.js | 12 +----------- .../plugins/coach/assets/src/routes/utils.js | 19 +++++++++++++++++++ 4 files changed, 22 insertions(+), 32 deletions(-) create mode 100644 kolibri/plugins/coach/assets/src/routes/utils.js diff --git a/kolibri/plugins/coach/assets/src/routes/index.js b/kolibri/plugins/coach/assets/src/routes/index.js index 3f2f6654e3f..6669c0f2a65 100644 --- a/kolibri/plugins/coach/assets/src/routes/index.js +++ b/kolibri/plugins/coach/assets/src/routes/index.js @@ -11,16 +11,7 @@ import { ClassesPageNames } from '../../../../learn/assets/src/constants'; import { PageNames } from '../constants'; import reportRoutes from './reportRoutes'; import planRoutes from './planRoutes'; - -function classIdParamRequiredGuard(toRoute, subtopicName) { - if (store.getters.userIsMultiFacilityAdmin && !toRoute.params.classId) { - router.replace({ - name: 'AllFacilitiesPage', - params: { subtopicName }, - }); - return true; - } -} +import { classIdParamRequiredGuard } from './utils'; export default [ ...planRoutes, diff --git a/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js b/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js index 410eee2ec15..a921ab4809d 100644 --- a/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js @@ -1,5 +1,4 @@ import store from 'kolibri.coreVue.vuex.store'; -import router from 'kolibri.coreVue.router'; import { showLessonResourceContentPreview, showLessonResourceSelectionRootPage, @@ -20,6 +19,7 @@ import LessonResourceSelectionPage from '../views/plan/LessonResourceSelectionPa import PlanLessonSelectionContentPreview from '../views/plan/PlanLessonSelectionContentPreview'; import LessonEditDetailsPage from '../views/plan/LessonEditDetailsPage'; import LessonCreationPage from '../views/plan/LessonCreationPage'; +import { classIdParamRequiredGuard } from './utils'; const CLASS = '/:classId?/plan'; const LESSON = '/lessons/:lessonId'; @@ -35,16 +35,6 @@ function path(...args) { const { showLessonsRootPage } = useLessons(); -function classIdParamRequiredGuard(toRoute, subtopicName) { - if (store.getters.userIsMultiFacilityAdmin && !toRoute.params.classId) { - router.replace({ - name: 'AllFacilitiesPage', - params: { subtopicName }, - }); - return true; - } -} - export default [ { name: LessonsPageNames.PLAN_LESSONS_ROOT, diff --git a/kolibri/plugins/coach/assets/src/routes/reportRoutes.js b/kolibri/plugins/coach/assets/src/routes/reportRoutes.js index c47ca8f34a4..5d32d984cda 100644 --- a/kolibri/plugins/coach/assets/src/routes/reportRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/reportRoutes.js @@ -1,5 +1,4 @@ import store from 'kolibri.coreVue.vuex.store'; -import router from 'kolibri.coreVue.router'; import { PageNames } from '../constants'; import pages from '../views/reports/allReportsPages'; import { @@ -15,6 +14,7 @@ import { generateQuestionListHandler } from '../modules/questionList/handlers'; import { generateResourceHandler } from '../modules/resourceDetail/handlers'; import LessonEditDetailsPage from '../views/plan/LessonEditDetailsPage'; import QuizEditDetailsPage from '../views/plan/QuizEditDetailsPage'; +import { classIdParamRequiredGuard } from './utils'; const ACTIVITY = '/activity'; const CLASS = '/:classId?/reports'; @@ -42,16 +42,6 @@ function defaultHandler() { store.dispatch('notLoading'); } -function classIdParamRequiredGuard(toRoute, subtopicName) { - if (store.getters.userIsMultiFacilityAdmin && !toRoute.params.classId) { - router.replace({ - name: 'AllFacilitiesPage', - params: { subtopicName }, - }); - return true; - } -} - export default [ { name: PageNames.REPORTS_PAGE, diff --git a/kolibri/plugins/coach/assets/src/routes/utils.js b/kolibri/plugins/coach/assets/src/routes/utils.js new file mode 100644 index 00000000000..329ffbf48fd --- /dev/null +++ b/kolibri/plugins/coach/assets/src/routes/utils.js @@ -0,0 +1,19 @@ +import store from 'kolibri.coreVue.vuex.store'; +import router from 'kolibri.coreVue.router'; + +export function classIdParamRequiredGuard(toRoute, subtopicName) { + if (!toRoute.params.classId) { + if (store.getters.userIsMultiFacilityAdmin) { + router.replace({ + name: 'AllFacilitiesPage', + params: { subtopicName }, + }); + return true; + } else { + router.replace({ + name: 'CoachClassListPage', + params: { subtopicName }, + }); + } + } +} From f4c3afe23e05f5feebda52513bc2c18bf4abb687 Mon Sep 17 00:00:00 2001 From: thanksameeelian Date: Thu, 14 Sep 2023 14:49:30 -0500 Subject: [PATCH 3/5] add subtopic param to class list page url --- kolibri/plugins/coach/assets/src/routes/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kolibri/plugins/coach/assets/src/routes/index.js b/kolibri/plugins/coach/assets/src/routes/index.js index 6669c0f2a65..aaf903583f8 100644 --- a/kolibri/plugins/coach/assets/src/routes/index.js +++ b/kolibri/plugins/coach/assets/src/routes/index.js @@ -26,7 +26,7 @@ export default [ }, }, { - path: '/:facility_id?/classes', + path: '/:subtopicName?/:facility_id?/classes', component: CoachClassListPage, props: true, handler(toRoute) { From 53562a37310d1a40173a19d7f1b4cd966ad9b74b Mon Sep 17 00:00:00 2001 From: thanksameeelian Date: Thu, 14 Sep 2023 15:26:51 -0500 Subject: [PATCH 4/5] adjust ordering of optional url params --- kolibri/plugins/coach/assets/src/routes/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/routes/index.js b/kolibri/plugins/coach/assets/src/routes/index.js index aaf903583f8..d6a8c0eaf30 100644 --- a/kolibri/plugins/coach/assets/src/routes/index.js +++ b/kolibri/plugins/coach/assets/src/routes/index.js @@ -18,7 +18,7 @@ export default [ ...reportRoutes, { name: 'AllFacilitiesPage', - path: '/:subtopicName?/facilities', + path: '/facilities/:subtopicName?', component: AllFacilitiesPage, props: true, handler() { @@ -26,7 +26,7 @@ export default [ }, }, { - path: '/:subtopicName?/:facility_id?/classes', + path: '/:facility_id?/classes/:subtopicName?', component: CoachClassListPage, props: true, handler(toRoute) { From 74d5725f7c6bae41aa393323f4dbe9d330599ae4 Mon Sep 17 00:00:00 2001 From: thanksameeelian Date: Thu, 14 Sep 2023 15:50:16 -0500 Subject: [PATCH 5/5] simplify navigation guard --- .../plugins/coach/assets/src/routes/utils.js | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/routes/utils.js b/kolibri/plugins/coach/assets/src/routes/utils.js index 329ffbf48fd..7af3b4cad99 100644 --- a/kolibri/plugins/coach/assets/src/routes/utils.js +++ b/kolibri/plugins/coach/assets/src/routes/utils.js @@ -3,17 +3,14 @@ import router from 'kolibri.coreVue.router'; export function classIdParamRequiredGuard(toRoute, subtopicName) { if (!toRoute.params.classId) { - if (store.getters.userIsMultiFacilityAdmin) { - router.replace({ - name: 'AllFacilitiesPage', - params: { subtopicName }, - }); - return true; - } else { - router.replace({ - name: 'CoachClassListPage', - params: { subtopicName }, - }); - } + const redirectPage = store.getters.userIsMultiFacilityAdmin + ? 'AllFacilitiesPage' + : 'CoachClassListPage'; + + router.replace({ + name: redirectPage, + params: { subtopicName }, + }); + return true; } }