Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements #175

Merged
merged 9 commits into from
Feb 11, 2018
Merged
18 changes: 15 additions & 3 deletions src/components/Exercises/FilesTable/FilesTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Icon from 'react-fontawesome';
import { Table } from 'react-bootstrap';
import Button from '../../widgets/FlatButton';
import Box from '../../widgets/Box';
import { SendIcon } from '../../icons';
import { SendIcon, DownloadIcon } from '../../icons';

import UploadContainer from '../../../containers/UploadContainer';
import ResourceRenderer from '../../helpers/ResourceRenderer';
Expand All @@ -31,7 +31,8 @@ const FilesTable = ({
RowComponent,
intl,
isOpen = true,
viewOnly = false
viewOnly = false,
downloadArchive
}) =>
<Box title={title} collapsable isOpen={isOpen} unlimitedHeight>
<div>
Expand Down Expand Up @@ -88,6 +89,16 @@ const FilesTable = ({
</p>}
</div>}
</ResourceRenderer>
{downloadArchive &&
<p>
<Button bsStyle="primary" onClick={downloadArchive}>
<DownloadIcon />{' '}
<FormattedMessage
id="app.filesTable.downloadArchive"
defaultMessage="Download all"
/>
</Button>
</p>}
</div>
</Box>;

Expand All @@ -113,7 +124,8 @@ FilesTable.propTypes = {
RowComponent: PropTypes.func.isRequired,
intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired,
isOpen: PropTypes.bool,
viewOnly: PropTypes.bool
viewOnly: PropTypes.bool,
downloadArchive: PropTypes.func
};

export default injectIntl(FilesTable);
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ const FailuresList = ({ failures, createActions }) =>
defaultMessage="Description"
/>
</th>
<th>
<FormattedMessage
id="app.failureList.headLink"
defaultMessage="Link"
/>
</th>
<th>
<FormattedMessage
id="app.failureList.headCreatedAt"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedDate, FormattedTime } from 'react-intl';
import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl';
import Icon from 'react-fontawesome';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
import { Link } from 'react-router';
import withLinks from '../../../hoc/withLinks';

const FailuresListItem = ({ id, createActions, failure }) =>
const FailuresListItem = ({
id,
createActions,
failure,
links: {
SUBMISSION_DETAIL_URI_FACTORY,
EXERCISE_REFERENCE_SOLUTION_URI_FACTORY
}
}) =>
<tr className={failure.resolvedAt ? 'success' : 'danger'}>
<td className="text-center">
<OverlayTrigger
Expand All @@ -26,6 +36,35 @@ const FailuresListItem = ({ id, createActions, failure }) =>
<td>
{failure.description}
</td>
<td>
{failure.assignmentSolutionId &&
<Link
to={SUBMISSION_DETAIL_URI_FACTORY(
failure.assignmentId,
failure.assignmentSolutionId
)}
>
<FormattedMessage
id="app.failureListItem.studentAssignment"
defaultMessage="Student assignment"
/>
</Link>}
{failure.referenceSolutionId &&
<Link
to={EXERCISE_REFERENCE_SOLUTION_URI_FACTORY(
failure.exerciseId,
failure.referenceSolutionId
)}
>
<FormattedMessage
id="app.failureListItem.referenceAssignment"
defaultMessage="Reference assignment"
/>
</Link>}
{failure.assignmentSolutionId === null &&
failure.referenceSolutionId === null &&
<span>&mdash;</span>}
</td>
<td>
<FormattedDate value={new Date(failure.createdAt * 1000)} />
{', '}
Expand Down Expand Up @@ -55,7 +94,8 @@ const FailuresListItem = ({ id, createActions, failure }) =>
FailuresListItem.propTypes = {
id: PropTypes.string.isRequired,
failure: PropTypes.object.isRequired,
createActions: PropTypes.func
createActions: PropTypes.func,
links: PropTypes.object
};

export default FailuresListItem;
export default withLinks(FailuresListItem);
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ const messages = defineMessages({
}
});

const ResultArchiveInfoBox = ({ id, intl: { formatMessage } }) => (
const ResultArchiveInfoBox = ({ id, intl: { formatMessage } }) =>
<SimpleInfoBox
icon="file-archive-o"
title={formatMessage(messages.title)}
description={formatMessage(messages.description)}
/>
);
color="green"
/>;

ResultArchiveInfoBox.propTypes = {
id: PropTypes.string.isRequired,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, defineMessages } from 'react-intl';
import { SimpleInfoBox } from '../../widgets/InfoBox';

const messages = defineMessages({
title: {
id: 'app.solutionArchiveInfoBox.title',
defaultMessage: 'Solution archive'
},
description: {
id: 'app.solutionArchiveInfoBox.description',
defaultMessage: 'All submitted source files in one ZIP archive'
}
});

const SolutionArchiveInfoBox = ({ id, intl: { formatMessage } }) =>
<SimpleInfoBox
icon="file-archive-o"
title={formatMessage(messages.title)}
description={formatMessage(messages.description)}
color="blue"
/>;

SolutionArchiveInfoBox.propTypes = {
id: PropTypes.string.isRequired,
intl: PropTypes.shape({ formatMessage: PropTypes.func.isRequired }).isRequired
};

export default injectIntl(SolutionArchiveInfoBox);
1 change: 1 addition & 0 deletions src/components/Submissions/SolutionArchiveInfoBox/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './SolutionArchiveInfoBox';
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import SourceCodeInfoBox from '../../widgets/SourceCodeInfoBox';
import TestResults from '../TestResults';
import BonusPointsContainer from '../../../containers/BonusPointsContainer';
import DownloadResultArchiveContainer from '../../../containers/DownloadResultArchiveContainer';
import DownloadSolutionArchiveContainer from '../../../containers/DownloadSolutionArchiveContainer';
import CommentThreadContainer from '../../../containers/CommentThreadContainer';
import SourceCodeViewerContainer from '../../../containers/SourceCodeViewerContainer';
import SubmissionEvaluations from '../SubmissionEvaluations';
Expand Down Expand Up @@ -137,6 +138,9 @@ class SubmissionDetail extends Component {
<Col lg={6} md={12}>
<DownloadResultArchiveContainer submissionId={restSub.id} />
</Col>
<Col lg={6} md={12}>
<DownloadSolutionArchiveContainer solutionId={id} />
</Col>
</Row>}
{activeSubmissionId &&
isSupervisor &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
import {
fetchAttachmentFiles,
addAttachmentFiles,
removeAttachmentFile
removeAttachmentFile,
downloadAttachmentArchive
} from '../../redux/modules/attachmentFiles';

import { createGetAttachmentFiles } from '../../redux/selectors/attachmentFiles';
Expand All @@ -23,7 +24,8 @@ const AttachmentFilesTableContainer = ({
attachmentFiles,
loadFiles,
addFiles,
removeFile
removeFile,
downloadArchive
}) =>
<FilesTableContainer
uploadId={`attachment-exercise-files-${exercise.id}`}
Expand All @@ -45,6 +47,7 @@ const AttachmentFilesTableContainer = ({
}
HeaderComponent={AttachmentFilesTableHeaderRow}
RowComponent={AttachmentFilesTableRow}
downloadArchive={downloadArchive}
/>;

AttachmentFilesTableContainer.propTypes = {
Expand All @@ -55,7 +58,8 @@ AttachmentFilesTableContainer.propTypes = {
attachmentFiles: ImmutablePropTypes.map,
loadFiles: PropTypes.func.isRequired,
addFiles: PropTypes.func.isRequired,
removeFile: PropTypes.func.isRequired
removeFile: PropTypes.func.isRequired,
downloadArchive: PropTypes.func
};

export default connect(
Expand All @@ -70,6 +74,10 @@ export default connect(
(dispatch, { exercise }) => ({
loadFiles: () => dispatch(fetchAttachmentFiles(exercise.id)),
addFiles: files => dispatch(addAttachmentFiles(exercise.id, files)),
removeFile: id => dispatch(removeAttachmentFile(exercise.id, id))
removeFile: id => dispatch(removeAttachmentFile(exercise.id, id)),
downloadArchive: e => {
e.preventDefault();
dispatch(downloadAttachmentArchive(exercise.id));
}
})
)(AttachmentFilesTableContainer);
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

import { downloadSolutionArchive } from '../../redux/modules/submissionEvaluations';
import SolutionArchiveInfoBox from '../../components/Submissions/SolutionArchiveInfoBox';

const DownloadResultArchiveContainer = ({
solutionId,
downloadSolutionArchive
}) =>
<a href="#" onClick={downloadSolutionArchive}>
<SolutionArchiveInfoBox id={solutionId} />
</a>;

DownloadResultArchiveContainer.propTypes = {
solutionId: PropTypes.string.isRequired,
downloadSolutionArchive: PropTypes.func.isRequired
};

export default connect(
(state, props) => ({}),
(dispatch, { solutionId }) => ({
downloadSolutionArchive: e => {
e.preventDefault();
dispatch(downloadSolutionArchive(solutionId));
}
})
)(DownloadResultArchiveContainer);
1 change: 1 addition & 0 deletions src/containers/DownloadSolutionArchiveContainer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './DownloadSolutionArchiveContainer';
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ class EvaluationProgressContainer extends Component {
task_state = 'OK', // eslint-disable-line camelcase
text = null
}) => ({
wasSuccessful: command !== 'TASK' || task_state === 'COMPLETED', // eslint-disable-line camelcase
text: text || this.props.intl.formatMessage(this.getRandomMessage()),
status: task_state // eslint-disable-line camelcase
});
wasSuccessful: command !== 'TASK' || task_state === 'COMPLETED', // eslint-disable-line camelcase
text: text || this.props.intl.formatMessage(this.getRandomMessage()),
status: task_state // eslint-disable-line camelcase
});

getRandomMessage = () => {
if (!this.availableMessages || this.availableMessages.length === 0) {
Expand Down Expand Up @@ -172,38 +172,38 @@ class EvaluationProgressContainer extends Component {

return this.state.realTimeProcessing === true
? <EvaluationProgress
isOpen={isOpen}
messages={displayedMessages}
completed={progress.completed}
skipped={progress.skipped}
failed={progress.failed}
finished={isFinished}
showContinueButton={isFinished || this.isClosed}
finishProcessing={this.finish}
onClose={this.userCloseAction}
/>
isOpen={isOpen}
messages={displayedMessages}
completed={progress.completed}
skipped={progress.skipped}
failed={progress.failed}
finished={isFinished}
showContinueButton={isFinished || this.isClosed}
finishProcessing={this.finish}
onClose={this.userCloseAction}
/>
: <EvaluationProgress
isOpen={isOpen}
completed={0}
skipped={100}
failed={0}
finished={false}
showContinueButton={true}
finishProcessing={this.finish}
onClose={this.userCloseAction}
messages={List([
this.formatMessage({
command: 'TASK',
task_state: 'SKIPPED',
text: (
<FormattedMessage
id="app.evaluationProgress.noWebSockets"
defaultMessage="Your browser does not support realtime progress monitoring or the connection to the server could not be estabelished or was lost. The evaluation has already started and you will be able to see the results soon."
/>
)
})
])}
/>;
isOpen={isOpen}
completed={0}
skipped={100}
failed={0}
finished={false}
showContinueButton={true}
finishProcessing={this.finish}
onClose={this.userCloseAction}
messages={List([
this.formatMessage({
command: 'TASK',
task_state: 'SKIPPED',
text: (
<FormattedMessage
id="app.evaluationProgress.noWebSockets"
defaultMessage="Your browser does not support realtime progress monitoring or the connection to the server could not be estabelished or was lost. The evaluation has already started and you will be able to see the results soon."
/>
)
})
])}
/>;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const ResubmitSolutionContainer = ({
monitor={monitor}
link={SUBMISSION_DETAIL_URI_FACTORY(assignmentId, newSubmissionId)}
onFinish={() => fetchSubmissions(userId)}
onUserClose={() => fetchSubmissions(userId)}
/>
</span>
);
Expand Down
Loading