Skip to content

Commit

Permalink
Basic submission failures page
Browse files Browse the repository at this point in the history
  • Loading branch information
SemaiCZE committed Jan 12, 2018
1 parent e046512 commit cef83f8
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 35 deletions.
72 changes: 72 additions & 0 deletions src/components/SubmissionFailures/FailuresList/FailuresList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Table } from 'react-bootstrap';
import { FormattedMessage } from 'react-intl';
import FailuresListItem from '../FailuresListItem';

const FailuresList = ({ failures, createActions }) =>
<Table striped hover>
<thead>
<tr>
<th>
<FormattedMessage
id="app.failureList.headType"
defaultMessage="Type"
/>
</th>
<th>
<FormattedMessage
id="app.failureList.headDescription"
defaultMessage="Description"
/>
</th>
<th>
<FormattedMessage
id="app.failureList.headCreatedAt"
defaultMessage="Created at"
/>
</th>
<th>
<FormattedMessage
id="app.failureList.headResolvedAt"
defaultMessage="Resolved at"
/>
</th>
<th>
<FormattedMessage
id="app.failureList.headResolutionNote"
defaultMessage="Resolution note"
/>
</th>
<th />
</tr>
</thead>
<tbody>
{failures.map((failure, i) =>
<FailuresListItem
id={failure.id}
createActions={createActions}
failure={failure}
key={i}
/>
)}

{failures.length === 0 &&
<tr>
<td className="text-center">
<FormattedMessage
id="app.failureList.noFailures"
defaultMessage="There are no failures in this list."
/>
</td>
</tr>}
</tbody>
</Table>;

FailuresList.propTypes = {
failures: PropTypes.array,
createActions: PropTypes.func,
failure: PropTypes.object
};

export default FailuresList;
1 change: 1 addition & 0 deletions src/components/SubmissionFailures/FailuresList/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './FailuresList';
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedDate, FormattedTime } from 'react-intl';
import Icon from 'react-fontawesome';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';

const FailuresListItem = ({ id, createActions, failure }) =>
<tr>
<td className="text-center">
<OverlayTrigger
placement="top"
overlay={
<Tooltip id={id}>
{failure.type}
</Tooltip>
}
>
<div>
{failure.type === 'broker_reject' && <Icon name="times-rectangle" />}
{failure.type === 'evaluation_failure' && <Icon name="tint" />}
{failure.type === 'loading_failure' && <Icon name="wrench" />}
</div>
</OverlayTrigger>
</td>
<td>
{failure.description}
</td>
<td>
<FormattedDate value={new Date(failure.createdAt * 1000)} />
{', '}
<FormattedTime value={new Date(failure.createdAt * 1000)} />
</td>
<td>
{failure.resolvedAt
? <span>
<FormattedDate value={new Date(failure.resolvedAt * 1000)} />
{', '}
<FormattedTime value={new Date(failure.resolvedAt * 1000)} />
</span>
: <span>&mdash;</span>}
</td>
<td>
{failure.resolutionNote
? <span>
{failure.resolutionNote}
</span>
: <span>&mdash;</span>}
</td>
<td className="text-right">
{createActions && createActions(id)}
</td>
</tr>;

FailuresListItem.propTypes = {
id: PropTypes.string.isRequired,
failure: PropTypes.object.isRequired,
createActions: PropTypes.func
};

export default FailuresListItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './FailuresListItem';
114 changes: 86 additions & 28 deletions src/pages/SubmissionFailures/SubmissionFailures.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,61 +3,119 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';

import Page from '../../components/layout/Page';
import ResourceRenderer from '../../components/helpers/ResourceRenderer';
import PageContent from '../../components/layout/PageContent';
import FetchManyResourceRenderer from '../../components/helpers/FetchManyResourceRenderer';
import { fetchAllFailures } from '../../redux/modules/submissionFailures';
import {
fetchManyStatus,
readySubmissionFailuresSelector
} from '../../redux/selectors/submissionFailures';
import FailuresList from '../../components/SubmissionFailures/FailuresList/FailuresList';
import Box from '../../components/widgets/Box/Box';

class SubmissionFailures extends Component {
static loadAsync = ({}, dispatch) =>
static loadAsync = (params, dispatch) =>
Promise.all([dispatch(fetchAllFailures)]);

componentWillMount() {
this.props.loadAsync();
}

render() {
const { submissionFailures = [] } = this.props;
const { submissionFailures, fetchStatus } = this.props;

return (
<Page
resource={submissionFailures}
title={
<FormattedMessage
id="app.submissionFailures.title"
defaultMessage="Submission Failures"
<FetchManyResourceRenderer
fetchManyStatus={fetchStatus}
loading={
<PageContent
title={
<FormattedMessage
id="app.submissionFailures.loading"
defaultMessage="Loading list of failures ..."
/>
}
description={
<FormattedMessage
id="app.submissionFailures.loadingDescription"
defaultMessage="Please wait while we are getting the list of failures ready."
/>
}
/>
}
description={
<FormattedMessage
id="app.submissionFailures.description"
defaultMessage="Submission Failures"
failed={
<PageContent
title={
<FormattedMessage
id="app.submissionFailures.failed"
defaultMessage="Cannot load the list of failures"
/>
}
description={
<FormattedMessage
id="app.submissionFailures.failedDescription"
defaultMessage="We are sorry for the inconvenience, please try again later."
/>
}
/>
}
breadcrumbs={[
{
text: (
>
{() =>
<PageContent
title={
<FormattedMessage
id="app.submissionFailures.title"
defaultMessage="Submission Failures"
/>
),
iconName: 'fort-awesome'
}
]}
>
<div />
</Page>
}
description={
<FormattedMessage
id="app.submissionFailures.description"
defaultMessage="Browse all submission failures"
/>
}
breadcrumbs={[
{
text: (
<FormattedMessage
id="app.submissionFailures.title"
defaultMessage="Submission Failures"
/>
),
iconName: 'fort-awesome'
}
]}
>
<Box
title={
<FormattedMessage
id="app.submissionFailures.listTitle"
defaultMessage="Submission Failures"
/>
}
unlimitedHeight
noPadding
>
<FailuresList failures={submissionFailures} />
</Box>
</PageContent>}
</FetchManyResourceRenderer>
);
}
}

SubmissionFailures.propTypes = {
loadAsync: PropTypes.func.isRequired
loadAsync: PropTypes.func.isRequired,
fetchStatus: PropTypes.string,
submissionFailures: PropTypes.array
};

export default connect(
(state, { params: {} }) => ({}),
(dispatch, { params }) => ({
loadAsync: () => SubmissionFailures.loadAsync(params, dispatch)
state => ({
fetchStatus: fetchManyStatus(state),
submissionFailures: readySubmissionFailuresSelector(state)
}),
dispatch => ({
loadAsync: () => SubmissionFailures.loadAsync({}, dispatch)
})
)(SubmissionFailures);
22 changes: 15 additions & 7 deletions src/redux/modules/submissionFailures.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { handleActions, createAction } from 'redux-actions';
import factory, {
initialState,
resourceStatus
} from '../helpers/resourceManager';
import { handleActions } from 'redux-actions';
import factory, { initialState } from '../helpers/resourceManager';
import { createApiAction } from '../middleware/apiMiddleware';

const resourceName = 'submissionFailures';
var { actions, actionTypes, reduceActions } = factory({ resourceName });
var { actions, reduceActions } = factory({ resourceName });

export const additionalActionTypes = {};
export const additionalActionTypes = {
RESOLVE: 'recodex/submissionFailures/RESOLVE'
};

/**
* Actions
Expand All @@ -19,6 +18,15 @@ export const fetchAllFailures = actions.fetchMany({
endpoint: fetchManyEndpoint
});

export const resolveFailure = (id, note) =>
createApiAction({
type: additionalActionTypes.RESOLVE,
method: 'POST',
endpoint: `/submission-failures/${id}/resolve`,
body: { note },
meta: { id }
});

/**
* Reducer takes mainly care about all the state of individual attachments
*/
Expand Down
31 changes: 31 additions & 0 deletions src/redux/selectors/submissionFailures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { createSelector } from 'reselect';
import { fetchManyEndpoint } from '../modules/submissionFailures';
import { isReady, getJsData } from '../helpers/resourceManager';

const getSubmissionFailures = state => state.submissionFailures;
const getResources = failures => failures.get('resources');

export const submissionFailuresSelector = createSelector(
getSubmissionFailures,
getResources
);

export const fetchManyStatus = createSelector(getSubmissionFailures, state =>
state.getIn(['fetchManyStatus', fetchManyEndpoint])
);

export const getSubmissionFailure = failureId =>
createSelector(submissionFailuresSelector, failures =>
failures.get(failureId)
);

export const readySubmissionFailuresSelector = createSelector(
submissionFailuresSelector,
failures =>
failures
.toList()
.filter(isReady)
.map(getJsData)
.sort((a, b) => a.createdAt - b.createdAt)
.toArray()
);

0 comments on commit cef83f8

Please sign in to comment.