diff --git a/.eslintignore b/.eslintignore
index 65588a7..fcea47f 100755
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,4 +1,5 @@
coverage/*
dist/
node_modules/
+src/postcss.config.js
src/segment.js
diff --git a/.travis.yml b/.travis.yml
index 7ec2f4d..789b5a7 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,6 +23,7 @@ before_script: greenkeeper-lockfile-update
after_script: greenkeeper-lockfile-upload
script:
- make validate-no-uncommitted-package-lock-changes
+ - npm run lint
- npm run test
- npm run build
after_success:
diff --git a/config/webpack.prod.config.js b/config/webpack.prod.config.js
index 644fe5b..aadc214 100755
--- a/config/webpack.prod.config.js
+++ b/config/webpack.prod.config.js
@@ -47,7 +47,7 @@ module.exports = Merge.smart(commonConfig, {
minimize: true,
},
},
- 'postcss-loader',
+ 'postcss-loader', // for autoprefixing, needs to be before the sass loader, not sure why
{
loader: 'sass-loader', // compiles Sass to CSS
options: {
diff --git a/src/components/Gradebook/index.jsx b/src/components/Gradebook/index.jsx
index 1905439..4956dfc 100644
--- a/src/components/Gradebook/index.jsx
+++ b/src/components/Gradebook/index.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import {
Button,
InputSelect,
@@ -132,8 +133,7 @@ export default class Gradebook extends React.Component {
this.props.selectedCohort,
selectedTrackSlug,
);
- const updatedQueryStrings = this.updateQueryParams('track', selectedTrackSlug);
- this.props.history.push(updatedQueryStrings);
+ this.updateQueryParams('track', selectedTrackSlug);
};
updateCohorts = (event) => {
@@ -147,8 +147,7 @@ export default class Gradebook extends React.Component {
selectedCohortId,
this.props.selectedTrack,
);
- const updatedQueryStrings = this.updateQueryParams('cohort', selectedCohortId);
- this.props.history.push(updatedQueryStrings);
+ this.updateQueryParams('cohort', selectedCohortId);
};
mapSelectedAssignmentTypeEntry = (entry) => {
@@ -264,30 +263,34 @@ export default class Gradebook extends React.Component {
Score View:
- this.props.toggleFormat('percent')}
- />
-
+
- this.props.toggleFormat('absolute')}
- />
-
+
- { this.props.assignmnetTypes.length > 0 &&
+ { this.props.assignmentTypes.length > 0 &&
Assignment Types:
@@ -295,8 +298,8 @@ export default class Gradebook extends React.Component {
@@ -328,9 +331,22 @@ export default class Gradebook extends React.Component {
Generate Grade Report
this.props.searchForUser(this.props.match.params.courseId, value, this.props.selectedCohort, this.props.selectedTrack)}
+ onSubmit={value =>
+ this.props.searchForUser(
+ this.props.match.params.courseId,
+ value,
+ this.props.selectedCohort,
+ this.props.selectedTrack,
+ )
+ }
onChange={filterValue => this.setState({ filterValue })}
- onClear={() => this.props.getUserGrades(this.props.match.params.courseId, this.props.selectedCohort, this.props.selectedTrack)}
+ onClear={() =>
+ this.props.getUserGrades(
+ this.props.match.params.courseId,
+ this.props.selectedCohort,
+ this.props.selectedTrack,
+ )
+ }
value={this.state.filterValue}
/>
@@ -346,7 +362,10 @@ export default class Gradebook extends React.Component {
diff --git a/src/components/PageButtons/index.jsx b/src/components/PageButtons/index.jsx
index d149eb9..e79981e 100644
--- a/src/components/PageButtons/index.jsx
+++ b/src/components/PageButtons/index.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import { Button } from '@edx/paragon';
@@ -15,16 +16,57 @@ export default function PageButtons({
style={{ margin: '20px' }}
buttonType="primary"
disabled={!prevPage}
- onClick={() => getPrevNextGrades(prevPage, selectedCohort, selectedTrack, match.params.courseId)}
+ onClick={() =>
+ getPrevNextGrades(
+ prevPage,
+ selectedCohort,
+ selectedTrack,
+ match.params.courseId,
+ )}
/>
);
}
+PageButtons.defaultProps = {
+ match: {
+ params: {
+ courseId: '',
+ },
+ },
+ nextPage: '',
+ prevPage: '',
+ selectedCohort: null,
+ selectedTrack: null,
+};
+
+PageButtons.propTypes = {
+ getPrevNextGrades: PropTypes.func.isRequired,
+ match: PropTypes.shape({
+ params: PropTypes.shape({
+ courseId: PropTypes.string,
+ }),
+ }),
+ nextPage: PropTypes.string,
+ prevPage: PropTypes.string,
+ selectedCohort: PropTypes.shape({
+ name: PropTypes.string,
+ }),
+ selectedTrack: PropTypes.shape({
+ name: PropTypes.string,
+ }),
+};
+
diff --git a/src/containers/GradebookPage/index.jsx b/src/containers/GradebookPage/index.jsx
index 2f1256f..164e201 100644
--- a/src/containers/GradebookPage/index.jsx
+++ b/src/containers/GradebookPage/index.jsx
@@ -15,6 +15,15 @@ import { fetchTracks } from '../../data/actions/tracks';
import { fetchAssignmentTypes } from '../../data/actions/assignmentTypes';
import { getRoles } from '../../data/actions/roles';
+function shouldShowSpinner(state) {
+ if (state.roles.canUserViewGradebook === true) {
+ return state.grades.showSpinner;
+ } else if (state.roles.canUserViewGradebook === false) {
+ return false;
+ } // canUserViewGradebook === null
+ return true;
+}
+
const mapStateToProps = state => (
{
grades: state.grades.results,
@@ -27,22 +36,13 @@ const mapStateToProps = state => (
showSuccess: state.grades.showSuccess,
prevPage: state.grades.prevPage,
nextPage: state.grades.nextPage,
- assignmnetTypes: state.assignmentTypes.results,
+ assignmentTypes: state.assignmentTypes.results,
areGradesFrozen: state.assignmentTypes.areGradesFrozen,
showSpinner: shouldShowSpinner(state),
canUserViewGradebook: state.roles.canUserViewGradebook,
}
);
-function shouldShowSpinner(state) {
- if (state.roles.canUserViewGradebook === true) {
- return state.grades.showSpinner;
- } else if (state.roles.canUserViewGradebook === false) {
- return false;
- } // canUserViewGradebook === null
- return true;
-}
-
const mapDispatchToProps = dispatch => (
{
getUserGrades: (courseId, cohort, track) => {
diff --git a/src/data/actions/grades.test.js b/src/data/actions/grades.test.js
index 9980311..b029ed7 100644
--- a/src/data/actions/grades.test.js
+++ b/src/data/actions/grades.test.js
@@ -120,9 +120,10 @@ describe('actions', () => {
axiosMock.onGet(fetchGradesURL)
.replyOnce(200, JSON.stringify(responseData));
- return store.dispatch(fetchGrades(courseId, expectedCohort, expectedTrack, false)).then(() => {
- expect(store.getActions()).toEqual(expectedActions);
- });
+ return store.dispatch(fetchGrades(courseId, expectedCohort, expectedTrack, false))
+ .then(() => {
+ expect(store.getActions()).toEqual(expectedActions);
+ });
});
it('dispatches failure action after fetching grades', () => {
@@ -135,9 +136,10 @@ describe('actions', () => {
axiosMock.onGet(fetchGradesURL)
.replyOnce(500, JSON.stringify({}));
- return store.dispatch(fetchGrades(courseId, expectedCohort, expectedTrack, false)).then(() => {
- expect(store.getActions()).toEqual(expectedActions);
- });
+ return store.dispatch(fetchGrades(courseId, expectedCohort, expectedTrack, false))
+ .then(() => {
+ expect(store.getActions()).toEqual(expectedActions);
+ });
});
});
});
diff --git a/src/data/actions/roles.test.js b/src/data/actions/roles.test.js
index 528b25a..f6d1b16 100644
--- a/src/data/actions/roles.test.js
+++ b/src/data/actions/roles.test.js
@@ -57,7 +57,10 @@ describe('actions', () => {
];
const store = mockStore();
axiosMock.onGet(rolesUrl)
- .replyOnce(200, JSON.stringify(makeRoleListObj([course1StaffRole, course2DummyRole], false)));
+ .replyOnce(
+ 200,
+ JSON.stringify(makeRoleListObj([course1StaffRole, course2DummyRole], false)),
+ );
return store.dispatch(getRoles(course1Id, urlParams)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
@@ -75,7 +78,10 @@ describe('actions', () => {
const store = mockStore();
axiosMock.onGet(rolesUrl)
- .replyOnce(200, JSON.stringify(makeRoleListObj([course1DummyRole, course2DummyRole], true)));
+ .replyOnce(
+ 200,
+ JSON.stringify(makeRoleListObj([course1DummyRole, course2DummyRole], true)),
+ );
return store.dispatch(getRoles(course1Id, urlParams)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
@@ -91,7 +97,10 @@ describe('actions', () => {
const store = mockStore();
axiosMock.onGet(rolesUrl)
- .replyOnce(200, JSON.stringify(makeRoleListObj([course1DummyRole, course2StaffRole], false)));
+ .replyOnce(
+ 200,
+ JSON.stringify(makeRoleListObj([course1DummyRole, course2StaffRole], false)),
+ );
return store.dispatch(getRoles(course1Id, urlParams)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
@@ -105,7 +114,10 @@ describe('actions', () => {
const store = mockStore();
axiosMock.onGet(rolesUrl)
- .replyOnce(200, JSON.stringify(makeRoleListObj([], false)));
+ .replyOnce(
+ 200,
+ JSON.stringify(makeRoleListObj([], false)),
+ );
return store.dispatch(getRoles(course1Id, urlParams)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
@@ -123,7 +135,10 @@ describe('actions', () => {
const store = mockStore();
axiosMock.onGet(rolesUrl)
- .replyOnce(200, JSON.stringify(makeRoleListObj([], true)));
+ .replyOnce(
+ 200,
+ JSON.stringify(makeRoleListObj([], true)),
+ );
return store.dispatch(getRoles(course1Id, urlParams)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
diff --git a/src/data/constants/actionTypes/roles.js b/src/data/constants/actionTypes/roles.js
index 2a91200..2e00503 100644
--- a/src/data/constants/actionTypes/roles.js
+++ b/src/data/constants/actionTypes/roles.js
@@ -1,5 +1,5 @@
const GOT_ROLES = 'GOT_ROLES';
-const ERROR_FETCHING_ROLES = 'ERROR_FETCHING_ROLES'
+const ERROR_FETCHING_ROLES = 'ERROR_FETCHING_ROLES';
export {
GOT_ROLES,
diff --git a/src/data/reducers/roles.js b/src/data/reducers/roles.js
index 2397dc4..4342275 100644
--- a/src/data/reducers/roles.js
+++ b/src/data/reducers/roles.js
@@ -1,26 +1,27 @@
import {
- GOT_ROLES,
- ERROR_FETCHING_ROLES,
- } from '../constants/actionTypes/roles';
+ GOT_ROLES,
+ ERROR_FETCHING_ROLES,
+} from '../constants/actionTypes/roles';
- const initialState = {
- canUserViewGradebook: null,
- };
+const initialState = {
+ canUserViewGradebook: null,
+};
- const roles = (state = initialState, action) => {
- switch (action.type) {
- case GOT_ROLES:
- return {
- ...state,
- canUserViewGradebook: action.canUserViewGradebook,
- };
- case ERROR_FETCHING_ROLES:
- return {
- ...state,
- canUserViewGradebook: false,
- };
- default:
- return state;
- }};
+const roles = (state = initialState, action) => {
+ switch (action.type) {
+ case GOT_ROLES:
+ return {
+ ...state,
+ canUserViewGradebook: action.canUserViewGradebook,
+ };
+ case ERROR_FETCHING_ROLES:
+ return {
+ ...state,
+ canUserViewGradebook: false,
+ };
+ default:
+ return state;
+ }
+};
- export default roles;
\ No newline at end of file
+export default roles;
diff --git a/src/data/reducers/roles.test.js b/src/data/reducers/roles.test.js
index cb29221..290f9e5 100644
--- a/src/data/reducers/roles.test.js
+++ b/src/data/reducers/roles.test.js
@@ -16,7 +16,7 @@ describe('tracks reducer', () => {
it('updates canUserViewGradebook to true', () => {
const expected = {
...initialState,
- canUserViewGradebook: true
+ canUserViewGradebook: true,
};
expect(roles(undefined, {
type: GOT_ROLES,
@@ -27,7 +27,7 @@ describe('tracks reducer', () => {
it('updates canUserViewGradebook to false', () => {
const expected = {
...initialState,
- canUserViewGradebook: false
+ canUserViewGradebook: false,
};
expect(roles(undefined, {
type: GOT_ROLES,
diff --git a/src/data/services/LmsApiService.js b/src/data/services/LmsApiService.js
index 547ea1b..286e704 100644
--- a/src/data/services/LmsApiService.js
+++ b/src/data/services/LmsApiService.js
@@ -25,7 +25,10 @@ class LmsApiService {
/*
updateData is expected to be a list of objects with the keys 'user_id' (an integer),
'usage_id' (a string) and 'grade', which is an object with the keys:
- 'earned_all_override', 'possible_all_override', 'earned_graded_override', and 'possible_graded_override',
+ 'earned_all_override',
+ 'possible_all_override',
+ 'earned_graded_override',
+ and 'possible_graded_override',
each of which should be an integer.
Example:
[
diff --git a/src/index.jsx b/src/index.jsx
index f91f6a9..fe3e85a 100755
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -12,8 +12,6 @@ import store from './data/store';
import FooterLogo from '../assets/edx-footer.png';
import './App.scss';
-var courseId = window.location.pathname.substring(1);
-
const App = () => (