feat: always show total as a pct, add tooltip (#170)

This commit is contained in:
Jansen Kantor
2021-04-29 09:54:00 -04:00
committed by GitHub
parent 93f45d0784
commit 61fdb31316
6 changed files with 61 additions and 23 deletions

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "@edx/frontend-app-gradebook",
"version": "1.4.22",
"version": "1.4.24",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -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",

View File

@@ -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]: (
<div><span className="wrap-text-in-cell">{learnerInformation}</span></div>
),
Email: (
[EMAIL_HEADING]: (
<span className="wrap-text-in-cell">{entry.email}</span>
),
};
@@ -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]: (
<div><span className="wrap-text-in-cell">{learnerInformation}</span></div>
),
Email: (
[EMAIL_HEADING]: (
<span className="wrap-text-in-cell">{entry.email}</span>
),
};
@@ -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] = (
<div>
<div>Username</div>
<div className="font-weight-normal student-key">Student Key*</div>
</div>
);
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] = (
<div>
<OverlayTrigger
trigger={['hover', 'focus']}
key="left-basic"
placement="left"
overlay={(<Tooltip id="course-grade-tooltip">{totalGradePercentageMessage}</Tooltip>)}
>
<div>
{TOTAL_COURSE_GRADE_HEADING}
<div id="courseGradeTooltipIcon">
<Icon className="fa fa-info-circle" screenReaderText={totalGradePercentageMessage} />
</div>
</div>
</OverlayTrigger>
</div>
);
// 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;

View File

@@ -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;
}

View File

@@ -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 };

View File

@@ -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);
}