diff --git a/package-lock.json b/package-lock.json index 61ea891..ccd9fe5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@edx/frontend-app-gradebook", - "version": "1.4.22", + "version": "1.4.24", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a1126e6..60805ac 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@edx/frontend-app-gradebook", - "version": "1.4.23", + "version": "1.4.24", "description": "edx editable gradebook-ui to manipulate grade overrides on subsections", "repository": { "type": "git", diff --git a/src/components/Gradebook/GradebookTable.jsx b/src/components/Gradebook/GradebookTable.jsx index d3e4b7e..bd2a764 100644 --- a/src/components/Gradebook/GradebookTable.jsx +++ b/src/components/Gradebook/GradebookTable.jsx @@ -2,12 +2,13 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; - -import { Table } from '@edx/paragon'; - +import { + Table, OverlayTrigger, Tooltip, Icon, +} from '@edx/paragon'; import { formatDateForDisplay } from '../../data/actions/utils'; import { getHeadings } from '../../data/selectors/grades'; import { fetchGradeOverrideHistory } from '../../data/actions/grades'; +import { EMAIL_HEADING, TOTAL_COURSE_GRADE_HEADING, USERNAME_HEADING } from '../../data/constants/grades'; const DECIMAL_PRECISION = 2; @@ -49,10 +50,10 @@ export class GradebookTable extends React.Component { percent: (entries, areGradesFrozen) => entries.map((entry) => { const learnerInformation = this.getLearnerInformation(entry); const results = { - Username: ( + [USERNAME_HEADING]: (
{learnerInformation}
), - Email: ( + [EMAIL_HEADING]: ( {entry.email} ), }; @@ -73,17 +74,17 @@ export class GradebookTable extends React.Component { } return acc; }, {}); - const totals = { Total: `${this.roundGrade(entry.percent * 100)}%` }; + const totals = { [TOTAL_COURSE_GRADE_HEADING]: `${this.roundGrade(entry.percent * 100)}%` }; return Object.assign(results, assignments, totals); }), absolute: (entries, areGradesFrozen) => entries.map((entry) => { const learnerInformation = this.getLearnerInformation(entry); const results = { - Username: ( + [USERNAME_HEADING]: (
{learnerInformation}
), - Email: ( + [EMAIL_HEADING]: ( {entry.email} ), }; @@ -111,7 +112,10 @@ export class GradebookTable extends React.Component { return acc; }, {}); - const totals = { Total: `${this.roundGrade(entry.percent * 100)}/100` }; + // Show this as a percent no matter what the other setting is. The data + // we're getting gives the final grade as a percentage so making it appear + // to be "out of" 100 is misleading. + const totals = { [TOTAL_COURSE_GRADE_HEADING]: `${this.roundGrade(entry.percent * 100)}%` }; return Object.assign(results, assignments, totals); }), }; @@ -120,22 +124,44 @@ export class GradebookTable extends React.Component { let headings = [...this.props.headings]; if (headings.length > 0) { - const userInformationHeadingLabel = ( + const headerLabelReplacements = {}; + headerLabelReplacements[USERNAME_HEADING] = (
Username
Student Key*
); - const emailHeadingLabel = 'Email*'; + headerLabelReplacements[EMAIL_HEADING] = 'Email*'; - headings = headings.map(heading => ({ - label: heading, - key: heading, - })); + const totalGradePercentageMessage = 'Total Grade values are always displayed as a percentage.'; + headerLabelReplacements[TOTAL_COURSE_GRADE_HEADING] = ( +
+ {totalGradePercentageMessage})} + > +
+ {TOTAL_COURSE_GRADE_HEADING} +
+ +
+
+
+
+ ); - // replace username heading label to include additional user data - headings[0].label = userInformationHeadingLabel; - headings[1].label = emailHeadingLabel; + headings = headings.map(heading => { + const result = { + label: heading, + key: heading, + }; + if (headerLabelReplacements[heading] !== undefined) { + result.label = headerLabelReplacements[heading]; + } + return result; + }); } return headings; diff --git a/src/components/Gradebook/gradebook.scss b/src/components/Gradebook/gradebook.scss index b643840..ec23700 100644 --- a/src/components/Gradebook/gradebook.scss +++ b/src/components/Gradebook/gradebook.scss @@ -72,7 +72,10 @@ .student-key { font-size: 14px; } - + + #courseGradeTooltipIcon { + float: right; + } .table thead tr { min-height: 60px; @@ -111,6 +114,9 @@ td:nth-child(2) { width: 240px; } + th:nth-last-of-type(1) { + width: 150px; + } th, td { width: 120px; } diff --git a/src/data/constants/grades.js b/src/data/constants/grades.js new file mode 100644 index 0000000..1eb0680 --- /dev/null +++ b/src/data/constants/grades.js @@ -0,0 +1,5 @@ +const EMAIL_HEADING = 'Email'; +const TOTAL_COURSE_GRADE_HEADING = 'Total Grade (%)'; +const USERNAME_HEADING = 'Username'; + +export { EMAIL_HEADING, TOTAL_COURSE_GRADE_HEADING, USERNAME_HEADING }; diff --git a/src/data/selectors/grades.js b/src/data/selectors/grades.js index c6ab62d..d08378a 100644 --- a/src/data/selectors/grades.js +++ b/src/data/selectors/grades.js @@ -1,5 +1,6 @@ import { formatDateForDisplay } from '../actions/utils'; import { getFilters } from './filters'; +import { EMAIL_HEADING, TOTAL_COURSE_GRADE_HEADING, USERNAME_HEADING } from '../constants/grades'; const getRowsProcessed = (data) => { const { @@ -52,13 +53,13 @@ const headingMapper = (category, label = 'All') => { return (entry) => { if (entry) { - const results = ['Username', 'Email']; + const results = [USERNAME_HEADING, EMAIL_HEADING]; const assignmentHeadings = entry .filter(filters[filter]) .map(s => s.label); - const totals = ['Total']; + const totals = [TOTAL_COURSE_GRADE_HEADING]; return results.concat(assignmentHeadings).concat(totals); }