From a1ab926e65753d126cfe022867966a41fe788f0c Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Mon, 12 Feb 2024 21:42:06 -0800 Subject: [PATCH 1/6] fix: checkbox logic to setup(); topic selection logic implemented - Implements topic selection logic (can select topic when all children are fetched and are exercises) - [De]select all accounts for possibility of topics, using new `hasCheckbox` logic - Only shows "Select all" when every child `hasCheckbox` based on the new logic - Generally begins moving logic into relevant blocks within setup() --- .../src/composables/useQuizResources.js | 12 +- .../plan/CreateExamPage/ResourceSelection.vue | 127 +++++++++++++----- 2 files changed, 101 insertions(+), 38 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/composables/useQuizResources.js b/kolibri/plugins/coach/assets/src/composables/useQuizResources.js index 052ae64addd..b243a8ca4ed 100644 --- a/kolibri/plugins/coach/assets/src/composables/useQuizResources.js +++ b/kolibri/plugins/coach/assets/src/composables/useQuizResources.js @@ -128,11 +128,17 @@ export default function useQuizResources({ topicId } = {}) { } /** @returns {Boolean} Whether the given node should be displayed with a checkbox - * @description Returns whether the given node is an exercise or not -- although, could be - * extended in the future to permit topic-level selection if desired + * @description Returns true for exercises and for topics that have no topic children and no + * more children to load */ function hasCheckbox(node) { - return node.kind === ContentNodeKinds.EXERCISE; + return ( + node.kind === ContentNodeKinds.EXERCISE || + // Has children, no more to load, and no children are topics + (node.children && + !node.children.more && + !node.children.results.some(c => c.kind === ContentNodeKinds.TOPIC)) + ); } function setResources(r) { 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 8ac5bb5af59..a640a934208 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue @@ -64,16 +64,16 @@ /> @@ -178,7 +178,29 @@ * a list of unique resources to avoid unnecessary duplication */ function addToWorkingResourcePool(resources = []) { - workingResourcePool.value = uniqWith([...workingResourcePool.value, ...resources], isEqual); + workingResourcePool.value = uniqWith( + [ + ...workingResourcePool.value, + ...resources.filter(r => r.kind === ContentNodeKinds.EXERCISE), + ], + isEqual + ); + } + + /** + * @description Returns the list of Exercises which can possibly be selected from the current + * contentList taking into consideration the logic for whether a topic can be selected or not. + * @returns {QuizExercise[]} - All contents which can be selected + */ + function selectableContentList() { + return contentList.value.reduce((newList, content) => { + if (content.kind === ContentNodeKinds.TOPIC && hasCheckbox(content)) { + newList = [...newList, ...content.children.results]; + } else { + newList.push(content); + } + return newList; + }, []); } /** @@ -202,6 +224,9 @@ */ function contentPresentInWorkingResourcePool(content) { const workingResourceIds = workingResourcePool.value.map(wr => wr.id); + if (content.kind === ContentNodeKinds.TOPIC) { + return content.children.results.every(child => workingResourceIds.includes(child.id)); + } return workingResourceIds.includes(content.id); } @@ -226,6 +251,63 @@ }); } + const selectAllChecked = computed(() => { + // Returns true if all the resources in the topic are in the working resource pool + const workingResourceIds = workingResourcePool.value.map(wr => wr.id); + const selectableIds = selectableContentList().map(content => content.id); + return selectableIds.every(id => workingResourceIds.includes(id)); + }); + + const selectAllIndeterminate = computed(() => { + // Returns true if some, but not all, of the resources in the topic are in the working + // resource + const workingResourceIds = workingResourcePool.value.map(wr => wr.id); + const selectableIds = selectableContentList().map(content => content.id); + return !selectAllChecked.value && selectableIds.some(id => workingResourceIds.includes(id)); + }); + + const showSelectAll = computed(() => { + return contentList.value.every(content => hasCheckbox(content)); + }); + + function handleSelectAll(isChecked) { + if (isChecked) { + this.addToWorkingResourcePool(this.contentList); + } else { + this.contentList.forEach(content => { + var contentToRemove = []; + if (content.kind === ContentNodeKinds.TOPIC) { + contentToRemove = content.children.results; + } else { + contentToRemove.push(content); + } + contentToRemove.forEach(c => { + this.removeFromWorkingResourcePool(c); + }); + }); + } + } + + /** + * @param {Object} param + * @param {ContentNode} param.content + * @param {boolean} param.checked + * @affects workingResourcePool - Adds or removes the content from the workingResourcePool + * When given a topic, it adds or removes all the exercises in the topic from the + * workingResourcePool. This assumes that topics which should not be added are not able to + * be checked and does not do any additional checks. + */ + function toggleSelected({ content, checked }) { + content = content.kind === ContentNodeKinds.TOPIC ? content.children.results : [content]; + if (checked) { + this.addToWorkingResourcePool(content); + } else { + content.forEach(c => { + this.removeFromWorkingResourcePool(c); + }); + } + } + const { hasCheckbox, topic, @@ -341,6 +423,11 @@ } return { + selectAllChecked, + selectAllIndeterminate, + showSelectAll, + handleSelectAll, + toggleSelected, topic, topicId, contentList, @@ -382,20 +469,6 @@ isTopicIdSet() { return this.$route.params.topic_id; }, - isSelectAllChecked() { - // Returns true if all the resources in the topic are in the working resource pool - const workingResourceIds = this.workingResourcePool.map(wr => wr.id); - return this.contentList.every(content => workingResourceIds.includes(content.id)); - }, - selectAllIndeterminate() { - // Returns true if some, but not all, of the resources in the topic are in the working - // resource - const workingResourceIds = this.workingResourcePool.map(wr => wr.id); - return ( - !this.isSelectAllChecked && - this.contentList.some(content => workingResourceIds.includes(content.id)) - ); - }, getBookmarksLink() { // Inject the showBookmarks parameter so that @@ -446,22 +519,6 @@ return {}; // or return {} if you prefer an empty object }, - toggleSelected({ content, checked }) { - if (checked) { - this.addToWorkingResourcePool([content]); - } else { - this.removeFromWorkingResourcePool(content); - } - }, - toggleTopicInWorkingResources(isChecked) { - if (isChecked) { - this.addToWorkingResourcePool(this.contentList); - } else { - this.contentList.forEach(content => { - this.removeFromWorkingResourcePool(content); - }); - } - }, topicListingLink({ topicId }) { return this.$router.getRoute( PageNames.QUIZ_SELECT_RESOURCES, From ecb592033db3c759ba274137e8736dbc448d751c Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Fri, 16 Feb 2024 11:15:35 -0800 Subject: [PATCH 2/6] add messages; slots for showing them w/out issues in other usages of card list --- .../plan/CreateExamPage/ResourceSelection.vue | 34 +++++++++++++++++-- .../ContentCardList.vue | 6 +++- .../LessonContentCard/index.vue | 1 + .../strings/enhancedQuizManagementStrings.js | 7 ++++ 4 files changed, 45 insertions(+), 3 deletions(-) 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 a640a934208..58293acfe7c 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue @@ -50,6 +50,14 @@ +
+ {{ cannotSelectSomeTopicWarning$() }} +
+ + @moreresults="fetchMoreQuizResources" + > + +
@@ -154,6 +169,8 @@ numberOfSelectedResources$, numberOfResources$, selectedResourcesInformation$, + cannotSelectTopicCard$, + cannotSelectSomeTopicWarning$, } = enhancedQuizManagementStrings; // TODO let's not use text for this @@ -440,6 +457,8 @@ resetWorkingResourcePool, contentPresentInWorkingResourcePool, //contentList, + cannotSelectTopicCard$, + cannotSelectSomeTopicWarning$, sectionSettings$, selectFromBookmarks$, numberOfSelectedBookmarks$, @@ -496,6 +515,12 @@ }, }, methods: { + showTopicSizeWarningCard(content) { + return !this.hasCheckbox(content) && content.kind === ContentNodeKinds.TOPIC; + }, + showTopicSizeWarning() { + return this.contentList.some(this.showTopicSizeWarningCard); + }, /** @public */ focusFirstEl() { this.$refs.textbox.focus(); @@ -664,4 +689,9 @@ margin-top: 2em; } + .shadow { + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), + 0 2px 1px -1px rgba(0, 0, 0, 0.12); + } + diff --git a/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/ContentCardList.vue b/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/ContentCardList.vue index d0dfd643cc9..ffc72b8e6c3 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/ContentCardList.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/ContentCardList.vue @@ -33,7 +33,11 @@ :link="contentCardLink(content)" :numCoachContents="content.num_coach_contents" :isLeaf="content.is_leaf" - /> + > + + diff --git a/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/LessonContentCard/index.vue b/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/LessonContentCard/index.vue index c64bf7f18ca..e3ed3035d4e 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/LessonContentCard/index.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/LessonContentCard/index.vue @@ -52,6 +52,7 @@ :isTopic="isTopic" />
+ diff --git a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js index 039a606f141..adff03bdcfa 100644 --- a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js +++ b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js @@ -154,4 +154,11 @@ export const enhancedQuizManagementStrings = createTranslator('EnhancedQuizManag message: '{count, number, integer} of {total, number, integer} {total, plural, one {resource selected} other {resources selected}}', }, + cannotSelectTopicCard: { + message: 'Folder exceeds 12 exercises', + }, + cannotSelectSomeTopicWarning: { + message: + 'Select only folders with 12 or fewer exercises and no subfolders to avoid oversized quizzes. Proceed to choose a smaller folder.', + }, }); From 0d60d8a900bda217dcb994ee058750569a82c0fb Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Mon, 26 Feb 2024 15:12:47 -0800 Subject: [PATCH 3/6] remove notification on each card --- .../views/plan/CreateExamPage/ResourceSelection.vue | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) 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 58293acfe7c..ada51b54eb6 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue @@ -70,6 +70,7 @@ @clear="clearSearchTerm" @searchterm="handleSearchTermChange" /> + - - + @moreresults="fetchMoreResources" + />
From 00d40c922794e65d1f73137c961ab5bed0b74a77 Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Mon, 26 Feb 2024 15:13:58 -0800 Subject: [PATCH 4/6] improve spacing of top notice --- .../assets/src/views/plan/CreateExamPage/ResourceSelection.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ada51b54eb6..688b7893da1 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue @@ -53,7 +53,7 @@
{{ cannotSelectSomeTopicWarning$() }}
From 37f2cba5e16a21d0d7125757e8180e3cec4f80b6 Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Mon, 26 Feb 2024 15:17:43 -0800 Subject: [PATCH 5/6] fix select all when topics are selectable --- .../assets/src/views/plan/CreateExamPage/ResourceSelection.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 688b7893da1..a5f58a2e9b6 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue @@ -283,7 +283,7 @@ function handleSelectAll(isChecked) { if (isChecked) { - this.addToWorkingResourcePool(this.contentList); + this.addToWorkingResourcePool(selectableContentList()); } else { this.contentList.forEach(content => { var contentToRemove = []; From c6e84500ef9409b19eef9013444094d386fc79b7 Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Mon, 26 Feb 2024 15:23:40 -0800 Subject: [PATCH 6/6] messaging update & clean-up for topic selection warning --- .../src/views/plan/CreateExamPage/ResourceSelection.vue | 2 -- .../kolibri-common/strings/enhancedQuizManagementStrings.js | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) 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 a5f58a2e9b6..d11589743bb 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue @@ -163,7 +163,6 @@ numberOfSelectedResources$, numberOfResources$, selectedResourcesInformation$, - cannotSelectTopicCard$, cannotSelectSomeTopicWarning$, } = enhancedQuizManagementStrings; @@ -451,7 +450,6 @@ resetWorkingResourcePool, contentPresentInWorkingResourcePool, //contentList, - cannotSelectTopicCard$, cannotSelectSomeTopicWarning$, sectionSettings$, selectFromBookmarks$, diff --git a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js index adff03bdcfa..6cb72972747 100644 --- a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js +++ b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js @@ -154,11 +154,8 @@ export const enhancedQuizManagementStrings = createTranslator('EnhancedQuizManag message: '{count, number, integer} of {total, number, integer} {total, plural, one {resource selected} other {resources selected}}', }, - cannotSelectTopicCard: { - message: 'Folder exceeds 12 exercises', - }, cannotSelectSomeTopicWarning: { message: - 'Select only folders with 12 or fewer exercises and no subfolders to avoid oversized quizzes. Proceed to choose a smaller folder.', + 'You can only select folders with 12 or less exercises and no subfolders to avoid oversized quizzes.', }, });