From 543cd623e173c7f310a0ef7b49010f4dc97326d7 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Fri, 28 Apr 2023 13:04:31 -0400 Subject: [PATCH] feat: add column for full name for masters students (#321) * feat: add column for full name for masters students * refactor: move masters asterisk out of messages file * refactor: simpletext -> text * refactor: asterisk const --- .../GradesView/GradebookTable/Fields.jsx | 14 ++++----- .../GradesView/GradebookTable/Fields.test.jsx | 10 +++--- .../GradebookTable/LabelReplacements.jsx | 20 ++++++++++++ .../GradebookTable/LabelReplacements.test.jsx | 11 +++++++ .../__snapshots__/Fields.test.jsx.snap | 2 +- .../LabelReplacements.test.jsx.snap | 22 ++++++++++++- .../__snapshots__/test.jsx.snap | 12 +++++-- .../GradesView/GradebookTable/index.jsx | 9 ++++-- .../GradesView/GradebookTable/messages.js | 9 ++++-- .../GradesView/GradebookTable/test.jsx | 31 +++++++++++++------ src/data/constants/grades.js | 9 ++++-- src/data/selectors/grades.js | 9 ++++-- src/data/selectors/grades.test.js | 8 ++++- 13 files changed, 129 insertions(+), 37 deletions(-) diff --git a/src/components/GradesView/GradebookTable/Fields.jsx b/src/components/GradesView/GradebookTable/Fields.jsx index 867d661..c2e184b 100644 --- a/src/components/GradesView/GradebookTable/Fields.jsx +++ b/src/components/GradesView/GradebookTable/Fields.jsx @@ -29,16 +29,16 @@ Username.propTypes = { }; /** - * Fields.Email - * Simple label field for email value. - * @param {string} email - email for display + * Fields.Text + * Simple label field for text value. + * @param {string} value - value for display */ -const Email = ({ email }) => {email}; -Email.propTypes = { - email: PropTypes.string.isRequired, +const Text = ({ value }) => ({value}); +Text.propTypes = { + value: PropTypes.string.isRequired, }; export default StrictDict({ - Email, + Text, Username, }); diff --git a/src/components/GradesView/GradebookTable/Fields.test.jsx b/src/components/GradesView/GradebookTable/Fields.test.jsx index 53c02fc..dd34237 100644 --- a/src/components/GradesView/GradebookTable/Fields.test.jsx +++ b/src/components/GradesView/GradebookTable/Fields.test.jsx @@ -41,13 +41,13 @@ describe('Gradebook Table Fields', () => { }); }); - describe('Email', () => { - const email = 'myTag@place.com'; + describe('Text', () => { + const value = 'myTag@place.com'; test('snapshot', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); - test('wraps entry email', () => { - expect(shallow().text()).toEqual(email); + test('wraps entry value', () => { + expect(shallow().text()).toEqual(value); }); }); }); diff --git a/src/components/GradesView/GradebookTable/LabelReplacements.jsx b/src/components/GradesView/GradebookTable/LabelReplacements.jsx index 959766a..86dd89c 100644 --- a/src/components/GradesView/GradebookTable/LabelReplacements.jsx +++ b/src/components/GradesView/GradebookTable/LabelReplacements.jsx @@ -45,6 +45,13 @@ const TotalGradeLabelReplacement = () => ( ); +/** + * Asterisk to display next to heading labels that are only used for masters students + */ +const mastersOnlyFieldAsterisk = ( + * +); + /** * * Username column header. Lists that Student Key is possibly available @@ -56,11 +63,24 @@ const UsernameLabelReplacement = () => (
+ { mastersOnlyFieldAsterisk }
); +/** + * + * Column header for fields that are only available for masters students + */ +const MastersOnlyLabelReplacement = (message) => ( +
+ + { mastersOnlyFieldAsterisk } +
+); + export default StrictDict({ TotalGradeLabelReplacement, UsernameLabelReplacement, + MastersOnlyLabelReplacement, }); diff --git a/src/components/GradesView/GradebookTable/LabelReplacements.test.jsx b/src/components/GradesView/GradebookTable/LabelReplacements.test.jsx index fc2bbb1..a37729a 100644 --- a/src/components/GradesView/GradebookTable/LabelReplacements.test.jsx +++ b/src/components/GradesView/GradebookTable/LabelReplacements.test.jsx @@ -9,6 +9,7 @@ import LabelReplacements from './LabelReplacements'; const { TotalGradeLabelReplacement, UsernameLabelReplacement, + MastersOnlyLabelReplacement, } = LabelReplacements; jest.mock('@edx/paragon', () => ({ @@ -35,6 +36,16 @@ describe('LabelReplacements', () => { expect(shallow()).toMatchSnapshot(); }); }); + describe('MastersOnlyLabelReplacement', () => { + test('snapshot', () => { + const message = { + id: 'id', + defaultMessage: 'defaultMessAge', + description: 'desCripTion', + }; + expect(shallow()).toMatchSnapshot(); + }); + }); }); describe('snapshot', () => { diff --git a/src/components/GradesView/GradebookTable/__snapshots__/Fields.test.jsx.snap b/src/components/GradesView/GradebookTable/__snapshots__/Fields.test.jsx.snap index cb1f257..7c0e555 100644 --- a/src/components/GradesView/GradebookTable/__snapshots__/Fields.test.jsx.snap +++ b/src/components/GradesView/GradebookTable/__snapshots__/Fields.test.jsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Gradebook Table Fields Email snapshot 1`] = ` +exports[`Gradebook Table Fields Text snapshot 1`] = ` diff --git a/src/components/GradesView/GradebookTable/__snapshots__/LabelReplacements.test.jsx.snap b/src/components/GradesView/GradebookTable/__snapshots__/LabelReplacements.test.jsx.snap index e0572bf..ed189e2 100644 --- a/src/components/GradesView/GradebookTable/__snapshots__/LabelReplacements.test.jsx.snap +++ b/src/components/GradesView/GradebookTable/__snapshots__/LabelReplacements.test.jsx.snap @@ -1,5 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`LabelReplacements MastersOnlyLabelReplacement snapshot 1`] = ` +
+ + + * + +
+`; + exports[`LabelReplacements TotalGradeLabelReplacement displays overlay tooltip 1`] = ` + + * + `; diff --git a/src/components/GradesView/GradebookTable/__snapshots__/test.jsx.snap b/src/components/GradesView/GradebookTable/__snapshots__/test.jsx.snap index 7bd40ff..228b171 100644 --- a/src/components/GradesView/GradebookTable/__snapshots__/test.jsx.snap +++ b/src/components/GradesView/GradebookTable/__snapshots__/test.jsx.snap @@ -13,8 +13,16 @@ exports[`GradebookTable component snapshot - fields1 and 2 between email and tot "accessor": "Username", }, Object { - "Header": , + "accessor": "Full Name", + }, + Object { + "Header": , diff --git a/src/components/GradesView/GradebookTable/index.jsx b/src/components/GradesView/GradebookTable/index.jsx index 902dd38..efdf04d 100644 --- a/src/components/GradesView/GradebookTable/index.jsx +++ b/src/components/GradesView/GradebookTable/index.jsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { DataTable } from '@edx/paragon'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import selectors from 'data/selectors'; import { Headings } from 'data/constants/grades'; @@ -38,7 +38,9 @@ export class GradebookTable extends React.Component { } else if (heading === Headings.username) { label = ; } else if (heading === Headings.email) { - label = ; + label = ; + } else if (heading === Headings.fullName) { + label = ; } else { label = heading; } @@ -49,7 +51,8 @@ export class GradebookTable extends React.Component { [Headings.username]: ( ), - [Headings.email]: (), + [Headings.fullName]: (), + [Headings.email]: (), [Headings.totalGrade]: `${roundGrade(entry.percent * 100)}${getLocalizedPercentSign()}`, ...entry.section_breakdown.reduce((acc, subsection) => ({ ...acc, diff --git a/src/components/GradesView/GradebookTable/messages.js b/src/components/GradesView/GradebookTable/messages.js index 2caf521..9ebc629 100644 --- a/src/components/GradesView/GradebookTable/messages.js +++ b/src/components/GradesView/GradebookTable/messages.js @@ -1,9 +1,14 @@ import { defineMessages } from '@edx/frontend-platform/i18n'; const messages = defineMessages({ + fullNameHeading: { + id: 'gradebook.GradesView.table.headings.fullName', + defaultMessage: 'Full Name', + description: 'Gradebook table full name column header', + }, emailHeading: { id: 'gradebook.GradesView.table.headings.email', - defaultMessage: 'Email*', + defaultMessage: 'Email', description: 'Gradebook table email column header', }, totalGradeHeading: { @@ -18,7 +23,7 @@ const messages = defineMessages({ }, studentKeyLabel: { id: 'gradebook.GradesView.table.labels.studentKey', - defaultMessage: 'Student Key*', + defaultMessage: 'Student Key', description: 'Gradebook table Student Key label', }, usernameLabel: { diff --git a/src/components/GradesView/GradebookTable/test.jsx b/src/components/GradesView/GradebookTable/test.jsx index 6970e06..ed416a6 100644 --- a/src/components/GradesView/GradebookTable/test.jsx +++ b/src/components/GradesView/GradebookTable/test.jsx @@ -2,7 +2,6 @@ import React from 'react'; import { shallow } from 'enzyme'; import { DataTable } from '@edx/paragon'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; import selectors from 'data/selectors'; import { Headings } from 'data/constants/grades'; @@ -22,7 +21,7 @@ jest.mock('./Fields', () => ({ __esModule: true, default: { Username: () => 'Fields.Username', - Email: () => 'Fields.Email', + Text: () => 'Fields.Text', }, })); jest.mock('./LabelReplacements', () => ({ @@ -30,6 +29,7 @@ jest.mock('./LabelReplacements', () => ({ default: { TotalGradeLabelReplacement: () => 'TotalGradeLabelReplacement', UsernameLabelReplacement: () => 'UsernameLabelReplacement', + MastersOnlyLabelReplacement: () => 'MastersOnlyLabelReplacement', }, })); jest.mock('./GradeButton', () => 'GradeButton'); @@ -75,6 +75,7 @@ describe('GradebookTable', () => { ], headings: [ Headings.username, + Headings.fullName, Headings.email, fields.field1, fields.field2, @@ -104,17 +105,22 @@ describe('GradebookTable', () => { expect(heading.accessor).toEqual(Headings.username); expect(heading.Header.type).toEqual(LabelReplacements.UsernameLabelReplacement); }); - test('email sets key and Header from header', () => { + test('full name sets key and Header from header', () => { const heading = headings[1]; + expect(heading.accessor).toEqual(Headings.fullName); + expect(heading.Header).toEqual(); + }); + test('email sets key and Header from header', () => { + const heading = headings[2]; expect(heading.accessor).toEqual(Headings.email); - expect(heading.Header).toEqual(); + expect(heading.Header).toEqual(); }); test('subsections set key and Header from header', () => { - expect(headings[2]).toEqual({ accessor: fields.field1, Header: fields.field1 }); - expect(headings[3]).toEqual({ accessor: fields.field2, Header: fields.field2 }); + expect(headings[3]).toEqual({ accessor: fields.field1, Header: fields.field1 }); + expect(headings[4]).toEqual({ accessor: fields.field2, Header: fields.field2 }); }); test('totalGrade sets key and replaces Header with component', () => { - const heading = headings[4]; + const heading = headings[5]; expect(heading.accessor).toEqual(Headings.totalGrade); expect(heading.Header.type).toEqual(LabelReplacements.TotalGradeLabelReplacement); }); @@ -139,10 +145,15 @@ describe('GradebookTable', () => { userKey: entry.external_user_key, }); }); - test('email set to Email Field', () => { + test('fullName set to Text Field', () => { + const field = row[Headings.fullName]; + expect(field.type).toEqual(Fields.Text); + expect(field.props).toEqual({ value: entry.full_name }); + }); + test('email set to Text Field', () => { const field = row[Headings.email]; - expect(field.type).toEqual(Fields.Email); - expect(field.props).toEqual({ email: entry.email }); + expect(field.type).toEqual(Fields.Text); + expect(field.props).toEqual({ value: entry.email }); }); test('totalGrade set to rounded percent grade * 100', () => { expect( diff --git a/src/data/constants/grades.js b/src/data/constants/grades.js index 5425308..2192158 100644 --- a/src/data/constants/grades.js +++ b/src/data/constants/grades.js @@ -3,6 +3,7 @@ import { StrictDict } from 'utils'; const EMAIL_HEADING = 'Email'; const TOTAL_COURSE_GRADE_HEADING = 'Total Grade (%)'; const USERNAME_HEADING = 'Username'; +const FULL_NAME_HEADING = 'Full Name'; const GradeFormats = StrictDict({ absolute: 'absolute', @@ -10,15 +11,17 @@ const GradeFormats = StrictDict({ }); const Headings = StrictDict({ - email: 'Email', - totalGrade: 'Total Grade (%)', - username: 'Username', + email: EMAIL_HEADING, + totalGrade: TOTAL_COURSE_GRADE_HEADING, + username: USERNAME_HEADING, + fullName: FULL_NAME_HEADING, }); export { EMAIL_HEADING, TOTAL_COURSE_GRADE_HEADING, USERNAME_HEADING, + FULL_NAME_HEADING, GradeFormats, Headings, }; diff --git a/src/data/selectors/grades.js b/src/data/selectors/grades.js index 6182873..15abbbe 100644 --- a/src/data/selectors/grades.js +++ b/src/data/selectors/grades.js @@ -105,12 +105,17 @@ export const headingMapper = (category, label = 'All') => { } else { filter = filters.byLabel; } - const { username, email, totalGrade } = Headings; + const { + username, + fullName, + email, + totalGrade, + } = Headings; const filteredLabels = (entry) => entry.filter(filter).map(s => s.label); return (entry) => ( entry - ? [username, email, ...filteredLabels(entry), totalGrade] + ? [username, fullName, email, ...filteredLabels(entry), totalGrade] : [] ); }; diff --git a/src/data/selectors/grades.test.js b/src/data/selectors/grades.test.js index e8a8830..bdd5f06 100644 --- a/src/data/selectors/grades.test.js +++ b/src/data/selectors/grades.test.js @@ -1,4 +1,9 @@ -import { EMAIL_HEADING, TOTAL_COURSE_GRADE_HEADING, USERNAME_HEADING } from '../constants/grades'; +import { + EMAIL_HEADING, + FULL_NAME_HEADING, + TOTAL_COURSE_GRADE_HEADING, + USERNAME_HEADING, +} from '../constants/grades'; import { formatDateForDisplay } from '../actions/utils'; import * as selectors from './grades'; import exportedSelectors from './grades'; @@ -179,6 +184,7 @@ describe('grades selectors', () => { describe('headingMapper', () => { const expectedHeaders = (subsectionLabels) => ([ USERNAME_HEADING, + FULL_NAME_HEADING, EMAIL_HEADING, ...subsectionLabels, TOTAL_COURSE_GRADE_HEADING,