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

Adding archived-group info on assignment solutions page and hiding close all reviews callout in archived groups. #546

Merged
merged 1 commit into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 61 additions & 35 deletions src/pages/AssignmentSolutions/AssignmentSolutions.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import FetchManyResourceRenderer from '../../components/helpers/FetchManyResourc
import { createUserNameComparator } from '../../components/helpers/users.js';
import { LocalizedExerciseName } from '../../components/helpers/LocalizedNames';
import EnvironmentsListItem from '../../components/helpers/EnvironmentsList/EnvironmentsListItem.js';
import GroupArchivedWarning from '../../components/Groups/GroupArchivedWarning/GroupArchivedWarning.js';
import GroupExamPending from '../../components/Groups/GroupExamPending';
import Callout from '../../components/widgets/Callout';

import { fetchByIds } from '../../redux/modules/users.js';
Expand All @@ -47,8 +49,8 @@ import { fetchGroupIfNeeded } from '../../redux/modules/groups.js';
import { fetchRuntimeEnvironments } from '../../redux/modules/runtimeEnvironments.js';
import { fetchAssignmentSolutions, fetchAssignmentSolversIfNeeded } from '../../redux/modules/solutions.js';
import { setSolutionReviewState } from '../../redux/modules/solutionReviews.js';
import { usersSelector } from '../../redux/selectors/users.js';
import { groupSelector } from '../../redux/selectors/groups.js';
import { usersSelector, loggedInUserSelector } from '../../redux/selectors/users.js';
import { groupSelector, groupDataAccessorSelector } from '../../redux/selectors/groups.js';
import { studentsIdsOfGroup } from '../../redux/selectors/usersGroups.js';
import {
getAssignment,
Expand Down Expand Up @@ -408,10 +410,12 @@ class AssignmentSolutions extends Component {
render() {
const {
loggedUserId,
currentUser,
assignmentId,
assignment,
getStudents,
getGroup,
groupsAccessor,
getUserSolutions,
runtimeEnvironments,
assignmentSolutions,
Expand Down Expand Up @@ -445,41 +449,59 @@ class AssignmentSolutions extends Component {
canViewExercise={true}
/>

{plagiarisms && plagiarisms.length > 0 && (
<Callout variant="danger" icon={<PlagiarismIcon />}>
<FormattedMessage
id="app.assignmentSolutions.plagiarismsDetected.authors"
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."
values={{ count: plagiarisms.length, authors: getPlagiarismUniqueAuthors(plagiarisms).length }}
/>
</Callout>
)}

{pendingReviews && pendingReviews.length > 0 && (
<Callout variant="warning">
<Row className="align-items-center">
<Col className="pr-3 py-2">
<FormattedMessage
id="app.assignmentSolutions.pendingReviews"
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."
values={{ count: pendingReviews.length }}
/>
</Col>
<Col xl="auto">
<Button
variant={this.state.closingReviewsFailed ? 'danger' : 'success'}
onClick={() => this.closeReviews(pendingReviews)}
disabled={this.state.closingReviews}>
{this.state.closingReviews ? <LoadingIcon gapRight /> : <Icon icon="boxes-packing" gapRight />}
<ResourceRenderer resource={[getGroup(assignment.groupId), currentUser]}>
{(group, currentUser) => (
<>
{group.privateData && <GroupExamPending {...group} currentUser={currentUser} />}

<GroupArchivedWarning
{...group}
groupsDataAccessor={groupsAccessor}
linkFactory={links.GROUP_EDIT_URI_FACTORY}
/>

{plagiarisms && plagiarisms.length > 0 && (
<Callout variant="danger" icon={<PlagiarismIcon />}>
<FormattedMessage
id="app.reviewSolutionButtons.closePendingReviews"
defaultMessage="Close pending reviews"
id="app.assignmentSolutions.plagiarismsDetected.authors"
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."
values={{ count: plagiarisms.length, authors: getPlagiarismUniqueAuthors(plagiarisms).length }}
/>
</Button>
</Col>
</Row>
</Callout>
)}
</Callout>
)}

{pendingReviews && pendingReviews.length > 0 && !group.archived && (
<Callout variant="warning">
<Row className="align-items-center">
<Col className="pr-3 py-2">
<FormattedMessage
id="app.assignmentSolutions.pendingReviews"
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."
values={{ count: pendingReviews.length }}
/>
</Col>
<Col xl="auto">
<Button
variant={this.state.closingReviewsFailed ? 'danger' : 'success'}
onClick={() => this.closeReviews(pendingReviews)}
disabled={this.state.closingReviews}>
{this.state.closingReviews ? (
<LoadingIcon gapRight />
) : (
<Icon icon="boxes-packing" gapRight />
)}
<FormattedMessage
id="app.reviewSolutionButtons.closePendingReviews"
defaultMessage="Close pending reviews"
/>
</Button>
</Col>
</Row>
</Callout>
)}
</>
)}
</ResourceRenderer>

<Row>
<Col sm={12} md>
Expand Down Expand Up @@ -667,10 +689,12 @@ class AssignmentSolutions extends Component {

AssignmentSolutions.propTypes = {
loggedUserId: PropTypes.string.isRequired,
currentUser: ImmutablePropTypes.map,
assignmentId: PropTypes.string.isRequired,
assignment: PropTypes.object,
getStudents: PropTypes.func.isRequired,
getGroup: PropTypes.func.isRequired,
groupsAccessor: PropTypes.func.isRequired,
getUserSolutions: PropTypes.func.isRequired,
runtimeEnvironments: PropTypes.array,
assignmentSolutions: ImmutablePropTypes.list,
Expand All @@ -697,13 +721,15 @@ export default withLinks(

return {
loggedUserId: loggedInUserIdSelector(state),
currentUser: loggedInUserSelector(state),
assignmentId,
assignment,
getStudentsIds,
getStudents: groupId => readyUsers.filter(user => getStudentsIds(groupId).includes(getId(user))).map(getJsData),
getUserSolutions: userId => getUserSolutionsSortedData(state)(userId, assignmentId),
assignmentSolutions: getAssignmentSolutions(state, assignmentId),
getGroup: id => groupSelector(state, id),
groupsAccessor: groupDataAccessorSelector(state),
runtimeEnvironments: getAssignmentEnvironments(state, assignmentId),
fetchManyStatus: fetchManyAssignmentSolutionsStatus(assignmentId)(state),
assignmentSolversLoading: isAssignmentSolversLoading(state),
Expand Down
2 changes: 1 addition & 1 deletion src/pages/GroupUserSolutions/GroupUserSolutions.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ class GroupUserSolutions extends Component {
</Callout>
)}

{pendingReviews && pendingReviews.length > 0 && (
{pendingReviews && pendingReviews.length > 0 && !group.archived && (
<Callout variant="warning">
<Row className="align-items-center">
<Col className="pr-3 py-2">
Expand Down
Loading