@@ -39,6 +39,8 @@ import FetchManyResourceRenderer from '../../components/helpers/FetchManyResourc
3939import { createUserNameComparator } from '../../components/helpers/users.js' ;
4040import { LocalizedExerciseName } from '../../components/helpers/LocalizedNames' ;
4141import EnvironmentsListItem from '../../components/helpers/EnvironmentsList/EnvironmentsListItem.js' ;
42+ import GroupArchivedWarning from '../../components/Groups/GroupArchivedWarning/GroupArchivedWarning.js' ;
43+ import GroupExamPending from '../../components/Groups/GroupExamPending' ;
4244import Callout from '../../components/widgets/Callout' ;
4345
4446import { fetchByIds } from '../../redux/modules/users.js' ;
@@ -47,8 +49,8 @@ import { fetchGroupIfNeeded } from '../../redux/modules/groups.js';
4749import { fetchRuntimeEnvironments } from '../../redux/modules/runtimeEnvironments.js' ;
4850import { fetchAssignmentSolutions , fetchAssignmentSolversIfNeeded } from '../../redux/modules/solutions.js' ;
4951import { setSolutionReviewState } from '../../redux/modules/solutionReviews.js' ;
50- import { usersSelector } from '../../redux/selectors/users.js' ;
51- import { groupSelector } from '../../redux/selectors/groups.js' ;
52+ import { usersSelector , loggedInUserSelector } from '../../redux/selectors/users.js' ;
53+ import { groupSelector , groupDataAccessorSelector } from '../../redux/selectors/groups.js' ;
5254import { studentsIdsOfGroup } from '../../redux/selectors/usersGroups.js' ;
5355import {
5456 getAssignment ,
@@ -408,10 +410,12 @@ class AssignmentSolutions extends Component {
408410 render ( ) {
409411 const {
410412 loggedUserId,
413+ currentUser,
411414 assignmentId,
412415 assignment,
413416 getStudents,
414417 getGroup,
418+ groupsAccessor,
415419 getUserSolutions,
416420 runtimeEnvironments,
417421 assignmentSolutions,
@@ -445,41 +449,59 @@ class AssignmentSolutions extends Component {
445449 canViewExercise = { true }
446450 />
447451
448- { plagiarisms && plagiarisms . length > 0 && (
449- < Callout variant = "danger" icon = { < PlagiarismIcon /> } >
450- < FormattedMessage
451- id = "app.assignmentSolutions.plagiarismsDetected.authors"
452- defaultMessage = "There {count, plural, one {is} other {are}} {count} {count, plural, one {solution} other {solutions}} (from {authors} {authors, plural, one {author} other {unique authors}}) with detected similarities. Such solutions may be plagiarisms."
453- values = { { count : plagiarisms . length , authors : getPlagiarismUniqueAuthors ( plagiarisms ) . length } }
454- />
455- </ Callout >
456- ) }
457-
458- { pendingReviews && pendingReviews . length > 0 && (
459- < Callout variant = "warning" >
460- < Row className = "align-items-center" >
461- < Col className = "pr-3 py-2" >
462- < FormattedMessage
463- id = "app.assignmentSolutions.pendingReviews"
464- defaultMessage = "There {count, plural, one {is} other {are}} {count} pending {count, plural, one {review} other {reviews}} among the solutions of the selected assignment. Remember that the review comments are visible to the author after a review is closed."
465- values = { { count : pendingReviews . length } }
466- />
467- </ Col >
468- < Col xl = "auto" >
469- < Button
470- variant = { this . state . closingReviewsFailed ? 'danger' : 'success' }
471- onClick = { ( ) => this . closeReviews ( pendingReviews ) }
472- disabled = { this . state . closingReviews } >
473- { this . state . closingReviews ? < LoadingIcon gapRight /> : < Icon icon = "boxes-packing" gapRight /> }
452+ < ResourceRenderer resource = { [ getGroup ( assignment . groupId ) , currentUser ] } >
453+ { ( group , currentUser ) => (
454+ < >
455+ { group . privateData && < GroupExamPending { ...group } currentUser = { currentUser } /> }
456+
457+ < GroupArchivedWarning
458+ { ...group }
459+ groupsDataAccessor = { groupsAccessor }
460+ linkFactory = { links . GROUP_EDIT_URI_FACTORY }
461+ />
462+
463+ { plagiarisms && plagiarisms . length > 0 && (
464+ < Callout variant = "danger" icon = { < PlagiarismIcon /> } >
474465 < FormattedMessage
475- id = "app.reviewSolutionButtons.closePendingReviews"
476- defaultMessage = "Close pending reviews"
466+ id = "app.assignmentSolutions.plagiarismsDetected.authors"
467+ defaultMessage = "There {count, plural, one {is} other {are}} {count} {count, plural, one {solution} other {solutions}} (from {authors} {authors, plural, one {author} other {unique authors}}) with detected similarities. Such solutions may be plagiarisms."
468+ values = { { count : plagiarisms . length , authors : getPlagiarismUniqueAuthors ( plagiarisms ) . length } }
477469 />
478- </ Button >
479- </ Col >
480- </ Row >
481- </ Callout >
482- ) }
470+ </ Callout >
471+ ) }
472+
473+ { pendingReviews && pendingReviews . length > 0 && ! group . archived && (
474+ < Callout variant = "warning" >
475+ < Row className = "align-items-center" >
476+ < Col className = "pr-3 py-2" >
477+ < FormattedMessage
478+ id = "app.assignmentSolutions.pendingReviews"
479+ defaultMessage = "There {count, plural, one {is} other {are}} {count} pending {count, plural, one {review} other {reviews}} among the solutions of the selected assignment. Remember that the review comments are visible to the author after a review is closed."
480+ values = { { count : pendingReviews . length } }
481+ />
482+ </ Col >
483+ < Col xl = "auto" >
484+ < Button
485+ variant = { this . state . closingReviewsFailed ? 'danger' : 'success' }
486+ onClick = { ( ) => this . closeReviews ( pendingReviews ) }
487+ disabled = { this . state . closingReviews } >
488+ { this . state . closingReviews ? (
489+ < LoadingIcon gapRight />
490+ ) : (
491+ < Icon icon = "boxes-packing" gapRight />
492+ ) }
493+ < FormattedMessage
494+ id = "app.reviewSolutionButtons.closePendingReviews"
495+ defaultMessage = "Close pending reviews"
496+ />
497+ </ Button >
498+ </ Col >
499+ </ Row >
500+ </ Callout >
501+ ) }
502+ </ >
503+ ) }
504+ </ ResourceRenderer >
483505
484506 < Row >
485507 < Col sm = { 12 } md >
@@ -667,10 +689,12 @@ class AssignmentSolutions extends Component {
667689
668690AssignmentSolutions . propTypes = {
669691 loggedUserId : PropTypes . string . isRequired ,
692+ currentUser : ImmutablePropTypes . map ,
670693 assignmentId : PropTypes . string . isRequired ,
671694 assignment : PropTypes . object ,
672695 getStudents : PropTypes . func . isRequired ,
673696 getGroup : PropTypes . func . isRequired ,
697+ groupsAccessor : PropTypes . func . isRequired ,
674698 getUserSolutions : PropTypes . func . isRequired ,
675699 runtimeEnvironments : PropTypes . array ,
676700 assignmentSolutions : ImmutablePropTypes . list ,
@@ -697,13 +721,15 @@ export default withLinks(
697721
698722 return {
699723 loggedUserId : loggedInUserIdSelector ( state ) ,
724+ currentUser : loggedInUserSelector ( state ) ,
700725 assignmentId,
701726 assignment,
702727 getStudentsIds,
703728 getStudents : groupId => readyUsers . filter ( user => getStudentsIds ( groupId ) . includes ( getId ( user ) ) ) . map ( getJsData ) ,
704729 getUserSolutions : userId => getUserSolutionsSortedData ( state ) ( userId , assignmentId ) ,
705730 assignmentSolutions : getAssignmentSolutions ( state , assignmentId ) ,
706731 getGroup : id => groupSelector ( state , id ) ,
732+ groupsAccessor : groupDataAccessorSelector ( state ) ,
707733 runtimeEnvironments : getAssignmentEnvironments ( state , assignmentId ) ,
708734 fetchManyStatus : fetchManyAssignmentSolutionsStatus ( assignmentId ) ( state ) ,
709735 assignmentSolversLoading : isAssignmentSolversLoading ( state ) ,
0 commit comments