Repository: learningequality/kolibri

Issue:
Enhance Quiz- Side panel doesn't show on mobile

## Overview

When I was explaining a certain piece of behavior in the  select resource component  to  @akolson .  I discovered that  when you  want to add resource while on mobile the side panel does not appear at all.  or  when it's loaded and the page change to mobile view everything get's distorted.



Uploading Screen Recording 2024-02-01 at 16.37.15.mov…



improve exam preview layout when there are many questions in a quiz

### Observed behavior

see comments in https://docs.google.com/document/d/1QeRghWCFdJgWV627DaIWRM80pJ3IkJr_TRQjI4uJXEw/edit#heading=h.kj33sjr8m9b5

### Expected behavior

don't scroll exercise preview offscreen

### User-facing consequences

extra scrolling when quizzes have many questions


### Steps to reproduce

create a quiz with 50 questions and then try to rearrange them 

### Context

0.12


Discussion:
Hello sir @AllanOXDi  can you assign me this issue ?
Hi @ProgrammingPirates - this will be worked on by our core development team, for issues you could help take on, please look for unassigned issues with the help wanted label. For a complete list of such issues across our repos, you can look at this link:

https://github.com/search?q=org%3Alearningequality+is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee&type=issues


Resolving patch:
diff --git a/kolibri/plugins/learn/viewsets.py b/kolibri/plugins/learn/viewsets.py
--- a/kolibri/plugins/learn/viewsets.py
+++ b/kolibri/plugins/learn/viewsets.py
@@ -16,6 +16,7 @@
 from kolibri.core.content.api import UserContentNodeViewset
 from kolibri.core.content.models import ContentNode
 from kolibri.core.exams.models import Exam
+from kolibri.core.exams.models import exam_assignment_lookup
 from kolibri.core.lessons.models import Lesson
 from kolibri.core.logger.models import AttemptLog
 from kolibri.core.logger.models import MasteryLog
@@ -182,14 +183,19 @@ def consolidate(self, items, queryset):
                 "title",
                 "closed",
                 "answer_count",
+                "data_model_version",
                 "score",
                 "question_sources",
             )
         )
         exam_node_ids = set()
+
         for exam in exams:
             exam_node_ids |= {
-                question["exercise_id"] for question in exam.get("question_sources")
+                exercise_id
+                for exercise_id, _ in exam_assignment_lookup(
+                    exam.get("question_sources", [])
+                )
             }
 
         available_exam_ids = set(
@@ -217,8 +223,10 @@ def consolidate(self, items, queryset):
                     "started": False,
                 }
             exam["missing_resource"] = any(
-                question["exercise_id"] not in available_exam_ids
-                for question in exam.get("question_sources")
+                exercise_id not in available_exam_ids
+                for exercise_id, _ in exam_assignment_lookup(
+                    exam.get("question_sources", [])
+                )
             )
         out_items = []
         for item in items:


Test patch:
diff --git a/kolibri/plugins/coach/assets/test/selectRandomExamQuestions.spec.js b/kolibri/plugins/coach/assets/test/selectRandomExamQuestions.spec.js
--- a/kolibri/plugins/coach/assets/test/selectRandomExamQuestions.spec.js
+++ b/kolibri/plugins/coach/assets/test/selectRandomExamQuestions.spec.js
@@ -1,4 +1,3 @@
-import filter from 'lodash/filter';
 import selectQuestions from '../src/utils/selectQuestions';
 
 jest.mock('kolibri.lib.logging');
@@ -84,16 +83,4 @@ describe('selectQuestions function', () => {
     const output2 = selectQuestions(numQs, EXERCISES_IDS, EXERCISES_TITLES, QUESTION_IDS, 2);
     expect(output1).not.toEqual(output2);
   });
-
-  it('will not add the same question twice', () => {
-    // Two copies of the same exercise, and a numQuestions that would previously
-    // force duplicates.
-    const exerciseIds = ['C1', 'C2'];
-    const titles = ['original c', 'copy of c'];
-    const assessments = ['A1', 'A2'];
-    const questionIds = [assessments, assessments];
-    const output = selectQuestions(4, exerciseIds, titles, questionIds, 1);
-    expect(filter(output, { question_id: 'A1' })).toHaveLength(1);
-    expect(filter(output, { question_id: 'A2' })).toHaveLength(1);
-  });
 });
diff --git a/kolibri/plugins/coach/assets/test/useQuizCreation.spec.js b/kolibri/plugins/coach/assets/test/useQuizCreation.spec.js
--- a/kolibri/plugins/coach/assets/test/useQuizCreation.spec.js
+++ b/kolibri/plugins/coach/assets/test/useQuizCreation.spec.js
@@ -53,7 +53,12 @@ function generateExercise(numQuestions) {
   const assessments = generateQuestions(numQuestions);
   const assessmentmetadata = { assessment_item_ids: assessments.map(q => q.question_id) };
   const exercise = objectWithDefaults(
-    { content_id: 'exercise_1', assessmentmetadata },
+    {
+      id: 'exercise_1',
+      content_id: 'exercise_1',
+      assessmentmetadata,
+      unique_question_ids: assessments.map(q => `exercise_1:${q.question_id}`),
+    },
     QuizExercise
   );
   return exercise;