Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const buildBlockTree = (blocks, excludeBlockTypes) => {
return blockTree(blocks.root, null);
};

const blocks = (state = {}, action) => {
export const blocks = (state = {}, action) => {
switch (action.type) {
case courseBlocksActions.fetch.SUCCESS:
return buildBlockTree(action.blocks, action.excludeBlockTypes);
Expand All @@ -27,7 +27,7 @@ const blocks = (state = {}, action) => {
}
};

const selectedBlock = (state = null, action) => {
export const selectedBlock = (state = null, action) => {
switch (action.type) {
case courseBlocksActions.SELECT_BLOCK:
return action.blockId;
Expand All @@ -37,7 +37,7 @@ const selectedBlock = (state = null, action) => {
};


const rootBlock = (state = null, action) => {
export const rootBlock = (state = null, action) => {
switch (action.type) {
case courseBlocksActions.fetch.SUCCESS:
return action.blocks.root;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ module.exports = {
},
},
},
rules: {
'import/prefer-default-export': 'off',
},
};
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
/* global gettext */
import { Button } from '@edx/paragon';
import { BlockBrowser } from 'BlockBrowser';
import BlockBrowserContainer from 'BlockBrowser/components/BlockBrowser/BlockBrowserContainer';
import * as PropTypes from 'prop-types';
import * as React from 'react';
import { ReportStatusContainer } from '../ReportStatus/ReportStatusContainer';

export default class Main extends React.Component {
constructor(props) {
super(props);
this.handleToggleDropdown = this.handleToggleDropdown.bind(this);
this.initiateReportGeneration = this.initiateReportGeneration.bind(this);
this.state = {
showDropdown: false,
};
Expand All @@ -22,33 +24,57 @@ export default class Main extends React.Component {
this.setState({ showDropdown: false });
}

initiateReportGeneration() {
this.props.createProblemResponsesReportTask(
this.props.problemResponsesEndpoint,
this.props.taskStatusEndpoint,
this.props.selectedBlock,
);
}

render() {
const { selectedBlock, onSelectBlock } = this.props;

return (
<div className="problem-browser">
<Button onClick={this.handleToggleDropdown} label={gettext('Select a section or problem')} />
<input type="text" name="problem-location" value={selectedBlock} disabled />
{this.state.showDropdown &&
<BlockBrowser onSelectBlock={(blockId) => {
this.hideDropdown();
onSelectBlock(blockId);
}}
/>}
<div className="problem-browser-container">
<div className="problem-browser">
<Button
onClick={this.handleToggleDropdown}
label={gettext('Select a section or problem')}
/>
<input type="text" name="problem-location" value={selectedBlock} disabled />
{this.state.showDropdown &&
<BlockBrowserContainer
onSelectBlock={(blockId) => {
this.hideDropdown();
onSelectBlock(blockId);
}}
/>}
<Button
onClick={this.initiateReportGeneration}
name="list-problem-responses-csv"
label={gettext('Create a report of problem responses')}
/>
</div>
<ReportStatusContainer />
</div>
);
}
}

Main.propTypes = {
courseId: PropTypes.string.isRequired,
createProblemResponsesReportTask: PropTypes.func.isRequired,
excludeBlockTypes: PropTypes.arrayOf(PropTypes.string),
fetchCourseBlocks: PropTypes.func.isRequired,
problemResponsesEndpoint: PropTypes.string.isRequired,
onSelectBlock: PropTypes.func.isRequired,
selectedBlock: PropTypes.string,
taskStatusEndpoint: PropTypes.string.isRequired,
};

Main.defaultProps = {
excludeBlockTypes: null,
selectedBlock: null,
selectedBlock: '',
timeout: null,
};
Original file line number Diff line number Diff line change
@@ -1,39 +1,53 @@
/* global jest,test,describe,expect */
import { Button } from '@edx/paragon';
import { BlockBrowser } from 'BlockBrowser';
import BlockBrowserContainer from 'BlockBrowser/components/BlockBrowser/BlockBrowserContainer';
import { Provider } from 'react-redux';
import { shallow } from 'enzyme';
import React from 'react';
import renderer from 'react-test-renderer';
import store from '../../data/store';

import Main from './Main';

describe('ProblemBrowser Main component', () => {
const courseId = 'testcourse';
const problemResponsesEndpoint = '/api/problem_responses/';
const taskStatusEndpoint = '/api/task_status/';
const excludedBlockTypes = [];

test('render with basic parameters', () => {
const component = renderer.create(
<Main
courseId={courseId}
excludeBlockTypes={excludedBlockTypes}
fetchCourseBlocks={jest.fn()}
onSelectBlock={jest.fn()}
selectedBlock={null}
/>,
<Provider store={store}>
<Main
courseId={courseId}
createProblemResponsesReportTask={jest.fn()}
excludeBlockTypes={excludedBlockTypes}
fetchCourseBlocks={jest.fn()}
problemResponsesEndpoint={problemResponsesEndpoint}
onSelectBlock={jest.fn()}
selectedBlock={null}
taskStatusEndpoint={taskStatusEndpoint}
/>
</Provider>,
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test('render with selected block', () => {
const component = renderer.create(
<Main
courseId={courseId}
excludeBlockTypes={excludedBlockTypes}
fetchCourseBlocks={jest.fn()}
onSelectBlock={jest.fn()}
selectedBlock={'some-selected-block'}
/>,
<Provider store={store}>
<Main
courseId={courseId}
createProblemResponsesReportTask={jest.fn()}
excludeBlockTypes={excludedBlockTypes}
fetchCourseBlocks={jest.fn()}
problemResponsesEndpoint={problemResponsesEndpoint}
onSelectBlock={jest.fn()}
selectedBlock={'some-selected-block'}
taskStatusEndpoint={taskStatusEndpoint}
/>
</Provider>,
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
Expand All @@ -42,15 +56,20 @@ describe('ProblemBrowser Main component', () => {
test('fetch course block on toggling dropdown', () => {
const fetchCourseBlocksMock = jest.fn();
const component = renderer.create(
<Main
courseId={courseId}
excludeBlockTypes={excludedBlockTypes}
fetchCourseBlocks={fetchCourseBlocksMock}
onSelectBlock={jest.fn()}
selectedBlock={'some-selected-block'}
/>,
<Provider store={store}>
<Main
courseId={courseId}
createProblemResponsesReportTask={jest.fn()}
excludeBlockTypes={excludedBlockTypes}
fetchCourseBlocks={fetchCourseBlocksMock}
problemResponsesEndpoint={problemResponsesEndpoint}
onSelectBlock={jest.fn()}
selectedBlock={'some-selected-block'}
taskStatusEndpoint={taskStatusEndpoint}
/>
</Provider>,
);
const instance = component.getInstance();
const instance = component.root.children[0].instance;
instance.handleToggleDropdown();
expect(fetchCourseBlocksMock.mock.calls.length).toBe(1);
});
Expand All @@ -59,13 +78,17 @@ describe('ProblemBrowser Main component', () => {
const component = shallow(
<Main
courseId={courseId}
createProblemResponsesReportTask={jest.fn()}
excludeBlockTypes={excludedBlockTypes}
fetchCourseBlocks={jest.fn()}
problemResponsesEndpoint={problemResponsesEndpoint}
onSelectBlock={jest.fn()}
selectedBlock={'some-selected-block'}
taskStatusEndpoint={taskStatusEndpoint}
/>,
);
component.find(Button).simulate('click');
expect(component.find(BlockBrowser)).toBeTruthy();
expect(component.find(BlockBrowserContainer).length).toBeFalsy();
component.find(Button).find({ label: 'Select a section or problem' }).simulate('click');
expect(component.find(BlockBrowserContainer).length).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { fetchCourseBlocks, selectBlock } from 'BlockBrowser/data/actions/courseBlocks';
import { connect } from 'react-redux';

import { createProblemResponsesReportTask } from '../../data/actions/problemResponses';
import Main from './Main';

const mapStateToProps = state => ({
Expand All @@ -10,8 +10,16 @@ const mapStateToProps = state => ({

const mapDispatchToProps = dispatch => ({
onSelectBlock: blockId => dispatch(selectBlock(blockId)),
fetchCourseBlocks: (courseId, excludeBlockTypes) =>
dispatch(fetchCourseBlocks(courseId, excludeBlockTypes)),
fetchCourseBlocks:
(courseId, excludeBlockTypes) =>
dispatch(fetchCourseBlocks(courseId, excludeBlockTypes)),
createProblemResponsesReportTask:
(problemResponsesEndpoint, taskStatusEndpoint, problemLocation) =>
dispatch(
createProblemResponsesReportTask(
problemResponsesEndpoint, taskStatusEndpoint, problemLocation,
),
),
});

const MainContainer = connect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,80 @@

exports[`ProblemBrowser Main component render with basic parameters 1`] = `
<div
className="problem-browser"
className="problem-browser-container"
>
<button
className="btn"
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
<div
className="problem-browser"
>
Select a section or problem
</button>
<input
disabled={true}
name="problem-location"
type="text"
value={null}
<button
className="btn"
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
Select a section or problem
</button>
<input
disabled={true}
name="problem-location"
type="text"
value={null}
/>
<button
className="btn"
name="list-problem-responses-csv"
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
Create a report of problem responses
</button>
</div>
<div
aria-live="polite"
className="report-generation-status"
/>
</div>
`;

exports[`ProblemBrowser Main component render with selected block 1`] = `
<div
className="problem-browser"
className="problem-browser-container"
>
<button
className="btn"
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
<div
className="problem-browser"
>
Select a section or problem
</button>
<input
disabled={true}
name="problem-location"
type="text"
value="some-selected-block"
<button
className="btn"
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
Select a section or problem
</button>
<input
disabled={true}
name="problem-location"
type="text"
value="some-selected-block"
/>
<button
className="btn"
name="list-problem-responses-csv"
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
Create a report of problem responses
</button>
</div>
<div
aria-live="polite"
className="report-generation-status"
/>
</div>
`;
Loading