feat: Bulk Management reorganization, phase 1 (#206)
* move GradesTab and BulkHistoryTab to views and control from container through redux * add data logic for view control and import success toast * add NetworkButton component for download/upload buttons * remove download button from Bulk History view and update heading and help text * add View control button to GradebookHeader if bulk management available * remove FilterMenuToggle from SearchControls * update BulkManagementControls to now include upload/download grades buttons * add Import Success toast * rename UserLabel to FilteredUsersLabel for clarity * add InterventionsReport component * update GradesView top-level component * messageing update (separate messages into per-component files) * style updates * update test plan * clean up css and add docstrings * typo fix * fix typo in bulk management view header
This commit is contained in:
@@ -54,12 +54,28 @@ const setModalState = createAction('setModalState', (modalState) => ({
|
||||
payload: Object.keys(modalFieldKeys).reduce(filterReducer(modalState), {}),
|
||||
}));
|
||||
|
||||
/**
|
||||
* setShowImportSuccessToast(shouldShow)
|
||||
* Set whether or not to show the Import Grades success toast
|
||||
* @param {bool} sholdShow - should show the toast?
|
||||
*/
|
||||
const setShowImportSuccessToast = createAction('setShowImportSuccessToast');
|
||||
|
||||
/**
|
||||
* setView(viewId)
|
||||
* sets the UI to display the tab indcated by the passed view id
|
||||
* @param {string} viewId - view id as set in app constants
|
||||
*/
|
||||
const setView = createAction('setView');
|
||||
|
||||
export default StrictDict({
|
||||
closeModal,
|
||||
filterMenu,
|
||||
setCourseId,
|
||||
setLocalFilter,
|
||||
setModalState,
|
||||
setModalStateFromTable,
|
||||
setSearchValue,
|
||||
setLocalFilter,
|
||||
setShowImportSuccessToast,
|
||||
setView,
|
||||
});
|
||||
|
||||
@@ -11,6 +11,8 @@ describe('actions', () => {
|
||||
actions.setSearchValue,
|
||||
actions.setLocalFilter,
|
||||
actions.setModalStateFromTable,
|
||||
actions.setShowImportSuccessToast,
|
||||
actions.setView,
|
||||
].map(action => action.toString());
|
||||
testActionTypes(actionTypes, dataKey);
|
||||
});
|
||||
@@ -19,6 +21,10 @@ describe('actions', () => {
|
||||
test('setCourseId action', () => testAction(actions.setCourseId));
|
||||
test('setModalStateFromTable action', () => testAction(actions.setModalStateFromTable));
|
||||
test('setSearchValue action', () => testAction(actions.setSearchValue));
|
||||
test('setView action', () => testAction(actions.setView));
|
||||
test('setShowImportSuccessToast action', () => (
|
||||
testAction(actions.setShowImportSuccessToast)
|
||||
));
|
||||
describe('setLocalFilter', () => {
|
||||
it('forwards all values with filter field keys and no others', () => {
|
||||
const extra = {
|
||||
|
||||
@@ -3,6 +3,11 @@ import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
export const routePath = `${getConfig().PUBLIC_PATH}:courseId`;
|
||||
|
||||
export const views = StrictDict({
|
||||
grades: 'grades',
|
||||
bulkManagementHistory: 'bulkManagementHistory',
|
||||
});
|
||||
|
||||
export const modalFieldKeys = StrictDict({
|
||||
adjustedGradePossible: 'adjustedGradePossible',
|
||||
adjustedGradeValue: 'adjustedGradeValue',
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import initialFilters from '../constants/filters';
|
||||
import { views } from '../constants/app';
|
||||
import { formatDateForDisplay } from '../actions/utils';
|
||||
import actions from '../actions/app';
|
||||
import filterActions from '../actions/filters';
|
||||
import gradesActions from '../actions/grades';
|
||||
|
||||
const initialState = {
|
||||
courseId: '',
|
||||
activeView: views.grades,
|
||||
filters: {
|
||||
assignmentGradeMax: initialFilters.assignmentGradeMax,
|
||||
assignmentGradeMin: initialFilters.assignmentGradeMin,
|
||||
@@ -26,6 +29,7 @@ const initialState = {
|
||||
open: false,
|
||||
transitioning: false,
|
||||
},
|
||||
showImportSuccessToast: false,
|
||||
searchValue: '',
|
||||
};
|
||||
|
||||
@@ -80,6 +84,10 @@ const app = (state = initialState, { type, payload }) => {
|
||||
}
|
||||
case actions.setSearchValue.toString():
|
||||
return { ...state, searchValue: payload };
|
||||
case actions.setShowImportSuccessToast.toString():
|
||||
return { ...state, showImportSuccessToast: payload };
|
||||
case actions.setView.toString():
|
||||
return { ...state, activeView: payload };
|
||||
// initialize the filter fields that are locally stored
|
||||
case filterActions.initialize.toString():
|
||||
return {
|
||||
@@ -103,6 +111,8 @@ const app = (state = initialState, { type, payload }) => {
|
||||
},
|
||||
}), { ...state });
|
||||
}
|
||||
case gradesActions.csvUpload.finished.toString():
|
||||
return { ...state, showImportSuccessToast: true };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import appActions from 'data/actions/app';
|
||||
import filterActions from 'data/actions/filters';
|
||||
import gradesActions from 'data/actions/grades';
|
||||
import { formatDateForDisplay } from 'data/actions/utils';
|
||||
import app, { initialState } from './app';
|
||||
|
||||
@@ -177,6 +178,20 @@ describe('app reducer', () => {
|
||||
).toEqual({ ...testingState, searchValue: testValue });
|
||||
});
|
||||
});
|
||||
describe('appActions.setShowImportSuccessToast', () => {
|
||||
it('loads showImportSuccessToast from payload', () => {
|
||||
expect(
|
||||
app(testingState, appActions.setShowImportSuccessToast(testValue)),
|
||||
).toEqual({ ...testingState, showImportSuccessToast: testValue });
|
||||
});
|
||||
});
|
||||
describe('appActions.setView', () => {
|
||||
it('loads activeView from payload', () => {
|
||||
expect(
|
||||
app(testingState, appActions.setView(testValue)),
|
||||
).toEqual({ ...testingState, activeView: testValue });
|
||||
});
|
||||
});
|
||||
describe('filterActions.initialize', () => {
|
||||
it('loads relevant filter values', () => {
|
||||
expect(
|
||||
@@ -216,5 +231,12 @@ describe('app reducer', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('grade actions csvUpload.finished', () => {
|
||||
it('sets showImportSuccessToast to true', () => {
|
||||
expect(
|
||||
app(testingState, gradesActions.csvUpload.finished()),
|
||||
).toEqual({ ...testingState, showImportSuccessToast: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,6 +25,9 @@ const initialState = {
|
||||
bulkManagement: {},
|
||||
totalUsersCount: 0,
|
||||
filteredUsersCount: 0,
|
||||
isImportGradesActive: false,
|
||||
isDownloadInterventionsActive: false,
|
||||
isDownloadGradesActive: false,
|
||||
};
|
||||
|
||||
const grades = (state = initialState, { type, payload }) => {
|
||||
|
||||
@@ -97,9 +97,11 @@ const filterMenuSelectors = simpleSelectorFactory(
|
||||
const simpleSelectors = simpleSelectorFactory(
|
||||
({ app }) => app,
|
||||
[
|
||||
'activeView',
|
||||
'courseId',
|
||||
'filters',
|
||||
'searchValue',
|
||||
'showImportSuccessToast',
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -159,8 +159,10 @@ describe('app selectors', () => {
|
||||
expect(exportedSelectors[key]({ app: { [key]: testVal } })).toEqual(testVal);
|
||||
});
|
||||
};
|
||||
testSimpleSelector('activeView');
|
||||
testSimpleSelector('courseId');
|
||||
testSimpleSelector('filters');
|
||||
testSimpleSelector('searchValue');
|
||||
testSimpleSelector('showImportSuccessToast');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -124,7 +124,7 @@ export const fetchPrevNextGrades = (endpoint) => (
|
||||
}
|
||||
);
|
||||
|
||||
export const submitFileUploadFormData = (formData) => (
|
||||
export const submitImportGradesButtonData = (formData) => (
|
||||
(dispatch, getState) => {
|
||||
const courseId = selectors.app.courseId(getState());
|
||||
dispatch(grades.csvUpload.started());
|
||||
@@ -167,6 +167,6 @@ export default StrictDict({
|
||||
fetchGradesIfAssignmentGradeFiltersSet,
|
||||
fetchGradeOverrideHistory,
|
||||
fetchPrevNextGrades,
|
||||
submitFileUploadFormData,
|
||||
submitImportGradesButtonData,
|
||||
updateGrades,
|
||||
});
|
||||
|
||||
@@ -516,11 +516,11 @@ describe('grades thunkActions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('submitFileUploadFormData', () => {
|
||||
describe('submitImportGradesButtonData', () => {
|
||||
const formData = { form: 'data' };
|
||||
const testFetch = createTestFetcher(
|
||||
lms.api.uploadGradeCsv,
|
||||
thunkActions.submitFileUploadFormData,
|
||||
thunkActions.submitImportGradesButtonData,
|
||||
[formData],
|
||||
() => expect(lms.api.uploadGradeCsv).toHaveBeenCalledWith(formData),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user