From 591a93cf7ec80a5f81b4f9b36ba6b72899ddfc17 Mon Sep 17 00:00:00 2001
From: Jacob Pierce
Date: Tue, 31 Oct 2023 08:51:58 -0700
Subject: [PATCH 01/50] set not loading when quiz creator comes up
---
.../coach/assets/src/views/plan/CreateExamPage/index.vue | 3 +++
1 file changed, 3 insertions(+)
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
index 41aadf022c..7b57201251 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
@@ -108,6 +108,9 @@
created() {
this.quizForge.initializeQuiz();
},
+ mounted() {
+ this.$store.dispatch('notLoading');
+ },
$trs: {
createNewExamLabel: {
message: 'Create new quiz',
From c6c2f8eb40016b327e3888ef9f41ef289af89b6f Mon Sep 17 00:00:00 2001
From: Jacob Pierce
Date: Thu, 12 Oct 2023 15:44:31 -0700
Subject: [PATCH 02/50] add DEBUG option to useQuizCreation; bootstrap basic
accordion setup
---
.../assets/src/composables/useQuizCreation.js | 44 ++++++++++--
.../plan/CreateExamPage/AccordionItem.vue | 2 +-
.../plan/CreateExamPage/CreateQuizSection.vue | 67 ++++++++++++++-----
.../src/views/plan/CreateExamPage/index.vue | 15 +++--
4 files changed, 100 insertions(+), 28 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/composables/useQuizCreation.js b/kolibri/plugins/coach/assets/src/composables/useQuizCreation.js
index 67e547dc9a..64b6ff280f 100644
--- a/kolibri/plugins/coach/assets/src/composables/useQuizCreation.js
+++ b/kolibri/plugins/coach/assets/src/composables/useQuizCreation.js
@@ -8,7 +8,7 @@ import { get, set } from '@vueuse/core';
import { computed, ref } from 'kolibri.lib.vueCompositionApi';
// TODO: Probably move this to this file's local dir
import selectQuestions from '../modules/examCreation/selectQuestions.js';
-import { Quiz, QuizSection } from './quizCreationSpecs.js';
+import { Quiz, QuizSection, QuizQuestion } from './quizCreationSpecs.js';
/** Validators **/
/* objectSpecs expects every property to be available -- but we don't want to have to make an
@@ -30,7 +30,7 @@ function isExercise(o) {
/**
* Composable function presenting primary interface for Quiz Creation
*/
-export default () => {
+export default (DEBUG = true) => {
// -----------
// Local state
// -----------
@@ -53,6 +53,38 @@ export default () => {
/** @type {ref} A counter for use in naming new sections */
const _sectionLabelCounter = ref(1);
+ // Debug Data Generators
+ function _quizQuestions(num = 5) {
+ const questions = [];
+ for (let i = 0; i <= num; i++) {
+ const overrides = {
+ title: `Quiz Question ${i}`,
+ question_id: `${i}`,
+ };
+ questions.push(objectWithDefaults(overrides, QuizQuestion));
+ }
+ return questions;
+ }
+
+ function _quizSections(num = 5, numQuestions = 5) {
+ const sections = [];
+ for (let i = 0; i <= num; i++) {
+ const overrides = {
+ section_id: `${i}`,
+ section_title: `A section ${i}`,
+ questions: _quizQuestions(numQuestions),
+ };
+ sections.push(objectWithDefaults(overrides, QuizSection));
+ }
+ return sections;
+ }
+
+ function _generateTestData(numSections = 5, numQuestions = 5) {
+ const sections = _quizSections(numSections, numQuestions);
+ updateQuiz({ question_sources: sections });
+ setActiveSection(sections[0].section_id);
+ }
+
// ------------------
// Section Management
// ------------------
@@ -162,8 +194,12 @@ export default () => {
* use */
function initializeQuiz() {
set(_quiz, objectWithDefaults({}, Quiz));
- const newSection = addSection();
- setActiveSection(newSection.section_id);
+ if (DEBUG) {
+ _generateTestData();
+ } else {
+ const newSection = addSection();
+ setActiveSection(newSection.section_id);
+ }
_fetchChannels();
}
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/AccordionItem.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/AccordionItem.vue
index f0d32869a5..27e61bc3ad 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/AccordionItem.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/AccordionItem.vue
@@ -32,7 +32,7 @@
required: true,
},
id: {
- type: Number,
+ type: String,
required: true,
},
},
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 6f9dc0adbb..8abe3f331c 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue
@@ -153,28 +153,51 @@
tabsId="quizSectionTabs"
:activeTabId="quizForge.activeSection.value ? quizForge.activeSection.value.section_id : ''"
>
-
- {{ quizForge.activeSection.value.section_id }}
-
- ?
-
+
+
+ ?
+
-
- {{ noQuestionsInSection$() }}
-
+
+ {{ noQuestionsInSection$() }}
+
-
{{ addQuizSectionQuestionsInstructions$() }}
+
{{ addQuizSectionQuestionsInstructions$() }}
-
- {{ addQuestionsLabel$() }}
-
+
+ {{ addQuestionsLabel$() }}
+
+
+
+
+
+
+
+
+
+
+
+ TODO: Use actual resources, render questions here
+
+
+
+
+
+
@@ -191,12 +214,16 @@
import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';
import { enhancedQuizManagementStrings } from 'kolibri-common/strings/enhancedQuizManagementStrings';
import commonCoach from '../../common';
- import SectionSidePanel from './SectionSidePanel.vue';
- import TabsWithOverflow from './TabsWithOverflow.vue';
+ import SectionSidePanel from './SectionSidePanel';
+ import TabsWithOverflow from './TabsWithOverflow';
+ import AccordionContainer from './AccordionContainer';
+ import AccordionItem from './AccordionItem';
export default {
name: 'CreateQuizSection',
components: {
+ AccordionContainer,
+ AccordionItem,
TabsWithOverflow,
SectionSidePanel,
},
@@ -264,6 +291,10 @@
},
];
},
+ accordionQuestions() {
+ const mapQuestionToAccordionItem = q => ({ id: q.question_id, title: q.title });
+ return get(this.quizForge.activeQuestions).map(mapQuestionToAccordionItem);
+ },
},
methods: {
tabRefLabel(section_id) {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
index 7b57201251..fba6c77f1c 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
@@ -20,7 +20,7 @@
:style="{ ...maxContainerHeight, maxWidth: '1000px', margin: '0 auto' }"
>
-
+
@@ -41,6 +41,8 @@
diff --git a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
index 296bbb08e1..c3b0a009a9 100644
--- a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
+++ b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
@@ -10,6 +10,10 @@ export const enhancedQuizManagementStrings = createTranslator('EnhancedQuizManag
createNewQuiz: {
message: 'Create new quiz',
},
+ quizSectionsLabel: {
+ message: 'Quiz sections',
+ context: 'Used as an aria-label for screen readers to describe the purpose of the list of tabs',
+ },
quizTitle: {
message: 'Quiz title',
},
From 444909933cc901b9fe8e717287126ffa8d85f9b4 Mon Sep 17 00:00:00 2001
From: Jacob Pierce
Date: Wed, 25 Oct 2023 22:04:37 -0700
Subject: [PATCH 18/50] handle quiz title field
---
.../assets/src/views/plan/CreateExamPage/CreateQuizSection.vue | 1 +
1 file changed, 1 insertion(+)
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 25bb10830b..ad0b77be76 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue
@@ -24,6 +24,7 @@
:autofocus="true"
:maxlength="100"
@blur="e => quizForge.updateQuiz({ title: e.target.value })"
+ @change="title => quizForge.updateQuiz({ title })"
/>
From f2b5f0ee62d8915ba6b63aa0528773c36438f114 Mon Sep 17 00:00:00 2001
From: Jacob Pierce
Date: Wed, 25 Oct 2023 22:22:02 -0700
Subject: [PATCH 19/50] update link to kds commit/pr
---
kolibri/core/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kolibri/core/package.json b/kolibri/core/package.json
index 2f6110f152..6744c698d4 100644
--- a/kolibri/core/package.json
+++ b/kolibri/core/package.json
@@ -21,7 +21,7 @@
"js-cookie": "^3.0.5",
"knuth-shuffle-seeded": "^1.0.6",
"kolibri-constants": "0.2.0",
- "kolibri-design-system": "https://github.com/learningequality/kolibri-design-system#83c9f97871ce7e09f0a6ebba023b126d51e91931",
+ "kolibri-design-system": "https://github.com/learningequality/kolibri-design-system#1f497630cbe15e35c777935e1d60632023885d50",
"lockr": "0.8.5",
"lodash": "^4.17.21",
"loglevel": "^1.8.1",
From 21e6893e6e35d8290367244c34363b11fee01e60 Mon Sep 17 00:00:00 2001
From: Jacob Pierce
Date: Wed, 15 Nov 2023 17:54:35 -0800
Subject: [PATCH 20/50] Ensure [Tab]-nav flow works properly when leaving
Options button
KDS commit 047379f579ad7067381a9576edc21abd12ad8378 is a req for this change
---
.../assets/src/views/plan/CreateExamPage/CreateQuizSection.vue | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
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 ad0b77be76..0f21e57384 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue
@@ -154,6 +154,7 @@
:disabled="false"
:hasIcons="true"
:options="activeSectionActions"
+ @tab="e => (e.preventDefault() || $refs.selectAllCheckbox.focus())"
@select="handleActiveSectionAction"
/>
@@ -161,7 +162,6 @@
-
expandedQuestionIds = items"
@@ -173,6 +173,7 @@
:layout12="{ span: 6 }"
>
Date: Wed, 15 Nov 2023 18:13:55 -0800
Subject: [PATCH 21/50] not debug by default
---
kolibri/plugins/coach/assets/src/composables/useQuizCreation.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kolibri/plugins/coach/assets/src/composables/useQuizCreation.js b/kolibri/plugins/coach/assets/src/composables/useQuizCreation.js
index 923fadeff1..db10418e6a 100644
--- a/kolibri/plugins/coach/assets/src/composables/useQuizCreation.js
+++ b/kolibri/plugins/coach/assets/src/composables/useQuizCreation.js
@@ -31,7 +31,7 @@ function isExercise(o) {
/**
* Composable function presenting primary interface for Quiz Creation
*/
-export default (DEBUG = true) => {
+export default (DEBUG = false) => {
// -----------
// Local state
// -----------
From 1ceee065e36925f009a63d2eafd22c5ad0f006bb Mon Sep 17 00:00:00 2001
From: Jacob Pierce
Date: Thu, 16 Nov 2023 15:09:41 -0800
Subject: [PATCH 22/50] fix eternal loading state when navigation routes
---
.../plan/CreateExamPage/CreateQuizSection.vue | 28 +++++++++++++++----
.../src/views/plan/CreateExamPage/index.vue | 4 +++
2 files changed, 27 insertions(+), 5 deletions(-)
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 0f21e57384..e7b78407e3 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/CreateQuizSection.vue
@@ -109,6 +109,28 @@
>
+
+
+
+
+ (e.preventDefault() || $refs.selectAllCheckbox.focus())"
+ @select="handleActiveSectionAction"
+ />
+
+
+
+
?
@@ -439,9 +461,6 @@
];
},
},
- mounted() {
- this.$store.dispatch('notLoading');
- },
methods: {
handleReplaceSelection() {
const section_id = get(this.quizForge.activeSection).section_id;
@@ -454,7 +473,6 @@
this.$router.replace({ path: 'new/' + section_id + '/edit' });
break;
case this.deleteSectionLabel$():
- console.log('Deleting, ', this.quizForge.activeSection.value.section_id);
this.quizForge.removeSection(this.quizForge.activeSection.value.section_id);
this.focusActiveSectionTab();
break;
@@ -698,7 +716,7 @@
}
/deep/ .overflow-tabs svg {
- top: 7px !important;
+ top: 5px !important;
}
.select-all-box {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
index fba6c77f1c..0ed911db4a 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
@@ -103,6 +103,10 @@
},
},
watch: {
+ $route: function() {
+ // FIXME Coach shouldn't be setting loading in a beforeEach here maybe?
+ this.$store.dispatch('notLoading');
+ },
filters(newVal) {
this.$router.push({
query: { ...this.$route.query, ...pickBy(newVal) },
From 4aa72d2a3f6f07fa97dcbde02b73bb517f9b6d92 Mon Sep 17 00:00:00 2001
From: Jacob Pierce
Date: Thu, 16 Nov 2023 15:35:12 -0800
Subject: [PATCH 23/50] update kds
---
kolibri/core/package.json | 2 +-
yarn.lock | 16 ++++++++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/kolibri/core/package.json b/kolibri/core/package.json
index 6744c698d4..d1d1535726 100644
--- a/kolibri/core/package.json
+++ b/kolibri/core/package.json
@@ -21,7 +21,7 @@
"js-cookie": "^3.0.5",
"knuth-shuffle-seeded": "^1.0.6",
"kolibri-constants": "0.2.0",
- "kolibri-design-system": "https://github.com/learningequality/kolibri-design-system#1f497630cbe15e35c777935e1d60632023885d50",
+ "kolibri-design-system": "https://github.com/learningequality/kolibri-design-system#f19ca3fc5677fc7f3b4cdbfee33950f5adde5290",
"lockr": "0.8.5",
"lodash": "^4.17.21",
"loglevel": "^1.8.1",
diff --git a/yarn.lock b/yarn.lock
index 83628e7410..bf2759e20f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7648,6 +7648,22 @@ kolibri-constants@0.2.0:
resolved "https://registry.yarnpkg.com/kolibri-constants/-/kolibri-constants-0.2.0.tgz#47c9d773894e23251ba5ac4db420822e45603142"
integrity sha512-WYDMGDzB9gNxRbpX1O2cGe1HrJvLvSZGwMuAv6dqrxJgPf7iO+Hi40/1CXjHM7nk5CRt+hn5bqnMzCBmj1omPA==
+"kolibri-design-system@https://github.com/learningequality/kolibri-design-system#f19ca3fc5677fc7f3b4cdbfee33950f5adde5290":
+ version "1.3.0"
+ resolved "https://github.com/learningequality/kolibri-design-system#f19ca3fc5677fc7f3b4cdbfee33950f5adde5290"
+ dependencies:
+ aphrodite "https://github.com/learningequality/aphrodite/"
+ autosize "^3.0.21"
+ css-element-queries "^1.2.0"
+ frame-throttle "^3.0.0"
+ fuzzysearch "^1.0.3"
+ keen-ui "^1.3.0"
+ lodash "^4.17.15"
+ popper.js "^1.14.6"
+ purecss "^0.6.2"
+ tippy.js "^4.2.1"
+ vue-intl "^3.1.0"
+
"kolibri-design-system@https://github.com/learningequality/kolibri-design-system#v2.0.0-beta1":
version "1.3.0"
resolved "https://github.com/learningequality/kolibri-design-system#13e539592fd87508cd32f60e4ad22c1ec320559b"
From b4f196f7b4da056e69af516e5e697ccf16a604d1 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Mon, 6 Nov 2023 22:20:15 +0300
Subject: [PATCH 24/50] fixed loading failure
---
.../coach/assets/src/views/plan/CreateExamPage/index.vue | 3 +++
1 file changed, 3 insertions(+)
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
index 0ed911db4a..8a12850b64 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
@@ -120,6 +120,9 @@
mounted() {
this.$store.dispatch('notLoading');
},
+ mounted() {
+ this.$store.dispatch('notLoading');
+ },
$trs: {
createNewExamLabel: {
message: 'Create new quiz',
From 63239d3a63be8d1eee7d7000d4206a2b06af7d26 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Tue, 7 Nov 2023 20:23:15 +0300
Subject: [PATCH 25/50] resource sidepanel header added
---
.../plan/CreateExamPage/ResourceSelection.vue | 61 ++++++++++++++++++-
1 file changed, 60 insertions(+), 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 86e9b8d5f0..4be8e0be68 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -1,14 +1,62 @@
-
+
+
+ {{ sectionSettings$() }}
+
+
+
+
+
+ Math
+
+
+
+ Early math
+
+
+
+
+
+ Addition and subtraction within 20A
+
+
+
+
+
+
From 5c97f6dd867023e75889121535335bd311457385 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Tue, 7 Nov 2023 22:09:49 +0300
Subject: [PATCH 26/50] added search component
---
.../plan/CreateExamPage/ResourceSelection.vue | 87 ++++++++++++-------
1 file changed, 54 insertions(+), 33 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 4be8e0be68..11011a1943 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -4,41 +4,42 @@
- {{ sectionSettings$() }}
+
+ Select folders or exercises from these channels
-
-
-
-
- Math
-
+ Select from bookmarks
+
+
-
- Early math
-
-
-
+
+ Addition and subtraction within 20A
+
+
+ Learn to add and subtract numbers that are 20 or less.
+
-
+
+
- Addition and subtraction within 20A
-
-
+ select all
+
+
@@ -47,9 +48,13 @@
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/QuizResourceCard.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/QuizResourceCard.vue
new file mode 100644
index 0000000000..947e479471
--- /dev/null
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/QuizResourceCard.vue
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Channel name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 11011a1943..f9607efce4 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -11,35 +11,45 @@
Select from bookmarks
+
+
-
- Addition and subtraction within 20A
-
-
- Learn to add and subtract numbers that are 20 or less.
-
-
-
-
-
- select all
-
-
+
@@ -49,11 +59,15 @@
import { enhancedQuizManagementStrings } from 'kolibri-common/strings/enhancedQuizManagementStrings';
import LessonsSearchBox from './../LessonResourceSelectionPage/SearchTools/LessonsSearchBox.vue';
+ import BookMarkedResource from './BookMarkedResource.vue';
+ // import ChannelCard from './ChannelCard.vue';
export default {
name: 'ResourceSelection',
components: {
LessonsSearchBox,
+ BookMarkedResource,
+ // ChannelCard,
},
setup() {
const { sectionSettings$ } = enhancedQuizManagementStrings;
@@ -81,20 +95,4 @@
font-weight:600;
font-size: 1.4em;
}
-.section-topic-style{
- font-weight:600;
- font-size: 1.4em;
-}
-.section-subtopic-style{
- font-size: 1.2em;
-}
-.select-all-style{
- font-size:1.2em;
- font-weight:600;
- display: inline-flex;
- justify-content: space-between;
-}
-.space-content-left{
- margin-left: .5em;
-}
From 827c0b6a3e2eb58214c1e4db1ea91344d8663c98 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Thu, 9 Nov 2023 01:57:09 +0300
Subject: [PATCH 28/50] adds channel cards to select resource side panel
---
.../plan/CreateExamPage/ResourceSelection.vue | 139 ++++++++++++++----
1 file changed, 110 insertions(+), 29 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 f9607efce4..073be07c44 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -18,38 +18,58 @@
placeholder="search by keyword"
searchTerm="searchTerm"
:inputPlaceHolderStyle="inputPlaceHolderStyle"
- style="margin-top:1em;"
+ style="margin-top:1em;margin-bottom:1em;"
@searchterm="search"
/>
-
-
+
+
+
@@ -57,17 +77,22 @@
+
+
+
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/QuizResourceCard.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/QuizResourceCard.vue
index 947e479471..b80354a763 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/QuizResourceCard.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/QuizResourceCard.vue
@@ -27,14 +27,12 @@
Channel name
-
+
@@ -45,12 +43,12 @@
-
From 53512bbd17ba6ddc8841d7cec25325dc5f5efd10 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Fri, 17 Nov 2023 21:58:45 +0300
Subject: [PATCH 34/50] added the bookmark card
---
.../CreateExamPage/BookMarkedResource.vue | 267 +++---------------
.../plan/CreateExamPage/ResourceSelection.vue | 191 +++++--------
.../strings/enhancedQuizManagementStrings.js | 3 +
3 files changed, 115 insertions(+), 346 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
index 28b4debe43..d26f2a8ff2 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
@@ -2,83 +2,28 @@
@@ -86,125 +31,41 @@
diff --git a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
index c3b0a009a9..8daeee61f0 100644
--- a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
+++ b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
@@ -71,6 +71,9 @@ export const enhancedQuizManagementStrings = createTranslator('EnhancedQuizManag
selectFoldersOrExercises: {
message: 'Select folders or exercises from these channels',
},
+ bookmarksLabel: {
+ message: 'Bookmark',
+ },
numberOfSelectedBookmarks: {
message: '{ count, number } { count, plural, one { bookmark } other { bookmarks }}',
},
From c683194b62a6c65c828b08efd848e5c679088e24 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Tue, 21 Nov 2023 20:19:00 +0300
Subject: [PATCH 35/50] replaced quizforge data with composable
---
.../assets/src/composables/useResources.js | 33 ++++++++
.../CreateExamPage/BookMarkedResource.vue | 64 +++++++--------
.../plan/CreateExamPage/ResourceSelection.vue | 80 ++-----------------
3 files changed, 72 insertions(+), 105 deletions(-)
create mode 100644 kolibri/plugins/coach/assets/src/composables/useResources.js
diff --git a/kolibri/plugins/coach/assets/src/composables/useResources.js b/kolibri/plugins/coach/assets/src/composables/useResources.js
new file mode 100644
index 0000000000..817a317237
--- /dev/null
+++ b/kolibri/plugins/coach/assets/src/composables/useResources.js
@@ -0,0 +1,33 @@
+import { ref, onMounted } from 'kolibri.lib.vueCompositionApi';
+import { ChannelResource, ContentNodeResource as bookMarkedResource } from 'kolibri.resources';
+
+export function useResources() {
+ const resources = ref(null);
+ const channels = ref([]);
+ const bookmarks = ref([]);
+
+ function fetchChannelResource() {
+ ChannelResource.fetchCollection({ params: { has_exercises: true, available: true } }).then(
+ response => {
+ channels.value = response;
+ }
+ );
+ }
+
+ function fetchBookMarkedResource() {
+ bookMarkedResource.fetchBookmarks({ params: { limit: 25, available: true } }).then(data => {
+ bookmarks.value = data.results ? data.results : [];
+ });
+ }
+
+ onMounted(() => {
+ fetchChannelResource();
+ fetchBookMarkedResource();
+ });
+
+ return {
+ resources,
+ channels,
+ bookmarks,
+ };
+}
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
index d26f2a8ff2..732b6f772c 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
@@ -3,27 +3,32 @@
@@ -32,7 +37,6 @@
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 e6ebca0301..c4e498c7e6 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -12,8 +12,10 @@
Select from bookmarks
import { ContentNodeKinds, ContentNodeResource } from 'kolibri.coreVue.vuex.constants';
- import { ContentNodeResource as bookMarkedResource } from 'kolibri.resources';
import { enhancedQuizManagementStrings } from 'kolibri-common/strings/enhancedQuizManagementStrings';
import every from 'lodash/every';
import pickBy from 'lodash/pickBy';
import { PageNames } from '../../../constants';
import { LessonsPageNames } from '../../../constants/lessonsConstants';
+ import { useResources } from '../../../composables/useResources';
import LessonsSearchBox from './../LessonResourceSelectionPage/SearchTools/LessonsSearchBox.vue';
import BookMarkedResource from './BookMarkedResource.vue';
import ContentCardList from './../LessonResourceSelectionPage/ContentCardList.vue';
- // import LessonContentCard from './../LessonResourceSelectionPage/LessonContentCard/index.vue';
- // import ResourceSelection from './ResourceSelection.vue';
- // import ResourceSelectionBreadcrumbs from './../../../views/plan/LessonResourceS
- // electionPage/SearchTools/ResourceSelectionBreadcrumbs.vue'
export default {
name: 'ResourceSelection',
@@ -66,23 +64,21 @@
LessonsSearchBox,
BookMarkedResource,
ContentCardList,
- // ResourceSelection,
- // ResourceSelectionBreadcrumbs,
- // LessonContentCard,
},
inject: ['quizForge'],
setup() {
const { sectionSettings$ } = enhancedQuizManagementStrings;
+ const { channels, bookmarks } = useResources();
return {
sectionSettings$,
+ channels,
+ bookmarks,
};
},
data() {
return {
viewMoreButtonState: 'no_more_results',
- // contentHasCheckbox: () => false,
- // contentIsSelected: () => '',
searchTerm: '',
search: '',
filters: {
@@ -91,29 +87,9 @@
role: this.$route.query.role || null,
},
visibleResources: [],
- bookmarks: [],
};
},
computed: {
- // filteredContentList() {
- // const { role } = this.filters;
- // if (!this.inSearchMode) {
- // return this.quizForge.channels.value;
- // }
- // const list = this.quizForge.channels.value
- // ? this.quizForge.channels.value
- // : this.bookmarksList;
- // return list.filter(contentNode => {
- // let passesFilters = true;
- // if (role === 'nonCoach') {
- // passesFilters = passesFilters && contentNode.num_coach_contents === 0;
- // }
- // if (role === 'coach') {
- // passesFilters = passesFilters && contentNode.num_coach_contents > 0;
- // }
- // return passesFilters;
- // });
- // },
inSearchMode() {
return this.pageName === LessonsPageNames.SELECTION_SEARCH;
},
@@ -190,16 +166,6 @@
});
}
},
- created() {
- console.log(this.quizForge.channels.value);
- bookMarkedResource.fetchBookmarks({ params: { limit: 25, available: true } }).then(data => {
- this.more = data.more;
- this.bookmarks = data.results ? data.results : [];
- console.log(this.bookmarks);
- this.loading = false;
- this.fetchContentNodeProgress({ ids: this.bookmarks.map(b => b.id) });
- });
- },
mounted() {
if (this.quizForge.channels.value.length > 0) {
this.visibleResources = this.quizForge.channels.value;
@@ -212,19 +178,7 @@
focusFirstEl() {
this.$refs.textbox.focus();
},
- // selectionMetadata(content) {
- // if (content.kind === ContentNodeKinds.TOPIC) {
- // const count = content.exercises.filter(exercise =>
- // Boolean(this.selectedExercises[exercise.id])
- // ).length;
- // if (count === 0) {
- // return '';
- // }
- // const total = content.exercises.length;
- // return this.$tr('total_number', { count, total });
- // }
- // return '';
- // },
+
contentLink(content) {
if (!content.is_leaf) {
return {
@@ -304,24 +258,6 @@
});
});
},
- // filteredquizForge.channels.value() {
- // const { role } = this.filters;
- // if (!this.inSearchMode) {
- // return this.quizForge.channels.value;
- // }
- // const list = this.quizForge.channels.value ?
- // this.quizForge.channels.value : this.bookmarksList;
- // return list.filter(contentNode => {
- // let passesFilters = true;
- // if (role === 'nonCoach') {
- // passesFilters = passesFilters && contentNode.num_coach_contents === 0;
- // }
- // if (role === 'coach') {
- // passesFilters = passesFilters && contentNode.num_coach_contents > 0;
- // }
- // return passesFilters;
- // });
- // },
},
};
From 59ab6dd479021a073c0da28927e4cba9e1f5da9d Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Tue, 21 Nov 2023 20:31:05 +0300
Subject: [PATCH 36/50] cleanedup bookmarkicon area
---
.../CreateExamPage/BookMarkedResource.vue | 53 ++++++++-----------
1 file changed, 23 insertions(+), 30 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
index 732b6f772c..ccb3330aa1 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
@@ -3,32 +3,29 @@
@@ -109,10 +106,6 @@
text-decoration: none;
}
- .thumb-area {
- margin-bottom: 16px;
- }
-
.text-area {
margin-bottom: $footer-height;
}
From 8ebe621f28deb1fcd420b41290718f33650595d6 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Wed, 22 Nov 2023 09:21:40 +0300
Subject: [PATCH 37/50] add show resourc component
---
.../coach/assets/src/constants/index.js | 1 +
.../coach/assets/src/routes/planExamRoutes.js | 4 +
.../CreateExamPage/BookMarkedResource.vue | 60 ++++++-----
.../plan/CreateExamPage/ResourceSelection.vue | 16 ++-
.../plan/CreateExamPage/SectionSidePanel.vue | 3 +
.../ShowBookMarkedResources.vue | 102 ++++++++++++++++++
6 files changed, 159 insertions(+), 27 deletions(-)
create mode 100644 kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue
diff --git a/kolibri/plugins/coach/assets/src/constants/index.js b/kolibri/plugins/coach/assets/src/constants/index.js
index 4dae241107..b9f407758a 100644
--- a/kolibri/plugins/coach/assets/src/constants/index.js
+++ b/kolibri/plugins/coach/assets/src/constants/index.js
@@ -17,6 +17,7 @@ export const PageNames = {
QUIZ_REPLACE_QUESTIONS: 'QUIZ_REPLACE_QUESTIONS',
QUIZ_SELECT_RESOURCES: 'QUIZ_SELECT_RESOURCES',
SELECT_FROM_RESOURCE:'SELECT_FROM_RESOURCE',
+ BOOK_MARKED_RESOURCES:'BOOK_MARKED_RESOURCES',
/** TODO Remove unused */
EXAM_CREATION_TOPIC: 'EXAM_CREATION_TOPIC',
diff --git a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
index 4ac868046c..c41c591254 100644
--- a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
+++ b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
@@ -57,6 +57,10 @@ export default [
}
]
},
+ {
+ name: PageNames.BOOK_MARKED_RESOURCES,
+ path: ':section_id/book-marked-resources',
+ },
],
},
{
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
index ccb3330aa1..3ec1358e47 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
@@ -3,29 +3,34 @@
@@ -54,6 +59,10 @@
type: Number,
required: true,
},
+ to:{
+ type:Object,
+ required:true,
+ }
},
computed: {
bookMarkBackgroundColor() {
@@ -62,6 +71,9 @@
};
},
},
+ mounted(){
+ console.log(this.$route.params);
+ }
};
@@ -91,7 +103,7 @@
.card {
position: relative;
vertical-align: top;
- border-radius: 8px;
+ border-radius: 2px;
transition: box-shadow $core-time ease;
&:focus {
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 c4e498c7e6..2d95d65b9c 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -15,6 +15,7 @@
v-if="bookmarks.length > 0"
kind="bookmark"
:isMobile="true"
+ :to="to"
:bookMarkedResoures="bookmarks.length"
/>
@@ -139,6 +140,15 @@
content => !this.contentIsDirectoryKind(content) && !this.contentIsInLesson(content)
);
},
+ to(){
+ return {
+ name: PageNames.BOOK_MARKED_RESOURCES,
+ params:{
+ classId: this.$route.params.classId,
+ section_id: this.$route.params.section_id,
+ }
+ }
+ }
},
watch: {
@@ -157,9 +167,9 @@
},
},
beforeRouteEnter(to, from, next) {
- console.log(to);
- console.log(from);
- console.log(to.params.topic_id);
+ // console.log(to);
+ // console.log(from);
+ // console.log(to.params.topic_id);
if (to.params.topic_id) {
this.showChannelQuizCreationTopicPage(this.$store, to.params).then(() => {
next();
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
index 0d88da67d3..0ae0338da1 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
@@ -23,11 +23,13 @@
import SectionEditor from './SectionEditor';
import ReplaceQuestions from './ReplaceQuestions';
import ResourceSelection from './ResourceSelection';
+ import ShowBookMarkedResources from './ShowBookMarkedResources.vue';
const pageNameComponentMap = {
[PageNames.QUIZ_SECTION_EDITOR]: SectionEditor,
[PageNames.QUIZ_REPLACE_QUESTIONS]: ReplaceQuestions,
[PageNames.QUIZ_SELECT_RESOURCES]: ResourceSelection,
+ [PageNames.BOOK_MARKED_RESOURCES]:ShowBookMarkedResources,
};
export default {
@@ -38,6 +40,7 @@
ReplaceQuestions,
ResourceSelection,
ResourceSelectionBreadcrumbs,
+ ShowBookMarkedResources,
},
inject: ['quizForge'],
data() {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue
new file mode 100644
index 0000000000..9ed71781b5
--- /dev/null
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
From b14457f4a848e4ff38a623ed6325cb67121bc41e Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Wed, 22 Nov 2023 18:10:42 +0300
Subject: [PATCH 38/50] implement content filtering for select resource side
panel
---
.../assets/src/composables/useResources.js | 76 ++++++++++++++++++-
.../coach/assets/src/routes/planExamRoutes.js | 8 ++
.../ShowBookMarkedResources.vue | 2 +-
3 files changed, 83 insertions(+), 3 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/composables/useResources.js b/kolibri/plugins/coach/assets/src/composables/useResources.js
index 817a317237..ca9704fac1 100644
--- a/kolibri/plugins/coach/assets/src/composables/useResources.js
+++ b/kolibri/plugins/coach/assets/src/composables/useResources.js
@@ -1,5 +1,7 @@
import { ref, onMounted } from 'kolibri.lib.vueCompositionApi';
-import { ChannelResource, ContentNodeResource as bookMarkedResource } from 'kolibri.resources';
+import { ChannelResource,ContentNodeResource} from 'kolibri.resources';
+import { ContentNodeKinds } from 'kolibri.coreVue.vuex.constants';
+import { getContentNodeThumbnail } from 'kolibri.utils.contentNode';
export function useResources() {
const resources = ref(null);
@@ -15,14 +17,84 @@ export function useResources() {
}
function fetchBookMarkedResource() {
- bookMarkedResource.fetchBookmarks({ params: { limit: 25, available: true } }).then(data => {
+ ContentNodeResource.fetchBookmarks({ params: { limit: 25, available: true } }).then(data => {
bookmarks.value = data.results ? data.results : [];
});
}
+ function _getTopicsWithExerciseDescendants(topicIds = []) {
+ return new Promise(resolve => {
+ if (!topicIds.length) {
+ resolve([]);
+ return;
+ }
+ const topicsNumAssessmentDescendantsPromise = ContentNodeResource.fetchDescendantsAssessments(
+ topicIds
+ );
+
+ topicsNumAssessmentDescendantsPromise.then(response => {
+ const topicsWithExerciseDescendants = [];
+ response.data.forEach(descendantAssessments => {
+ if (descendantAssessments.num_assessments > 0) {
+ topicsWithExerciseDescendants.push({
+ id: descendantAssessments.id,
+ numAssessments: descendantAssessments.num_assessments,
+ exercises: [],
+ });
+ }
+ });
+
+ ContentNodeResource.fetchDescendants(
+ topicsWithExerciseDescendants.map(topic => topic.id),
+ {
+ descendant_kind: ContentNodeKinds.EXERCISE,
+ }
+ ).then(response => {
+ response.data.forEach(exercise => {
+ const topic = topicsWithExerciseDescendants.find(t => t.id === exercise.ancestor_id);
+ topic.exercises.push(exercise);
+ });
+ resolve(topicsWithExerciseDescendants);
+ });
+ });
+ });
+ }
+
+ function filterAndAnnotateContentList(childNodes) {
+ return new Promise(resolve => {
+ const childTopics = childNodes.filter(({ kind }) => kind === ContentNodeKinds.TOPIC);
+ const topicIds = childTopics.map(({ id }) => id);
+ const topicsThatHaveExerciseDescendants = _getTopicsWithExerciseDescendants(topicIds);
+
+ topicsThatHaveExerciseDescendants.then(topics => {
+ const childNodesWithExerciseDescendants = childNodes
+ .map(childNode => {
+ const index = topics.findIndex(topic => topic.id === childNode.id);
+ if (index !== -1) {
+ return { ...childNode, ...topics[index] };
+ }
+ return childNode;
+ })
+ .filter(childNode => {
+ if (childNode.kind === ContentNodeKinds.TOPIC && (childNode.numAssessments || 0) < 1) {
+ return false;
+ }
+ return true;
+ });
+
+ const contentList = childNodesWithExerciseDescendants.map(node => ({
+ ...node,
+ thumbnail: getContentNodeThumbnail(node),
+ }));
+ resolve(contentList);
+ });
+ });
+ }
+
onMounted(() => {
fetchChannelResource();
fetchBookMarkedResource();
+ filterAndAnnotateContentList()
});
return {
diff --git a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
index c41c591254..54ae6b9cdd 100644
--- a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
+++ b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
@@ -47,6 +47,8 @@ export default [
path: ':section_id/replace-questions',
},
{
+ // this is basically show how the routing works once you in the select resources page and bookmarked resources page
+ // once you are in the bookmark resources page the only thing that we are interested in is the topic Id that always get updated
name: PageNames.QUIZ_SELECT_RESOURCES,
path: ':section_id/select-resources',
@@ -60,6 +62,12 @@ export default [
{
name: PageNames.BOOK_MARKED_RESOURCES,
path: ':section_id/book-marked-resources',
+ children:[
+ {
+ name:PageNames.SELECT_FROM_RESOURCE,
+ path:':topic_id',
+ }
+ ]
},
],
},
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue
index 9ed71781b5..7cdcd67905 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue
@@ -1,4 +1,4 @@
-
+
Date: Wed, 22 Nov 2023 19:36:48 +0300
Subject: [PATCH 39/50] displays boomarked resources
---
.../assets/src/composables/useResources.js | 143 ++++++------
.../ShowBookMarkedResources.vue | 205 ++++++++++--------
2 files changed, 187 insertions(+), 161 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/composables/useResources.js b/kolibri/plugins/coach/assets/src/composables/useResources.js
index ca9704fac1..1c549cfae6 100644
--- a/kolibri/plugins/coach/assets/src/composables/useResources.js
+++ b/kolibri/plugins/coach/assets/src/composables/useResources.js
@@ -1,7 +1,7 @@
import { ref, onMounted } from 'kolibri.lib.vueCompositionApi';
-import { ChannelResource,ContentNodeResource} from 'kolibri.resources';
-import { ContentNodeKinds } from 'kolibri.coreVue.vuex.constants';
-import { getContentNodeThumbnail } from 'kolibri.utils.contentNode';
+import { ChannelResource, ContentNodeResource } from 'kolibri.resources';
+// import { ContentNodeKinds } from 'kolibri.coreVue.vuex.constants';
+// import { getContentNodeThumbnail } from 'kolibri.utils.contentNode';
export function useResources() {
const resources = ref(null);
@@ -22,79 +22,80 @@ export function useResources() {
});
}
- function _getTopicsWithExerciseDescendants(topicIds = []) {
- return new Promise(resolve => {
- if (!topicIds.length) {
- resolve([]);
- return;
- }
- const topicsNumAssessmentDescendantsPromise = ContentNodeResource.fetchDescendantsAssessments(
- topicIds
- );
-
- topicsNumAssessmentDescendantsPromise.then(response => {
- const topicsWithExerciseDescendants = [];
- response.data.forEach(descendantAssessments => {
- if (descendantAssessments.num_assessments > 0) {
- topicsWithExerciseDescendants.push({
- id: descendantAssessments.id,
- numAssessments: descendantAssessments.num_assessments,
- exercises: [],
- });
- }
- });
-
- ContentNodeResource.fetchDescendants(
- topicsWithExerciseDescendants.map(topic => topic.id),
- {
- descendant_kind: ContentNodeKinds.EXERCISE,
- }
- ).then(response => {
- response.data.forEach(exercise => {
- const topic = topicsWithExerciseDescendants.find(t => t.id === exercise.ancestor_id);
- topic.exercises.push(exercise);
- });
- resolve(topicsWithExerciseDescendants);
- });
- });
- });
- }
-
- function filterAndAnnotateContentList(childNodes) {
- return new Promise(resolve => {
- const childTopics = childNodes.filter(({ kind }) => kind === ContentNodeKinds.TOPIC);
- const topicIds = childTopics.map(({ id }) => id);
- const topicsThatHaveExerciseDescendants = _getTopicsWithExerciseDescendants(topicIds);
-
- topicsThatHaveExerciseDescendants.then(topics => {
- const childNodesWithExerciseDescendants = childNodes
- .map(childNode => {
- const index = topics.findIndex(topic => topic.id === childNode.id);
- if (index !== -1) {
- return { ...childNode, ...topics[index] };
- }
- return childNode;
- })
- .filter(childNode => {
- if (childNode.kind === ContentNodeKinds.TOPIC && (childNode.numAssessments || 0) < 1) {
- return false;
- }
- return true;
- });
-
- const contentList = childNodesWithExerciseDescendants.map(node => ({
- ...node,
- thumbnail: getContentNodeThumbnail(node),
- }));
- resolve(contentList);
- });
- });
+ // function _getTopicsWithExerciseDescendants(topicIds = []) {
+ // return new Promise(resolve => {
+ // if (!topicIds.length) {
+ // resolve([]);
+ // return;
+ // }
+ // const topicsNumAssessmentDescendantsPromise
+ // = ContentNodeResource.fetchDescendantsAssessments(
+ // topicIds
+ // );
+
+ // topicsNumAssessmentDescendantsPromise.then(response => {
+ // const topicsWithExerciseDescendants = [];
+ // response.data.forEach(descendantAssessments => {
+ // if (descendantAssessments.num_assessments > 0) {
+ // topicsWithExerciseDescendants.push({
+ // id: descendantAssessments.id,
+ // numAssessments: descendantAssessments.num_assessments,
+ // exercises: [],
+ // });
+ // }
+ // });
+
+ // ContentNodeResource.fetchDescendants(
+ // topicsWithExerciseDescendants.map(topic => topic.id),
+ // {
+ // descendant_kind: ContentNodeKinds.EXERCISE,
+ // }
+ // ).then(response => {
+ // response.data.forEach(exercise => {
+ // const topic = topicsWithExerciseDescendants.find(t =>
+ // t.id === exercise.ancestor_id);
+ // topic.exercises.push(exercise);
+ // });
+ // resolve(topicsWithExerciseDescendants);
+ // });
+ // });
+ // });
+ // }
+
+ function filterAndAnnotateContentList(/*childNodes*/) {
+ // return new Promise(resolve => {
+ // const childTopics = childNodes.filter(({ kind }) => kind === ContentNodeKinds.TOPIC);
+ // const topicIds = childTopics.map(({ id }) => id);
+ // const topicsThatHaveExerciseDescendants = _getTopicsWithExerciseDescendants(topicIds);
+ // topicsThatHaveExerciseDescendants.then(topics => {
+ // const childNodesWithExerciseDescendants = childNodes
+ // .map(childNode => {
+ // const index = topics.findIndex(topic => topic.id === childNode.id);
+ // if (index !== -1) {
+ // return { ...childNode, ...topics[index] };
+ // }
+ // return childNode;
+ // })
+ // .filter(childNode => {
+ // if (childNode.kind === ContentNodeKinds.TOPIC &&
+ // (childNode.numAssessments || 0) < 1) {
+ // return false;
+ // }
+ // return true;
+ // });
+ // const contentList = childNodesWithExerciseDescendants.map(node => ({
+ // ...node,
+ // thumbnail: getContentNodeThumbnail(node),
+ // }));
+ // resolve(contentList);
+ // });
+ // } );
}
onMounted(() => {
fetchChannelResource();
fetchBookMarkedResource();
- filterAndAnnotateContentList()
+ filterAndAnnotateContentList();
});
return {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue
index 7cdcd67905..3a10e84a89 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ShowBookMarkedResources.vue
@@ -1,102 +1,127 @@
-
-
+
\ No newline at end of file
+
From 776ba5c76916e0e7591100323f83fa4e94c936bd Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Thu, 23 Nov 2023 18:07:50 +0300
Subject: [PATCH 40/50] added the component for the channels
---
.../plan/CreateExamPage/ResourceSelection.vue | 18 +-
.../plan/CreateExamPage/SectionSidePanel.vue | 3 +
.../plan/CreateExamPage/SelectedChannel.vue | 177 ++++++++++++++++++
.../strings/enhancedQuizManagementStrings.js | 3 +
4 files changed, 197 insertions(+), 4 deletions(-)
create mode 100644 kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
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 2d95d65b9c..8300c6b065 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -4,12 +4,12 @@
-
- Select folders or exercises from these channels
+ {{ selectFoldersOrExercises$() }}
- Select from bookmarks
+ {{ selectFromBookmarks$() }}
+
+
+
+ {{ selectFoldersOrExercises$() }}
+
+
+
channel name
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
index 8daeee61f0..5cdc810bfa 100644
--- a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
+++ b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
@@ -71,6 +71,9 @@ export const enhancedQuizManagementStrings = createTranslator('EnhancedQuizManag
selectFoldersOrExercises: {
message: 'Select folders or exercises from these channels',
},
+ selectFromBookmarks:{
+ message:"Select from bookmarks"
+ },
bookmarksLabel: {
message: 'Bookmark',
},
From 75ec4ecbb12402606015f8177f988900b674dad4 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Thu, 23 Nov 2023 18:13:28 +0300
Subject: [PATCH 41/50] added the component for the channels
---
.../plan/CreateExamPage/ResourceSelection.vue | 14 +-
.../plan/CreateExamPage/SectionSidePanel.vue | 4 +-
.../plan/CreateExamPage/SelectedChannel.vue | 318 +++++++++---------
.../strings/enhancedQuizManagementStrings.js | 4 +-
4 files changed, 171 insertions(+), 169 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 8300c6b065..c6229d20cf 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -68,7 +68,7 @@
},
inject: ['quizForge'],
setup() {
- const {
+ const {
sectionSettings$,
selectFoldersOrExercises$,
selectFromBookmarks$,
@@ -147,15 +147,15 @@
content => !this.contentIsDirectoryKind(content) && !this.contentIsInLesson(content)
);
},
- to(){
+ to() {
return {
name: PageNames.BOOK_MARKED_RESOURCES,
- params:{
+ params: {
classId: this.$route.params.classId,
section_id: this.$route.params.section_id,
- }
- }
- }
+ },
+ };
+ },
},
watch: {
@@ -204,7 +204,7 @@
params: {
topic_id: content.id,
classId: this.$route.params.classId,
- section_id: this.$route.params.section_id
+ section_id: this.$route.params.section_id,
},
};
}
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
index 33fa3b9d6f..724128cf60 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
@@ -30,8 +30,8 @@
[PageNames.QUIZ_SECTION_EDITOR]: SectionEditor,
[PageNames.QUIZ_REPLACE_QUESTIONS]: ReplaceQuestions,
[PageNames.QUIZ_SELECT_RESOURCES]: ResourceSelection,
- [PageNames.BOOK_MARKED_RESOURCES]:ShowBookMarkedResources,
- [PageNames.SELECT_FROM_RESOURCE]:SelectedChannel,
+ [PageNames.BOOK_MARKED_RESOURCES]: ShowBookMarkedResources,
+ [PageNames.SELECT_FROM_RESOURCE]: SelectedChannel,
};
export default {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
index bad43a04f9..5216a4c580 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
@@ -1,177 +1,179 @@
+
+
-
-
- {{ selectFoldersOrExercises$() }}
-
+
+ {{ selectFoldersOrExercises$() }}
+
-
channel name
+
channel name
-
+
+
+
+
+
-
-
-
\ No newline at end of file
+ toggleSelected({ content, checked }) {
+ if (checked) {
+ this.addToSelectedResources(content);
+ } else {
+ this.removeFromSelectedResources([content]);
+ }
+ },
+ handleMoreResults() {
+ this.fetchAdditionalSearchResults({
+ searchTerm: '',
+ kind: this.filters.kind,
+ channelId: this.filters.channel,
+ })
+ .then(() => {
+ this.moreResultsState = null;
+ })
+ .catch(() => {
+ this.moreResultsState = 'error';
+ });
+ },
+ },
+ };
+
+
diff --git a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
index 5cdc810bfa..4e06fcdedb 100644
--- a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
+++ b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
@@ -71,8 +71,8 @@ export const enhancedQuizManagementStrings = createTranslator('EnhancedQuizManag
selectFoldersOrExercises: {
message: 'Select folders or exercises from these channels',
},
- selectFromBookmarks:{
- message:"Select from bookmarks"
+ selectFromBookmarks: {
+ message: 'Select from bookmarks',
},
bookmarksLabel: {
message: 'Bookmark',
From 300b355733d4868a68fdb556ff9f079e11543c35 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Mon, 27 Nov 2023 23:43:27 +0300
Subject: [PATCH 42/50] added dragging feature
---
.../assets/src/composables/useResources.js | 169 +++--
.../coach/assets/src/routes/planExamRoutes.js | 22 +-
.../CreateExamPage/BookMarkedResource.vue | 11 +-
.../plan/CreateExamPage/ResourceSelection.vue | 653 +++++++++++++-----
.../plan/CreateExamPage/SectionSidePanel.vue | 1 -
.../src/views/plan/CreateExamPage/index.vue | 3 +-
6 files changed, 596 insertions(+), 263 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/composables/useResources.js b/kolibri/plugins/coach/assets/src/composables/useResources.js
index 1c549cfae6..aed6a874d0 100644
--- a/kolibri/plugins/coach/assets/src/composables/useResources.js
+++ b/kolibri/plugins/coach/assets/src/composables/useResources.js
@@ -1,17 +1,34 @@
import { ref, onMounted } from 'kolibri.lib.vueCompositionApi';
import { ChannelResource, ContentNodeResource } from 'kolibri.resources';
-// import { ContentNodeKinds } from 'kolibri.coreVue.vuex.constants';
-// import { getContentNodeThumbnail } from 'kolibri.utils.contentNode';
+import { ContentNodeKinds } from 'kolibri.coreVue.vuex.constants';
+import { getContentNodeThumbnail } from 'kolibri.utils.contentNode';
+import { set } from '@vueuse/core';
+import store from 'kolibri.coreVue.vuex.store';
+
+// import { store } from 'vuex';
export function useResources() {
const resources = ref(null);
const channels = ref([]);
const bookmarks = ref([]);
+ const contentList = ref([]);
function fetchChannelResource() {
ChannelResource.fetchCollection({ params: { has_exercises: true, available: true } }).then(
response => {
- channels.value = response;
+ // channels.value = response;
+ set(
+ channels,
+ response.map(chnl => {
+ return {
+ ...chnl,
+ id: chnl.root,
+ title: chnl.name,
+ kind: ContentNodeKinds.CHANNEL,
+ is_leaf: false,
+ };
+ })
+ );
}
);
}
@@ -22,85 +39,101 @@ export function useResources() {
});
}
- // function _getTopicsWithExerciseDescendants(topicIds = []) {
- // return new Promise(resolve => {
- // if (!topicIds.length) {
- // resolve([]);
- // return;
- // }
- // const topicsNumAssessmentDescendantsPromise
- // = ContentNodeResource.fetchDescendantsAssessments(
- // topicIds
- // );
+ function _getTopicsWithExerciseDescendants(topicIds = []) {
+ return new Promise(resolve => {
+ if (!topicIds.length) {
+ resolve([]);
+ return;
+ }
+ const topicsNumAssessmentDescendantsPromise = ContentNodeResource.fetchDescendantsAssessments(
+ topicIds
+ );
+
+ topicsNumAssessmentDescendantsPromise.then(response => {
+ const topicsWithExerciseDescendants = [];
+ response.data.forEach(descendantAssessments => {
+ if (descendantAssessments.num_assessments > 0) {
+ topicsWithExerciseDescendants.push({
+ id: descendantAssessments.id,
+ numAssessments: descendantAssessments.num_assessments,
+ exercises: [],
+ });
+ }
+ });
- // topicsNumAssessmentDescendantsPromise.then(response => {
- // const topicsWithExerciseDescendants = [];
- // response.data.forEach(descendantAssessments => {
- // if (descendantAssessments.num_assessments > 0) {
- // topicsWithExerciseDescendants.push({
- // id: descendantAssessments.id,
- // numAssessments: descendantAssessments.num_assessments,
- // exercises: [],
- // });
- // }
- // });
+ ContentNodeResource.fetchDescendants(
+ topicsWithExerciseDescendants.map(topic => topic.id),
+ {
+ descendant_kind: ContentNodeKinds.EXERCISE,
+ }
+ ).then(response => {
+ response.data.forEach(exercise => {
+ const topic = topicsWithExerciseDescendants.find(t => t.id === exercise.ancestor_id);
+ topic.exercises.push(exercise);
+ });
+ resolve(topicsWithExerciseDescendants);
+ });
+ });
+ });
+ }
- // ContentNodeResource.fetchDescendants(
- // topicsWithExerciseDescendants.map(topic => topic.id),
- // {
- // descendant_kind: ContentNodeKinds.EXERCISE,
- // }
- // ).then(response => {
- // response.data.forEach(exercise => {
- // const topic = topicsWithExerciseDescendants.find(t =>
- // t.id === exercise.ancestor_id);
- // topic.exercises.push(exercise);
- // });
- // resolve(topicsWithExerciseDescendants);
- // });
- // });
- // });
- // }
+ function filterAndAnnotateContentList(childNodes) {
+ return new Promise(resolve => {
+ if (childNodes) {
+ const childTopics = childNodes.filter(({ kind }) => kind === ContentNodeKinds.TOPIC);
+ const topicIds = childTopics.map(({ id }) => id);
+ const topicsThatHaveExerciseDescendants = _getTopicsWithExerciseDescendants(topicIds);
+ topicsThatHaveExerciseDescendants.then(topics => {
+ const childNodesWithExerciseDescendants = childNodes
+ .map(childNode => {
+ const index = topics.findIndex(topic => topic.id === childNode.id);
+ if (index !== -1) {
+ return { ...childNode, ...topics[index] };
+ }
+ return childNode;
+ })
+ .filter(childNode => {
+ if (
+ childNode.kind === ContentNodeKinds.TOPIC &&
+ (childNode.numAssessments || 0) < 1
+ ) {
+ return false;
+ }
+ return true;
+ });
+ const contentList = childNodesWithExerciseDescendants.map(node => ({
+ ...node,
+ thumbnail: getContentNodeThumbnail(node),
+ }));
+ resolve(contentList);
+ });
+ }
+ });
+ }
- function filterAndAnnotateContentList(/*childNodes*/) {
- // return new Promise(resolve => {
- // const childTopics = childNodes.filter(({ kind }) => kind === ContentNodeKinds.TOPIC);
- // const topicIds = childTopics.map(({ id }) => id);
- // const topicsThatHaveExerciseDescendants = _getTopicsWithExerciseDescendants(topicIds);
- // topicsThatHaveExerciseDescendants.then(topics => {
- // const childNodesWithExerciseDescendants = childNodes
- // .map(childNode => {
- // const index = topics.findIndex(topic => topic.id === childNode.id);
- // if (index !== -1) {
- // return { ...childNode, ...topics[index] };
- // }
- // return childNode;
- // })
- // .filter(childNode => {
- // if (childNode.kind === ContentNodeKinds.TOPIC &&
- // (childNode.numAssessments || 0) < 1) {
- // return false;
- // }
- // return true;
- // });
- // const contentList = childNodesWithExerciseDescendants.map(node => ({
- // ...node,
- // thumbnail: getContentNodeThumbnail(node),
- // }));
- // resolve(contentList);
- // });
- // } );
+ function filterLessonResource(lessonId) {
+ store
+ .dispatch('lessonSummary/saveLessonResources', {
+ lessonId: lessonId,
+ resources: store.state.lessonSummary.workingResources,
+ })
+ .then(content => {
+ console.log(content);
+ });
}
onMounted(() => {
fetchChannelResource();
fetchBookMarkedResource();
filterAndAnnotateContentList();
+ filterLessonResource();
});
return {
resources,
channels,
bookmarks,
+ contentList,
+ filterLessonResource,
};
}
diff --git a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
index 54ae6b9cdd..bca0810263 100644
--- a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
+++ b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
@@ -47,27 +47,25 @@ export default [
path: ':section_id/replace-questions',
},
{
- // this is basically show how the routing works once you in the select resources page and bookmarked resources page
- // once you are in the bookmark resources page the only thing that we are interested in is the topic Id that always get updated
name: PageNames.QUIZ_SELECT_RESOURCES,
path: ':section_id/select-resources',
- children:[
+ children: [
{
- name:PageNames.SELECT_FROM_RESOURCE,
- path:':topic_id',
- }
- ]
+ name: PageNames.SELECT_FROM_RESOURCE,
+ path: ':topic_id',
+ },
+ ],
},
{
name: PageNames.BOOK_MARKED_RESOURCES,
path: ':section_id/book-marked-resources',
- children:[
+ children: [
{
- name:PageNames.SELECT_FROM_RESOURCE,
- path:':topic_id',
- }
- ]
+ name: PageNames.SELECT_FROM_RESOURCE,
+ path: ':topic_id',
+ },
+ ],
},
],
},
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
index 3ec1358e47..569dc6c76c 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/BookMarkedResource.vue
@@ -59,10 +59,10 @@
type: Number,
required: true,
},
- to:{
- type:Object,
- required:true,
- }
+ to: {
+ type: Object,
+ required: true,
+ },
},
computed: {
bookMarkBackgroundColor() {
@@ -71,9 +71,6 @@
};
},
},
- mounted(){
- console.log(this.$route.params);
- }
};
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 c6229d20cf..dd9a4b6887 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -1,41 +1,69 @@
-
-
-
- {{ selectFoldersOrExercises$() }}
-
-
{{ selectFromBookmarks$() }}
-
-
+
-
-
+
+
+
+
+
+
+
{{ coreString('bookmarksLabel') }}
+
{{ $tr('resources', { count: bookmarksCount }) }}
+
+
+
+
+
+
+ {{ contentList }}
+
+
+
+
{{ topicTitle }}
+
{{ topicDescription }}
+
- import { ContentNodeKinds, ContentNodeResource } from 'kolibri.coreVue.vuex.constants';
- import { enhancedQuizManagementStrings } from 'kolibri-common/strings/enhancedQuizManagementStrings';
+ import { mapState, mapActions, mapGetters, mapMutations } from 'vuex';
+ import samePageCheckGenerator from 'kolibri.utils.samePageCheckGenerator';
+ import { BookmarksResource } from 'kolibri.resources';
+ import debounce from 'lodash/debounce';
import every from 'lodash/every';
import pickBy from 'lodash/pickBy';
- import { PageNames } from '../../../constants';
- import { LessonsPageNames } from '../../../constants/lessonsConstants';
+ import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';
+ import useKResponsiveWindow from 'kolibri-design-system/lib/useKResponsiveWindow';
import { useResources } from '../../../composables/useResources';
- import LessonsSearchBox from './../LessonResourceSelectionPage/SearchTools/LessonsSearchBox.vue';
- import BookMarkedResource from './BookMarkedResource.vue';
- import ContentCardList from './../LessonResourceSelectionPage/ContentCardList.vue';
+ import commonCoach from '../../common';
+ import { PageNames } from '../../../constants';
+ import LessonsSearchBox from './../LessonResourceSelectionPage/SearchTools/LessonsSearchBox';
+ import LessonsSearchFilters from './../LessonResourceSelectionPage/SearchTools/LessonsSearchFilters';
+ import ResourceSelectionBreadcrumbs from './../LessonResourceSelectionPage/SearchTools/ResourceSelectionBreadcrumbs';
+ import ContentCardList from './../LessonResourceSelectionPage/ContentCardList';
+ import BookmarkIcon from './../LessonResourceSelectionPage/LessonContentCard/BookmarkIcon';
export default {
+ // this is inaccurately named because it applies to exams also
name: 'ResourceSelection',
+ metaInfo() {
+ return {
+ title: this.$tr('documentTitle', { lessonName: this.currentLesson.title }),
+ };
+ },
components: {
- LessonsSearchBox,
- BookMarkedResource,
ContentCardList,
+ LessonsSearchFilters,
+ LessonsSearchBox,
+ ResourceSelectionBreadcrumbs,
+ BookmarkIcon,
},
- inject: ['quizForge'],
+ mixins: [commonCoach, commonCoreStrings],
setup() {
- const {
- sectionSettings$,
- selectFoldersOrExercises$,
- selectFromBookmarks$,
- } = enhancedQuizManagementStrings;
-
- const { channels, bookmarks } = useResources();
-
+ const { windowIsSmall } = useKResponsiveWindow();
+ const { channels, filterLessonResource } = useResources();
return {
- sectionSettings$,
- selectFoldersOrExercises$,
- selectFromBookmarks$,
+ windowIsSmall,
channels,
- bookmarks,
+ filterLessonResource,
};
},
data() {
return {
- viewMoreButtonState: 'no_more_results',
- searchTerm: '',
- search: '',
+ // null corresponds to 'All' filter value
filters: {
channel: this.$route.query.channel || null,
kind: this.$route.query.kind || null,
role: this.$route.query.role || null,
},
- visibleResources: [],
+ isExiting: false,
+ moreResultsState: null,
+ resourcesChanged: false,
+ bookmarksCount: 0,
+ showChannels: true,
};
},
computed: {
+ ...mapState(['pageName']),
+ ...mapState('classSummary', { classId: 'id' }),
+ ...mapState('lessonSummary', ['currentLesson', 'workingResources']),
+ ...mapState('lessonSummary/resources', [
+ 'ancestorCounts',
+ 'contentList',
+ 'bookmarksList',
+ 'searchResults',
+ 'ancestors',
+ ]),
+ ...mapGetters('lessonSummary/resources', ['numRemainingSearchResults']),
+ ...mapGetters(['getUserPermissions']),
+ toolbarRoute() {
+ if (this.$route.query.last) {
+ return this.$router.getRoute(this.$route.query.last);
+ }
+ return this.$store.state.toolbarRoute;
+ },
+ bookmarksContentList() {
+ return this.bookmarksList ? this.bookmarksList : [];
+ },
+ filteredContentList() {
+ const { role } = this.filters;
+ if (!this.inSearchMode) {
+ return this.channels;
+ }
+ console.log(this.contentList);
+ const list = this.channels ? this.channels : this.bookmarksList;
+ return list.filter(contentNode => {
+ let passesFilters = true;
+ if (role === 'nonCoach') {
+ passesFilters = passesFilters && contentNode.num_coach_contents === 0;
+ }
+ if (role === 'coach') {
+ passesFilters = passesFilters && contentNode.num_coach_contents > 0;
+ }
+ return passesFilters;
+ });
+ },
+ lessonId() {
+ return this.currentLesson.id;
+ },
inSearchMode() {
- return this.pageName === LessonsPageNames.SELECTION_SEARCH;
+ // return this.pageName === LessonsPageNames.SELECTION_SEARCH;
+ return this.pageName === PageNames.SELECT_FROM_RESOURCE;
},
- inputPlaceHolderStyle() {
+ page() {
+ return this.getUserPermissions.can_manage_content
+ ? 'CoachImmersivePage'
+ : 'CoachAppBarPage';
+ },
+ searchTerm() {
+ return this.$route.params.searchTerm || '';
+ },
+ routerParams() {
return {
- color: this.$themeTokens.annotation,
+ classId: this.classId,
+ lessonId: this.lessonId ? this.lessonId : this.$route.params.lessonId,
};
},
+ debouncedSaveResources() {
+ return debounce(this.saveResources, 1000);
+ },
selectAllIsVisible() {
// Do not show 'Select All' if on Search Results, on Channels Page,
// or if all contents are topics
return (
!this.inSearchMode &&
- this.pageName !== LessonsPageNames.SELECTION_ROOT &&
- !every(this.quizForge.channels.value, this.contentIsDirectoryKind)
+ this.pageName !== PageNames.SELECT_FROM_RESOURCE &&
+ !every(this.contentList, this.contentIsDirectoryKind)
);
},
+ viewMoreButtonState() {
+ if (this.moreResultsState === 'waiting' || this.moreResultsState === 'error') {
+ return this.moreResultsState;
+ }
+ if (!this.inSearchMode || this.numRemainingSearchResults === 0) {
+ return 'no_more_results';
+ }
+ return 'visible';
+ },
contentIsInLesson() {
return ({ id }) =>
Boolean(this.workingResources.find(resource => resource.contentnode_id === id));
},
- selectionMetadata(/*content*/) {
- return '';
- // let count = 0;
- // let total = 0;
- // if (this.ancestorCounts[content.id]) {
- // count = this.ancestorCounts[content.id].count;
- // total = this.ancestorCounts[content.id].total;
- // }
- // if (count) {
- // return this.$tr('selectionInformation', {
- // count,
- // total,
- // });
- // }
- // return '';
- // return function() {
- // console.log('Dynamic function called');
- // };
- },
addableContent() {
// Content in the topic that can be added if 'Select All' is clicked
- const list = this.quizForge.channels.value
- ? this.quizForge.channels.value
- : this.bookmarksList;
+ const list = this.contentList ? this.contentList : this.bookmarksList;
return list.filter(
content => !this.contentIsDirectoryKind(content) && !this.contentIsInLesson(content)
);
},
- to() {
- return {
- name: PageNames.BOOK_MARKED_RESOURCES,
- params: {
- classId: this.$route.params.classId,
- section_id: this.$route.params.section_id,
- },
- };
+ channelsLink() {
+ return this.selectionRootLink();
+ },
+ topicTitle() {
+ if (!this.ancestors.length) {
+ return '';
+ }
+ return this.ancestors[this.ancestors.length - 1].title;
+ },
+ topicDescription() {
+ if (!this.ancestors.length) {
+ return '';
+ }
+ return this.ancestors[this.ancestors.length - 1].description;
+ },
+ exitButtonRoute() {
+ const lastId = this.$route.query.last_id;
+ if (this.inSearchMode && lastId) {
+ const queryCopy = { ...this.$route.query };
+ delete queryCopy.last_id;
+ return this.$router.getRoute(
+ PageNames.SELECT_FROM_RESOURCE,
+ { topicId: lastId },
+ queryCopy
+ );
+ } else if (this.inSearchMode) {
+ return this.selectionRootLink({ ...this.routerParams });
+ } else if (this.$route.query.last === 'ReportsLessonReportPage') {
+ // HACK to fix #7583 and #7584
+ return {
+ name: 'ReportsLessonReportPage',
+ };
+ } else if (this.$route.query.last === 'ReportsLessonLearnerListPage') {
+ // HACK to fix similar bug in Learner version of the report page
+ return {
+ name: 'ReportsLessonLearnerListPage',
+ };
+ } else {
+ return this.toolbarRoute;
+ }
},
},
-
watch: {
workingResources(newVal, oldVal) {
this.showResourcesDifferenceMessage(newVal.length - oldVal.length);
@@ -173,65 +283,86 @@
});
},
},
- beforeRouteEnter(to, from, next) {
- // console.log(to);
- // console.log(from);
- // console.log(to.params.topic_id);
- if (to.params.topic_id) {
- this.showChannelQuizCreationTopicPage(this.$store, to.params).then(() => {
- next();
- });
- }
- },
- mounted() {
- if (this.quizForge.channels.value.length > 0) {
- this.visibleResources = this.quizForge.channels.value;
+ beforeRouteLeave(to, from, next) {
+ // Block the UI and show a notification in case last save takes too long
+ this.isExiting = true;
+
+ // If the working resources array hasn't changed at least once,
+ // just exit without autosaving
+ if (!this.resourcesChanged) {
+ next();
+ this.isExiting = false;
} else {
- this.visibleResources = [];
- }
- console.log(this.channels);
- },
- methods: {
- /** @public */
- focusFirstEl() {
- this.$refs.textbox.focus();
- },
+ this.resourcesChanged = true;
+ const isSamePage = samePageCheckGenerator(this.$store);
+ setTimeout(() => {
+ if (isSamePage()) {
+ this.createSnackbar(this.$tr('saveBeforeExitSnackbarText'));
+ }
+ }, 500);
- contentLink(content) {
- if (!content.is_leaf) {
- return {
- name: PageNames.SELECT_FROM_RESOURCE,
- params: {
- topic_id: content.id,
- classId: this.$route.params.classId,
- section_id: this.$route.params.section_id,
- },
- };
- }
- },
- handleMoreResults() {
- this.moreResultsState = 'waiting';
- this.fetchAdditionalSearchResults({
- searchTerm: this.searchTerm,
- kind: this.filters.kind,
- channelId: this.filters.channel,
- currentResults: this.searchResults.results,
+ // Cancel any debounced calls
+ this.debouncedSaveResources.cancel();
+ this.saveLessonResources({
+ lessonId: this.lessonId,
+ resources: [...this.workingResources],
})
.then(() => {
- this.moreResultsState = null;
- this.moreResultsState;
+ this.clearSnackbar();
+ this.isExiting = false;
+ next();
})
.catch(() => {
- this.moreResultsState = 'error';
+ this.showResourcesChangedError();
+ this.isExiting = false;
+ next(false);
});
+ }
+ },
+ created() {
+ this.getBookmarks().then(count => {
+ this.bookmarksCount = count;
+ });
+ },
+ methods: {
+ ...mapActions(['createSnackbar', 'clearSnackbar']),
+ ...mapActions('lessonSummary', ['saveLessonResources', 'addToResourceCache']),
+ ...mapActions('lessonSummary/resources', ['fetchAdditionalSearchResults']),
+ ...mapMutations('lessonSummary', {
+ addToWorkingResources: 'ADD_TO_WORKING_RESOURCES',
+ removeFromSelectedResources: 'REMOVE_FROM_WORKING_RESOURCES',
+ }),
+ getBookmarks() {
+ return BookmarksResource.fetchCollection().then(bookmarks => {
+ return bookmarks.length;
+ });
},
- toggleSelected({ content, checked }) {
- if (checked) {
- this.addToSelectedResources(content);
+ getBookmarksLink() {
+ return {
+ name: PageNames.BOOK_MARKED_RESOURCES,
+ params: {
+ classId: this.$route.params.classId,
+ section_id: this.$route.params.section_id,
+ },
+ };
+ },
+ lessonCardClicked() {
+ this.showChannels = false;
+ },
+ showResourcesDifferenceMessage(difference) {
+ if (difference === 0) {
+ return;
+ }
+ this.resourcesChanged = true;
+ if (difference > 0) {
+ this.showSnackbarNotification('resourcesAddedWithCount', { count: difference });
} else {
- this.removeFromSelectedResources([content]);
+ this.showSnackbarNotification('resourcesRemovedWithCount', { count: -difference });
}
},
+ showResourcesChangedError() {
+ this.createSnackbar(this.coachString('saveLessonError'));
+ },
toggleTopicInWorkingResources(isChecked) {
if (isChecked) {
this.addableContent.forEach(resource => {
@@ -241,55 +372,231 @@
});
this.addToWorkingResources(this.addableContent);
} else {
- this.removeFromSelectedResources(this.quizForge.channels.value);
+ this.removeFromSelectedResources(this.contentList);
}
},
+ addToSelectedResources(content) {
+ const list =
+ this.contentList && this.contentList.length ? this.contentList : this.bookmarksList;
+ this.addToResourceCache({
+ node: list.find(n => n.id === content.id),
+ });
+ this.addToWorkingResources([content]);
+ },
contentIsDirectoryKind({ is_leaf }) {
return !is_leaf;
},
- showChannelQuizCreationTopicPage(store, params) {
- return store.dispatch('loading').then(() => {
- const { topic_id } = params;
- const topicNodePromise = ContentNodeResource.fetchModel({ id: topic_id });
- const childNodesPromise = ContentNodeResource.fetchCollection({
- getParams: {
- parent: topic_id,
- kind_in: [ContentNodeKinds.TOPIC, ContentNodeKinds.EXERCISE],
- contains_quiz: true,
- },
- });
- const loadRequirements = [topicNodePromise, childNodesPromise];
-
- return Promise.all(loadRequirements).then(([, /*topicNoitde*/ childNodes]) => {
- console.log(childNodes);
- this.visibleResources = childNodes;
- // return filterAndAnnotateContentList(childNodes).then(contentList => {
- // store.commit('SET_TOOLBAR_ROUTE', {
- // name: PageNames.EXAMS,
- // });
-
- // return showExamCreationPage(store, {
- // classId: params.classId,
- // contentList,
- // pageName: PageNames.EXAM_CREATION_SELECT_CHANNEL_QUIZ_TOPIC,
- // ancestors: [...topicNode.ancestors, topicNode],
- // });
- // });
+ selectionRootLink() {
+ return this.$router.getRoute(PageNames.SELECTION_CONTENT_PREVIEW, {}, this.$route.query);
+ },
+ topicListingLink({ topicId }) {
+ return this.$router.getRoute(
+ PageNames.SELECT_FROM_RESOURCE,
+ { topicId },
+ this.$route.query
+ );
+ },
+ bookmarkListingLink({ topicId }) {
+ return this.$router.getRoute(
+ PageNames.SELECT_FROM_RESOURCE,
+ { topicId },
+ this.$route.query
+ );
+ },
+ bookmarkLink(content) {
+ if (this.contentIsDirectoryKind(content)) {
+ return this.bookmarkListingLink({ ...this.routerParams, topicId: content.id });
+ }
+ const { query } = this.$route;
+ return {
+ name: PageNames.SELECTION_CONTENT_PREVIEW,
+ params: {
+ ...this.routerParams,
+ contentId: content.id,
+ },
+ query: {
+ ...query,
+ ...pickBy({
+ searchTerm: this.$route.params.searchTerm,
+ }),
+ },
+ };
+ },
+ contentLink(content) {
+ if (this.contentIsDirectoryKind(content)) {
+ return this.topicListingLink({ ...this.routerParams, topicId: content.id });
+ }
+ const { query } = this.$route;
+ return {
+ name: PageNames.SELECTION_CONTENT_PREVIEW,
+ params: {
+ ...this.routerParams,
+ contentId: content.id,
+ },
+ query: {
+ ...query,
+ ...pickBy({
+ searchTerm: this.$route.params.searchTerm,
+ }),
+ },
+ };
+ },
+ saveResources() {
+ return this.saveLessonResources({
+ lessonId: this.lessonId,
+ resources: this.workingResources,
+ });
+ },
+ selectionMetadata(content) {
+ let count = 0;
+ let total = 0;
+ if (this.ancestorCounts[content.id]) {
+ count = this.ancestorCounts[content.id].count;
+ total = this.ancestorCounts[content.id].total;
+ }
+ if (count) {
+ return this.$tr('selectionInformation', {
+ count,
+ total,
});
+ }
+ return '';
+ },
+ toggleSelected({ content, checked }) {
+ if (checked) {
+ this.addToSelectedResources(content);
+ } else {
+ this.removeFromSelectedResources([content]);
+ }
+ },
+ handleSearchTerm(searchTerm) {
+ const query = {
+ last_id: this.$route.query.last_id || this.$route.params.topicId,
+ };
+ const lastPage = this.$route.query.last;
+ if (lastPage) {
+ query.last = lastPage;
+ }
+ this.$router.push({
+ name: PageNames.SELECTION_SEARCH,
+ params: {
+ searchTerm,
+ },
+ query,
});
},
+ handleMoreResults() {
+ this.moreResultsState = 'waiting';
+ this.fetchAdditionalSearchResults({
+ searchTerm: this.searchTerm,
+ kind: this.filters.kind,
+ channelId: this.filters.channel,
+ currentResults: this.searchResults.results,
+ })
+ .then(() => {
+ this.moreResultsState = null;
+ })
+ .catch(() => {
+ this.moreResultsState = 'error';
+ });
+ },
+ topicsLink(topicId) {
+ return this.topicListingLink({ ...this.$route.params, topicId });
+ },
+ },
+ $trs: {
+ resources: {
+ message: '{count} {count, plural, one {resource} other {resources}}',
+ context: "Only translate 'resource' and 'resources'.",
+ },
+ selectionInformation: {
+ message:
+ '{count, number, integer} of {total, number, integer} {total, plural, one {resource selected} other {resources selected}}',
+
+ context:
+ "Indicates the amount of resources selected for a lesson in the 'Manage lesson resources' section.\n\nFor example: '7 of 10 resources selected'.",
+ },
+ totalResourcesSelected: {
+ message:
+ '{total, number, integer} {total, plural, one {resource} other {resources}} in this lesson',
+ context:
+ "Indicates the amount of resources for a lesson in the 'Manage lesson resources' section. For example:\n\n'8 resources in this lesson'",
+ },
+ documentTitle: {
+ message: `Manage resources in '{lessonName}'`,
+ context:
+ "Title of window that displays when the user clicks on the 'manage resources' button within an individual lesson.\n\nOn this page the user can add new learning resources to the lesson.",
+ },
+ saveBeforeExitSnackbarText: {
+ message: 'Saving your changes…',
+ context: 'Notification that changes are being saved.',
+ },
+ // only shown on search page
+ exitSearchButtonLabel: {
+ message: 'Exit search',
+ context: "Button to exit the search function of the 'Manage lesson resources' window.",
+ },
+ manageResourcesAction: {
+ message: 'Manage lesson resources',
+ context:
+ "In the 'Manage lesson resources' coaches can add new resource material to a lesson.",
+ },
},
};
-
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
index 724128cf60..c4c27aebc8 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
@@ -31,7 +31,6 @@
[PageNames.QUIZ_REPLACE_QUESTIONS]: ReplaceQuestions,
[PageNames.QUIZ_SELECT_RESOURCES]: ResourceSelection,
[PageNames.BOOK_MARKED_RESOURCES]: ShowBookMarkedResources,
- [PageNames.SELECT_FROM_RESOURCE]: SelectedChannel,
};
export default {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
index 13ada04040..8937142296 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue
@@ -114,8 +114,7 @@
},
mounted() {
this.$store.dispatch('notLoading');
- },
- mounted() {
+
ChannelResource.fetchCollection({
getParams: { available: true, has_exercise: true },
}).then(channels => {
From 81300e4b1adcb582f64aabff2b27ca408b3dec08 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Tue, 28 Nov 2023 08:19:26 +0300
Subject: [PATCH 43/50] add bookmarked resources
---
.../plan/CreateExamPage/ResourceSelection.vue | 41 ++++++++++---------
1 file changed, 21 insertions(+), 20 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 dd9a4b6887..18ecfb43d2 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -1,5 +1,4 @@
-
-
+
+
+
+
+
+
+
+
- {{ contentList }}
-
{
this.bookmarksCount = count;
});
+ console.log(this.filterLessonResource(this.$route.params.lessonId))
},
methods: {
...mapActions(['createSnackbar', 'clearSnackbar']),
@@ -340,10 +345,10 @@
getBookmarksLink() {
return {
name: PageNames.BOOK_MARKED_RESOURCES,
- params: {
- classId: this.$route.params.classId,
- section_id: this.$route.params.section_id,
- },
+ params:{
+ classId: this.$route.params.classId,
+ section_id: this.$route.params.section_id,
+ }
};
},
lessonCardClicked() {
@@ -390,11 +395,7 @@
return this.$router.getRoute(PageNames.SELECTION_CONTENT_PREVIEW, {}, this.$route.query);
},
topicListingLink({ topicId }) {
- return this.$router.getRoute(
- PageNames.SELECT_FROM_RESOURCE,
- { topicId },
- this.$route.query
- );
+ return this.$router.getRoute(PageNames.SELECT_FROM_RESOURCE, { topicId }, this.$route.query);
},
bookmarkListingLink({ topicId }) {
return this.$router.getRoute(
From 3fc3ba5214c2174b7672b5c67c45a1c021684d2e Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Tue, 28 Nov 2023 20:04:34 +0300
Subject: [PATCH 44/50] can navigate to the first level of the topic tree
---
.../assets/src/composables/useResources.js | 76 +-
.../coach/assets/src/routes/planExamRoutes.js | 5 +-
.../plan/CreateExamPage/ResourceSelection.vue | 714 +++++++-----------
.../plan/CreateExamPage/SectionSidePanel.vue | 1 +
.../plan/CreateExamPage/SelectedChannel.vue | 21 +-
5 files changed, 346 insertions(+), 471 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/composables/useResources.js b/kolibri/plugins/coach/assets/src/composables/useResources.js
index aed6a874d0..0274bc89a1 100644
--- a/kolibri/plugins/coach/assets/src/composables/useResources.js
+++ b/kolibri/plugins/coach/assets/src/composables/useResources.js
@@ -11,9 +11,13 @@ export function useResources() {
const resources = ref(null);
const channels = ref([]);
const bookmarks = ref([]);
- const contentList = ref([]);
+ const channelTopics = ref([]);
+ const contentList = ref([]);
+
+
function fetchChannelResource() {
+
ChannelResource.fetchCollection({ params: { has_exercises: true, available: true } }).then(
response => {
// channels.value = response;
@@ -45,7 +49,8 @@ export function useResources() {
resolve([]);
return;
}
- const topicsNumAssessmentDescendantsPromise = ContentNodeResource.fetchDescendantsAssessments(
+ const topicsNumAssessmentDescendantsPromise
+ = ContentNodeResource.fetchDescendantsAssessments(
topicIds
);
@@ -68,7 +73,9 @@ export function useResources() {
}
).then(response => {
response.data.forEach(exercise => {
- const topic = topicsWithExerciseDescendants.find(t => t.id === exercise.ancestor_id);
+ channelTopics.value.push(exercise);
+ const topic = topicsWithExerciseDescendants.find(t =>
+ t.id === exercise.ancestor_id);
topic.exercises.push(exercise);
});
resolve(topicsWithExerciseDescendants);
@@ -79,54 +86,48 @@ export function useResources() {
function filterAndAnnotateContentList(childNodes) {
return new Promise(resolve => {
- if (childNodes) {
+ if(childNodes){
const childTopics = childNodes.filter(({ kind }) => kind === ContentNodeKinds.TOPIC);
const topicIds = childTopics.map(({ id }) => id);
const topicsThatHaveExerciseDescendants = _getTopicsWithExerciseDescendants(topicIds);
- topicsThatHaveExerciseDescendants.then(topics => {
- const childNodesWithExerciseDescendants = childNodes
- .map(childNode => {
- const index = topics.findIndex(topic => topic.id === childNode.id);
- if (index !== -1) {
- return { ...childNode, ...topics[index] };
- }
- return childNode;
- })
- .filter(childNode => {
- if (
- childNode.kind === ContentNodeKinds.TOPIC &&
- (childNode.numAssessments || 0) < 1
- ) {
+ topicsThatHaveExerciseDescendants.then(topics => {
+ const childNodesWithExerciseDescendants = childNodes
+ .map(childNode => {
+ const index = topics.findIndex(topic => topic.id === childNode.id);
+ if (index !== -1) {
+ return { ...childNode, ...topics[index] };
+ }
+ return childNode;
+ }).filter(childNode => {
+ if (childNode.kind === ContentNodeKinds.TOPIC &&
+ (childNode.numAssessments || 0) < 1) {
return false;
}
- return true;
- });
- const contentList = childNodesWithExerciseDescendants.map(node => ({
- ...node,
- thumbnail: getContentNodeThumbnail(node),
- }));
- resolve(contentList);
- });
+ return true;
+ });
+ const contentList = childNodesWithExerciseDescendants.map(node => ({
+ ...node,
+ thumbnail: getContentNodeThumbnail(node),
+ }));
+ resolve(contentList);
+ });
}
});
}
- function filterLessonResource(lessonId) {
- store
- .dispatch('lessonSummary/saveLessonResources', {
- lessonId: lessonId,
- resources: store.state.lessonSummary.workingResources,
- })
- .then(content => {
- console.log(content);
- });
+ function filterLessonResource(lessonId){
+ store.dispatch('lessonSummary/saveLessonResources', {
+ lessonId: lessonId,
+ resources: store.state.lessonSummary.workingResources,
+ }).then((content) => {
+ console.log(content);
+ });
}
onMounted(() => {
fetchChannelResource();
fetchBookMarkedResource();
filterAndAnnotateContentList();
- filterLessonResource();
});
return {
@@ -134,6 +135,7 @@ export function useResources() {
channels,
bookmarks,
contentList,
- filterLessonResource,
+ channelTopics,
+ _getTopicsWithExerciseDescendants
};
}
diff --git a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
index bca0810263..8953b1304c 100644
--- a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
+++ b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
@@ -61,10 +61,7 @@ export default [
name: PageNames.BOOK_MARKED_RESOURCES,
path: ':section_id/book-marked-resources',
children: [
- {
- name: PageNames.SELECT_FROM_RESOURCE,
- path: ':topic_id',
- },
+
],
},
],
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 18ecfb43d2..e4748a6a6e 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -1,82 +1,92 @@
-
-
-
-
-
-
-
-
-
-
{{ coreString('bookmarksLabel') }}
-
{{ $tr('resources', { count: bookmarksCount }) }}
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Select folders or exercises from these channels
+
+
Select from bookmarks
+
+
+
+
+
+
+
+
+
+
+
{{ coreString('bookmarksLabel') }}
+
{{ numberOfSelectedBookmarks$({ count: bookmarksCount }) }}
+
+
+
+
+
+
+
+
-
+
+
-
+
-
{{ topicTitle }}
-
{{ topicDescription }}
+
-
+
+
@@ -84,92 +94,80 @@
-
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
index c4c27aebc8..3f3c6e7f31 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
@@ -31,6 +31,7 @@
[PageNames.QUIZ_REPLACE_QUESTIONS]: ReplaceQuestions,
[PageNames.QUIZ_SELECT_RESOURCES]: ResourceSelection,
[PageNames.BOOK_MARKED_RESOURCES]: ShowBookMarkedResources,
+ [PageNames.SELECT_FROM_RESOURCE]:SelectedChannel,
};
export default {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
index 5216a4c580..8044f8980d 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
@@ -2,8 +2,9 @@
-
{{ selectFoldersOrExercises$() }}
@@ -17,7 +18,7 @@
/>
Date: Wed, 29 Nov 2023 19:35:40 +0300
Subject: [PATCH 45/50] removed unused data elements and components
---
.../plan/CreateExamPage/ResourceSelection.vue | 36 +++++++++++--------
1 file changed, 21 insertions(+), 15 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 e4748a6a6e..beb6ad6af6 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -11,7 +11,13 @@
Select from bookmarks
-
+
+
+
+ :text="coreString"('channelsLabel')"
+ :to="channelsLink"
+
+
false,
// contentIsSelected: () => '',
searchTerm: '',
- search: '',
+ // search: '',
isExiting: false,
filters: {
channel: this.$route.query.channel || null,
@@ -182,11 +189,11 @@
inSearchMode() {
return this.pageName === LessonsPageNames.SELECTION_SEARCH;
},
- inputPlaceHolderStyle() {
- return {
- color: this.$themeTokens.annotation,
- };
- },
+ // inputPlaceHolderStyle() {
+ // return {
+ // color: this.$themeTokens.annotation,
+ // };
+ // },
selectAllIsVisible() {
// Do not show 'Select All' if on Search Results, on Channels Page,
// or if all contents are topics
@@ -429,7 +436,8 @@
// if (!this.inSearchMode) {
// return this.quizForge.channels.value;
// }
- // const list = this.quizForge.channels.value ? this.quizForge.channels.value : this.bookmarksList;
+ // const list =
+ // this.quizForge.channels.value ? this.quizForge.channels.value : this.bookmarksList;
// return list.filter(contentNode => {
// let passesFilters = true;
// if (role === 'nonCoach') {
@@ -443,9 +451,7 @@
// },
},
$trs: {
- selectionInformation: {
- message: 'Channels',
- },
+
},
};
From a389f14a8d6d01a71c46399daadef8f2b097511b Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Thu, 30 Nov 2023 10:44:07 +0300
Subject: [PATCH 46/50] changed structure to only allow contentCardlist
component to update
---
.../assets/src/composables/useResources.js | 18 ++---
.../plan/CreateExamPage/ResourceSelection.vue | 77 ++++++++++++-------
.../plan/CreateExamPage/SectionSidePanel.vue | 6 +-
3 files changed, 60 insertions(+), 41 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/composables/useResources.js b/kolibri/plugins/coach/assets/src/composables/useResources.js
index 0274bc89a1..5c54b33485 100644
--- a/kolibri/plugins/coach/assets/src/composables/useResources.js
+++ b/kolibri/plugins/coach/assets/src/composables/useResources.js
@@ -3,7 +3,7 @@ import { ChannelResource, ContentNodeResource } from 'kolibri.resources';
import { ContentNodeKinds } from 'kolibri.coreVue.vuex.constants';
import { getContentNodeThumbnail } from 'kolibri.utils.contentNode';
import { set } from '@vueuse/core';
-import store from 'kolibri.coreVue.vuex.store';
+// import store from 'kolibri.coreVue.vuex.store';
// import { store } from 'vuex';
@@ -20,7 +20,6 @@ export function useResources() {
ChannelResource.fetchCollection({ params: { has_exercises: true, available: true } }).then(
response => {
- // channels.value = response;
set(
channels,
response.map(chnl => {
@@ -78,6 +77,7 @@ export function useResources() {
t.id === exercise.ancestor_id);
topic.exercises.push(exercise);
});
+ channels.value = channelTopics.value;
resolve(topicsWithExerciseDescendants);
});
});
@@ -105,29 +105,24 @@ export function useResources() {
}
return true;
});
- const contentList = childNodesWithExerciseDescendants.map(node => ({
+ contentList.value = childNodesWithExerciseDescendants.map(node => ({
...node,
thumbnail: getContentNodeThumbnail(node),
}));
+ channels.value = contentList.value;
resolve(contentList);
});
}
});
}
- function filterLessonResource(lessonId){
- store.dispatch('lessonSummary/saveLessonResources', {
- lessonId: lessonId,
- resources: store.state.lessonSummary.workingResources,
- }).then((content) => {
- console.log(content);
- });
- }
onMounted(() => {
fetchChannelResource();
fetchBookMarkedResource();
filterAndAnnotateContentList();
+ _getTopicsWithExerciseDescendants([]);
+
});
return {
@@ -136,6 +131,7 @@ export function useResources() {
bookmarks,
contentList,
channelTopics,
+ filterAndAnnotateContentList,
_getTopicsWithExerciseDescendants
};
}
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 beb6ad6af6..837615dbe7 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -11,7 +11,10 @@
Select from bookmarks
-
+
{{ $route.params.topic_id }}
+
{{ channels }}
+
+
+
{
let passesFilters = true;
@@ -187,7 +200,7 @@
});
},
inSearchMode() {
- return this.pageName === LessonsPageNames.SELECTION_SEARCH;
+ return this.pageName === PageNames.SELECT_FROM_RESOURCE;
},
// inputPlaceHolderStyle() {
// return {
@@ -241,18 +254,21 @@
workingResources(newVal, oldVal) {
this.showResourcesDifferenceMessage(newVal.length - oldVal.length);
this.debouncedSaveResources();
+
},
filters(newVal) {
const newQuery = {
...this.$route.query,
...newVal,
};
+
+
this.$router.push({
query: pickBy(newQuery),
});
},
},
- beforeRouteEnter (to, from, next) {
+ beforeEnter (to, from, next) {
console.log(to);
console.log(from);
console.log(to.params.topic_id);
@@ -265,6 +281,7 @@
beforeRouteLeave(to, from, next) {
// Block the UI and show a notification in case last save takes too long
this.isExiting = true;
+
// If the working resources array hasn't changed at least once,
// just exit without autosaving
@@ -301,8 +318,6 @@
created() {
console.log(this.quizForge.channels.value);
this.bookmarksCount = this.getBookmarks();
-
-
},
mounted() {
if(this.quizForge.channels.value.length > 0){
@@ -310,6 +325,10 @@
}else{
this.visibleResources =[];
}
+
+ setTimeout(() => {
+ this.checkRoute();
+ }, 1000);
},
methods: {
@@ -400,22 +419,26 @@
contentIsDirectoryKind({ is_leaf }) {
return !is_leaf;
},
- showChannelQuizCreationTopicPage(store, params) {
- return store.dispatch('loading').then(() => {
- const { topic_id } = params;
- const topicNodePromise = ContentNodeResource.fetchModel({ id: topic_id });
- const childNodesPromise = ContentNodeResource.fetchCollection({
- getParams: {
- parent: topic_id,
- kind_in: [ContentNodeKinds.TOPIC, ContentNodeKinds.EXERCISE],
- contains_quiz: true,
- },
- });
+ checkRoute(){
+ if(this.$route.params.topic_id){
+ this._getTopicsWithExerciseDescendants(this.$route.params.topic_id);
+ }
+ },
+ showChannelQuizCreationTopicPage(store, params) {
+ return store.dispatch('loading').then(() => {
+ const { topic_id } = params;
+ const topicNodePromise = ContentNodeResource.fetchModel({ id: topic_id });
+ const childNodesPromise = ContentNodeResource.fetchCollection({
+ getParams: {
+ parent: topic_id,
+ kind_in: [ContentNodeKinds.TOPIC, ContentNodeKinds.EXERCISE],
+ contains_quiz: true,
+ },
+ });
const loadRequirements = [topicNodePromise, childNodesPromise];
return Promise.all(loadRequirements).then(([/*topicNoitde*/, childNodes]) => {
- console.log(childNodes);
- this.visibleResources = childNodes;
+ this.filterAndAnnotateContentList(childNodes);
// return filterAndAnnotateContentList(childNodes).then(contentList => {
// store.commit('SET_TOOLBAR_ROUTE', {
// name: PageNames.EXAMS,
@@ -429,8 +452,8 @@
// });
// });
});
- });
-}
+ });
+ }
// filteredquizForge.channels.value() {
// const { role } = this.filters;
// if (!this.inSearchMode) {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
index 3f3c6e7f31..a2938e3b7c 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
@@ -24,14 +24,14 @@
import ReplaceQuestions from './ReplaceQuestions';
import ResourceSelection from './ResourceSelection';
import ShowBookMarkedResources from './ShowBookMarkedResources.vue';
- import SelectedChannel from './SelectedChannel.vue';
+ // import SelectedChannel from './SelectedChannel.vue';
const pageNameComponentMap = {
[PageNames.QUIZ_SECTION_EDITOR]: SectionEditor,
[PageNames.QUIZ_REPLACE_QUESTIONS]: ReplaceQuestions,
[PageNames.QUIZ_SELECT_RESOURCES]: ResourceSelection,
[PageNames.BOOK_MARKED_RESOURCES]: ShowBookMarkedResources,
- [PageNames.SELECT_FROM_RESOURCE]:SelectedChannel,
+ [PageNames.SELECT_FROM_RESOURCE]: ResourceSelection,
};
export default {
@@ -41,7 +41,7 @@
SectionEditor,
ReplaceQuestions,
ResourceSelection,
- SelectedChannel,
+ // SelectedChannel,
ResourceSelectionBreadcrumbs,
ShowBookMarkedResources,
},
From 5d0e71aad421cf5ce9f1629e5c51e6bd3bc219af Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Thu, 30 Nov 2023 21:52:45 +0300
Subject: [PATCH 47/50] can navigate backwards using the back arrow
---
.../assets/src/composables/useResources.js | 99 +++++++++-----
.../coach/assets/src/routes/planExamRoutes.js | 6 +-
.../plan/CreateExamPage/ResourceSelection.vue | 128 +++++++++---------
.../plan/CreateExamPage/SectionSidePanel.vue | 4 +-
.../plan/CreateExamPage/SelectedChannel.vue | 40 +++---
5 files changed, 158 insertions(+), 119 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/composables/useResources.js b/kolibri/plugins/coach/assets/src/composables/useResources.js
index 5c54b33485..8644d116b6 100644
--- a/kolibri/plugins/coach/assets/src/composables/useResources.js
+++ b/kolibri/plugins/coach/assets/src/composables/useResources.js
@@ -1,8 +1,10 @@
import { ref, onMounted } from 'kolibri.lib.vueCompositionApi';
-import { ChannelResource, ContentNodeResource } from 'kolibri.resources';
+import { ChannelResource, ContentNodeResource, ContentNodeSearchResource } from 'kolibri.resources';
import { ContentNodeKinds } from 'kolibri.coreVue.vuex.constants';
import { getContentNodeThumbnail } from 'kolibri.utils.contentNode';
import { set } from '@vueuse/core';
+// import pickBy from 'lodash/pickBy';
+import uniq from 'lodash/uniq';
// import store from 'kolibri.coreVue.vuex.store';
// import { store } from 'vuex';
@@ -12,12 +14,9 @@ export function useResources() {
const channels = ref([]);
const bookmarks = ref([]);
const channelTopics = ref([]);
- const contentList = ref([]);
-
-
+ const contentList = ref([]);
function fetchChannelResource() {
-
ChannelResource.fetchCollection({ params: { has_exercises: true, available: true } }).then(
response => {
set(
@@ -48,8 +47,7 @@ export function useResources() {
resolve([]);
return;
}
- const topicsNumAssessmentDescendantsPromise
- = ContentNodeResource.fetchDescendantsAssessments(
+ const topicsNumAssessmentDescendantsPromise = ContentNodeResource.fetchDescendantsAssessments(
topicIds
);
@@ -73,8 +71,7 @@ export function useResources() {
).then(response => {
response.data.forEach(exercise => {
channelTopics.value.push(exercise);
- const topic = topicsWithExerciseDescendants.find(t =>
- t.id === exercise.ancestor_id);
+ const topic = topicsWithExerciseDescendants.find(t => t.id === exercise.ancestor_id);
topic.exercises.push(exercise);
});
channels.value = channelTopics.value;
@@ -86,43 +83,80 @@ export function useResources() {
function filterAndAnnotateContentList(childNodes) {
return new Promise(resolve => {
- if(childNodes){
+ if (childNodes) {
const childTopics = childNodes.filter(({ kind }) => kind === ContentNodeKinds.TOPIC);
const topicIds = childTopics.map(({ id }) => id);
const topicsThatHaveExerciseDescendants = _getTopicsWithExerciseDescendants(topicIds);
- topicsThatHaveExerciseDescendants.then(topics => {
- const childNodesWithExerciseDescendants = childNodes
- .map(childNode => {
- const index = topics.findIndex(topic => topic.id === childNode.id);
- if (index !== -1) {
- return { ...childNode, ...topics[index] };
- }
- return childNode;
- }).filter(childNode => {
- if (childNode.kind === ContentNodeKinds.TOPIC &&
- (childNode.numAssessments || 0) < 1) {
+ topicsThatHaveExerciseDescendants.then(topics => {
+ const childNodesWithExerciseDescendants = childNodes
+ .map(childNode => {
+ const index = topics.findIndex(topic => topic.id === childNode.id);
+ if (index !== -1) {
+ return { ...childNode, ...topics[index] };
+ }
+ return childNode;
+ })
+ .filter(childNode => {
+ if (
+ childNode.kind === ContentNodeKinds.TOPIC &&
+ (childNode.numAssessments || 0) < 1
+ ) {
return false;
}
- return true;
- });
- contentList.value = childNodesWithExerciseDescendants.map(node => ({
- ...node,
- thumbnail: getContentNodeThumbnail(node),
- }));
- channels.value = contentList.value;
- resolve(contentList);
- });
+ return true;
+ });
+ contentList.value = childNodesWithExerciseDescendants.map(node => ({
+ ...node,
+ thumbnail: getContentNodeThumbnail(node),
+ }));
+ channels.value = contentList.value;
+ resolve(contentList);
+ });
}
});
}
+ function showChannelLevel(store, params, query = {}) {
+ let kinds;
+ if (query.kind) {
+ kinds = [query.kind];
+ } else {
+ kinds = [ContentNodeKinds.EXERCISE, ContentNodeKinds.TOPIC];
+ }
+
+ ContentNodeSearchResource.fetchCollection({
+ getParams: {
+ search: '',
+ kind_in: kinds,
+ // ...pickBy({ channel_id: query.channel }),
+ },
+ }).then(results => {
+ return filterAndAnnotateContentList(results.results).then(contentList => {
+ const searchResults = {
+ ...results,
+ results: contentList,
+ content_kinds: results.content_kinds.filter(kind =>
+ [ContentNodeKinds.TOPIC, ContentNodeKinds.EXERCISE].includes(kind)
+ ),
+ contentIdsFetched: uniq(results.results.map(({ content_id }) => content_id)),
+ };
+ // return showExamCreationPage(store, {
+ // classId: params.classId,
+ // contentList: contentList,
+ // pageName: PageNames.EXAM_CREATION_SEARCH,
+ // searchResults,
+ // });
+ this.channelTopics.value = searchResults.results;
+ console.log(searchResults.results);
+ });
+ });
+ }
onMounted(() => {
fetchChannelResource();
fetchBookMarkedResource();
filterAndAnnotateContentList();
_getTopicsWithExerciseDescendants([]);
-
});
return {
@@ -132,6 +166,7 @@ export function useResources() {
contentList,
channelTopics,
filterAndAnnotateContentList,
- _getTopicsWithExerciseDescendants
+ _getTopicsWithExerciseDescendants,
+ showChannelLevel,
};
}
diff --git a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
index 8953b1304c..ba09d0e313 100644
--- a/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
+++ b/kolibri/plugins/coach/assets/src/routes/planExamRoutes.js
@@ -53,16 +53,14 @@ export default [
children: [
{
name: PageNames.SELECT_FROM_RESOURCE,
- path: ':topic_id',
+ path: ':topic_id/resource',
},
],
},
{
name: PageNames.BOOK_MARKED_RESOURCES,
path: ':section_id/book-marked-resources',
- children: [
-
- ],
+ children: [],
},
],
},
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 837615dbe7..9dcdef68f5 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -4,16 +4,17 @@
-
+
+
+
Select folders or exercises from these channels
Select from bookmarks
- {{ $route.params.topic_id }}
- {{ channels }}
-
-
+
- import { ContentNodeKinds , ContentNodeResource} from 'kolibri.coreVue.vuex.constants';
+ import { ContentNodeKinds, ContentNodeResource } from 'kolibri.coreVue.vuex.constants';
import { enhancedQuizManagementStrings } from 'kolibri-common/strings/enhancedQuizManagementStrings';
import every from 'lodash/every';
import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';
@@ -112,14 +112,14 @@
import useKResponsiveWindow from 'kolibri-design-system/lib/useKResponsiveWindow';
import { LessonsPageNames } from '../../../constants/lessonsConstants';
import { PageNames } from '../../../constants';
- import BookmarkIcon from '../LessonResourceSelectionPage/LessonContentCard/BookmarkIcon.vue'
+ import BookmarkIcon from '../LessonResourceSelectionPage/LessonContentCard/BookmarkIcon.vue';
import { useResources } from './../../../composables/useResources';
import LessonsSearchBox from './../LessonResourceSelectionPage/SearchTools/LessonsSearchBox.vue';
// import BookMarkedResource from './BookMarkedResource.vue';
import ContentCardList from './../LessonResourceSelectionPage/ContentCardList.vue';
// import LessonContentCard from './../LessonResourceSelectionPage/LessonContentCard/index.vue';
import LessonsSearchFilters from './../LessonResourceSelectionPage/SearchTools/LessonsSearchFilters';
- // import ResourceSelectionBreadcrumbs
+ // import ResourceSelectionBreadcrumbs
// from './../LessonResourceSelectionPage/SearchTools/ResourceSelectionBreadcrumbs.vue';
export default {
@@ -132,21 +132,17 @@
// ResourceSelection,
// ResourceSelectionBreadcrumbs,
// LessonContentCard,
- LessonsSearchFilters
-
+ LessonsSearchFilters,
},
inject: ['quizForge'],
- mixins:[commonCoreStrings],
+ mixins: [commonCoreStrings],
setup() {
- const {
- sectionSettings$,
- numberOfSelectedBookmarks$
- } = enhancedQuizManagementStrings;
- const {
- bookmarks,
+ const { sectionSettings$, numberOfSelectedBookmarks$ } = enhancedQuizManagementStrings;
+ const {
+ bookmarks,
channelTopics,
channels,
- _getTopicsWithExerciseDescendants
+ _getTopicsWithExerciseDescendants,
} = useResources();
const { windowIsSmall } = useKResponsiveWindow();
@@ -173,9 +169,8 @@
kind: this.$route.query.kind || null,
role: this.$route.query.role || null,
},
- visibleResources:[],
- showChannels:true,
-
+ visibleResources: [],
+ showChannels: true,
};
},
computed: {
@@ -185,9 +180,7 @@
return this.channels;
}
- const list = this.channels
- ? this.channels
- : this.bookmarksList;
+ const list = this.channels ? this.channels : this.bookmarksList;
return list.filter(contentNode => {
let passesFilters = true;
if (role === 'nonCoach') {
@@ -221,7 +214,7 @@
Boolean(this.workingResources.find(resource => resource.contentnode_id === id));
},
selectionMetadata(/*content*/) {
- return function(){};
+ return function() {};
// let count = 0;
// let total = 0;
// if (this.ancestorCounts[content.id]) {
@@ -241,20 +234,25 @@
},
addableContent() {
// Content in the topic that can be added if 'Select All' is clicked
- const list = this.quizForge.channels.value
- ? this.quizForge.channels.value
- : this.bookmarksList;
+ const list = this.channels ? this.channels : this.bookmarksList;
return list.filter(
content => !this.contentIsDirectoryKind(content) && !this.contentIsInLesson(content)
);
},
- },
+ goBack() {
+ return {
+ name: PageNames.QUIZ_SECTION_EDITOR,
+ params: {
+ section_id: this.$route.params.section_id,
+ },
+ };
+ },
+ },
watch: {
workingResources(newVal, oldVal) {
this.showResourcesDifferenceMessage(newVal.length - oldVal.length);
this.debouncedSaveResources();
-
},
filters(newVal) {
const newQuery = {
@@ -262,26 +260,25 @@
...newVal,
};
-
this.$router.push({
query: pickBy(newQuery),
});
},
},
- beforeEnter (to, from, next) {
+ beforeEnter(to, from, next) {
console.log(to);
console.log(from);
console.log(to.params.topic_id);
- if(to.params.topic_id){
- this.showChannelQuizCreationTopicPage(this.$store,to.params).then(() => {
+ if (to.params.topic_id) {
+ this.showChannelQuizCreationTopicPage(this.$store, to.params).then(() => {
next();
});
}
},
+
beforeRouteLeave(to, from, next) {
// Block the UI and show a notification in case last save takes too long
this.isExiting = true;
-
// If the working resources array hasn't changed at least once,
// just exit without autosaving
@@ -320,16 +317,15 @@
this.bookmarksCount = this.getBookmarks();
},
mounted() {
- if(this.quizForge.channels.value.length > 0){
+ if (this.quizForge.channels.value.length > 0) {
this.visibleResources = this.quizForge.channels.value;
- }else{
- this.visibleResources =[];
+ } else {
+ this.visibleResources = [];
}
setTimeout(() => {
this.checkRoute();
}, 1000);
-
},
methods: {
/** @public */
@@ -350,7 +346,7 @@
// return '';
// },
getBookmarks() {
- return this.bookmarks.length;
+ return this.bookmarks.length;
},
lessonCardClicked() {
this.showChannels = false;
@@ -361,9 +357,13 @@
name: PageNames.SELECT_FROM_RESOURCE,
params: {
topic_id: content.id,
+ classId: this.$route.params.classId,
+ section_id: this.$route.params.section_id,
},
};
}
+
+ return null; // or return {} if you prefer an empty object
},
handleSearchTerm(searchTerm) {
const query = {
@@ -419,8 +419,8 @@
contentIsDirectoryKind({ is_leaf }) {
return !is_leaf;
},
- checkRoute(){
- if(this.$route.params.topic_id){
+ checkRoute() {
+ if (this.$route.params.topic_id) {
this._getTopicsWithExerciseDescendants(this.$route.params.topic_id);
}
},
@@ -435,31 +435,31 @@
contains_quiz: true,
},
});
- const loadRequirements = [topicNodePromise, childNodesPromise];
+ const loadRequirements = [topicNodePromise, childNodesPromise];
- return Promise.all(loadRequirements).then(([/*topicNoitde*/, childNodes]) => {
- this.filterAndAnnotateContentList(childNodes);
- // return filterAndAnnotateContentList(childNodes).then(contentList => {
- // store.commit('SET_TOOLBAR_ROUTE', {
- // name: PageNames.EXAMS,
- // });
+ return Promise.all(loadRequirements).then(([, /*topicNoitde*/ childNodes]) => {
+ this.filterAndAnnotateContentList(childNodes);
+ // return filterAndAnnotateContentList(childNodes).then(contentList => {
+ // store.commit('SET_TOOLBAR_ROUTE', {
+ // name: PageNames.EXAMS,
+ // });
- // return showExamCreationPage(store, {
- // classId: params.classId,
- // contentList,
- // pageName: PageNames.EXAM_CREATION_SELECT_CHANNEL_QUIZ_TOPIC,
- // ancestors: [...topicNode.ancestors, topicNode],
- // });
- // });
+ // return showExamCreationPage(store, {
+ // classId: params.classId,
+ // contentList,
+ // pageName: PageNames.EXAM_CREATION_SELECT_CHANNEL_QUIZ_TOPIC,
+ // ancestors: [...topicNode.ancestors, topicNode],
+ // });
+ // });
+ });
});
- });
- }
+ },
// filteredquizForge.channels.value() {
// const { role } = this.filters;
// if (!this.inSearchMode) {
// return this.quizForge.channels.value;
// }
- // const list =
+ // const list =
// this.quizForge.channels.value ? this.quizForge.channels.value : this.bookmarksList;
// return list.filter(contentNode => {
// let passesFilters = true;
@@ -473,9 +473,7 @@
// });
// },
},
- $trs: {
-
- },
+ $trs: {},
};
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
index a2938e3b7c..a0833ef5a0 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
@@ -24,14 +24,14 @@
import ReplaceQuestions from './ReplaceQuestions';
import ResourceSelection from './ResourceSelection';
import ShowBookMarkedResources from './ShowBookMarkedResources.vue';
- // import SelectedChannel from './SelectedChannel.vue';
+ import SelectedChannel from './SelectedChannel.vue';
const pageNameComponentMap = {
[PageNames.QUIZ_SECTION_EDITOR]: SectionEditor,
[PageNames.QUIZ_REPLACE_QUESTIONS]: ReplaceQuestions,
[PageNames.QUIZ_SELECT_RESOURCES]: ResourceSelection,
[PageNames.BOOK_MARKED_RESOURCES]: ShowBookMarkedResources,
- [PageNames.SELECT_FROM_RESOURCE]: ResourceSelection,
+ [PageNames.SELECT_FROM_RESOURCE]: SelectedChannel,
};
export default {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
index 8044f8980d..9278ed6264 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
@@ -2,10 +2,11 @@
-
+
+
+
{{ selectFoldersOrExercises$() }}
@@ -39,7 +40,7 @@
-
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
index a0833ef5a0..a2938e3b7c 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionSidePanel.vue
@@ -24,14 +24,14 @@
import ReplaceQuestions from './ReplaceQuestions';
import ResourceSelection from './ResourceSelection';
import ShowBookMarkedResources from './ShowBookMarkedResources.vue';
- import SelectedChannel from './SelectedChannel.vue';
+ // import SelectedChannel from './SelectedChannel.vue';
const pageNameComponentMap = {
[PageNames.QUIZ_SECTION_EDITOR]: SectionEditor,
[PageNames.QUIZ_REPLACE_QUESTIONS]: ReplaceQuestions,
[PageNames.QUIZ_SELECT_RESOURCES]: ResourceSelection,
[PageNames.BOOK_MARKED_RESOURCES]: ShowBookMarkedResources,
- [PageNames.SELECT_FROM_RESOURCE]: SelectedChannel,
+ [PageNames.SELECT_FROM_RESOURCE]: ResourceSelection,
};
export default {
diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
index 9278ed6264..0e30dece1f 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SelectedChannel.vue
@@ -19,7 +19,7 @@
/>
import pickBy from 'lodash/pickBy';
- import { useResources } from '../../../composables/useResources';
+ import { useExerciseResources } from '../../../composables/useExerciseResources';
import { PageNames } from '../../../constants';
import ContentCardList from './../LessonResourceSelectionPage/ContentCardList.vue';
@@ -32,10 +32,11 @@
ContentCardList,
},
setup() {
- const { bookmarks } = useResources();
+ const { bookmarks, fetchTopicResource } = useExerciseResources();
return {
bookmarks,
+ fetchTopicResource,
};
},
data() {
@@ -61,6 +62,13 @@
return '';
},
},
+ beforeEnter(to, from, next) {
+ if (to.params.topic_id) {
+ next(vm => {
+ vm.updateResource();
+ });
+ }
+ },
watch: {
workingResources(newVal, oldVal) {
this.showResourcesDifferenceMessage(newVal.length - oldVal.length);
@@ -76,18 +84,28 @@
});
},
},
+ mounted() {
+ setTimeout(() => {
+ this.updateResource();
+ }, 1000);
+ },
methods: {
contentLink(content) {
- if (!content.is_leaf) {
- return {
- name: PageNames.SELECT_FROM_RESOURCE,
- params: {
- topic_id: content.id,
- },
- };
- } else {
- return {};
- }
+ // if (!content.is_leaf) {
+ this.fetchTopicResource(this.$route.params.topic_id).then(resource => {
+ this.bookmarks = resource.contentList;
+ });
+ return {
+ name: PageNames.SELECTED_BOOKMARKS,
+ params: {
+ topic_id: content.id,
+ classId: this.$route.params.classId,
+ section_id: this.$route.params.section_id,
+ },
+ };
+ // }else{
+ // return {};
+ // }
},
toggleTopicInWorkingResources(isChecked) {
if (isChecked) {
@@ -121,6 +139,11 @@
contentIsDirectoryKind({ is_leaf }) {
return !is_leaf;
},
+ updateResource() {
+ this.fetchTopicResource(this.$route.params.topic_id).then(resource => {
+ this.bookmarks = resource.contentList;
+ });
+ },
},
};
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 fe321cfb27..0c1f37fda7 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/ContentCardList.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/LessonResourceSelectionPage/ContentCardList.vue
@@ -10,8 +10,8 @@
@change="$emit('changeselectall', $event)"
/>
Date: Fri, 1 Dec 2023 23:03:08 +0300
Subject: [PATCH 49/50] added selection breadcrumbs
---
.../src/composables/useExerciseResources.js | 29 +-----
.../plan/CreateExamPage/ResourceSelection.vue | 93 ++++++-------------
2 files changed, 31 insertions(+), 91 deletions(-)
diff --git a/kolibri/plugins/coach/assets/src/composables/useExerciseResources.js b/kolibri/plugins/coach/assets/src/composables/useExerciseResources.js
index c531216a56..32b57ee5bf 100644
--- a/kolibri/plugins/coach/assets/src/composables/useExerciseResources.js
+++ b/kolibri/plugins/coach/assets/src/composables/useExerciseResources.js
@@ -13,6 +13,7 @@ export function useExerciseResources() {
const bookmarks = ref([]);
const channelTopics = ref([]);
const contentList = ref([]);
+ const ancestors = ref([]);
const currentTopicId = ref(null);
const currentTopic = ref(null);
const currentTopicResource = ref(null);
@@ -82,30 +83,6 @@ export function useExerciseResources() {
});
}
- // function fetchCurrentTopicId(id) {
- // currentTopicId.value = id;
- // if (id) {
- // currentTopicResource.value = fetchTopicResource(id);
- // } else {
- // currentTopicId.value = null;
- // }
- // }
-
- // // watch(currentTopicId, async (newTopicId, oldTopicId) => {
- // // if (newTopicId !== oldTopicId) {
- // // currentTopicResource.value = await fetchTopicResource(newTopicId);
- // // }
- // // });
-
- // function fetchCurrentTopic(id) {
- // currentTopic.value = id;
- // if (id) {
- // currentTopicResource.value = fetchTopicResource(id);
- // } else {
- // currentTopic.value = null;
-
- // }
-
function fetchTopicResource(topicId) {
const topicNodePromise = ContentNodeResource.fetchModel({ id: topicId });
const childNodesPromise = ContentNodeResource.fetchCollection({
@@ -118,7 +95,8 @@ export function useExerciseResources() {
return Promise.all(loadRequirements).then(([topicNode, childNodes]) => {
return filterAndAnnotateContentList(childNodes).then(contentList => {
- set(topicId, topicNode.id);
+ // set(topicId, topicNode.id);
+ ancestors.value = [...topicNode.ancestors, topicNode];
return {
...topicNode,
...contentList,
@@ -210,6 +188,7 @@ export function useExerciseResources() {
currentTopicId,
currentTopic,
currentTopicResource,
+ ancestors,
fetchChannelResource,
filterAndAnnotateContentList,
_getTopicsWithExerciseDescendants,
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 7dde913693..cabe7ec943 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -53,12 +53,12 @@
:searchResults="searchResults"
/> -->
-
+ />
{
- // if (isSamePage()) {
- // this.createSnackbar(this.$tr('saveBeforeExitSnackbarText'));
- // }
- // }, 500);
// Cancel any debounced calls
this.debouncedSaveResources.cancel();
@@ -351,6 +346,7 @@
if (!content.is_leaf) {
this.fetchTopicResource(this.$route.params.topic_id).then(resource => {
this.channels = resource.contentList;
+ // this.ancestors = resource.ancestors;
});
return {
name: PageNames.SELECT_FROM_RESOURCE,
@@ -396,6 +392,9 @@
this.moreResultsState = 'error';
});
},
+ selectionRootLink() {
+ return this.$router.getRoute(PageNames.SELECT_FROM_RESOURCE, {}, this.$route.query);
+ },
toggleSelected({ content, checked }) {
if (checked) {
this.addToSelectedResources(content);
@@ -423,60 +422,22 @@
this._getTopicsWithExerciseDescendants(this.$route.params.topic_id);
}
},
- // showChannelQuizCreationTopicPage(store, params) {
- // return store.dispatch('loading').then(() => {
- // const { topic_id } = params;
- // const topicNodePromise = ContentNodeResource.fetchModel({ id: topic_id });
- // const childNodesPromise = ContentNodeResource.fetchCollection({
- // getParams: {
- // parent: topic_id,
- // kind_in: [ContentNodeKinds.TOPIC, ContentNodeKinds.EXERCISE],
- // contains_quiz: true,
- // },
- // });
- // const loadRequirements = [topicNodePromise, childNodesPromise];
-
- // return Promise.all(loadRequirements).then(([, /*topicNoitde*/ childNodes]) => {
- // this.filterAndAnnotateContentList(childNodes);
- // return filterAndAnnotateContentList(childNodes).then(contentList => {
- // store.commit('SET_TOOLBAR_ROUTE', {
- // name: PageNames.EXAMS,
- // });
-
- // return showExamCreationPage(store, {
- // classId: params.classId,
- // contentList,
- // pageName: PageNames.EXAM_CREATION_SELECT_CHANNEL_QUIZ_TOPIC,
- // ancestors: [...topicNode.ancestors, topicNode],
- // });
- // });
- // });
- // });
- // },
updateResource() {
this.fetchTopicResource(this.$route.params.topic_id).then(resource => {
this.channels = resource.contentList;
+ this.ancestors = resource.ancestors;
});
},
-
- // filteredquizForge.channels.value() {
- // const { role } = this.filters;
- // if (!this.inSearchMode) {
- // return this.quizForge.channels.value;
- // }
- // const list =
- // this.quizForge.channels.value ? this.quizForge.channels.value : this.bookmarksList;
- // return list.filter(contentNode => {
- // let passesFilters = true;
- // if (role === 'nonCoach') {
- // passesFilters = passesFilters && contentNode.num_coach_contents === 0;
- // }
- // if (role === 'coach') {
- // passesFilters = passesFilters && contentNode.num_coach_contents > 0;
- // }
- // return passesFilters;
- // });
- // },
+ topicListingLink({ topicId }) {
+ return this.$router.getRoute(
+ PageNames.SELECT_FROM_RESOURCE,
+ { topicId },
+ this.$route.query
+ );
+ },
+ topicsLink(topicId) {
+ return this.topicListingLink({ ...this.$route.params, topicId });
+ },
},
$trs: {},
};
From eea8aeb9af929e68f7f742060f2a34f6a5f252c8 Mon Sep 17 00:00:00 2001
From: Allan Otodi Opeto <103313919+AllanOXDi@users.noreply.github.com>
Date: Sat, 2 Dec 2023 01:20:04 +0300
Subject: [PATCH 50/50] added selection breadcrumbs
---
.../plan/CreateExamPage/ResourceSelection.vue | 51 +++++++++++++++----
.../strings/enhancedQuizManagementStrings.js | 3 ++
2 files changed, 43 insertions(+), 11 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 cabe7ec943..f2eebb53a0 100644
--- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
+++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/ResourceSelection.vue
@@ -74,8 +74,31 @@
@change_content_card="toggleSelected"
@moreresults="handleMoreResults"
/>
+
+
+
+ {{ numberOfResources$({ count: channels.length }) }}
+
+
+
+
+
+
+
@@ -117,6 +140,8 @@
selectFromBookmarks$,
numberOfSelectedBookmarks$,
selectFoldersOrExercises$,
+ numberOfSelectedResources$,
+ numberOfResources$,
} = enhancedQuizManagementStrings;
const {
bookmarks,
@@ -132,6 +157,8 @@
selectFromBookmarks$,
numberOfSelectedBookmarks$,
selectFoldersOrExercises$,
+ numberOfSelectedResources$,
+ numberOfResources$,
windowIsSmall,
bookmarks,
channels,
@@ -166,8 +193,7 @@
return this.channels;
}
- const list = this.channels ? this.channels : this.bookmarksList;
- return list.filter(contentNode => {
+ return this.channels.filter(contentNode => {
let passesFilters = true;
if (role === 'nonCoach') {
passesFilters = passesFilters && contentNode.num_coach_contents === 0;
@@ -201,9 +227,7 @@
contentIsInLesson() {
return ({ id }) =>
Boolean(
- this.channels.find(resource => {
- id === resource.id;
- })
+ this.channels
);
},
selectionMetadata(/*content*/) {
@@ -417,11 +441,6 @@
contentIsDirectoryKind({ is_leaf }) {
return !is_leaf;
},
- checkRoute() {
- if (this.$route.params.topic_id) {
- this._getTopicsWithExerciseDescendants(this.$route.params.topic_id);
- }
- },
updateResource() {
this.fetchTopicResource(this.$route.params.topic_id).then(resource => {
this.channels = resource.contentList;
@@ -439,7 +458,7 @@
return this.topicListingLink({ ...this.$route.params, topicId });
},
},
- $trs: {},
+
};
@@ -506,4 +525,14 @@
margin-left: 15rem;
}
+ .bottom-navigation {
+ background-color: white;
+ color: black;
+ padding: 10px;
+ position: fixed;
+ bottom: 0;
+ width: 50%;
+ text-align: center;
+ }
+
diff --git a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
index 4e06fcdedb..5e1f43cbce 100644
--- a/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
+++ b/packages/kolibri-common/strings/enhancedQuizManagementStrings.js
@@ -150,4 +150,7 @@ export const enhancedQuizManagementStrings = createTranslator('EnhancedQuizManag
message:
'{ count, number } { count, plural, one { question successfully replaced } other { questions successfully replaced }} ',
},
+ numberOfResources:{
+ message:'{count, number} {count, plural, one {resource selected} other {resources selected}}',
+ },
});