diff --git a/.env b/.env index c8064b4664..3423229dce 100644 --- a/.env +++ b/.env @@ -47,3 +47,4 @@ TERMS_OF_SERVICE_URL='' TWITTER_HASHTAG='' TWITTER_URL='' USER_INFO_COOKIE_NAME='' +SHOW_UNGRADED_ASSIGNMENT_PROGRESS='' diff --git a/.env.development b/.env.development index f0cae5b828..cf1782a39c 100644 --- a/.env.development +++ b/.env.development @@ -47,3 +47,4 @@ TWITTER_HASHTAG='myedxjourney' TWITTER_URL='https://twitter.com/edXOnline' USER_INFO_COOKIE_NAME='edx-user-info' SESSION_COOKIE_DOMAIN='localhost' +SHOW_UNGRADED_ASSIGNMENT_PROGRESS='' diff --git a/.env.test b/.env.test index d183517053..e6f0855392 100644 --- a/.env.test +++ b/.env.test @@ -45,3 +45,4 @@ TERMS_OF_SERVICE_URL='https://www.edx.org/edx-terms-service' TWITTER_HASHTAG='myedxjourney' TWITTER_URL='https://twitter.com/edXOnline' USER_INFO_COOKIE_NAME='edx-user-info' +SHOW_UNGRADED_ASSIGNMENT_PROGRESS='' diff --git a/src/course-home/progress-tab/ProgressTab.test.jsx b/src/course-home/progress-tab/ProgressTab.test.jsx index 9f6dc3dbf5..8fa1aa1b3b 100644 --- a/src/course-home/progress-tab/ProgressTab.test.jsx +++ b/src/course-home/progress-tab/ProgressTab.test.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { Factory } from 'rosie'; -import { getConfig } from '@edx/frontend-platform'; +import { getConfig, setConfig } from '@edx/frontend-platform'; import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { breakpoints } from '@edx/paragon'; @@ -520,6 +520,111 @@ describe('Progress Tab', () => { await fetchAndRender(); expect(screen.getByText('Grades & Credit')).toBeInTheDocument(); }); + + it('does not render ungraded subsections when SHOW_UNGRADED_ASSIGNMENT_PROGRESS is false', async () => { + // The second assignment has has_graded_assignment set to false, so it should not be shown. + setTabData({ + section_scores: [ + { + display_name: 'First section', + subsections: [ + { + assignment_type: 'Homework', + block_key: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@12345', + display_name: 'First subsection', + learner_has_access: true, + has_graded_assignment: true, + num_points_earned: 1, + num_points_possible: 2, + percent_graded: 1.0, + show_correctness: 'always', + show_grades: true, + url: 'http://learning.edx.org/course/course-v1:edX+Test+run/first_subsection', + }, + ], + }, + { + display_name: 'Second section', + subsections: [ + { + assignment_type: 'Homework', + display_name: 'Second subsection', + learner_has_access: true, + has_graded_assignment: false, + num_points_earned: 1, + num_points_possible: 1, + percent_graded: 1.0, + show_correctness: 'always', + show_grades: true, + url: 'http://learning.edx.org/course/course-v1:edX+Test+run/second_subsection', + }, + ], + }, + ], + }); + + await fetchAndRender(); + expect(screen.getByText('First subsection')).toBeInTheDocument(); + expect(screen.queryByText('Second subsection')).not.toBeInTheDocument(); + }); + + it('renders both graded and ungraded subsections when SHOW_UNGRADED_ASSIGNMENT_PROGRESS is true', async () => { + // The second assignment has has_graded_assignment set to false. + setConfig({ + ...getConfig(), + SHOW_UNGRADED_ASSIGNMENT_PROGRESS: true, + }); + + setTabData({ + section_scores: [ + { + display_name: 'First section', + subsections: [ + { + assignment_type: 'Homework', + block_key: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@12345', + display_name: 'First subsection', + learner_has_access: true, + has_graded_assignment: true, + num_points_earned: 1, + num_points_possible: 2, + percent_graded: 1.0, + show_correctness: 'always', + show_grades: true, + url: 'http://learning.edx.org/course/course-v1:edX+Test+run/first_subsection', + }, + ], + }, + { + display_name: 'Second section', + subsections: [ + { + assignment_type: 'Homework', + display_name: 'Second subsection', + learner_has_access: true, + has_graded_assignment: false, + num_points_earned: 1, + num_points_possible: 1, + percent_graded: 1.0, + show_correctness: 'always', + show_grades: true, + url: 'http://learning.edx.org/course/course-v1:edX+Test+run/second_subsection', + }, + ], + }, + ], + }); + + await fetchAndRender(); + expect(screen.getByText('First subsection')).toBeInTheDocument(); + expect(screen.getByText('Second subsection')).toBeInTheDocument(); + + // reset config for other tests + setConfig({ + ...getConfig(), + SHOW_UNGRADED_ASSIGNMENT_PROGRESS: false, + }); + }); }); describe('Grade Summary', () => { @@ -784,7 +889,7 @@ describe('Progress Tab', () => { // Open the problem score drawer fireEvent.click(problemScoreDrawerToggle); - expect(screen.getByText('Problem Scores:')).toBeInTheDocument(); + expect(screen.getAllByText('Graded Scores:').length).toBeGreaterThan(1); expect(screen.getAllByText('0/1')).toHaveLength(3); }); @@ -796,6 +901,14 @@ describe('Progress Tab', () => { expect(screen.getByText('Detailed grades')).toBeInTheDocument(); expect(screen.getByText('You currently have no graded problem scores.')).toBeInTheDocument(); }); + + it('renders Detailed Grades table when section scores are populated', async () => { + await fetchAndRender(); + expect(screen.getByText('Detailed grades')).toBeInTheDocument(); + + expect(screen.getByText('First subsection')); + expect(screen.getByText('Second subsection')); + }); }); describe('Certificate Status', () => { diff --git a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx index c7f2b1138a..256626e06f 100644 --- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx +++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { useSelector } from 'react-redux'; +import { getConfig } from '@edx/frontend-platform'; import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; @@ -28,6 +29,11 @@ const DetailedGrades = ({ intl }) => { } = useModel('progress', courseId); const hasSectionScores = sectionScores.length > 0; + const showUngradedAssignments = ( + getConfig().SHOW_UNGRADED_ASSIGNMENT_PROGRESS === 'true' + || getConfig().SHOW_UNGRADED_ASSIGNMENT_PROGRESS === true + ); + const emptyTableMsg = showUngradedAssignments ? messages.detailedGradesEmpty : messages.detailedGradesEmptyOnlyGraded; const logOutlineLinkClick = () => { sendTrackEvent('edx.ui.lms.course_progress.detailed_grades.course_outline_link.clicked', { @@ -54,7 +60,25 @@ const DetailedGrades = ({ intl }) => { return (
-

{intl.formatMessage(messages.detailedGrades)}

+

{intl.formatMessage(messages.detailedGrades)}

+ {gradesFeatureIsPartiallyLocked && (
@@ -65,9 +89,9 @@ const DetailedGrades = ({ intl }) => { )} {!hasSectionScores && ( -

{intl.formatMessage(messages.detailedGradesEmpty)}

+

{intl.formatMessage(emptyTableMsg)}

)} - {overviewTabUrl && ( + {overviewTabUrl && !showUngradedAssignments && (

{ } = useModel('progress', courseId); const isLocaleRtl = isRtl(getLocale()); + const showUngradedAssignments = ( + getConfig().SHOW_UNGRADED_ASSIGNMENT_PROGRESS === 'true' + || getConfig().SHOW_UNGRADED_ASSIGNMENT_PROGRESS === true + ); return ( sectionScores.map((chapter) => { const subsectionScores = chapter.subsections.filter( (subsection) => !!( - subsection.hasGradedAssignment - && subsection.showGrades - && (subsection.numPointsPossible > 0 || subsection.numPointsEarned > 0)), + (showUngradedAssignments || subsection.hasGradedAssignment) + && subsection.showGrades + && (subsection.numPointsPossible > 0 || subsection.numPointsEarned > 0) + ), ); if (subsectionScores.length === 0) { diff --git a/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx b/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx index 855f3dfe46..15b20c46aa 100644 --- a/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx +++ b/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx @@ -10,9 +10,12 @@ import messages from '../messages'; const ProblemScoreDrawer = ({ intl, problemScores, subsection }) => { const isLocaleRtl = isRtl(getLocale()); + + const scoreLabel = subsection.hasGradedAssignment ? messages.gradedScoreLabel : messages.practiceScoreLabel; + return ( - {intl.formatMessage(messages.problemScoreLabel)} + {intl.formatMessage(scoreLabel)}

    {problemScores.map(problemScore => ( @@ -30,7 +33,10 @@ ProblemScoreDrawer.propTypes = { earned: PropTypes.number.isRequired, possible: PropTypes.number.isRequired, })).isRequired, - subsection: PropTypes.shape({ learnerHasAccess: PropTypes.bool }).isRequired, + subsection: PropTypes.shape({ + learnerHasAccess: PropTypes.bool, + hasGradedAssignment: PropTypes.bool, + }).isRequired, }; export default injectIntl(ProblemScoreDrawer); diff --git a/src/course-home/progress-tab/grades/messages.js b/src/course-home/progress-tab/grades/messages.js index 72a6624b2b..fb57809852 100644 --- a/src/course-home/progress-tab/grades/messages.js +++ b/src/course-home/progress-tab/grades/messages.js @@ -91,9 +91,14 @@ const messages = defineMessages({ defaultMessage: 'Detailed grades', description: 'Headline for the (detailed grade) section in the progress tab', }, - detailedGradesEmpty: { + detailedGradesEmptyOnlyGraded: { id: 'progress.detailedGrades.emptyTable', defaultMessage: 'You currently have no graded problem scores.', + description: 'It indicate that there are no graded problem or assignments to be scored', + }, + detailedGradesEmpty: { + id: 'progress.detailedGrades.including-ungraded.emptyTable', + defaultMessage: 'You currently have no graded or ungraded problem scores.', description: 'It indicate that there are no problem or assignments to be scored', }, footnotesTitle: { @@ -158,11 +163,16 @@ const messages = defineMessages({ defaultMessage: 'Passing grade', description: 'Label for mark on the (grade bar) chart which indicate the poisition of passing grade on the bar', }, - problemScoreLabel: { + gradedScoreLabel: { id: 'progress.detailedGrades.problemScore.label', - defaultMessage: 'Problem Scores:', + defaultMessage: 'Graded Scores:', description: 'Label text which precedes detailed view of all scores per assignment', }, + practiceScoreLabel: { + id: 'progress.detailedGrades.practice.problemScore.label', + defaultMessage: 'Practice Scores:', + description: 'Label text which precedes detailed view of all ungraded problem scores per assignment', + }, problemScoreToggleAltText: { id: 'progress.detailedGrades.problemScore.toggleButton', defaultMessage: 'Toggle individual problem scores for {subsectionTitle}', diff --git a/src/index.jsx b/src/index.jsx index fe4dc124d2..e5bb53ffe1 100755 --- a/src/index.jsx +++ b/src/index.jsx @@ -140,6 +140,7 @@ initialize({ EXAMS_BASE_URL: process.env.EXAMS_BASE_URL || null, PROCTORED_EXAM_FAQ_URL: process.env.PROCTORED_EXAM_FAQ_URL || null, PROCTORED_EXAM_RULES_URL: process.env.PROCTORED_EXAM_RULES_URL || null, + SHOW_UNGRADED_ASSIGNMENT_PROGRESS: process.env.SHOW_UNGRADED_ASSIGNMENT_PROGRESS || false, }, 'LearnerAppConfig'); }, },