def get_context_data(self, **kwargs):
        self.secondary_nav_items = copy.deepcopy(self.secondary_nav_items_base)
        if switch_is_active('enable_performance_learning_outcome'):
            if not any(d['name'] == 'learning_outcomes'
                       for d in self.secondary_nav_items):
                self.secondary_nav_items.append({
                    'name':
                    'learning_outcomes',
                    'text':
                    ugettext_noop('Learning Outcomes'),
                    'view':
                    'courses:performance:learning_outcomes',
                    'scope':
                    'course',
                    'lens':
                    'performance',
                    'report':
                    'outcomes',
                    'depth':
                    ''
                })
                translate_dict_values(self.secondary_nav_items, ('text', ))

        context_data = super().get_context_data(**kwargs)
        self.presenter = CoursePerformancePresenter(self.access_token,
                                                    self.course_id)

        context_data['no_data_message'] = self.no_data_message
        context_data['js_data']['course'].update({
            'contentTableHeading':
            _('Assignment Name')  # overwrite for different heading
        })

        return context_data
    def test_translate_dict_values(self):
        list_of_dicts = [
            {
                'foo': '1',
                'bar': '2',
                'baz': '2'
            },
            {
                'foo': '4',
                'bar': '2',
                'baz': '3'
            },
        ]
        expected = deepcopy(list_of_dicts)
        for a_dict in expected:
            a_dict['translated_foo'] = _(a_dict['foo'])

        self.assertTrue(translate_dict_values(list_of_dicts, ('foo', )))

        self.assertListEqual(expected, list_of_dicts)

        self.assertFalse(translate_dict_values(list_of_dicts, ('foo', )))

        with self.assertRaises(KeyError):
            translate_dict_values(list_of_dicts, ('bad', ))
def _enrollment_tertiary_nav():
    tertiary_age = [{
        'name': 'age',
        'text': ugettext_noop('Age'),
        'view': 'courses:enrollment:demographics_age',
        'scope': 'course',
        'lens': 'enrollment',
        'report': 'demographics',
        'depth': 'age'
    }] if age_available() else []
    tertiary_nav_items = tertiary_age + [{
        'name': 'education',
        'text': ugettext_noop('Education'),
        'view': 'courses:enrollment:demographics_education',
        'scope': 'course',
        'lens': 'enrollment',
        'report': 'demographics',
        'depth': 'education'
    }, {
        'name': 'gender',
        'text': ugettext_noop('Gender'),
        'view': 'courses:enrollment:demographics_gender',
        'scope': 'course',
        'lens': 'enrollment',
        'report': 'demographics',
        'depth': 'gender'
    }]
    translate_dict_values(tertiary_nav_items, ('text', ))
    return tertiary_nav_items
示例#4
0
    def get_primary_nav_items(self, request):
        """
        Return the primary nav items.
        """

        items = [{
            'name': 'enrollment',
            'text': ugettext_noop('Enrollment'),
            'view': 'courses:enrollment:activity',
            'icon': 'fa-child',
            'fragment': '',
            'scope': 'course',
            'lens': 'enrollment',
            'report': 'activity',
            'depth': ''
        }, {
            'name': 'engagement',
            'text': ugettext_noop('Engagement'),
            'view': 'courses:engagement:content',
            'icon': 'fa-bar-chart',
            'fragment': '',
            'scope': 'course',
            'lens': 'engagement',
            'report': 'content',
            'depth': ''
        }, {
            'name': 'performance',
            'text': ugettext_noop('Performance'),
            'view': 'courses:performance:graded_content',
            'icon': 'fa-check-square-o',
            'switch': 'enable_course_api',
            'fragment': '',
            'scope': 'course',
            'lens': 'performance',
            'report': 'graded',
            'depth': ''
        }, {
            'name': 'learners',
            'text': ugettext_noop('Learners'),
            'view': 'courses:learners:learners',
            'icon': 'fa-users',
            'flag': 'display_learner_analytics',
            'fragment': '#?ignore_segments=inactive',
            'scope': 'course',
            'lens': 'learners',
            'report': 'roster',
            'depth': ''
        }]

        translate_dict_values(items, ('text', ))

        # Remove disabled items
        items = [item for item in items if is_feature_enabled(item, request)]

        # Clean each item
        list(map(self.clean_item, items))

        return items
示例#5
0
class EngagementTemplateView(CourseTemplateWithNavView):
    """
    Base view for course engagement pages.
    """
    secondary_nav_items = [
        {
            'name': 'content',
            # Translators: Content as in course content (e.g. things, not the feeling)
            'text': ugettext_noop('Content'),
            'view': 'courses:engagement:content',
            'scope': 'course',
            'lens': 'engagement',
            'report': 'content',
            'depth': ''
        },
        {
            'name': 'videos',
            'text': ugettext_noop('Videos'),
            'view': 'courses:engagement:videos',
            'switch': 'enable_engagement_videos_pages',
            'scope': 'course',
            'lens': 'engagement',
            'report': 'videos',
            'depth': ''
        },
    ]
    translate_dict_values(secondary_nav_items, ('text', ))
    active_primary_nav_item = 'engagement'
    presenter = None
class EnrollmentTemplateView(CourseTemplateWithNavView):
    """
    Base view for course enrollment pages.
    """
    secondary_nav_items = [
        {
            'name': 'activity',
            'text': ugettext_noop('Activity'),
            'view': 'courses:enrollment:activity',
            'scope': 'course',
            'lens': 'enrollment',
            'report': 'activity',
            'depth': ''
        },
        {
            'name': 'demographics',
            'text': ugettext_noop('Demographics'),
            'view': 'courses:enrollment:demographics_age',
            'scope': 'course',
            'lens': 'enrollment',
            'report': 'demographics',
            'depth': 'age'
        },
        {
            'name': 'geography',
            'text': ugettext_noop('Geography'),
            'view': 'courses:enrollment:geography',
            'scope': 'course',
            'lens': 'enrollment',
            'report': 'geography',
            'depth': ''
        },
    ]
    translate_dict_values(secondary_nav_items, ('text', ))
    active_primary_nav_item = 'enrollment'
class PerformanceTemplateView(CourseStructureExceptionMixin, CourseTemplateWithNavView, CourseAPIMixin):
    """
    Base view for course performance pages.
    """
    presenter = None
    problem_id = None
    part_id = None
    no_data_message = None

    # Translators: Do not translate UTC.
    update_message = _('Problem submission data was last updated %(update_date)s at %(update_time)s UTC.')

    secondary_nav_items_base = [
        {
            'name': 'graded_content',
            'text': ugettext_noop('Graded Content'),
            'view': 'courses:performance:graded_content',
            'scope': 'course',
            'lens': 'performance',
            'report': 'graded',
            'depth': ''
        },
        {
            'name': 'ungraded_content',
            'text': ugettext_noop('Ungraded Problems'),
            'view': 'courses:performance:ungraded_content',
            'scope': 'course',
            'lens': 'performance',
            'report': 'ungraded',
            'depth': ''
        },
    ]
    translate_dict_values(secondary_nav_items_base, ('text',))
    secondary_nav_items = None
    active_primary_nav_item = 'performance'

    def get_context_data(self, **kwargs):
        self.secondary_nav_items = copy.deepcopy(self.secondary_nav_items_base)
        if switch_is_active('enable_performance_learning_outcome'):
            if not any(d['name'] == 'learning_outcomes' for d in self.secondary_nav_items):
                self.secondary_nav_items.append({
                    'name': 'learning_outcomes',
                    'text': ugettext_noop('Learning Outcomes'),
                    'view': 'courses:performance:learning_outcomes',
                    'scope': 'course',
                    'lens': 'performance',
                    'report': 'outcomes',
                    'depth': ''
                })
                translate_dict_values(self.secondary_nav_items, ('text',))

        context_data = super(PerformanceTemplateView, self).get_context_data(**kwargs)
        self.presenter = CoursePerformancePresenter(self.access_token, self.course_id)

        context_data['no_data_message'] = self.no_data_message
        context_data['js_data']['course'].update({
            'contentTableHeading': _('Assignment Name')  # overwrite for different heading
        })

        return context_data
def _enrollment_secondary_nav():
    demographics_landing_view = {
        'name': 'demographics',
        'text': ugettext_noop('Demographics'),
        'view': 'courses:enrollment:demographics_age',
        'scope': 'course',
        'lens': 'enrollment',
        'report': 'demographics',
        'depth': 'age'
    } if age_available() else {
        'name': 'demographics',
        'text': ugettext_noop('Demographics'),
        'view': 'courses:enrollment:demographics_education',
        'scope': 'course',
        'lens': 'enrollment',
        'report': 'demographics',
        'depth': 'education'
    }

    secondary_nav_items = [
        {
            'name': 'activity',
            'text': ugettext_noop('Activity'),
            'view': 'courses:enrollment:activity',
            'scope': 'course',
            'lens': 'enrollment',
            'report': 'activity',
            'depth': ''
        },
        demographics_landing_view,
        {
            'name': 'geography',
            'text': ugettext_noop('Geography'),
            'view': 'courses:enrollment:geography',
            'scope': 'course',
            'lens': 'enrollment',
            'report': 'geography',
            'depth': ''
        },
    ]
    translate_dict_values(secondary_nav_items, ('text', ))
    return secondary_nav_items
class EnrollmentDemographicsTemplateView(EnrollmentTemplateView):
    """
    Base view for course enrollment demographics pages.
    """
    active_secondary_nav_item = 'demographics'
    tertiary_nav_items = [{
        'name': 'age',
        'text': ugettext_noop('Age'),
        'view': 'courses:enrollment:demographics_age',
        'scope': 'course',
        'lens': 'enrollment',
        'report': 'demographics',
        'depth': 'age'
    }, {
        'name': 'education',
        'text': ugettext_noop('Education'),
        'view': 'courses:enrollment:demographics_education',
        'scope': 'course',
        'lens': 'enrollment',
        'report': 'demographics',
        'depth': 'education'
    }, {
        'name': 'gender',
        'text': ugettext_noop('Gender'),
        'view': 'courses:enrollment:demographics_gender',
        'scope': 'course',
        'lens': 'enrollment',
        'report': 'demographics',
        'depth': 'gender'
    }]
    translate_dict_values(tertiary_nav_items, ('text', ))

    # Translators: Do not translate UTC.
    update_message = _(
        'Demographic learner data was last updated %(update_date)s at %(update_time)s UTC.'
    )

    # pylint: disable=line-too-long
    # Translators: This sentence is displayed at the bottom of the page and describe the demographics data displayed.
    data_information_message = _(
        'All above demographic data was self-reported at the time of registration.'
    )

    def format_percentage(self, value):
        if value is None:
            formatted_percent = u'0'
        else:
            formatted_percent = intcomma(round(value, 3) * 100)

        return formatted_percent
示例#10
0
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({'table_items': self.get_table_items()})

        context['page_data'] = self.get_page_data(context)

        # Some orgs do not wish to allow access to learner analytics.
        # See https://openedx.atlassian.net/browse/DENG-536
        course_org = CourseKey.from_string(self.course_id).org
        if course_org in settings.BLOCK_LEARNER_ANALYTICS_ORG_LIST:
            user = self.request.user.get_username()
            logger.info(
                'Removing learner analytics from the %s course home page user %s',
                self.course_id, user)
            context['primary_nav_items'] = [
                item for item in context['primary_nav_items']
                if item['name'] != 'learners'
            ]
            context['table_items'] = [
                item for item in context['table_items']
                if item['name'] != _('Learners')
            ]

        overview_data = []
        if self.course_api_enabled:
            if switch_is_active('display_course_name_in_nav'):
                # Translators: 'Course ID' is 'Course Identifier', the unique code that identifies the course
                overview_data.append((_('Course ID'), self.course_id))
            else:
                overview_data.append(
                    (_('Course Name'), self.course_info.get('name')))

            def parse_course_date(date_str):
                return datetime.strptime(
                    date_str, CourseStructureApiClient.DATETIME_FORMAT
                ) if date_str else None

            def format_date(date):
                return dateformat.format(
                    date, settings.DATE_FORMAT) if date else "--"

            start_date = parse_course_date(self.course_info.get('start'))
            end_date = parse_course_date(self.course_info.get('end'))
            todays_date = datetime.now()
            status_str = '--'
            if start_date:
                if todays_date >= start_date:
                    in_progress = (end_date is None or end_date > todays_date)
                    # Translators: 'In Progress' and 'Ended' refer to whether learners are
                    # actively using the course or it is over.
                    status_str = _('In Progress') if in_progress else _(
                        'Ended')
                else:
                    # Translators: This refers to a course that has not yet begun.
                    status_str = _('Not Started Yet')
            overview_data += [
                (_('Start Date'), format_date(start_date)),
                (_('End Date'), format_date(end_date)),
                (_('Status'), status_str),
            ]

        context['course_overview'] = overview_data

        external_tools = []

        if settings.LMS_COURSE_SHORTCUT_BASE_URL:
            external_tools.append({
                'title':
                ugettext_noop('Instructor Dashboard'),
                'url':
                f"{settings.LMS_COURSE_SHORTCUT_BASE_URL}/{self.course_id}/instructor",
                'icon':
                'fa-dashboard',
            })
            external_tools.append({
                'title': ugettext_noop('Courseware'),
                'url':
                f"{settings.LMS_COURSE_SHORTCUT_BASE_URL}/{self.course_id}/courseware",
                'icon': 'fa-pencil-square-o',
            })
        if settings.CMS_COURSE_SHORTCUT_BASE_URL:
            external_tools.append({
                'title': 'Studio',
                'translated_title':
                'Studio',  # As a brand name, "Studio" is not translated.
                'url':
                f"{settings.CMS_COURSE_SHORTCUT_BASE_URL}/{self.course_id}",
                'icon': 'fa-sliders',
            })

        translate_dict_values(external_tools, ('title', ))
        context['external_course_tools'] = external_tools

        return context
示例#11
0
    def get_table_items(self):
        items = []

        enrollment_subitems = [{
            'title':
            ugettext_noop('How many learners are in my course?'),
            'view':
            'courses:enrollment:activity',
            'breadcrumbs': [_('Activity')],
            'fragment':
            '',
            'scope':
            'course',
            'lens':
            'enrollment',
            'report':
            'activity',
            'depth':
            ''
        }]
        if age_available():
            enrollment_subitems = enrollment_subitems + [
                {
                    'title': ugettext_noop('How old are my learners?'),
                    'view': 'courses:enrollment:demographics_age',
                    'breadcrumbs': [_('Demographics'),
                                    _('Age')],
                    'fragment': '',
                    'scope': 'course',
                    'lens': 'enrollment',
                    'report': 'demographics',
                    'depth': 'age'
                }
            ]
        enrollment_subitems = enrollment_subitems + [
            {
                'title':
                ugettext_noop('What level of education do my learners have?'),
                'view':
                'courses:enrollment:demographics_education',
                'breadcrumbs': [_('Demographics'),
                                _('Education')],
                'fragment':
                '',
                'scope':
                'course',
                'lens':
                'enrollment',
                'report':
                'demographics',
                'depth':
                'education'
            },
            {
                'title':
                ugettext_noop('What is the learner gender breakdown?'),
                'view': 'courses:enrollment:demographics_gender',
                'breadcrumbs': [_('Demographics'),
                                _('Gender')],
                'fragment': '',
                'scope': 'course',
                'lens': 'enrollment',
                'report': 'demographics',
                'depth': 'gender'
            },
            {
                'title': ugettext_noop('Where are my learners?'),
                'view': 'courses:enrollment:geography',
                'breadcrumbs': [_('Geography')],
                'fragment': '',
                'scope': 'course',
                'lens': 'enrollment',
                'report': 'geography',
                'depth': ''
            },
        ]

        enrollment_items = {
            'name': _('Enrollment'),
            'icon': 'fa-child',
            'heading': _('Who are my learners?'),
            'items': enrollment_subitems,
        }
        items.append(enrollment_items)

        engagement_items = {
            'name':
            _('Engagement'),
            'icon':
            'fa-bar-chart',
            'heading':
            _('What are learners doing in my course?'),
            'items': [{
                'title':
                ugettext_noop(
                    'How many learners are interacting with my course?'),
                'view':
                'courses:engagement:content',
                'breadcrumbs': [_('Content')],
                'fragment':
                '',
                'scope':
                'course',
                'lens':
                'engagement',
                'report':
                'content',
                'depth':
                ''
            }]
        }
        if switch_is_active('enable_engagement_videos_pages'):
            engagement_items['items'].append({
                'title':
                ugettext_noop('How did learners interact with course videos?'),
                'view':
                'courses:engagement:videos',
                'breadcrumbs': [_('Videos')],
                'fragment':
                '',
                'scope':
                'course',
                'lens':
                'engagement',
                'report':
                'videos',
                'depth':
                ''
            })

        items.append(engagement_items)

        if self.course_api_enabled:
            subitems = [{
                'title':
                ugettext_noop(
                    'How are learners doing on graded course assignments?'),
                'view':
                'courses:performance:graded_content',
                'breadcrumbs': [_('Graded Content')],
                'fragment':
                '',
                'scope':
                'course',
                'lens':
                'performance',
                'report':
                'graded',
                'depth':
                ''
            }, {
                'title':
                ugettext_noop('How are learners doing on ungraded exercises?'),
                'view':
                'courses:performance:ungraded_content',
                'breadcrumbs': [_('Ungraded Problems')],
                'fragment':
                '',
                'scope':
                'course',
                'lens':
                'performance',
                'report':
                'ungraded',
                'depth':
                ''
            }]

            if switch_is_active('enable_performance_learning_outcome'):
                subitems.append({
                    'title':
                    ugettext_noop(
                        'What is the breakdown for course learning outcomes?'),
                    'view':
                    'courses:performance:learning_outcomes',
                    'breadcrumbs': [_('Learning Outcomes')],
                    'fragment':
                    '',
                    'scope':
                    'course',
                    'lens':
                    'performance',
                    'report':
                    'outcomes',
                    'depth':
                    ''
                })

            if switch_is_active('enable_problem_response_download'):
                try:
                    info = CourseReportDownloadPresenter(
                        self.course_id, self.analytics_client).get_report_info(
                            report_name=CourseReportDownloadPresenter.
                            PROBLEM_RESPONSES)
                except NotFoundError:
                    info = {}
                if 'download_url' in info:
                    # A problem response report CSV is available:
                    subitems.append({
                        'title':
                        ugettext_noop(
                            'How are learners responding to questions?'),
                        'view':
                        'courses:csv:performance_problem_responses',
                        'breadcrumbs': [_('Problem Response Report')],
                        'format':
                        'csv',
                    })

            items.append({
                'name':
                _('Performance'),
                'icon':
                'fa-check-square-o',
                'heading':
                _('How are learners doing on course assignments?'),
                'items':
                subitems
            })

        if DISPLAY_LEARNER_ANALYTICS.is_enabled():
            items.append({
                'name':
                _('Learners'),
                'icon':
                'fa-users',
                'heading':
                _('What are individual learners doing?'),
                'items': [
                    {
                        'title': ugettext_noop("Who is engaged? Who isn't?"),
                        'view': 'courses:learners:learners',
                        'breadcrumbs': [_('All Learners')],
                        'fragment': '#?ignore_segments=inactive',
                        'scope': 'course',
                        'lens': 'learners',
                        'report': 'roster',
                        'depth': ''
                    },
                    # TODO: this is commented out until we complete the deep linking work, AN-6671
                    # {
                    #     'title': _('Who has been active recently?'),
                    #     'view': 'courses:learners:learners',  # TODO: map this to the actual action in AN-6205
                    #     # TODO: what would the breadcrumbs be?
                    #     'breadcrumbs': [_('Learners')]
                    # },
                    # {
                    #     'title': _('Who is most engaged in the discussions?'),
                    #     'view': 'courses:learners:learners',  # TODO: map this to the actual action in AN-6205
                    #     # TODO: what would the breadcrumbs be?
                    #     'breadcrumbs': [_('Learners')]
                    # },
                    # {
                    #     'title': _("Who hasn't watched videos recently?"),
                    #     'view': 'courses:learners:learners',  # TODO: map this to the actual action in AN-6205
                    #     # TODO: what would the breadcrumbs be?
                    #     'breadcrumbs': [_('Learners')]
                    # }
                ]
            })

        translate_dict_values(items, ('name', ))
        for item in items:
            translate_dict_values(item['items'], ('title', ))

        return items
示例#12
0
    def get_context_data(self, **kwargs):
        context = super(CourseHome, self).get_context_data(**kwargs)
        context.update({
            'table_items': self.get_table_items(self.request)
        })

        context['page_data'] = self.get_page_data(context)

        overview_data = []
        if self.course_api_enabled:
            if switch_is_active('display_course_name_in_nav'):
                # Translators: 'Course ID' is 'Course Identifier', the unique code that identifies the course
                overview_data.append((_('Course ID'), self.course_id))
            else:
                overview_data.append((_('Course Name'), self.course_info.get('name')))

            def parse_course_date(date_str):
                return datetime.strptime(date_str, CourseStructureApiClient.DATETIME_FORMAT) if date_str else None

            def format_date(date):
                return dateformat.format(date, settings.DATE_FORMAT) if date else "--"

            start_date = parse_course_date(self.course_info.get('start'))
            end_date = parse_course_date(self.course_info.get('end'))
            todays_date = datetime.now()
            status_str = '--'
            if start_date:
                if todays_date >= start_date:
                    in_progress = (end_date is None or end_date > todays_date)
                    # Translators: 'In Progress' and 'Ended' refer to whether learners are
                    # actively using the course or it is over.
                    status_str = _('In Progress') if in_progress else _('Ended')
                else:
                    # Translators: This refers to a course that has not yet begun.
                    status_str = _('Not Started Yet')
            overview_data += [
                (_('Start Date'), format_date(start_date)),
                (_('End Date'), format_date(end_date)),
                (_('Status'), status_str),
            ]

        context['course_overview'] = overview_data

        external_tools = []

        if settings.LMS_COURSE_SHORTCUT_BASE_URL:
            external_tools.append({
                'title': ugettext_noop('Instructor Dashboard'),
                'url': "{}/{}/instructor".format(settings.LMS_COURSE_SHORTCUT_BASE_URL, self.course_id),
                'icon': 'fa-dashboard',
            })
            external_tools.append({
                'title': ugettext_noop('Courseware'),
                'url': "{}/{}/courseware".format(settings.LMS_COURSE_SHORTCUT_BASE_URL, self.course_id),
                'icon': 'fa-pencil-square-o',
            })
        if settings.CMS_COURSE_SHORTCUT_BASE_URL:
            external_tools.append({
                'title': 'Studio',
                'translated_title': 'Studio',  # As a brand name, "Studio" is not translated.
                'url': "{}/{}".format(settings.CMS_COURSE_SHORTCUT_BASE_URL, self.course_id),
                'icon': 'fa-sliders',
            })

        translate_dict_values(external_tools, ('title',))
        context['external_course_tools'] = external_tools

        return context
示例#13
0
    def get_table_items(self):
        items = []

        enrollment_subitems = [
            {
                'title': ugettext_noop('How many learners are in my course?'),
                'view': 'courses:enrollment:activity',
                'breadcrumbs': [_('Activity')],
                'fragment': '',
                'scope': 'course',
                'lens': 'enrollment',
                'report': 'activity',
                'depth': ''
            }]
        if age_available():
            enrollment_subitems = enrollment_subitems + [
                {
                    'title': ugettext_noop('How old are my learners?'),
                    'view': 'courses:enrollment:demographics_age',
                    'breadcrumbs': [_('Demographics'), _('Age')],
                    'fragment': '',
                    'scope': 'course',
                    'lens': 'enrollment',
                    'report': 'demographics',
                    'depth': 'age'
                }]
        enrollment_subitems = enrollment_subitems + [
            {
                'title': ugettext_noop('What level of education do my learners have?'),
                'view': 'courses:enrollment:demographics_education',
                'breadcrumbs': [_('Demographics'), _('Education')],
                'fragment': '',
                'scope': 'course',
                'lens': 'enrollment',
                'report': 'demographics',
                'depth': 'education'
            },
            {
                'title': ugettext_noop('What is the learner gender breakdown?'),
                'view': 'courses:enrollment:demographics_gender',
                'breadcrumbs': [_('Demographics'), _('Gender')],
                'fragment': '',
                'scope': 'course',
                'lens': 'enrollment',
                'report': 'demographics',
                'depth': 'gender'
            },
            {
                'title': ugettext_noop('Where are my learners?'),
                'view': 'courses:enrollment:geography',
                'breadcrumbs': [_('Geography')],
                'fragment': '',
                'scope': 'course',
                'lens': 'enrollment',
                'report': 'geography',
                'depth': ''
            },
        ]

        enrollment_items = {
            'name': _('Enrollment'),
            'icon': 'fa-child',
            'heading': _('Who are my learners?'),
            'items': enrollment_subitems,
        }
        items.append(enrollment_items)

        engagement_items = {
            'name': _('Engagement'),
            'icon': 'fa-bar-chart',
            'heading': _('What are learners doing in my course?'),
            'items': [
                {
                    'title': ugettext_noop('How many learners are interacting with my course?'),
                    'view': 'courses:engagement:content',
                    'breadcrumbs': [_('Content')],
                    'fragment': '',
                    'scope': 'course',
                    'lens': 'engagement',
                    'report': 'content',
                    'depth': ''
                }
            ]
        }
        if switch_is_active('enable_engagement_videos_pages'):
            engagement_items['items'].append({
                'title': ugettext_noop('How did learners interact with course videos?'),
                'view': 'courses:engagement:videos',
                'breadcrumbs': [_('Videos')],
                'fragment': '',
                'scope': 'course',
                'lens': 'engagement',
                'report': 'videos',
                'depth': ''
            })

        items.append(engagement_items)

        if self.course_api_enabled:
            subitems = [{
                'title': ugettext_noop('How are learners doing on graded course assignments?'),
                'view': 'courses:performance:graded_content',
                'breadcrumbs': [_('Graded Content')],
                'fragment': '',
                'scope': 'course',
                'lens': 'performance',
                'report': 'graded',
                'depth': ''
            }, {
                'title': ugettext_noop('How are learners doing on ungraded exercises?'),
                'view': 'courses:performance:ungraded_content',
                'breadcrumbs': [_('Ungraded Problems')],
                'fragment': '',
                'scope': 'course',
                'lens': 'performance',
                'report': 'ungraded',
                'depth': ''
            }]

            if switch_is_active('enable_performance_learning_outcome'):
                subitems.append({
                    'title': ugettext_noop('What is the breakdown for course learning outcomes?'),
                    'view': 'courses:performance:learning_outcomes',
                    'breadcrumbs': [_('Learning Outcomes')],
                    'fragment': '',
                    'scope': 'course',
                    'lens': 'performance',
                    'report': 'outcomes',
                    'depth': ''
                })

            if switch_is_active('enable_problem_response_download'):
                try:
                    info = CourseReportDownloadPresenter(self.course_id, self.analytics_client).get_report_info(
                        report_name=CourseReportDownloadPresenter.PROBLEM_RESPONSES
                    )
                except NotFoundError:
                    info = {}
                if 'download_url' in info:
                    # A problem response report CSV is available:
                    subitems.append({
                        'title': ugettext_noop('How are learners responding to questions?'),
                        'view': 'courses:csv:performance_problem_responses',
                        'breadcrumbs': [_('Problem Response Report')],
                        'format': 'csv',
                    })

            items.append({
                'name': _('Performance'),
                'icon': 'fa-check-square-o',
                'heading': _('How are learners doing on course assignments?'),
                'items': subitems
            })

        translate_dict_values(items, ('name',))
        for item in items:
            translate_dict_values(item['items'], ('title',))

        return items