Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add quiz report visibility control for coaches #13064

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from

Conversation

LianaHarris360
Copy link
Member

Summary

This pull request implements the functionality to enable coaches to select when a quiz report is visible to learners. Coaches can now choose to allow learners to see their quiz report immediately after submitting the quiz or only after the coach ends the quiz.

The Exam model, api, and serializer have been updated to include the boolean field instant_report_visibility, which defaults to true, indicating that learners will instantly see their quiz report once they complete a quiz. When this field is false, learners will see their quiz reports after the quiz is closed. A new migration file has been created to include the new field to the exam model.

When creating a new quiz, the icon circleCheckmark beside the Report Visibility selection button will be available in KDS V5.0.0

Creating a new quiz:

CreateNewQuiz.mov

Learner quiz report unavailable:

CannotViewQuizReport.mov

Quiz Status page:
QuizStatusVisibleAfterCoachEndsQuiz

QuizStatusInstantVisibility

References

Figma (see "Quiz report Visibility" including "Learner Experience" below)
Closes #12902

Reviewer guidance

  1. Create a quiz as a coach, and select 'After learner submits quiz' or 'After coach ends the quiz'.
  2. Take the quiz as a learner and confirm that the quiz report is shown or not shown to the learner, based on the quiz instant_report_visibility
  3. Confirm that the learner can see the quiz report if the quiz has been closed.
  4. After the coach ends the quiz, the Report Visibility section on the Quiz Status page is not displayed.

@github-actions github-actions bot added DEV: backend Python, databases, networking, filesystem... APP: Learn Re: Learn App (content, quizzes, lessons, etc.) APP: Coach Re: Coach App (lessons, quizzes, groups, reports, etc.) DEV: frontend labels Feb 11, 2025
Copy link
Member

@nucleogenesis nucleogenesis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave the code a look and had one minor question. I think that so long as the exam's value for the visibility field reflects the exam's previously saved value then it's all good.

Overall, the code changes here LGTM! I'll leave approval to QA and others.

@@ -217,6 +256,7 @@
formIsSubmitted: false,
showServerError: false,
showTitleError: false,
instantReportVisibility: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be dynamic rather than hard-set? For example, when I open an exam for editing, should this be set to the value previously saved to the exam?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oi, just realized that you've set it in mounted - curious if you tried assigning it to instantReportVisibility: this.assignment.instant_report_visibility || true; here rather than in mounted below?

Copy link
Member Author

@LianaHarris360 LianaHarris360 Feb 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, the only thing is if this.assignement.instant_report_visibility is false, true would still be returned. But I could do:
instantReportVisibility: this.assignment.instant_report_visibility ?? true
Since doing so would remove the need to set it in the mounted hook, I will update the PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just read that the Nullish coalescing operator (??) is mainly supported on newer browsers so I've decided to set it as instantReportVisibility: this.assignment.instant_report_visibility !== false, because false !== false evaluates to false, and for all other values, it is set to true.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: I went with setting instantReportVisibility: this.assignment.instant_report_visibility, since that is what previously happened in the mounted hook anyway.

Setting it as: instantReportVisibility: this.assignment.instant_report_visibility !== false, caused lessons to also contain a instant_report_visibility which broke the tests, and only quizzes should have this field.

This field is set to true by default in kolibri/plugins/coach/assets/src/composables/quizCreationSpecs.js, so when a new quiz is created, it has the correct setting. So it was unnecessary to set it in mounted(), thanks for pointing this out!

@marcellamaki
Copy link
Member

@radinamatic @pcenov - could this go on the QA team list for tomorrow? Thank you!

@pcenov
Copy link
Member

pcenov commented Feb 19, 2025

Hi @LianaHarris360 - I confirm that everything is implemented and working as specified above.
The only issue that I want to mention is that when I have assigned a quiz to a learner on a learn only device, then if the learner is at the page with the assigned quizzes just after the sync with the server has happened the learner can click on the quiz card which is displayed as if the report can be previewed while for some reason it has not loaded yet. If I navigate to another plugin and come back then everything is fine. This is an edge case but can be confusing so if it can be handled better that would be great!

LOD.mp4

@nucleogenesis
Copy link
Member

IMO the issue @pcenov reported re: the synced data not being reflected in the Learn UI might be an issue beyond the scope of this PR and should probably be a new issue addressed separately - should be confirmed w/ @marcellamaki

@radinamatic
Copy link
Member

Similar to recent PR I tested for non-editable quizzes from previous versions, it seemed to me that this feature could also have potential issues during upgrade scenarios, so I upgraded a 0.16.2 Kolibri install with the asset from this PR.

  1. Class on that 0.16.2 facility that was upgraded had 2 quizzes that were not ended by the coach, but the learner had already submitted one of them (and presumably already seen the report).

    • If the coach goes and edits the quiz details to change the report visibility to after the quiz ends, learner is not able to open the report anymore and modal appears as expected.

    • However, once coach ends the quiz, that same learner is still unable to open the report, and they continue to see the modal. No amount of navigating away and back on either learner or coach side makes it possible for learner to see the report again.

      reports-visible.mp4

      Granted this seems like an edge case, but just raises some concerns and doubts whether we considered all the implications that this new report visibility feature can have in a variety of upgrade scenarios

  2. Another thing I noticed (marked at timestamp 1:44), is that report on the coach side states that this same quiz ended 1 minute ago, but the report was made visible 207 days ago... (F)actually correct, but very confusing!

Full home folder used in this test case.

@@ -158,6 +158,10 @@ class Meta:
"""
data_model_version = models.SmallIntegerField(default=3)

# If True, learners have instant access to exam reports after submission.
# Otherwise, reports are visible only after the coach ends the exam.
instant_report_visibility = models.BooleanField(default=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we may want to be careful about exactly how we add this field - my specific thought is in relation to the migration this will produce on KDP.

When we add a Django model field with a default value, this can result in a very long running migration, if the table is large.

The way to avoid this is to allow the field to be nullable null=True - and handle the null values, and return them as True via the API.

We create the migration with null=True and no default. Then we add the default=True and create another migration. At this point, we can merge the two migration files into one, just as long as the AddField operations are first, and then the AlterField to add the default comes after.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a good point. It would be simpler and safer to allow the field to be null and return a True value for it. I will update the field and do the migration adjustments.

@LianaHarris360
Copy link
Member Author

Thank you for adding the home folder for that use case @radinamatic I think navigating away from the plugin and back to see the report is a problem I can fix within this PR. The learner should be able to see those updates as soon as they're available, especially if they’ve just recently synced. However, I can see how this might be outside the scope of the PR, so I can open an separate issue to address this if necessary.

And the report visibility timestamp that the coach sees after the ending the quiz should be updated to reflect the correct timestamp that the report was available, if it was set to “After coach ends the quiz”. I will update this pull request to fix that.

@@ -69,6 +69,7 @@ class ExamViewset(ValuesViewset):
"creator",
"data_model_version",
"learners_see_fixed_order",
"instant_report_visibility",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only thing I can think of here, is that we should probably return True for this if the backend value is null - that will save the frontend from having to worry about the nullability of the field, and leave it entirely as a backend concern (as we only really introduced it for the purposes of migration).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
APP: Coach Re: Coach App (lessons, quizzes, groups, reports, etc.) APP: Learn Re: Learn App (content, quizzes, lessons, etc.) DEV: backend Python, databases, networking, filesystem... DEV: frontend
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow coaches to choose when a quiz report should become visible to learner
6 participants