From 85eda612d01dcc569a5f63d714e617a09071b884 Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Fri, 18 Oct 2024 01:09:03 -0500 Subject: [PATCH 01/15] Check tableHasRows for transition-groups --- kolibri/core/assets/src/views/CoreTable.vue | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/kolibri/core/assets/src/views/CoreTable.vue b/kolibri/core/assets/src/views/CoreTable.vue index 09dbc67dd03..bbc978aa8a4 100644 --- a/kolibri/core/assets/src/views/CoreTable.vue +++ b/kolibri/core/assets/src/views/CoreTable.vue @@ -64,7 +64,18 @@ // if in regular const tgroupChildren = get(tbody, 'componentOptions.children'); if (tgroupChildren) { - tableHasRows = tgroupChildren.length > 0; + if (tgroupChildren.length === 0) { + tableHasRows = false; + } else if ( + tgroupChildren.length === 1 && + tgroupChildren[0]?.tag?.includes('transition-group') + ) { + const [child] = tgroupChildren; + const children = child.children || child.componentOptions?.children; + tableHasRows = !!children?.length > 0; + } else { + tableHasRows = true; + } } if (tbody.children) { From 6be46d708b99b1ec75e13ac2d924b5e4547e4197 Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Fri, 18 Oct 2024 01:27:02 -0500 Subject: [PATCH 02/15] Make report lessons resources table editable --- .../assets/src/routes/planLessonsRoutes.js | 11 + .../reports/ReportsLessonResourcesList.vue | 203 ++++++++++++++---- yarn.lock | 9 - 3 files changed, 178 insertions(+), 45 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js b/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js index 2ad60d24e17..9f137dd9dad 100644 --- a/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js @@ -104,6 +104,17 @@ export default [ }, ], }, + { + name: LessonsPageNames.SUMMARY, + path: '/:classId/plan/lessonstemp/:lessonId', + component: LessonSummaryPage, + handler(toRoute) { + return showLessonSummaryPage(store, toRoute.params); + }, + meta: { + titleParts: ['LESSON_NAME', 'CLASS_NAME'], + }, + }, { name: LessonsPageNames.SUMMARY, path: path(CLASS, LESSON), diff --git a/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesList.vue b/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesList.vue index 691692430e6..e9fb2b70993 100644 --- a/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesList.vue +++ b/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesList.vue @@ -5,45 +5,81 @@ {{ coachString('titleLabel') }} {{ coreString('progressLabel') }} {{ coachString('avgTimeSpentLabel') }} + @@ -55,8 +91,12 @@ import CoreTable from 'kolibri.coreVue.components.CoreTable'; import TimeDuration from 'kolibri.coreVue.components.TimeDuration'; import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings'; - import { coachStringsMixin } from '../common/commonCoachStrings'; + import DragContainer from 'kolibri.coreVue.components.DragContainer'; + import DragHandle from 'kolibri.coreVue.components.DragHandle'; + import DragSortWidget from 'kolibri.coreVue.components.DragSortWidget'; + import Draggable from 'kolibri.coreVue.components.Draggable'; import StatusSummary from '../common/status/StatusSummary'; + import { coachStringsMixin } from '../common/commonCoachStrings'; export default { name: 'ReportsLessonResourcesList', @@ -64,6 +104,10 @@ CoreTable, StatusSummary, TimeDuration, + DragContainer, + DragHandle, + DragSortWidget, + Draggable, }, mixins: [coachStringsMixin, commonCoreStrings], props: { @@ -71,7 +115,94 @@ type: Array, default: () => [], }, + editable: { + type: Boolean, + default: false, + }, + }, + data() { + return { + dragActive: false, + }; + }, + methods: { + handleDragStart() { + // Used to mitigate the issue of text being selected while dragging + this.dragActive = true; + }, + handleResourcesOrderChange({ newArray }) { + this.$emit('sort', { newArray }); + this.dragActive = false; + }, + handleRemoveEntry(entry) { + this.$emit('remove', entry); + }, + moveUpOne(oldIndex) { + this.swap(oldIndex, oldIndex - 1); + }, + moveDownOne(oldIndex) { + this.swap(oldIndex, oldIndex + 1); + }, + swap(oldIndex, newIndex) { + const newArray = [...this.entries]; + const oldResource = newArray[newIndex]; + newArray[newIndex] = newArray[oldIndex]; + newArray[oldIndex] = oldResource; + + this.handleResourcesOrderChange({ newArray }); + }, + }, + $trs: { + moveResourceUpButtonDescription: { + message: 'Move this resource one position up in this lesson', + context: 'Refers to ordering resources.', + }, + moveResourceDownButtonDescription: { + message: 'Move this resource one position down in this lesson', + context: 'Refers to ordering resources.', + }, }, }; + + + diff --git a/yarn.lock b/yarn.lock index f62830be73b..f7641cb9fbd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2963,15 +2963,6 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -"aphrodite@git+https://github.com/learningequality/aphrodite.git": - version "2.2.3" - uid fdc8d7be8912a5cf17f74ff10f124013c52c3e32 - resolved "git+https://github.com/learningequality/aphrodite.git#fdc8d7be8912a5cf17f74ff10f124013c52c3e32" - dependencies: - asap "^2.0.3" - inline-style-prefixer "^4.0.2" - string-hash "^1.1.3" - "aphrodite@https://github.com/learningequality/aphrodite/": version "2.2.3" resolved "https://github.com/learningequality/aphrodite/#fdc8d7be8912a5cf17f74ff10f124013c52c3e32" From 9971b4a6d91f47da691b527be922da9a18c9d828 Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Fri, 18 Oct 2024 01:29:28 -0500 Subject: [PATCH 03/15] Rename ReportsLessonResourcesTable --- .../coach/assets/src/views/reports/ReportsLessonBase.vue | 6 +++--- ...sonResourcesList.vue => ReportsLessonResourcesTable.vue} | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename kolibri/plugins/coach/assets/src/views/reports/{ReportsLessonResourcesList.vue => ReportsLessonResourcesTable.vue} (99%) diff --git a/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonBase.vue b/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonBase.vue index cca4a5c7467..bbd7eefe0d6 100644 --- a/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonBase.vue +++ b/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonBase.vue @@ -44,7 +44,7 @@ @click="() => saveTabsClick(REPORTS_LESSON_TABS_ID)" /> - @@ -74,7 +74,7 @@ import { useCoachTabs } from '../../composables/useCoachTabs'; import ReportsControls from './ReportsControls'; import ReportsLessonLearnersList from './ReportsLessonLearnersList'; - import ReportsLessonResourcesList from './ReportsLessonResourcesList'; + import ReportsLessonResourcesTable from './ReportsLessonResourcesTable.vue'; export default { name: 'ReportsLessonBase', @@ -83,7 +83,7 @@ ReportsControls, LessonOptionsDropdownMenu, ReportsLessonLearnersList, - ReportsLessonResourcesList, + ReportsLessonResourcesTable, }, mixins: [commonCoach, commonCoreStrings], setup() { diff --git a/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesList.vue b/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesTable.vue similarity index 99% rename from kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesList.vue rename to kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesTable.vue index e9fb2b70993..306b856baed 100644 --- a/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesList.vue +++ b/kolibri/plugins/coach/assets/src/views/reports/ReportsLessonResourcesTable.vue @@ -99,7 +99,7 @@ import { coachStringsMixin } from '../common/commonCoachStrings'; export default { - name: 'ReportsLessonResourcesList', + name: 'ReportsLessonResourcesTable', components: { CoreTable, StatusSummary, From 0e577b6da59b8ca279db8d92f04455a6d1a32fe1 Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Fri, 18 Oct 2024 10:03:35 -0500 Subject: [PATCH 04/15] Introduce lessonResourcesTable in lessonSummaryPage --- .../assets/src/routes/planLessonsRoutes.js | 2 +- .../views/plan/LessonSummaryPage/index.vue | 169 +++++++++++++----- 2 files changed, 128 insertions(+), 43 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js b/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js index 9f137dd9dad..763973e0799 100644 --- a/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js +++ b/kolibri/plugins/coach/assets/src/routes/planLessonsRoutes.js @@ -106,7 +106,7 @@ export default [ }, { name: LessonsPageNames.SUMMARY, - path: '/:classId/plan/lessonstemp/:lessonId', + path: '/:classId/plan/lessonstemp/:lessonId/:tabId?', component: LessonSummaryPage, handler(toRoute) { return showLessonSummaryPage(store, toRoute.params); diff --git a/kolibri/plugins/coach/assets/src/views/plan/LessonSummaryPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/LessonSummaryPage/index.vue index 52cc37f812a..8e611500450 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/LessonSummaryPage/index.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/LessonSummaryPage/index.vue @@ -16,7 +16,7 @@ - +

{{ coachString('generalInformationLabel') }}

@@ -26,43 +26,46 @@ :groupNames="getRecipientNamesForLesson(currentLesson)" />
- - -
-
-
-
-
-

- {{ coreString('resourcesLabel') }} -

-
-
- -
-
-
- - - -

- {{ coachString('noResourcesInLessonLabel') }} -

- - + + + + + + + + + + + @@ -75,12 +78,15 @@ import { mapState } from 'vuex'; import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings'; - import CoachAppBarPage from '../../CoachAppBarPage'; import commonCoach from '../../common'; + import CoachAppBarPage from '../../CoachAppBarPage'; + import ReportsControls from '../../reports/ReportsControls'; import { selectionRootLink } from '../../../routes/planLessonsRouterUtils'; - import ManageLessonModals from './ManageLessonModals'; - import ResourceListTable from './ResourceListTable'; + import { LessonsPageNames } from '../../../constants/lessonsConstants'; + import { REPORTS_LESSON_TABS_ID, ReportsLessonTabs } from '../../../constants/tabsConstants'; + import ReportsLessonResourcesTable from '../../reports/ReportsLessonResourcesTable.vue'; import LessonOptionsDropdownMenu from './LessonOptionsDropdownMenu'; + import ManageLessonModals from './ManageLessonModals'; export default { name: 'LessonSummaryPage', @@ -90,20 +96,23 @@ }; }, components: { + ReportsControls, CoachAppBarPage, - ResourceListTable, ManageLessonModals, LessonOptionsDropdownMenu, + ReportsLessonResourcesTable, }, mixins: [commonCoach, commonCoreStrings], data() { return { currentAction: '', + ReportsLessonTabs, + REPORTS_LESSON_TABS_ID, }; }, computed: { ...mapState('classSummary', { classId: 'id' }), - ...mapState('lessonSummary', ['currentLesson', 'workingResources']), + ...mapState('lessonSummary', ['currentLesson', 'workingResources', 'resourceCache']), loading() { return this.$store.state.core.loading; }, @@ -113,6 +122,58 @@ lessonSelectionRootPage() { return selectionRootLink({ lessonId: this.lessonId, classId: this.classId }); }, + activeTabId() { + const { tabId } = this.$route.params; + if (Object.values(ReportsLessonTabs).includes(tabId)) { + return tabId; + } + return ReportsLessonTabs.REPORTS; + }, + tabs() { + const tabsList = [ + { + id: ReportsLessonTabs.REPORTS, + label: this.coreString('resourcesLabel'), + }, + { + id: ReportsLessonTabs.LEARNERS, + label: this.coachString('learnersLabel'), + }, + ]; + + tabsList.forEach(tab => { + tab.to = this.classRoute(LessonsPageNames.SUMMARY, { tabId: tab.id }); + }); + + return tabsList; + }, + recipients() { + return this.getLearnersForLesson(this.currentLesson); + }, + resourcesTable() { + return this.workingResources.map(resource => { + const content = this.resourceCache[resource.contentnode_id]; + if (!content) { + return this.missingResourceObj(resource.contentnode_id); + } + + const tally = this.getContentStatusTally(content.content_id, this.recipients); + const tableRow = { + ...content, + node_id: content.id, + avgTimeSpent: this.getContentAvgTimeSpent(content.content_id, this.recipients), + tally, + hasAssignments: Object.values(tally).reduce((a, b) => a + b, 0), + }; + + const link = this.resourceLink(tableRow); + if (link) { + tableRow.link = link; + } + + return tableRow; + }); + }, }, methods: { handleSelectOption(action) { @@ -122,6 +183,30 @@ this.currentAction = action; } }, + exportCSV() { + if (typeof this.$refs.table.exportCSV === 'function') { + this.$refs.table.exportCSV(); + } + }, + resourceLink(resource) { + if (resource.hasAssignments) { + if (resource.kind === this.ContentNodeKinds.EXERCISE) { + return this.classRoute( + this.group + ? 'ReportsGroupReportLessonExerciseLearnerListPage' + : 'ReportsLessonExerciseLearnerListPage', + { exerciseId: resource.content_id }, + ); + } else { + return this.classRoute( + this.group + ? 'ReportsGroupReportLessonResourceLearnerListPage' + : 'ReportsLessonResourceLearnerListPage', + { resourceId: resource.content_id }, + ); + } + } + }, }, }; From bb4309651db614f748e6cbda319fb93d936f7233 Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Fri, 18 Oct 2024 15:49:23 -0500 Subject: [PATCH 05/15] Add functionality to sort and delete resources --- .../views/plan/LessonSummaryPage/index.vue | 84 ++++++++++++++++++- .../reports/ReportsLessonResourcesTable.vue | 5 +- 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/views/plan/LessonSummaryPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/LessonSummaryPage/index.vue index 8e611500450..62acb3ec669 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/LessonSummaryPage/index.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/LessonSummaryPage/index.vue @@ -54,8 +54,9 @@