Merge pull request #98 from edx/matthugs/add-table-for-bulk-management-operation-history

Add table corresponding to what new history endpoint supports
This commit is contained in:
Matt Hughes
2019-07-10 10:08:54 -04:00
committed by GitHub
10 changed files with 79 additions and 24 deletions

View File

@@ -487,6 +487,14 @@ export default class Gradebook extends React.Component {
buttonType="primary"
onClick={this.handleClickImportGrades}
/>
<Table
data={this.props.bulkManagementHistory}
columns={[
{ key: 'user', label: 'Uploaded By', columnSortable: false },
{ key: 'operation', label: 'Operation', columnSortable: false },
{ key: 'modified', label: 'Uploaded Date', columnSortable: false },
]}
/>
</div>)}
</Tabs>
</div>
@@ -513,6 +521,7 @@ Gradebook.defaultProps = {
tracks: [],
bulkImportError: '',
showBulkManagement: false,
bulkManagementHistory: [],
};
Gradebook.propTypes = {
@@ -565,4 +574,9 @@ Gradebook.propTypes = {
submitFileUploadFormData: PropTypes.func.isRequired,
bulkImportError: PropTypes.string,
showBulkManagement: PropTypes.bool,
bulkManagementHistory: PropTypes.arrayOf(PropTypes.shape({
operation: PropTypes.oneOf(['commit', 'error']),
user: PropTypes.string,
modified: PropTypes.string,
})),
};

View File

@@ -13,7 +13,8 @@ import {
} from '../../data/actions/grades';
import { fetchCohorts } from '../../data/actions/cohorts';
import { fetchTracks } from '../../data/actions/tracks';
import hasMastersTrack from '../../data/selectors/tracks';
import stateHasMastersTrack from '../../data/selectors/tracks';
import getBulkManagementHistory from '../../data/selectors/grades';
import { fetchAssignmentTypes } from '../../data/actions/assignmentTypes';
import { getRoles } from '../../data/actions/roles';
import LmsApiService from '../../data/services/LmsApiService';
@@ -53,7 +54,8 @@ const mapStateToProps = (state, ownProps) => (
state.grades.bulkManagement.errorMessages ?
`Errors while processing: ${state.grades.bulkManagement.errorMessages.join(', ')}` :
'',
showBulkManagement: hasMastersTrack(state),
showBulkManagement: stateHasMastersTrack(state),
bulkManagementHistory: getBulkManagementHistory(state),
}
);

View File

@@ -13,6 +13,8 @@ import {
START_UPLOAD,
UPLOAD_COMPLETE,
UPLOAD_ERR,
GOT_BULK_HISTORY,
BULK_HISTORY_ERR,
} from '../constants/actionTypes/grades';
import LmsApiService from '../services/LmsApiService';
import { headingMapper, sortAlphaAsc } from './utils';
@@ -23,6 +25,8 @@ const defaultAssignmentFilter = 'All';
const startedCsvUpload = () => ({ type: START_UPLOAD });
const finishedCsvUpload = () => ({ type: UPLOAD_COMPLETE });
const csvUploadError = data => ({ type: UPLOAD_ERR, data });
const gotBulkHistory = data => ({ type: GOT_BULK_HISTORY, data });
const bulkHistoryError = () => ({ type: BULK_HISTORY_ERR });
const startedFetchingGrades = () => ({ type: STARTED_FETCHING_GRADES });
const finishedFetchingGrades = () => ({ type: FINISHED_FETCHING_GRADES });
@@ -163,7 +167,7 @@ const submitFileUploadFormData = (courseId, formData) => (
return LmsApiService.uploadGradeCsv(courseId, formData).then(() => (
dispatch(finishedCsvUpload())
)).catch((err) => {
if (err.status === 200 && err.data.error_messages.length) {
if (err.response.status === 200 && err.response.error_messages.length) {
const { error_messages: errorMessages, saved, total } = err.data;
return dispatch(csvUploadError({ errorMessages, saved, total }));
}
@@ -172,6 +176,14 @@ const submitFileUploadFormData = (courseId, formData) => (
}
);
const fetchBulkUpgradeHistory = courseId => (
dispatch =>
// todo add loading effect
LmsApiService.fetchGradeBulkOperationHistory(courseId).then((response) => {
dispatch(gotBulkHistory(response));
}).catch(() => dispatch(bulkHistoryError()))
);
export {
startedFetchingGrades,
finishedFetchingGrades,
@@ -188,4 +200,5 @@ export {
filterColumns,
closeBanner,
submitFileUploadFormData,
fetchBulkUpgradeHistory,
};

View File

@@ -3,6 +3,8 @@ import {
GOT_TRACKS,
ERROR_FETCHING_TRACKS,
} from '../constants/actionTypes/tracks';
import { hasMastersTrack } from '../selectors/tracks';
import { fetchBulkUpgradeHistory } from './grades';
import LmsApiService from '../services/LmsApiService';
const startedFetchingTracks = () => ({ type: STARTED_FETCHING_TRACKS });
@@ -16,6 +18,9 @@ const fetchTracks = courseId => (
.then(response => response.data)
.then((data) => {
dispatch(gotTracks(data.course_modes));
if (hasMastersTrack(data.course_modes)) {
dispatch(fetchBulkUpgradeHistory(courseId));
}
})
.catch(() => {
dispatch(errorFetchingTracks());

View File

@@ -15,6 +15,8 @@ const OPEN_BANNER = 'OPEN_BANNER';
const START_UPLOAD = 'START_UPLOAD';
const UPLOAD_COMPLETE = 'UPLOAD_COMPLETE';
const UPLOAD_ERR = 'UPLOAD_ERR';
const GOT_BULK_HISTORY = 'GOT_BULK_HISTORY';
const BULK_HISTORY_ERR = 'BULK_HISTORY_ERR';
export {
STARTED_FETCHING_GRADES,
@@ -31,4 +33,6 @@ export {
START_UPLOAD,
UPLOAD_COMPLETE,
UPLOAD_ERR,
GOT_BULK_HISTORY,
BULK_HISTORY_ERR,
};

View File

@@ -9,6 +9,7 @@ import {
START_UPLOAD,
UPLOAD_COMPLETE,
UPLOAD_ERR,
GOT_BULK_HISTORY,
} from '../constants/actionTypes/grades';
const initialState = {
@@ -22,6 +23,7 @@ const initialState = {
prevPage: null,
nextPage: null,
showSpinner: true,
bulkManagement: {},
};
const grades = (state = initialState, action) => {
@@ -79,24 +81,35 @@ const grades = (state = initialState, action) => {
...state,
showSpinner: true,
};
case UPLOAD_COMPLETE:
case UPLOAD_COMPLETE: {
const { errorMessages, ...rest } = state.bulkManagement;
return {
...state,
showSpinner: false,
bulkManagement: {},
bulkManagement: { ...rest },
};
}
case UPLOAD_ERR:
return {
...state,
showSpinner: false,
bulkManagement: {
...(state.bulkManagement || {}),
...state.bulkManagement,
...action.data,
},
};
case GOT_BULK_HISTORY:
return {
...state,
bulkManagement: {
...state.bulkManagement,
history: action.data,
},
};
default:
return state;
}
};
export { initialState as initialGradesState };
export default grades;

View File

@@ -1,4 +1,4 @@
import grades from './grades';
import grades, { initialGradesState as initialState } from './grades';
import {
STARTED_FETCHING_GRADES,
ERROR_FETCHING_GRADES,
@@ -8,19 +8,6 @@ import {
OPEN_BANNER,
} from '../constants/actionTypes/grades';
const initialState = {
results: [],
headings: [],
startedFetching: false,
finishedFetching: false,
errorFetching: false,
gradeFormat: 'percent',
showSuccess: false,
prevPage: null,
nextPage: null,
showSpinner: true,
};
const courseId = 'course-v1:edX+DemoX+Demo_Course';
const headingsData = [
{ name: 'exam' },

View File

@@ -0,0 +1,3 @@
const getBulkManagementHistory = state => state.grades.bulkManagement.history;
export default getBulkManagementHistory;

View File

@@ -1,4 +1,13 @@
const getTracks = state => state.tracks.results || [];
const hasMastersTrack = state => getTracks(state).some(track => track.slug === 'masters');
const compose = (...fns) => {
const [firstFunc, ...rest] = fns.reverse();
return (...args) =>
rest.reduce((accum, fn) => fn(accum), firstFunc(...args));
};
export default hasMastersTrack;
const getTracks = state => state.tracks.results || [];
const trackIsMasters = track => track.slug === 'masters';
const hasMastersTrack = tracks => tracks.some(trackIsMasters);
const stateHasMastersTrack = compose(hasMastersTrack, getTracks);
export { hasMastersTrack, trackIsMasters };
export default stateHasMastersTrack;

View File

@@ -72,7 +72,7 @@ class LmsApiService {
const trackQueryParam = options.track ? [`track=${options.track}`] : [];
const cohortQueryParam = options.cohort ? [`cohort=${options.cohort}`] : [];
const queryParams = [...trackQueryParam, ...cohortQueryParam].join('&');
const downloadUrl = `${LmsApiService.baseUrl}/api/bulk_grades/course/${courseId}?${queryParams}`;
const downloadUrl = `${LmsApiService.baseUrl}/api/bulk_grades/course/${courseId}/?${queryParams}`;
return downloadUrl;
}
@@ -87,6 +87,11 @@ class LmsApiService {
return Promise.reject(result);
});
}
static fetchGradeBulkOperationHistory(courseId) {
const url = `${LmsApiService.baseUrl}/api/bulk_grades/course/${courseId}/history/`;
return apiClient.get(url).then(response => response.data).catch(() => Promise.reject(Error('unhandled response error')));
}
}
export default LmsApiService;