Skip to content

Commit

Permalink
Merge pull request #164 from ReCodEx/submission_failures
Browse files Browse the repository at this point in the history
Submission failures page
  • Loading branch information
SemaiCZE committed Jan 15, 2018
2 parents 547a0e6 + f5eb6ff commit e1c05e1
Show file tree
Hide file tree
Showing 14 changed files with 502 additions and 5 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 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 className={failure.resolvedAt ? 'success' : 'danger'}>
<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';
105 changes: 105 additions & 0 deletions src/components/SubmissionFailures/ResolveFailure/ResolveFailure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal, Button } from 'react-bootstrap';
import { CloseIcon } from '../../icons';
import { FormattedMessage } from 'react-intl';
import { Field, reduxForm } from 'redux-form';
import TextField from '../../forms/Fields/TextField';
import SubmitButton from '../../forms/SubmitButton';

const maxNoteLength = value =>
value && value.length >= 255
? <FormattedMessage
id="app.submissionFailures.resolveMaxLengthExceeded"
defaultMessage="Maximum length of the note exceeded."
/>
: undefined;

const ResolveFailure = ({
isOpen,
onClose,
submitting,
handleSubmit,
anyTouched,
submitFailed = false,
submitSucceeded = false,
invalid,
reset
}) =>
<Modal show={isOpen} backdrop="static" onHide={onClose}>
<Modal.Header closeButton>
<Modal.Title>
<FormattedMessage
id="app.submissionFailures.resolveTitle"
defaultMessage="Resolve Failure"
/>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<Field
name="note"
component={TextField}
label={
<FormattedMessage
id="app.submissionFailures.resolveNote"
defaultMessage="Resolve note:"
/>
}
validate={maxNoteLength}
/>
</Modal.Body>
<Modal.Footer>
<SubmitButton
id="resolve-failure"
handleSubmit={data => handleSubmit(data).then(() => reset())}
submitting={submitting}
dirty={anyTouched}
hasSucceeded={submitSucceeded}
hasFailed={submitFailed}
invalid={invalid}
messages={{
submit: (
<FormattedMessage
id="app.submissionFailures.resolveSave"
defaultMessage="Save"
/>
),
submitting: (
<FormattedMessage
id="app.submissionFailures.resolveSaving"
defaultMessage="Saving ..."
/>
),
success: (
<FormattedMessage
id="app.submissionFailures.resolveSuccesss"
defaultMessage="Saved"
/>
)
}}
/>

<Button bsStyle="default" className="btn-flat" onClick={onClose}>
<CloseIcon />{' '}
<FormattedMessage
id="app.submissionFailures.resolveClose"
defaultMessage="Close"
/>
</Button>
</Modal.Footer>
</Modal>;

ResolveFailure.propTypes = {
handleSubmit: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
submitFailed: PropTypes.bool,
anyTouched: PropTypes.bool,
submitSucceeded: PropTypes.bool,
submitting: PropTypes.bool,
invalid: PropTypes.bool,
reset: PropTypes.func,
onClose: PropTypes.func.isRequired,
isOpen: PropTypes.bool.isRequired
};

export default reduxForm({ form: 'resolve-failure' })(ResolveFailure);
1 change: 1 addition & 0 deletions src/components/SubmissionFailures/ResolveFailure/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './ResolveFailure';
19 changes: 16 additions & 3 deletions src/components/layout/Sidebar/Admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import MenuItem from '../../widgets/Sidebar/MenuItem';

import withLinks from '../../../hoc/withLinks';

const Admin = ({ currentUrl, links: { ADMIN_INSTANCES_URI, USERS_URI } }) => (
const Admin = ({
currentUrl,
links: { ADMIN_INSTANCES_URI, USERS_URI, FAILURES_URI }
}) =>
<ul className="sidebar-menu">
<MenuTitle
title={
Expand Down Expand Up @@ -39,8 +42,18 @@ const Admin = ({ currentUrl, links: { ADMIN_INSTANCES_URI, USERS_URI } }) => (
currentPath={currentUrl}
link={USERS_URI}
/>
</ul>
);
<MenuItem
icon="fort-awesome"
title={
<FormattedMessage
id="app.sidebar.menu.admin.failures"
defaultMessage="Submission Failures"
/>
}
currentPath={currentUrl}
link={FAILURES_URI}
/>
</ul>;

Admin.propTypes = {
currentUrl: PropTypes.string.isRequired,
Expand Down
6 changes: 5 additions & 1 deletion src/links/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ export const linksFactory = lang => {
const ADMIN_EDIT_INSTANCE_URI_FACTORY = instanceId =>
`${ADMIN_INSTANCES_URI}/${instanceId}/edit`;

// failures details
const FAILURES_URI = `${prefix}/app/submission-failures`;

// download files
const DOWNLOAD = fileId => `${API_BASE}/uploaded-files/${fileId}/download`;

Expand Down Expand Up @@ -127,7 +130,8 @@ export const linksFactory = lang => {
ADMIN_EDIT_INSTANCE_URI_FACTORY,
DOWNLOAD,
REFERENCE_SOLUTION_EVALUATION_URI_FACTORY,
LOGIN_EXTERN_FINALIZATION
LOGIN_EXTERN_FINALIZATION,
FAILURES_URI
};
};

Expand Down
Loading

0 comments on commit e1c05e1

Please sign in to comment.