Skip to content

Commit e69114a

Browse files
authored
feat: option to show/hide ungraded assignment in progress page (#1380)
* feat: option to show/hide ungraded assignment in progress page test: add tests for show ungraded toggle feat: update score label in progress page based on grading refactor: update score label text and add tooltip refactor: move label tooltip near header as normal text refactor: update problem score label Graded scores * refactor: move config check to utils
1 parent 2d63a14 commit e69114a

File tree

10 files changed

+176
-13
lines changed

10 files changed

+176
-13
lines changed

.env

+1
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ TWITTER_HASHTAG=''
4848
TWITTER_URL=''
4949
USER_INFO_COOKIE_NAME=''
5050
OPTIMIZELY_FULL_STACK_SDK_KEY=''
51+
SHOW_UNGRADED_ASSIGNMENT_PROGRESS=''

.env.development

+1
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,4 @@ SESSION_COOKIE_DOMAIN='localhost'
5050
CHAT_RESPONSE_URL='http://localhost:18000/api/learning_assistant/v1/course_id'
5151
PRIVACY_POLICY_URL='http://localhost:18000/privacy'
5252
OPTIMIZELY_FULL_STACK_SDK_KEY=''
53+
SHOW_UNGRADED_ASSIGNMENT_PROGRESS=''

.env.test

+1
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ TWITTER_HASHTAG='myedxjourney'
4747
TWITTER_URL='https://twitter.com/edXOnline'
4848
USER_INFO_COOKIE_NAME='edx-user-info'
4949
PRIVACY_POLICY_URL='http://localhost:18000/privacy'
50+
SHOW_UNGRADED_ASSIGNMENT_PROGRESS=''

src/course-home/progress-tab/ProgressTab.test.jsx

+115-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import { Factory } from 'rosie';
3-
import { getConfig } from '@edx/frontend-platform';
3+
import { getConfig, setConfig } from '@edx/frontend-platform';
44
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
55
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
66
import { breakpoints } from '@openedx/paragon';
@@ -545,6 +545,111 @@ describe('Progress Tab', () => {
545545
await fetchAndRender();
546546
expect(screen.getByText('Grades & Credit')).toBeInTheDocument();
547547
});
548+
549+
it('does not render ungraded subsections when SHOW_UNGRADED_ASSIGNMENT_PROGRESS is false', async () => {
550+
// The second assignment has has_graded_assignment set to false, so it should not be shown.
551+
setTabData({
552+
section_scores: [
553+
{
554+
display_name: 'First section',
555+
subsections: [
556+
{
557+
assignment_type: 'Homework',
558+
block_key: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@12345',
559+
display_name: 'First subsection',
560+
learner_has_access: true,
561+
has_graded_assignment: true,
562+
num_points_earned: 1,
563+
num_points_possible: 2,
564+
percent_graded: 1.0,
565+
show_correctness: 'always',
566+
show_grades: true,
567+
url: 'http://learning.edx.org/course/course-v1:edX+Test+run/first_subsection',
568+
},
569+
],
570+
},
571+
{
572+
display_name: 'Second section',
573+
subsections: [
574+
{
575+
assignment_type: 'Homework',
576+
display_name: 'Second subsection',
577+
learner_has_access: true,
578+
has_graded_assignment: false,
579+
num_points_earned: 1,
580+
num_points_possible: 1,
581+
percent_graded: 1.0,
582+
show_correctness: 'always',
583+
show_grades: true,
584+
url: 'http://learning.edx.org/course/course-v1:edX+Test+run/second_subsection',
585+
},
586+
],
587+
},
588+
],
589+
});
590+
591+
await fetchAndRender();
592+
expect(screen.getByText('First subsection')).toBeInTheDocument();
593+
expect(screen.queryByText('Second subsection')).not.toBeInTheDocument();
594+
});
595+
596+
it('renders both graded and ungraded subsections when SHOW_UNGRADED_ASSIGNMENT_PROGRESS is true', async () => {
597+
// The second assignment has has_graded_assignment set to false.
598+
setConfig({
599+
...getConfig(),
600+
SHOW_UNGRADED_ASSIGNMENT_PROGRESS: true,
601+
});
602+
603+
setTabData({
604+
section_scores: [
605+
{
606+
display_name: 'First section',
607+
subsections: [
608+
{
609+
assignment_type: 'Homework',
610+
block_key: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@12345',
611+
display_name: 'First subsection',
612+
learner_has_access: true,
613+
has_graded_assignment: true,
614+
num_points_earned: 1,
615+
num_points_possible: 2,
616+
percent_graded: 1.0,
617+
show_correctness: 'always',
618+
show_grades: true,
619+
url: 'http://learning.edx.org/course/course-v1:edX+Test+run/first_subsection',
620+
},
621+
],
622+
},
623+
{
624+
display_name: 'Second section',
625+
subsections: [
626+
{
627+
assignment_type: 'Homework',
628+
display_name: 'Second subsection',
629+
learner_has_access: true,
630+
has_graded_assignment: false,
631+
num_points_earned: 1,
632+
num_points_possible: 1,
633+
percent_graded: 1.0,
634+
show_correctness: 'always',
635+
show_grades: true,
636+
url: 'http://learning.edx.org/course/course-v1:edX+Test+run/second_subsection',
637+
},
638+
],
639+
},
640+
],
641+
});
642+
643+
await fetchAndRender();
644+
expect(screen.getByText('First subsection')).toBeInTheDocument();
645+
expect(screen.getByText('Second subsection')).toBeInTheDocument();
646+
647+
// reset config for other tests
648+
setConfig({
649+
...getConfig(),
650+
SHOW_UNGRADED_ASSIGNMENT_PROGRESS: false,
651+
});
652+
});
548653
});
549654

550655
describe('Grade Summary', () => {
@@ -809,7 +914,7 @@ describe('Progress Tab', () => {
809914

810915
// Open the problem score drawer
811916
fireEvent.click(problemScoreDrawerToggle);
812-
expect(screen.getByText('Problem Scores:')).toBeInTheDocument();
917+
expect(screen.getAllByText('Graded Scores:').length).toBeGreaterThan(1);
813918
expect(screen.getAllByText('0/1')).toHaveLength(3);
814919
});
815920

@@ -821,6 +926,14 @@ describe('Progress Tab', () => {
821926
expect(screen.getByText('Detailed grades')).toBeInTheDocument();
822927
expect(screen.getByText('You currently have no graded problem scores.')).toBeInTheDocument();
823928
});
929+
930+
it('renders Detailed Grades table when section scores are populated', async () => {
931+
await fetchAndRender();
932+
expect(screen.getByText('Detailed grades')).toBeInTheDocument();
933+
934+
expect(screen.getByText('First subsection'));
935+
expect(screen.getByText('Second subsection'));
936+
});
824937
});
825938

826939
describe('Certificate Status', () => {

src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx

+24-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/
77
import { Blocked } from '@openedx/paragon/icons';
88
import { Icon, Hyperlink } from '@openedx/paragon';
99
import { useModel } from '../../../../generic/model-store';
10+
import { showUngradedAssignments } from '../../utils';
1011

1112
import DetailedGradesTable from './DetailedGradesTable';
1213

@@ -28,6 +29,8 @@ const DetailedGrades = ({ intl }) => {
2829
} = useModel('progress', courseId);
2930

3031
const hasSectionScores = sectionScores.length > 0;
32+
const emptyTableMsg = showUngradedAssignments()
33+
? messages.detailedGradesEmpty : messages.detailedGradesEmptyOnlyGraded;
3134

3235
const logOutlineLinkClick = () => {
3336
sendTrackEvent('edx.ui.lms.course_progress.detailed_grades.course_outline_link.clicked', {
@@ -54,7 +57,25 @@ const DetailedGrades = ({ intl }) => {
5457

5558
return (
5659
<section className="text-dark-700">
57-
<h3 className="h4 mb-3">{intl.formatMessage(messages.detailedGrades)}</h3>
60+
<h3 className="h4">{intl.formatMessage(messages.detailedGrades)}</h3>
61+
<ul className="micro mb-3 pl-3 text-gray-700">
62+
<li>
63+
<b>{intl.formatMessage(messages.practiceScoreLabel)} </b>
64+
<FormattedMessage
65+
id="progress.detailedGrades.practice-label.info.text"
66+
defaultMessage="Scores from non-graded activities meant for practice and self-assessment."
67+
description="Information text about non-graded practice score label"
68+
/>
69+
</li>
70+
<li>
71+
<b>{intl.formatMessage(messages.gradedScoreLabel)} </b>
72+
<FormattedMessage
73+
id="progress.detailedGrades.problem-label.info.text"
74+
defaultMessage="Scores from activities that contribute to your final grade."
75+
description="Information text about graded problem score label"
76+
/>
77+
</li>
78+
</ul>
5879
{gradesFeatureIsPartiallyLocked && (
5980
<div className="mb-3 small ml-0 d-inline">
6081
<Icon className="mr-1 mt-1 d-inline-flex" style={{ height: '1rem', width: '1rem' }} src={Blocked} data-testid="blocked-icon" />
@@ -65,9 +86,9 @@ const DetailedGrades = ({ intl }) => {
6586
<DetailedGradesTable />
6687
)}
6788
{!hasSectionScores && (
68-
<p className="small">{intl.formatMessage(messages.detailedGradesEmpty)}</p>
89+
<p className="small">{intl.formatMessage(emptyTableMsg)}</p>
6990
)}
70-
{overviewTabUrl && (
91+
{overviewTabUrl && !showUngradedAssignments() && (
7192
<p className="x-small m-0">
7293
<FormattedMessage
7394
id="progress.ungradedAlert"

src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { DataTable } from '@openedx/paragon';
99
import { useModel } from '../../../../generic/model-store';
1010
import messages from '../messages';
1111
import SubsectionTitleCell from './SubsectionTitleCell';
12+
import { showUngradedAssignments } from '../../utils';
1213

1314
const DetailedGradesTable = ({ intl }) => {
1415
const {
@@ -24,9 +25,10 @@ const DetailedGradesTable = ({ intl }) => {
2425
sectionScores.map((chapter) => {
2526
const subsectionScores = chapter.subsections.filter(
2627
(subsection) => !!(
27-
subsection.hasGradedAssignment
28-
&& subsection.showGrades
29-
&& (subsection.numPointsPossible > 0 || subsection.numPointsEarned > 0)),
28+
(showUngradedAssignments() || subsection.hasGradedAssignment)
29+
&& subsection.showGrades
30+
&& (subsection.numPointsPossible > 0 || subsection.numPointsEarned > 0)
31+
),
3032
);
3133

3234
if (subsectionScores.length === 0) {

src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ import messages from '../messages';
1010

1111
const ProblemScoreDrawer = ({ intl, problemScores, subsection }) => {
1212
const isLocaleRtl = isRtl(getLocale());
13+
14+
const scoreLabel = subsection.hasGradedAssignment ? messages.gradedScoreLabel : messages.practiceScoreLabel;
15+
1316
return (
1417
<span className="row w-100 m-0 x-small ml-4 pt-2 pl-1 text-gray-700 flex-nowrap">
15-
<span id="problem-score-label" className="col-auto p-0">{intl.formatMessage(messages.problemScoreLabel)}</span>
18+
<span id="problem-score-label" className="col-auto p-0">{intl.formatMessage(scoreLabel)}</span>
1619
<div className={classNames('col', 'p-0', { 'greyed-out': !subsection.learnerHasAccess })}>
1720
<ul className="list-unstyled row w-100 m-0" aria-labelledby="problem-score-label">
1821
{problemScores.map((problemScore, i) => (
@@ -31,7 +34,10 @@ ProblemScoreDrawer.propTypes = {
3134
earned: PropTypes.number.isRequired,
3235
possible: PropTypes.number.isRequired,
3336
})).isRequired,
34-
subsection: PropTypes.shape({ learnerHasAccess: PropTypes.bool }).isRequired,
37+
subsection: PropTypes.shape({
38+
learnerHasAccess: PropTypes.bool,
39+
hasGradedAssignment: PropTypes.bool,
40+
}).isRequired,
3541
};
3642

3743
export default injectIntl(ProblemScoreDrawer);

src/course-home/progress-tab/grades/messages.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,14 @@ const messages = defineMessages({
9191
defaultMessage: 'Detailed grades',
9292
description: 'Headline for the (detailed grade) section in the progress tab',
9393
},
94-
detailedGradesEmpty: {
94+
detailedGradesEmptyOnlyGraded: {
9595
id: 'progress.detailedGrades.emptyTable',
9696
defaultMessage: 'You currently have no graded problem scores.',
97+
description: 'It indicate that there are no graded problem or assignments to be scored',
98+
},
99+
detailedGradesEmpty: {
100+
id: 'progress.detailedGrades.including-ungraded.emptyTable',
101+
defaultMessage: 'You currently have no graded or ungraded problem scores.',
97102
description: 'It indicate that there are no problem or assignments to be scored',
98103
},
99104
footnotesTitle: {
@@ -158,11 +163,16 @@ const messages = defineMessages({
158163
defaultMessage: 'Passing grade',
159164
description: 'Label for mark on the (grade bar) chart which indicate the poisition of passing grade on the bar',
160165
},
161-
problemScoreLabel: {
166+
gradedScoreLabel: {
162167
id: 'progress.detailedGrades.problemScore.label',
163-
defaultMessage: 'Problem Scores:',
168+
defaultMessage: 'Graded Scores:',
164169
description: 'Label text which precedes detailed view of all scores per assignment',
165170
},
171+
practiceScoreLabel: {
172+
id: 'progress.detailedGrades.practice.problemScore.label',
173+
defaultMessage: 'Practice Scores:',
174+
description: 'Label text which precedes detailed view of all ungraded problem scores per assignment',
175+
},
166176
problemScoreToggleAltText: {
167177
id: 'progress.detailedGrades.problemScore.toggleButton',
168178
defaultMessage: 'Toggle individual problem scores for {subsectionTitle}',

src/course-home/progress-tab/utils.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { getConfig } from '@edx/frontend-platform';
2+
3+
/* eslint-disable import/prefer-default-export */
4+
export const showUngradedAssignments = () => (
5+
getConfig().SHOW_UNGRADED_ASSIGNMENT_PROGRESS === 'true'
6+
|| getConfig().SHOW_UNGRADED_ASSIGNMENT_PROGRESS === true
7+
);

src/index.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ initialize({
173173
PROCTORED_EXAM_RULES_URL: process.env.PROCTORED_EXAM_RULES_URL || null,
174174
CHAT_RESPONSE_URL: process.env.CHAT_RESPONSE_URL || null,
175175
PRIVACY_POLICY_URL: process.env.PRIVACY_POLICY_URL || null,
176+
SHOW_UNGRADED_ASSIGNMENT_PROGRESS: process.env.SHOW_UNGRADED_ASSIGNMENT_PROGRESS || false,
176177
}, 'LearnerAppConfig');
177178
},
178179
},

0 commit comments

Comments
 (0)