Compare commits
5 Commits
bw/compone
...
matthugs/w
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43266546e3 | ||
|
|
dc5652d336 | ||
|
|
f4c40eaffc | ||
|
|
3e405b06db | ||
|
|
11d9c9eb3e |
@@ -1,3 +1,5 @@
|
||||
$drawer-width: 350px;
|
||||
|
||||
.spinner-overlay {
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
@@ -17,18 +19,11 @@
|
||||
color: black;
|
||||
}
|
||||
|
||||
.gradebook-container{
|
||||
width: 500px;
|
||||
@media only screen and (min-width: 640px) {
|
||||
width: 630px;
|
||||
.gradebook-contents {
|
||||
transition: transform 300ms cubic-bezier(0.4,0,0.2,1);
|
||||
.drawer.open + & {
|
||||
transform: translateX($drawer-width);
|
||||
}
|
||||
@media only screen and (min-width: 992px) {
|
||||
width: 900px;
|
||||
}
|
||||
@media only screen and (min-width: 1200px) {
|
||||
width: 1024px;
|
||||
}
|
||||
|
||||
.search-help-text {
|
||||
margin-left: 20px;
|
||||
}
|
||||
@@ -38,6 +33,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.drawer-container {
|
||||
overflow-x: hidden;
|
||||
.collapsible {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer {
|
||||
height: 100%;
|
||||
width: $drawer-width;
|
||||
position: absolute;
|
||||
transform: translateX(-$drawer-width);
|
||||
flex-direction: column;
|
||||
transition: transform 300ms cubic-bezier(0.4,0,0.2,1);
|
||||
&.open {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
}
|
||||
|
||||
.student-filters{
|
||||
display: flex;
|
||||
.label{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
Button,
|
||||
Collapsible,
|
||||
@@ -41,6 +42,8 @@ export default class Gradebook extends React.Component {
|
||||
assignmentGradeMax: '100',
|
||||
isMinCourseGradeFilterValid: true,
|
||||
isMaxCourseGradeFilterValid: true,
|
||||
drawerOpen: true,
|
||||
drawerTransitioning: false,
|
||||
};
|
||||
this.fileFormRef = React.createRef();
|
||||
this.fileInputRef = React.createRef();
|
||||
@@ -471,10 +474,166 @@ export default class Gradebook extends React.Component {
|
||||
return valueAsInt >= 0 && valueAsInt <= 100;
|
||||
};
|
||||
|
||||
closeFilterDrawer = () => {
|
||||
this.setState({ drawerOpen: false, drawerTransitioning: true });
|
||||
};
|
||||
|
||||
toggleFilterDrawer = () => {
|
||||
this.setState({ drawerTransitioning: true });
|
||||
// defer the transition to the next repaint so we can be sure that
|
||||
// opening drawer is visible before it transitions
|
||||
// (the start state of the opening animation doesn't work if the element starts hidden)
|
||||
window.requestAnimationFrame(() =>
|
||||
this.setState(prevState => ({ drawerOpen: !prevState.drawerOpen })));
|
||||
};
|
||||
|
||||
handleDrawerSlideDone = () => {
|
||||
this.setState({ drawerTransitioning: false });
|
||||
};
|
||||
|
||||
render() {
|
||||
// todo: add aria label for close button (is this broken for modal buttons?)
|
||||
return (
|
||||
<div className="d-flex justify-content-center">
|
||||
<div className="gradebook-container">
|
||||
<div className="d-flex drawer-container">
|
||||
<aside
|
||||
className={classNames(
|
||||
'drawer',
|
||||
{
|
||||
open: this.state.drawerOpen,
|
||||
'd-none': !this.state.drawerTransitioning && !this.state.drawerOpen,
|
||||
},
|
||||
)}
|
||||
onTransitionEnd={this.handleDrawerSlideDone}
|
||||
>
|
||||
<div className="drawer-header">
|
||||
<h2><Icon className="fa fa-filter" />Filter By...</h2>
|
||||
<Button
|
||||
className="p-1"
|
||||
onClick={this.closeFilterDrawer}
|
||||
inputRef={this.setFirstFocusableElement}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
>
|
||||
<Icon className="fa fa-times" />
|
||||
</Button>
|
||||
</div>
|
||||
<Collapsible title="Assignments" isOpen className="filter-group">
|
||||
<div>
|
||||
<div className="student-filters">
|
||||
<span className="label">
|
||||
Assignment Types:
|
||||
</span>
|
||||
<InputSelect
|
||||
name="assignment-types"
|
||||
aria-label="Assignment Types"
|
||||
value={this.props.selectedAssignmentType}
|
||||
options={this.mapAssignmentTypeEntries(this.props.assignmentTypes)}
|
||||
onChange={this.updateAssignmentTypes}
|
||||
disabled={this.props.assignmentFilterOptions.length === 0}
|
||||
/>
|
||||
</div>
|
||||
<div className="student-filters">
|
||||
<span className="label">
|
||||
Assignment:
|
||||
</span>
|
||||
<InputSelect
|
||||
name="assignment"
|
||||
aria-label="Assignment"
|
||||
value={this.props.selectedAssignment}
|
||||
options={this.getAssignmentFilterOptions()}
|
||||
onChange={this.handleAssignmentFilterChange}
|
||||
disabled={this.props.assignmentFilterOptions.length === 0}
|
||||
/>
|
||||
</div>
|
||||
<p>Grade Range (0% - 100%)</p>
|
||||
<form className="d-flex justify-content-between align-items-center" onSubmit={this.handleSubmitAssignmentGrade}>
|
||||
<InputText
|
||||
label="Min Grade"
|
||||
name="assignmentGradeMin"
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
value={this.state.assignmentGradeMin}
|
||||
disabled={!this.props.selectedAssignment}
|
||||
onChange={this.handleMinAssigGradeChange}
|
||||
/>
|
||||
<span className="input-percent-label">%</span>
|
||||
<InputText
|
||||
label="Max Grade"
|
||||
name="assignmentGradeMax"
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
value={this.state.assignmentGradeMax}
|
||||
disabled={!this.props.selectedAssignment}
|
||||
onChange={this.handleMaxAssigGradeChange}
|
||||
/>
|
||||
<span className="input-percent-label">%</span>
|
||||
<div className="d-flex align-items-center">
|
||||
<Button
|
||||
type="submit"
|
||||
className="btn-outline-secondary"
|
||||
name="assignmentGradeMinMax"
|
||||
disabled={!this.props.selectedAssignment}
|
||||
>
|
||||
Apply
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Collapsible>
|
||||
<Collapsible title="Overall Grade" isOpen className="filter-group">
|
||||
<div className="d-flex justify-content-between align-items-center">
|
||||
<InputText
|
||||
value={this.state.courseGradeMin}
|
||||
name="minimum-grade"
|
||||
label="Min Grade"
|
||||
onChange={value => this.handleCourseGradeFilterChange('min', value)}
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
/>
|
||||
<span className="input-percent-label">%</span>
|
||||
<InputText
|
||||
value={this.state.courseGradeMax}
|
||||
name="max-grade"
|
||||
label="Max Grade"
|
||||
onChange={value => this.handleCourseGradeFilterChange('max', value)}
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
/>
|
||||
<span className="input-percent-label">%</span>
|
||||
<Button
|
||||
buttonType="outline-secondary"
|
||||
className="align-self-center"
|
||||
onClick={this.handleCourseGradeFilterApplyButtonClick}
|
||||
>
|
||||
Apply
|
||||
</Button>
|
||||
</div>
|
||||
</Collapsible>
|
||||
<Collapsible title="Student Groups" isOpen className="filter-group">
|
||||
<InputSelect
|
||||
name="Tracks"
|
||||
aria-label="Tracks"
|
||||
disabled={this.props.tracks.length === 0}
|
||||
value={this.mapSelectedTrackEntry(this.props.selectedTrack)}
|
||||
options={this.mapTracksEntries(this.props.tracks)}
|
||||
onChange={this.updateTracks}
|
||||
/>
|
||||
<InputSelect
|
||||
name="Cohorts"
|
||||
aria-label="Cohorts"
|
||||
disabled={this.props.cohorts.length === 0}
|
||||
value={this.mapSelectedCohortEntry(this.props.selectedCohort)}
|
||||
options={this.mapCohortsEntries(this.props.cohorts)}
|
||||
onChange={this.updateCohorts}
|
||||
/>
|
||||
</Collapsible>
|
||||
</aside>
|
||||
<div className="px-3 mw-100 gradebook-contents">
|
||||
<div>
|
||||
<a
|
||||
href={this.lmsInstructorDashboardUrl(this.props.courseId)}
|
||||
@@ -499,130 +658,7 @@ export default class Gradebook extends React.Component {
|
||||
<h4>Step 1: Filter the Grade Report</h4>
|
||||
<div className="d-flex justify-content-between" >
|
||||
{this.props.showSpinner && <div className="spinner-overlay"><Icon className="fa fa-spinner fa-spin fa-5x color-black" /></div>}
|
||||
<div>
|
||||
<Collapsible title="Assignments" isOpen>
|
||||
<div>
|
||||
<div className="student-filters">
|
||||
<span className="label">
|
||||
Assignment Types:
|
||||
</span>
|
||||
<InputSelect
|
||||
name="assignment-types"
|
||||
aria-label="Assignment Types"
|
||||
value={this.props.selectedAssignmentType}
|
||||
options={this.mapAssignmentTypeEntries(this.props.assignmentTypes)}
|
||||
onChange={this.updateAssignmentTypes}
|
||||
disabled={this.props.assignmentFilterOptions.length === 0}
|
||||
/>
|
||||
</div>
|
||||
<div className="student-filters">
|
||||
<span className="label">
|
||||
Assignment:
|
||||
</span>
|
||||
<InputSelect
|
||||
name="assignment"
|
||||
aria-label="Assignment"
|
||||
value={this.props.selectedAssignment}
|
||||
options={this.getAssignmentFilterOptions()}
|
||||
onChange={this.handleAssignmentFilterChange}
|
||||
disabled={this.props.assignmentFilterOptions.length === 0}
|
||||
/>
|
||||
</div>
|
||||
<p>Grade Range (0% - 100%)</p>
|
||||
<form className="d-flex justify-content-between align-items-center" onSubmit={this.handleSubmitAssignmentGrade}>
|
||||
<InputText
|
||||
label="Min Grade"
|
||||
name="assignmentGradeMin"
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
value={this.state.assignmentGradeMin}
|
||||
disabled={!this.props.selectedAssignment}
|
||||
onChange={this.handleMinAssigGradeChange}
|
||||
/>
|
||||
<span className="input-percent-label">%</span>
|
||||
<InputText
|
||||
label="Max Grade"
|
||||
name="assignmentGradeMax"
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
value={this.state.assignmentGradeMax}
|
||||
disabled={!this.props.selectedAssignment}
|
||||
onChange={this.handleMaxAssigGradeChange}
|
||||
/>
|
||||
<span className="input-percent-label">%</span>
|
||||
<div className="d-flex align-items-center">
|
||||
<Button
|
||||
type="submit"
|
||||
className="btn-outline-secondary"
|
||||
name="assignmentGradeMinMax"
|
||||
disabled={!this.props.selectedAssignment}
|
||||
>
|
||||
Apply
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Collapsible>
|
||||
<div className="student-filters">
|
||||
<span className="label">
|
||||
Student Groups:
|
||||
</span>
|
||||
<InputSelect
|
||||
name="Tracks"
|
||||
aria-label="Tracks"
|
||||
disabled={this.props.tracks.length === 0}
|
||||
value={this.mapSelectedTrackEntry(this.props.selectedTrack)}
|
||||
options={this.mapTracksEntries(this.props.tracks)}
|
||||
onChange={this.updateTracks}
|
||||
/>
|
||||
<InputSelect
|
||||
name="Cohorts"
|
||||
aria-label="Cohorts"
|
||||
disabled={this.props.cohorts.length === 0}
|
||||
value={this.mapSelectedCohortEntry(this.props.selectedCohort)}
|
||||
options={this.mapCohortsEntries(this.props.cohorts)}
|
||||
onChange={this.updateCohorts}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span className="label">
|
||||
Course Grade (0%-100%)
|
||||
</span>
|
||||
<div className="d-flex justify-content-between align-items-center">
|
||||
<InputText
|
||||
value={this.state.courseGradeMin}
|
||||
name="minimum-grade"
|
||||
label="Min Grade"
|
||||
onChange={value => this.handleCourseGradeFilterChange('min', value)}
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
/>
|
||||
<span className="input-percent-label">%</span>
|
||||
<InputText
|
||||
value={this.state.courseGradeMax}
|
||||
name="max-grade"
|
||||
label="Max Grade"
|
||||
onChange={value => this.handleCourseGradeFilterChange('max', value)}
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
/>
|
||||
<span className="input-percent-label">%</span>
|
||||
<Button
|
||||
buttonType="outline-secondary"
|
||||
className="align-self-center"
|
||||
onClick={this.handleCourseGradeFilterApplyButtonClick}
|
||||
>
|
||||
Apply
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button className="btn-primary align-self-start" onClick={this.toggleFilterDrawer}><Icon className="fa fa-filter" /> Edit Filters</Button>
|
||||
<div>
|
||||
<SearchField
|
||||
onSubmit={value =>
|
||||
@@ -686,7 +722,7 @@ export default class Gradebook extends React.Component {
|
||||
{this.props.showBulkManagement && (
|
||||
<div>
|
||||
<StatefulButton
|
||||
buttonType="primary"
|
||||
buttonType="outline-primary"
|
||||
onClick={this.handleClickExportGrades}
|
||||
state={this.props.showSpinner ? 'pending' : 'default'}
|
||||
labels={{
|
||||
@@ -700,7 +736,7 @@ export default class Gradebook extends React.Component {
|
||||
disabledStates={['pending']}
|
||||
/>
|
||||
<StatefulButton
|
||||
buttonType="primary"
|
||||
buttonType="outline-primary"
|
||||
onClick={this.handleClickDownloadInterventions}
|
||||
state={this.props.showSpinner ? 'pending' : 'default'}
|
||||
className="ml-2"
|
||||
@@ -717,15 +753,17 @@ export default class Gradebook extends React.Component {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="gbook">
|
||||
<Table
|
||||
columns={this.formatHeadings()}
|
||||
data={this.formatter[this.props.format](
|
||||
this.props.grades,
|
||||
this.props.areGradesFrozen,
|
||||
)}
|
||||
rowHeaderColumnKey="username"
|
||||
/>
|
||||
<div className="gradebook-container">
|
||||
<div className="gbook">
|
||||
<Table
|
||||
columns={this.formatHeadings()}
|
||||
data={this.formatter[this.props.format](
|
||||
this.props.grades,
|
||||
this.props.areGradesFrozen,
|
||||
)}
|
||||
rowHeaderColumnKey="username"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{PageButtons(this.props)}
|
||||
<Modal
|
||||
|
||||
Reference in New Issue
Block a user