From 7547f6e3d1bef290c3fcb358412eb60c2b436c21 Mon Sep 17 00:00:00 2001 From: Reuben Pasquini Date: Fri, 20 Oct 2017 12:29:51 -0500 Subject: [PATCH 1/2] chore(Submission): enhance submission feedback * break down submission counts by type on success * extract errors on failure * show note on timeout --- src/Submission/ReduxProjectSubmission.js | 22 ++---- src/Submission/SubmissionResult.jsx | 95 ++++++++++++++++++++++++ src/Submission/SubmissionResult.test.jsx | 48 ++++++++++++ src/Submission/SubmitTSV.jsx | 19 +---- 4 files changed, 151 insertions(+), 33 deletions(-) create mode 100644 src/Submission/SubmissionResult.jsx create mode 100644 src/Submission/SubmissionResult.test.jsx diff --git a/src/Submission/ReduxProjectSubmission.js b/src/Submission/ReduxProjectSubmission.js index 5bccbc740f..199a80a550 100644 --- a/src/Submission/ReduxProjectSubmission.js +++ b/src/Submission/ReduxProjectSubmission.js @@ -48,22 +48,12 @@ const submitToServer = (methodIn = 'PUT') => (dispatch, getState) => { body: file, dispatch, }).then( - ({ status, data }) => { - switch (status) { - case 200: - return { - type: 'RECEIVE_SUBMISSION', - submit_status: `succeed: ${status}`, - data, - }; - default: - return { - type: 'RECEIVE_SUBMISSION', - submit_status: `failed: ${status}`, - data, - }; - } - }, + ({ status, data }) => ( + { + type: 'RECEIVE_SUBMISSION', + submit_status: status, + data, + }), ).then(msg => dispatch(msg)); }; diff --git a/src/Submission/SubmissionResult.jsx b/src/Submission/SubmissionResult.jsx new file mode 100644 index 0000000000..5c2c689b65 --- /dev/null +++ b/src/Submission/SubmissionResult.jsx @@ -0,0 +1,95 @@ +import React from 'react'; +import styled from 'styled-components'; +import brace from 'brace'; // needed by AceEditor +import 'brace/mode/json'; +import 'brace/theme/kuroir'; +import AceEditor from 'react-ace'; +import PropTypes from 'prop-types'; + +import { button } from '../theme'; + +const Container = styled.div` +border-top: 1px dashed ${props => props.theme.mid_gray}; +padding-top: 1em; +margin-top: 1em; +`; + +const Status = styled.div` +${button}; +background-color: ${props => ((props.status === 200) ? '#168616' : 'gray')}; +color: white; +margin-bottom: 1em; +`; + +const summaryDivStyle = { + maxHeight: '250px', + overflow: 'auto', +}; + +const summaryListStyle = { + listStyle: 'disc', + padding: '0px 0px 25px 25px', +}; + +/** + * Present summary of a submission success or failure given + * the HTTP status code and response data object. + * + * @param {number} status + * @param {object} data + */ +const SubmissionResult = ({ status, data }) => { + let summary = null; + + if (status === 200) { + // List number of entites of each type created + const entityType2Count = (data.entities || []) + .map(ent => ent.type || 'unknown') + .reduce((db, type) => { db[type] = (db[type] || 0) + 1; return db; }, {}); + summary = (
+

Successfully created entities:

+ +
); + } else if (status >= 400 && status < 500) { + const errorList = (data.entities || []).filter(ent => !!ent.errors); + if (errorList.length > 0) { + summary = (

+ Errors: +

+ +
); + } + } else if (status === 504) { + summary = (

+ Submission timed out. Try submitting the data in chunks of 1000 entries or less. +

); + } + + return ( + + {status === 200 ? `succeeded: ${status}` : `failed: ${status}`} + {summary} +

Full response:

+ +
+ ); +}; + +SubmissionResult.propTypes = { + status: PropTypes.number.isRequired, + data: PropTypes.object.isRequired, +}; + + +export default SubmissionResult; diff --git a/src/Submission/SubmissionResult.test.jsx b/src/Submission/SubmissionResult.test.jsx new file mode 100644 index 0000000000..394e4ddfe6 --- /dev/null +++ b/src/Submission/SubmissionResult.test.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import AceEditor from 'react-ace'; + +import SubmissionResult from './SubmissionResult'; + +describe('the submission result component', () => { + const testData = { + entities: [ + { + type: 'type1', + }, + { + type: 'type2', + errors: ['bla bla bla'], + }, + { + type: 'type2', + }, + { + type: 'type2', + errors: ['bla bla bla'], + }, + ], + }; + + it('presents a summary of a successful submission', () => { + const $dom = shallow(); + const $summary = $dom.find('#cd-summary__result_200'); + expect($summary).toHaveLength(1); + const $li = $summary.find('li'); + expect($li).toHaveLength(2); // type1 and type2 + }); + + it('presents a summary of a failed submission', () => { + const $dom = shallow(); + const $summary = $dom.find('#cd-summary__result_400'); + expect($summary).toHaveLength(1); + const $jsonError = $summary.find(AceEditor); + expect($jsonError).toHaveLength(1); + }); + + it('tries to help on a 504 timeout', () => { + const $dom = shallow(); + const $summary = $dom.find('#cd-summary__result_504'); + expect($summary).toHaveLength(1); + }); +}); diff --git a/src/Submission/SubmitTSV.jsx b/src/Submission/SubmitTSV.jsx index f24e0eccfd..c9e9adab29 100644 --- a/src/Submission/SubmitTSV.jsx +++ b/src/Submission/SubmitTSV.jsx @@ -1,5 +1,4 @@ import React from 'react'; -import styled from 'styled-components'; import brace from 'brace'; // needed by AceEditor import 'brace/mode/json'; import 'brace/theme/kuroir'; @@ -8,20 +7,9 @@ import PropTypes from 'prop-types'; import { predictFileType } from '../utils'; import { button, UploadButton, SubmitButton } from '../theme'; +import SubmissionResult from './SubmissionResult'; -const SubmissionResult = styled.div` - border-top: 1px dashed ${props => props.theme.mid_gray}; - padding-top: 1em; - margin-top: 1em; -`; -const Status = styled.div` - ${button}; - background-color: ${props => ((props.status === 'succeed: 200') ? '#168616' : 'gray')}; - color: white; - margin-bottom: 1em; -`; - /** * Manage TSV/JSON submission * @@ -96,10 +84,7 @@ const SubmitTSV = ({ path, submission, onUploadClick, onSubmitClick, onFileChang /> } {submission.submit_result && - - {submission.submit_status} - - + } ); From 2d5b6666db9a74e16113c38bd867ef1acc2e4b96 Mon Sep 17 00:00:00 2001 From: Reuben Pasquini Date: Tue, 24 Oct 2017 11:21:01 -0500 Subject: [PATCH 2/2] fix(SubmitTSV.test): sync tests with code changes Introduction of SubmissionResult component required tweak of SubmitTSV.test due to DOM changes --- src/Submission/SubmissionResult.jsx | 2 +- src/Submission/SubmitTSV.jsx | 4 ++-- src/Submission/SubmitTSV.test.jsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Submission/SubmissionResult.jsx b/src/Submission/SubmissionResult.jsx index 5c2c689b65..8c866ccf53 100644 --- a/src/Submission/SubmissionResult.jsx +++ b/src/Submission/SubmissionResult.jsx @@ -77,7 +77,7 @@ const SubmissionResult = ({ status, data }) => { } return ( - + {status === 200 ? `succeeded: ${status}` : `failed: ${status}`} {summary}

Full response:

diff --git a/src/Submission/SubmitTSV.jsx b/src/Submission/SubmitTSV.jsx index c9e9adab29..deb2bc1128 100644 --- a/src/Submission/SubmitTSV.jsx +++ b/src/Submission/SubmitTSV.jsx @@ -6,7 +6,7 @@ import AceEditor from 'react-ace'; import PropTypes from 'prop-types'; import { predictFileType } from '../utils'; -import { button, UploadButton, SubmitButton } from '../theme'; +import { UploadButton, SubmitButton } from '../theme'; import SubmissionResult from './SubmissionResult'; @@ -84,7 +84,7 @@ const SubmitTSV = ({ path, submission, onUploadClick, onSubmitClick, onFileChang /> } {submission.submit_result && - + } ); diff --git a/src/Submission/SubmitTSV.test.jsx b/src/Submission/SubmitTSV.test.jsx index fdbff7c481..32a425656e 100644 --- a/src/Submission/SubmitTSV.test.jsx +++ b/src/Submission/SubmitTSV.test.jsx @@ -53,7 +53,7 @@ describe('the TSV submission componet', () => { it('shows a submit result when appropriate', () => { const state = { file: JSON.stringify({ type: 'whatever', submitter_id: 'frickjack' }), - submit_result: JSON.stringify({ message: 'submission failed' }), + submit_result: { message: 'submission ok', entities: [{ type: 'frickjack' }] }, submit_status: 200, }; const { $dom } = buildTest(state);