Difference between revisions of "My course overview improvements"

Jump to: navigation, search
 
(8 intermediate revisions by 3 users not shown)
Line 16: Line 16:
  
 
== Requirements ==
 
== Requirements ==
 +
https://docs.google.com/document/d/13ukTgOBdDzkKmPhfyMH81inWkbfJL5CPsyQmLBDWq5k/edit
  
 +
== Technical Details ==
 
=== Course Overview Block ===
 
=== Course Overview Block ===
 
The course overview block will communicate exclusively with the Todo API and will present the Todo's as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.
 
The course overview block will communicate exclusively with the Todo API and will present the Todo's as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.
Line 31: Line 33:
 
*** As above, single template for a course
 
*** As above, single template for a course
 
* Javascript
 
* Javascript
** Add a module to interact with the Todo API (no bespoke ajax requests everywhere please)
 
 
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)
 
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)
 
** Module for timeline view (maybe even have separate modules for "sort by dates" and "sort by courses"?). Handles requesting the data and rendering the templates etc.
 
** Module for timeline view (maybe even have separate modules for "sort by dates" and "sort by courses"?). Handles requesting the data and rendering the templates etc.
Line 38: Line 39:
 
*** Module needs to handle paginated results (view more button being clicked)
 
*** Module needs to handle paginated results (view more button being clicked)
 
** Use the new pie chart we add
 
** Use the new pie chart we add
 +
** User the todo api javascript module to interact with the server external API
 
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)
 
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)
 
** Style Boost theme
 
** Style Boost theme
Line 47: Line 49:
 
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)
 
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)
  
=== Todo API ===
+
=== Action Event API ===
This will be a new API in core to represent the concept of "todos" in Moodle, i.e. the list of items displayed in the course overview block. A todo is made up of a calendar event and an associated action for the user.  
+
This will be a new API in core to represent the concept of "action events" in Moodle, i.e. the list of items displayed in the course overview block. A action event is made up of a calendar event and an associated action for the user.  
  
 
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can't be started until after another module has been completed etc.  
 
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can't be started until after another module has been completed etc.  
Line 62: Line 64:
 
*** url - the url of the thing the todo relates to (e.g. view.php of the module)
 
*** url - the url of the thing the todo relates to (e.g. view.php of the module)
 
*** user id - the id of the user this todo belong to
 
*** user id - the id of the user this todo belong to
*** course id - the course if that the todo relates to
+
*** course id - the course that the todo relates to
 
*** icon url - the icon for the todo (default to the module icon)
 
*** icon url - the icon for the todo (default to the module icon)
 
*** start date (optional) - when the todo starts
 
*** start date (optional) - when the todo starts
Line 70: Line 72:
 
*** action url - url of the todo action (e.g. link to the assignment submission page)
 
*** action url - url of the todo action (e.g. link to the assignment submission page)
 
*** action start date - a date after which the todo can be actioned (only display the action url after this date)
 
*** action start date - a date after which the todo can be actioned (only display the action url after this date)
 +
*** action state - Has this been actioned? Eg, The assignment was submitted.
 
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).
 
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).
 
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).
 
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).
Line 78: Line 81:
 
** Support pagination as above
 
** Support pagination as above
 
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).
 
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).
** The core todo API can't (and shouldn't) know every place that will want to create a todo, so we need to provide a standard way for each plugin to register itself as something that will create a todo and an interface for them to do the data manipulation required.
+
** The core action event API can't (and shouldn't) know every place that will want to create a action event, so we need to provide a standard way for each plugin to register itself as something that will create an action event and an interface for them to do the data manipulation required.
 
* Add an external API class.
 
* Add an external API class.
 
** This class shouldn't contain any business logic (that all lives in the API class).  
 
** This class shouldn't contain any business logic (that all lives in the API class).  
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the todo.
+
** All it needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the action event.
 
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.
 
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.
* Add some renderables for the todo
+
* Add some renderables for the action event
** The todos should probably just be renderable / template-able themselves
+
** The action events should probably just be renderable / template-able themselves
 
** These will be used by the external API class.
 
** These will be used by the external API class.
 
* Improve performance using caching (this will be trial and error with the performance testing)
 
* Improve performance using caching (this will be trial and error with the performance testing)
 
* Write unit tests for all new API functions and external API functions
 
* Write unit tests for all new API functions and external API functions
 +
* Add a javascript module to interact with the action event API (no bespoke ajax requests everywhere please)
  
 
=== Chart.js ===
 
=== Chart.js ===
Line 93: Line 97:
  
 
=== Calendar Event API ===
 
=== Calendar Event API ===
We'll be using the existing calendar events as the basis for the "todos". The current calendar event data structure contains most of the data that we'll need so we'll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we'll need.
+
We'll be using the existing calendar events as the basis for the "action events". The current calendar event data structure contains most of the data that we'll need so we'll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we'll need.
  
 
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation
 
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation
Line 108: Line 112:
  
 
=== Calendar Block ===
 
=== Calendar Block ===
* Make sure all of the todos are showing up in the calendar for the user
+
* Make sure all of the action events are showing up in the calendar for the user
 
** Note: we *should* get this for free since we are simply creating calendar events
 
** Note: we *should* get this for free since we are simply creating calendar events
 +
* Make sure we are only displaying appropriate events (ie. if there is a user override then show that for the user, not multiple).
  
 
=== Course Completion Tracking ===
 
=== Course Completion Tracking ===
Line 118: Line 123:
 
** Assess performance of both options
 
** Assess performance of both options
 
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate
 
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate
 +
 +
==== Notes ====
 +
There are different ways of calculating the completion percentage for a course and some will be more informative than others, depending on the type of usage of the course.
 +
 +
Some possible options are:
 +
* The number of completed+visible activities / The number of visible activities
 +
* The number of completed activities / The number of activities
 +
* The current week / the number of weeks
 +
* The (current date - course start date) / (course end date - course start date) * Requires a course end date
 +
* The current course grade / the required course grade (don’t expose hidden grades)
 +
* The enrolment duration / the required enrolment duration
 +
 +
Because each course completion criteria requires a different calculation, one possible method is:
 +
 +
'''If course completion is enabled'''
 +
 +
for each course completion criteria - get the current and total possible values for completion
 +
 +
'''if all are required:'''
 +
 +
normalise and sum/average the values
 +
 +
'''if any is required'''
 +
 +
calculate the highest percentage completion
 +
 +
'''If only activity completion is enabled (and not course completion)'''
 +
 +
calculate the completion percentage purely on the number of activities complete / the total number of activities. (Ignoring activities with no completion - should we ignore activities the current user cannot see via access restrictions?)
 +
 +
'''If course completion is not enabled'''
 +
 +
Try and calculation the completion based purely on the course start / end date
 +
 +
'''To calculate the current and total values for each completion criteria:'''
 +
* Activity completion - number of activities complete / number of activities required to be completed
 +
* Completion of other courses - number of courses complete / number of courses required to be completed
 +
* Enrolment Date - the current date - course start date / the enrolled until date - course start date. If there is no course start date use the enrolment start date. Max of 1.
 +
* Enroled duration - the number of days enrolled / the number of days required to be enrolled. Max of 1.
 +
* Unenrollment. 0 if enrolled, 1 if unenrolled.
 +
* Course grade - current course grade / required course grade. Max of 1.
 +
* Manual self completion. 0 if not complete, 1 if complete
 +
* Manual completion by others. 0 if not complete, 1 if complete
  
 
=== General Moodle stuff ===
 
=== General Moodle stuff ===
Line 130: Line 178:
 
=== General Testing ===
 
=== General Testing ===
 
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.
 
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.
 
=== Proof Of Concept Code ===
 
I've knocked together a little proof of concept type branch that does a skeleton implementation of some of this stuff. You can find it here https://github.com/moodle/moodle/compare/e6cb76d...ryanwyllie:todos_poc_2
 
 
Please review it and add any comments or what ever.
 
 
== Questions for the UX team ==
 
* How many items to display in "Next 7 days"? Is there a limit, or we always show all of the items?
 
* In the prototype 6c (the one that we are supposed to develop from) the todo disappears from the list when it is actioned. Is this the correct behaviour? What happens to the corresponding event in the calendar? Does that also get removed?
 
* What do we show when a todo is only available for a certain duration? E.g. chat where it's open for only 3 days. Only having the end date seems weird in that case.
 
* Is the list of courses paginated in the courses view? Is there a "More" button to load more courses?
 
* What happens with courses which do not have a start date, and end date? Will they show in "In progress" for as long as I am enrolled in them? Note that if I unenrol from the course, I will lose access to it.
 
* Are all the three tabs (in progress, upcoming, completed) always shown, even if they are empty?
 

Latest revision as of 17:46, 16 March 2017

This page will detail the technical specification for the improvements to the My course overview block.

Improvements to my course overview block.
Project state Starting
Tracker issue MDL-55611
Discussion https://tracker.moodle.org/browse/UX-8
Assignee HQ Projects Team


Summary

The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of "date based" tasks for the current user.

The existing "mod print_overview" callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview).

Requirements

https://docs.google.com/document/d/13ukTgOBdDzkKmPhfyMH81inWkbfJL5CPsyQmLBDWq5k/edit

Technical Details

Course Overview Block

The course overview block will communicate exclusively with the Todo API and will present the Todo's as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.

  • Mustache templates:
    • General template for the block (wrapping template)
      • Timeline view
        • Sort by dates (wrapping template)
          • Template for displaying single todo (rendered in list)
        • Sort by courses (wrapping template)
          • Single course section, includes list of todos similar to "sort by dates" (can maybe re-use the template for a single todo here)
    • Courses view
      • Single template can probably be re-used for "in progress", "upcoming" and "completed" views, just rendered with different data
      • As above, single template for a course
  • Javascript
    • Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)
    • Module for timeline view (maybe even have separate modules for "sort by dates" and "sort by courses"?). Handles requesting the data and rendering the templates etc.
      • Module needs to handle paginated results (view more button being clicked)
    • Module for courses view that handles requesting the data and rendering the templates
      • Module needs to handle paginated results (view more button being clicked)
    • Use the new pie chart we add
    • User the todo api javascript module to interact with the server external API
  • CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)
    • Style Boost theme
    • Style bootstrap base theme (e.g. clean)
    • Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)
  • Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)
  • Update blocks/course_overview/block_course_overview.php "get_content" to render a template via the renderer (need to add a new function)
  • Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)
  • Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)

Action Event API

This will be a new API in core to represent the concept of "action events" in Moodle, i.e. the list of items displayed in the course overview block. A action event is made up of a calendar event and an associated action for the user.

The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can't be started until after another module has been completed etc.

Given the intensity of some of these calculations we'll need to look into aggressively caching results and maybe even avoid doing the calculations per request.

Since we're leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.

  • Add a todo class (pretty please can we have an actual class rather than just stdClass)
    • Some properties of the class:
      • unique id (context id, component, area and item id?)
      • name - the name of the thing the todo relates to (e.g. activity name)
      • url - the url of the thing the todo relates to (e.g. view.php of the module)
      • user id - the id of the user this todo belong to
      • course id - the course that the todo relates to
      • icon url - the icon for the todo (default to the module icon)
      • start date (optional) - when the todo starts
      • end date (optional) - when the todo must be actioned by
      • item count - how many associated items there are (e.g. 4 unread posts)
      • action name - display name of the todo (e.g. "submit assignment")
      • action url - url of the todo action (e.g. link to the assignment submission page)
      • action start date - a date after which the todo can be actioned (only display the action url after this date)
      • action state - Has this been actioned? Eg, The assignment was submitted.
  • Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).
    • Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).
  • Add a data access layer that abstracts away all of the SQL so that we don't have that logic everywhere (ideally).
    • The API class would benefit from this.
    • It can also hide the fact that we're piggy backing on the calendar events, just in case we want to change that in the future.
    • It can also handle all of the caching
    • Support pagination as above
  • Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).
    • The core action event API can't (and shouldn't) know every place that will want to create a action event, so we need to provide a standard way for each plugin to register itself as something that will create an action event and an interface for them to do the data manipulation required.
  • Add an external API class.
    • This class shouldn't contain any business logic (that all lives in the API class).
    • All it needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the action event.
    • All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.
  • Add some renderables for the action event
    • The action events should probably just be renderable / template-able themselves
    • These will be used by the external API class.
  • Improve performance using caching (this will be trial and error with the performance testing)
  • Write unit tests for all new API functions and external API functions
  • Add a javascript module to interact with the action event API (no bespoke ajax requests everywhere please)

Chart.js

  • Add a new chart type (pie chart) to Moodle's chart API for use in the templates above

Calendar Event API

We'll be using the existing calendar events as the basis for the "action events". The current calendar event data structure contains most of the data that we'll need so we'll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we'll need.

  • Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation
  • Add indexes to the event table if they are missing
    • display/order by date
    • course id
    • user id
  • Add functions to the calendar event API to retrieve groups of events for a given user(s)
    • currently it seems the API only loads one at a time so you need to do direct SQL in the calling code
    • API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set
    • API needs to support order by new date field
    • API needs to support limit and offset
  • Add unit tests for new API functions

Calendar Block

  • Make sure all of the action events are showing up in the calendar for the user
    • Note: we *should* get this for free since we are simply creating calendar events
  • Make sure we are only displaying appropriate events (ie. if there is a user override then show that for the user, not multiple).

Course Completion Tracking

  • Develop a way to track completion on for all courses
    • This needs to take into account all activities within the course, even ones that don't have any completion tracking enabled
  • Add an API to query the completion status of a course that implements the agreed approach
  • Do we need to persist the course progress somewhere or can it be calculated at run time?
    • Assess performance of both options
  • If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate

Notes

There are different ways of calculating the completion percentage for a course and some will be more informative than others, depending on the type of usage of the course.

Some possible options are:

  • The number of completed+visible activities / The number of visible activities
  • The number of completed activities / The number of activities
  • The current week / the number of weeks
  • The (current date - course start date) / (course end date - course start date) * Requires a course end date
  • The current course grade / the required course grade (don’t expose hidden grades)
  • The enrolment duration / the required enrolment duration

Because each course completion criteria requires a different calculation, one possible method is:

If course completion is enabled

for each course completion criteria - get the current and total possible values for completion

if all are required:

normalise and sum/average the values

if any is required

calculate the highest percentage completion

If only activity completion is enabled (and not course completion)

calculate the completion percentage purely on the number of activities complete / the total number of activities. (Ignoring activities with no completion - should we ignore activities the current user cannot see via access restrictions?)

If course completion is not enabled

Try and calculation the completion based purely on the course start / end date

To calculate the current and total values for each completion criteria:

  • Activity completion - number of activities complete / number of activities required to be completed
  • Completion of other courses - number of courses complete / number of courses required to be completed
  • Enrolment Date - the current date - course start date / the enrolled until date - course start date. If there is no course start date use the enrolment start date. Max of 1.
  • Enroled duration - the number of days enrolled / the number of days required to be enrolled. Max of 1.
  • Unenrollment. 0 if enrolled, 1 if unenrolled.
  • Course grade - current course grade / required course grade. Max of 1.
  • Manual self completion. 0 if not complete, 1 if complete
  • Manual completion by others. 0 if not complete, 1 if complete

General Moodle stuff

  • Remove all uses of the "print_overview" callback thingo we're using through Moodle for modules to add stuff to the course overview block
  • Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events
  • Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)
  • Add an implementation of the callback interface thingo to each module that will be creating a todo
    • This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc
    • It will then create the appropriate todo from the calendar event and add all of the action stuff.

General Testing

  • We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.