Skip to content

Commit 7f16431

Browse files
committed
Making revisions more eye-catching and easily accessible for students.
1 parent 93b6593 commit 7f16431

File tree

6 files changed

+54
-6
lines changed

6 files changed

+54
-6
lines changed

src/components/Solutions/SolutionReviewIcon/SolutionReviewIcon.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const SolutionReviewIcon = ({ id, review, isReviewer = false, placement = 'botto
3131
<>
3232
<FormattedMessage
3333
id="app.solutionReviewIcon.tooltip.closedAt"
34-
defaultMessage="The review was closed at {closed}, the comments are available at source codes page."
34+
defaultMessage="The review was closed at {closed}, the comments are available on the submitted files page."
3535
values={{ closed: <DateTime unixts={review.closedAt} /> }}
3636
/>{' '}
3737
{review.issues > 0 ? (

src/components/Solutions/SolutionStatus/SolutionStatus.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class SolutionStatus extends Component {
100100
editNote = null,
101101
assignmentSolversLoading,
102102
assignmentSolverSelector,
103-
links: { SOLUTION_DETAIL_URI_FACTORY },
103+
links: { SOLUTION_DETAIL_URI_FACTORY, SOLUTION_SOURCE_CODES_URI_FACTORY },
104104
} = this.props;
105105

106106
const important = getImportantSolutions(otherSolutions, id);
@@ -366,7 +366,7 @@ class SolutionStatus extends Component {
366366
)}
367367

368368
{review && review.issues > 0 && (
369-
<small className="text-muted">
369+
<small className="text-muted ml-3">
370370
(
371371
<FormattedMessage
372372
id="app.solution.reviewIssuesCount"
@@ -377,6 +377,16 @@ class SolutionStatus extends Component {
377377
</small>
378378
)}
379379

380+
{review.closedAt && (
381+
<Link to={SOLUTION_SOURCE_CODES_URI_FACTORY(assignmentId, id)}>
382+
<ReviewIcon
383+
review={review}
384+
gapLeft
385+
className={review.issues > 0 ? 'text-warning' : 'text-success'}
386+
/>
387+
</Link>
388+
)}
389+
380390
{important.lastReviewed && (
381391
<span className="small float-right mx-2">
382392
<Link to={SOLUTION_DETAIL_URI_FACTORY(assignmentId, important.lastReviewed.id)}>

src/locales/cs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,7 @@
16611661
"app.solution.pointsExplainDialog.epsilonExplain": "Epsilon (1e-6) je přičteno, aby kompenzovalo zaokrouhlovací chyby.",
16621662
"app.solution.pointsExplainDialog.overriddenPoints": "Vedoucí ručně přepsal hodnocení úlohy na <strong>{overriddenPoints}</strong> {overriddenPoints, plural, one {bod} =2 {body} =3 {body} =4 {body} other {bodů}} (a {bonusPoints} {bonusPoints, plural, one {bonusový bod} =2 {bonusové body} =3 {bonusové body} =4 {bonusové body} other {bonusových bodů}}).",
16631663
"app.solution.pointsExplainDialog.title": "Vysvětlení hodnotícího procesu",
1664+
"app.solution.reviewAvailableCallout": "K tomuto řešení byla vytvořena revize, která se vám zobrazí na stránce s odevzdanými soubory.",
16641665
"app.solution.reviewClosedAt": "Revidováno v",
16651666
"app.solution.reviewIssuesCount": "{issues} {count, plural, one {připomínka} =2 {připomínky} =3 {připomínky} =4 {připomínky} other {připomínek}} k vyřešení",
16661667
"app.solution.reviewNotStartedYet": "dosud nezahájeno",

src/locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,7 @@
16611661
"app.solution.pointsExplainDialog.epsilonExplain": "The epsilon (1e-6) is added to compensate for rounding errors.",
16621662
"app.solution.pointsExplainDialog.overriddenPoints": "A supervisor has manually overridden the points to <strong>{overriddenPoints}</strong> (and {bonusPoints} {bonusPoints, plural, one {point} other {points}}).",
16631663
"app.solution.pointsExplainDialog.title": "Explanation of the scoring process",
1664+
"app.solution.reviewAvailableCallout": "A review of this solution is available on the submitted files page.",
16641665
"app.solution.reviewClosedAt": "Reviewed at",
16651666
"app.solution.reviewIssuesCount": "{issues} {issues, plural, one {issue} other {issues}} to resolve",
16661667
"app.solution.reviewNotStartedYet": "not started yet",
@@ -1697,7 +1698,7 @@
16971698
"app.solutionPlagiarisms.suspectedSourcesAvailable": "of {count} available",
16981699
"app.solutionPlagiarisms.title": "Similarities Detected — Suspected Plagiarism",
16991700
"app.solutionPlagiarisms.unableCompareMalformed": "Malformed files cannot be visualized in comparison mode.",
1700-
"app.solutionReviewIcon.tooltip.closedAt": "The review was closed at {closed}, the comments are available at source codes page.",
1701+
"app.solutionReviewIcon.tooltip.closedAt": "The review was closed at {closed}, the comments are available on the submitted files page.",
17011702
"app.solutionReviewIcon.tooltip.issues": "The reviewer created {issues} {issues, plural, one {issue} other {issues}}, please, fix {issues, plural, one {it} other {them}} in the next solution.",
17021703
"app.solutionReviewIcon.tooltip.noIssues": "No issues were created.",
17031704
"app.solutionReviewIcon.tooltip.startedAt": "The review was started at {started} and has not been closed yet.",

src/pages/Solution/Solution.js

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
44
import { Row, Col } from 'react-bootstrap';
55
import { connect } from 'react-redux';
66
import { FormattedMessage, injectIntl } from 'react-intl';
7+
import { Link } from 'react-router-dom';
78
import { defaultMemoize } from 'reselect';
89

910
import Page from '../../components/layout/Page';
@@ -41,10 +42,13 @@ import {
4142
} from '../../redux/selectors/assignments';
4243
import { evaluationsForSubmissionSelector, fetchManyStatus } from '../../redux/selectors/submissionEvaluations';
4344
import { assignmentSubmissionScoreConfigSelector } from '../../redux/selectors/exerciseScoreConfig';
45+
import { isLoggedAsStudent } from '../../redux/selectors/users';
4446

4547
import { registerSolutionVisit } from '../../components/Solutions/RecentlyVisited/functions';
4648
import { hasPermissions } from '../../helpers/common';
47-
import { PlagiarismIcon, SolutionResultsIcon, WarningIcon } from '../../components/icons';
49+
import { LinkIcon, PlagiarismIcon, SolutionResultsIcon, WarningIcon } from '../../components/icons';
50+
51+
import withLinks from '../../helpers/withLinks';
4852

4953
const assignmentHasRuntime = defaultMemoize(
5054
(assignment, runtimeId) =>
@@ -98,7 +102,9 @@ class Solution extends Component {
98102
fetchScoreConfigIfNeeded,
99103
assignmentSolversLoading,
100104
assignmentSolverSelector,
105+
isStudent = false,
101106
intl: { locale },
107+
links: { SOLUTION_SOURCE_CODES_URI_FACTORY },
102108
} = this.props;
103109

104110
return (
@@ -195,6 +201,29 @@ class Solution extends Component {
195201
</Callout>
196202
)}
197203

204+
{isStudent && hasPermissions(solution, 'viewReview') && solution.review && solution.review.closedAt && (
205+
<Callout variant={solution.review.issues > 0 ? 'warning' : 'success'}>
206+
<FormattedMessage
207+
id="app.solution.reviewAvailableCallout"
208+
defaultMessage="A review of this solution is available on the submitted files page."
209+
/>
210+
{solution.review.issues > 0 && (
211+
<>
212+
{' ('}
213+
<FormattedMessage
214+
id="app.solution.reviewIssuesCount"
215+
defaultMessage="{issues} {issues, plural, one {issue} other {issues}} to resolve"
216+
values={{ issues: solution.review.issues }}
217+
/>
218+
{')'}
219+
</>
220+
)}
221+
<Link to={SOLUTION_SOURCE_CODES_URI_FACTORY(assignmentId, solution.id)}>
222+
<LinkIcon largeGapLeft className="text-primary" />
223+
</Link>
224+
</Callout>
225+
)}
226+
198227
<ResourceRenderer resource={runtimeEnvironments} returnAsArray>
199228
{runtimes => (
200229
<FetchManyResourceRenderer fetchManyStatus={fetchStatus}>
@@ -248,11 +277,13 @@ Solution.propTypes = {
248277
scoreConfigSelector: PropTypes.func,
249278
assignmentSolversLoading: PropTypes.bool,
250279
assignmentSolverSelector: PropTypes.func.isRequired,
280+
isStudent: PropTypes.bool,
251281
editNote: PropTypes.func.isRequired,
252282
deleteEvaluation: PropTypes.func.isRequired,
253283
refreshSolutionEvaluations: PropTypes.func.isRequired,
254284
download: PropTypes.func.isRequired,
255285
intl: PropTypes.object,
286+
links: PropTypes.object.isRequired,
256287
};
257288

258289
export default connect(
@@ -274,6 +305,7 @@ export default connect(
274305
scoreConfigSelector: assignmentSubmissionScoreConfigSelector(state),
275306
assignmentSolversLoading: isAssignmentSolversLoading(state),
276307
assignmentSolverSelector: getAssignmentSolverSelector(state),
308+
isStudent: isLoggedAsStudent(state),
277309
}),
278310
(dispatch, { match: { params } }) => ({
279311
loadAsync: () => Solution.loadAsync(params, dispatch),
@@ -290,4 +322,4 @@ export default connect(
290322
),
291323
download: (id, entry = null) => dispatch(download(id, entry)),
292324
})
293-
)(injectIntl(Solution));
325+
)(injectIntl(withLinks(Solution)));

src/redux/selectors/users.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ export const isLoggedAsSuperAdmin = createSelector(getLoggedInUserEffectiveRole,
7878
isSuperadminRole(effectiveRole)
7979
);
8080

81+
export const isLoggedAsStudent = createSelector(getLoggedInUserEffectiveRole, effectiveRole =>
82+
isStudentRole(effectiveRole)
83+
);
84+
8185
export const memberOfInstancesIdsSelector = userId =>
8286
createSelector(getUser(userId), user =>
8387
user && isReady(user) ? user.getIn(['data', 'privateData', 'instancesIds'], EMPTY_LIST) : EMPTY_LIST

0 commit comments

Comments
 (0)