From 6027a15073929973b61e68be45c6d70c73812ca1 Mon Sep 17 00:00:00 2001 From: Martin Krulis Date: Wed, 8 Mar 2023 00:37:03 +0100 Subject: [PATCH] Suspected plagiarism indicator icon added in solutions tables. --- .../SolutionsTable/SolutionTableRowIcons.js | 20 +++++++++++ .../SolutionsTable/SolutionsTableRow.js | 3 ++ src/components/icons/index.js | 1 + src/locales/cs.json | 1 + src/locales/en.json | 1 + src/pages/AssignmentStats/AssignmentStats.js | 36 ++++++++++++++----- 6 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/components/Assignments/SolutionsTable/SolutionTableRowIcons.js b/src/components/Assignments/SolutionsTable/SolutionTableRowIcons.js index 737772163..33d288632 100644 --- a/src/components/Assignments/SolutionsTable/SolutionTableRowIcons.js +++ b/src/components/Assignments/SolutionsTable/SolutionTableRowIcons.js @@ -1,9 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { OverlayTrigger, Tooltip } from 'react-bootstrap'; +import { FormattedMessage } from 'react-intl'; import SolutionReviewIcon from '../../Solutions/SolutionReviewIcon'; import AssignmentStatusIcon, { getStatusDesc } from '../Assignment/AssignmentStatusIcon'; import CommentsIcon from './CommentsIcon'; +import { PlagiarismIcon } from '../../icons'; const SolutionTableRowIcons = ({ id, @@ -14,6 +17,7 @@ const SolutionTableRowIcons = ({ lastSubmission, commentsStats = null, isReviewer = false, + plagiarism = false, }) => ( <> } + {plagiarism && isReviewer && ( + + + + }> + + + )} + ); @@ -47,6 +66,7 @@ SolutionTableRowIcons.propTypes = { }), }), isReviewer: PropTypes.bool, + plagiarism: PropTypes.bool, }; export default SolutionTableRowIcons; diff --git a/src/components/Assignments/SolutionsTable/SolutionsTableRow.js b/src/components/Assignments/SolutionsTable/SolutionsTableRow.js index 40b549407..84cf2b7cc 100644 --- a/src/components/Assignments/SolutionsTable/SolutionsTableRow.js +++ b/src/components/Assignments/SolutionsTable/SolutionsTableRow.js @@ -37,6 +37,7 @@ const SolutionsTableRow = ({ accepted = false, review = null, isBestSolution = false, + plagiarism = null, runtimeEnvironment = null, commentsStats = null, permissionHints = null, @@ -88,6 +89,7 @@ const SolutionsTableRow = ({ lastSubmission={lastSubmission} commentsStats={commentsStats} isReviewer={permissionHints && permissionHints.review} + plagiarism={Boolean(plagiarism)} /> @@ -227,6 +229,7 @@ SolutionsTableRow.propTypes = { }), isBestSolution: PropTypes.bool, commentsStats: PropTypes.object, + plagiarism: PropTypes.string, runtimeEnvironment: PropTypes.object, permissionHints: PropTypes.object, noteMaxlen: PropTypes.number, diff --git a/src/components/icons/index.js b/src/components/icons/index.js index 679c4c6a9..93516846e 100644 --- a/src/components/icons/index.js +++ b/src/components/icons/index.js @@ -78,6 +78,7 @@ export const ObserverIcon = props => ; export const OutputIcon = props => ; export const PipelineIcon = props => ; export const PipelineStructureIcon = props => ; +export const PlagiarismIcon = props => ; export const PointsDecreasedIcon = props => ; export const PointsGraphIcon = props => ; export const PointsInterpolationIcon = props => ( diff --git a/src/locales/cs.json b/src/locales/cs.json index 5639d48b5..5794e34e4 100644 --- a/src/locales/cs.json +++ b/src/locales/cs.json @@ -1713,6 +1713,7 @@ "app.solutionsTable.commentsIcon.last": "Poslední komentář: {last}", "app.solutionsTable.environment": "Cílový jazyk", "app.solutionsTable.failedLoading": "Nebylo možné načíst odevzdaná řešení.", + "app.solutionsTable.icons.suspectedPlagiarism": "Podezření na plagiátorství (byly nalezeny podobnosti s jinými řešeními)", "app.solutionsTable.loading": "Načítají se odezvdaná řešení...", "app.solutionsTable.noSolutionsFound": "Zatím nebyla odevzdána žádná řešení.", "app.solutionsTable.note": "Poznámka", diff --git a/src/locales/en.json b/src/locales/en.json index 7ad87296c..136b02b56 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1713,6 +1713,7 @@ "app.solutionsTable.commentsIcon.last": "Last Comment: {last}", "app.solutionsTable.environment": "Target language", "app.solutionsTable.failedLoading": "Could not load this submission.", + "app.solutionsTable.icons.suspectedPlagiarism": "Suspected plagiarism (similarities with other solutions were found)", "app.solutionsTable.loading": "Loading submitted solutions...", "app.solutionsTable.noSolutionsFound": "No solutions were submitted yet.", "app.solutionsTable.note": "Note", diff --git a/src/pages/AssignmentStats/AssignmentStats.js b/src/pages/AssignmentStats/AssignmentStats.js index 0eb6e39cd..8f48c5a92 100644 --- a/src/pages/AssignmentStats/AssignmentStats.js +++ b/src/pages/AssignmentStats/AssignmentStats.js @@ -15,7 +15,15 @@ import CommentThreadContainer from '../../containers/CommentThreadContainer'; import Page from '../../components/layout/Page'; import { AssignmentNavigation } from '../../components/layout/Navigation'; -import Icon, { ChatIcon, DownloadIcon, DetailIcon, LoadingIcon, ResultsIcon, UserIcon } from '../../components/icons'; +import Icon, { + ChatIcon, + DownloadIcon, + DetailIcon, + CodeFileIcon, + LoadingIcon, + ResultsIcon, + UserIcon, +} from '../../components/icons'; import SolutionTableRowIcons from '../../components/Assignments/SolutionsTable/SolutionTableRowIcons'; import UsersName from '../../components/Users/UsersName'; import Points from '../../components/Assignments/SolutionsTable/Points'; @@ -62,7 +70,7 @@ import withLinks from '../../helpers/withLinks'; import { safeGet, identity, arrayToObject, toPlainAscii, hasPermissions } from '../../helpers/common'; const prepareTableColumnDescriptors = defaultMemoize((loggedUserId, assignmentId, groupId, locale, links) => { - const { SOLUTION_DETAIL_URI_FACTORY, GROUP_USER_SOLUTIONS_URI_FACTORY } = links; + const { SOLUTION_DETAIL_URI_FACTORY, SOLUTION_SOURCE_CODES_URI_FACTORY, GROUP_USER_SOLUTIONS_URI_FACTORY } = links; const nameComparator = createUserNameComparator(locale); const columns = [ @@ -78,6 +86,7 @@ const prepareTableColumnDescriptors = defaultMemoize((loggedUserId, assignmentId status={info.lastSubmission ? info.lastSubmission.evaluationStatus : null} lastSubmission={info.lastSubmission} commentsStats={info.commentsStats} + plagiarism={Boolean(info.plagiarism)} /> ), }), @@ -170,12 +179,20 @@ const prepareTableColumnDescriptors = defaultMemoize((loggedUserId, assignmentId cellRenderer: solution => ( {solution.permissionHints && solution.permissionHints.viewDetail && ( - - - + <> + + + + + + + )} {solution.permissionHints && solution.permissionHints.setFlag && ( @@ -218,12 +235,13 @@ const prepareTableData = defaultMemoize( isBestSolution, commentsStats, permissionHints, + plagiarism = null, }) => { const statusEvaluated = lastSubmission && (lastSubmission.evaluationStatus === 'done' || lastSubmission.evaluationStatus === 'failed'); return { - icon: { id, commentsStats, lastSubmission, accepted, review, permissionHints, isBestSolution }, + icon: { id, commentsStats, lastSubmission, accepted, review, permissionHints, isBestSolution, plagiarism }, user: usersIndex[authorId], date: createdAt, validity: statusEvaluated ? safeGet(lastSubmission, ['evaluation', 'score']) : null,