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..d6a8c0eaf30 100644 --- a/kolibri/plugins/coach/assets/src/routes/index.js +++ b/kolibri/plugins/coach/assets/src/routes/index.js @@ -11,32 +11,36 @@ import { ClassesPageNames } from '../../../../learn/assets/src/constants'; import { PageNames } from '../constants'; import reportRoutes from './reportRoutes'; import planRoutes from './planRoutes'; +import { classIdParamRequiredGuard } from './utils'; export default [ ...planRoutes, ...reportRoutes, { - path: '/facilities', + name: 'AllFacilitiesPage', + path: '/facilities/:subtopicName?', component: AllFacilitiesPage, + props: true, handler() { store.dispatch('notLoading'); }, }, { - path: '/classes', + path: '/:facility_id?/classes/:subtopicName?', 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 +56,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 +78,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..a921ab4809d 100644 --- a/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js @@ -19,8 +19,9 @@ 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 CLASS = '/:classId?/plan'; const LESSON = '/lessons/:lessonId'; const ALL_LESSONS = '/lessons'; const SELECTION = '/selection'; @@ -40,6 +41,9 @@ export default [ 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..5d32d984cda 100644 --- a/kolibri/plugins/coach/assets/src/routes/reportRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/reportRoutes.js @@ -14,9 +14,10 @@ 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'; +const CLASS = '/:classId?/reports'; const GROUPS = '/groups'; const GROUP = '/groups/:groupId'; const LEARNERS = '/learners'; @@ -445,7 +446,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/routes/utils.js b/kolibri/plugins/coach/assets/src/routes/utils.js new file mode 100644 index 00000000000..7af3b4cad99 --- /dev/null +++ b/kolibri/plugins/coach/assets/src/routes/utils.js @@ -0,0 +1,16 @@ +import store from 'kolibri.coreVue.vuex.store'; +import router from 'kolibri.coreVue.router'; + +export function classIdParamRequiredGuard(toRoute, subtopicName) { + if (!toRoute.params.classId) { + const redirectPage = store.getters.userIsMultiFacilityAdmin + ? 'AllFacilitiesPage' + : 'CoachClassListPage'; + + router.replace({ + name: redirectPage, + params: { subtopicName }, + }); + return true; + } +} 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 @@