Skip to content

Commit

Permalink
Improving submission failure reporting for regular users.
Browse files Browse the repository at this point in the history
  • Loading branch information
krulis-martin committed Dec 31, 2023
1 parent fe3bbb0 commit c5408d5
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import ReferenceSolutionStatus from '../ReferenceSolutionStatus/ReferenceSolutio

import Button from '../../widgets/TheButton';
import Callout from '../../widgets/Callout';
import DateTime from '../../widgets/DateTime';
import FailureReport from '../../SubmissionFailures/FailureReport';
import ResourceRenderer from '../../helpers/ResourceRenderer';
import { RefreshIcon, WarningIcon, EvaluationFailedIcon } from '../../icons';
import { RefreshIcon, WarningIcon } from '../../icons';

import { EMPTY_OBJ, getFirstItemInOrder } from '../../../helpers/common';

Expand Down Expand Up @@ -155,56 +155,7 @@ class ReferenceSolutionDetail extends Component {
</Callout>
)}

{failure && (
<>
<Callout variant="danger" icon={<EvaluationFailedIcon />}>
<h4>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailedHeading"
defaultMessage="The evaluation has failed!"
/>
</h4>

{typeof failure === 'object' ? (
<p>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailedMessage"
defaultMessage="Backend message"
/>
: <em>{failure.description}</em>
</p>
) : (
<p>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailedInternalError"
defaultMessage="Internal backend error."
/>
</p>
)}
</Callout>

{Boolean(typeof failure === 'object' && failure.resolvedAt && failure.resolutionNote) && (
<Callout variant="success" icon="fire-extinguisher">
<span className="small float-right">
(<DateTime unixts={failure.resolvedAt} />)
</span>
<h4>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailureResolved"
defaultMessage="The failure has been resolved by admin!"
/>
</h4>
<p>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailureResolvedNote"
defaultMessage="Resolution note"
/>
: <em>{failure.resolutionNote}</em>
</p>
</Callout>
)}
</>
)}
{failure && <FailureReport failure={failure} />}

{evaluation && (
<EvaluationDetail
Expand Down
55 changes: 3 additions & 52 deletions src/components/Solutions/SolutionDetail/SolutionDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import ResourceRenderer from '../../helpers/ResourceRenderer';
import SolutionFiles from '../SolutionFiles';
import EvaluationDetail from '../EvaluationDetail';
import CompilationLogs from '../CompilationLogs';
import { RefreshIcon, EvaluationFailedIcon } from '../../icons';
import { RefreshIcon } from '../../icons';
import FailureReport from '../../SubmissionFailures/FailureReport';
import Button from '../../widgets/TheButton';
import Callout from '../../widgets/Callout';
import DateTime from '../../widgets/DateTime';

import { safeGet, EMPTY_OBJ } from '../../../helpers/common';

Expand Down Expand Up @@ -152,56 +152,7 @@ class SolutionDetail extends Component {
</Callout>
)}

{failure && (
<>
<Callout variant="danger" icon={<EvaluationFailedIcon />}>
<h4>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailedHeading"
defaultMessage="The evaluation has failed!"
/>
</h4>

{typeof failure === 'object' ? (
<p>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailedMessage"
defaultMessage="Backend message"
/>
: <em>{failure.description}</em>
</p>
) : (
<p>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailedInternalError"
defaultMessage="Internal backend error."
/>
</p>
)}
</Callout>

{Boolean(typeof failure === 'object' && failure.resolvedAt && failure.resolutionNote) && (
<Callout variant="success" icon="fire-extinguisher">
<span className="small float-right">
(<DateTime unixts={failure.resolvedAt} />)
</span>
<h4>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailureResolved"
defaultMessage="The failure has been resolved by admin!"
/>
</h4>
<p>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailureResolvedNote"
defaultMessage="Resolution note"
/>
: <em>{failure.resolutionNote}</em>
</p>
</Callout>
)}
</>
)}
{failure && <FailureReport failure={failure} />}

{activeSubmissionId !== safeGet(lastSubmission, ['id']) && (
<Callout variant="warning">
Expand Down
140 changes: 140 additions & 0 deletions src/components/SubmissionFailures/FailureReport/FailureReport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';

import { EvaluationFailedIcon, InfoIcon } from '../../icons';
import DateTime from '../../widgets/DateTime';
import Callout from '../../widgets/Callout';
import InsetPanel from '../../widgets/InsetPanel';

const FAILURE_TYPES = {
broker_reject: (
<FormattedMessage
id="app.submissionEvaluation.evaluationFailed.brokerReject"
defaultMessage="The backend rejected the evaluation job."
/>
),
evaluation_failure: (
<FormattedMessage
id="app.submissionEvaluation.evaluationFailed.evaluationFailure"
defaultMessage="The evaluation failed during processing."
/>
),
config_error: (
<FormattedMessage
id="app.submissionEvaluation.evaluationFailed.configError"
defaultMessage="Exercise configuration could not be compiled in the evaluation execution plan."
/>
),
soft_config_error: (
<FormattedMessage
id="app.submissionEvaluation.evaluationFailed.softConfigError"
defaultMessage="The evaluation execution plan could not be compiled due to problems with submission."
/>
),
};

const FAILURE_DETAILS = {
broker_reject: (
<FormattedMessage
id="app.submissionEvaluation.evaluationFailed.brokerRejectDetails"
defaultMessage="This type of error occurs when the backend cannot accept the evaluation job. The exercise configuration is not valid or the backend workers responsible for this type of submissions are currently offline."
/>
),
evaluation_failure: (
<FormattedMessage
id="app.submissionEvaluation.evaluationFailed.evaluationFailureDetails"
defaultMessage="This type of error could be caused by invalid exercise configuration or by internal error of the backend worker. Complex exercises may also run into this error when names of the submitted or compiled files are clashing."
/>
),
config_error: (
<FormattedMessage
id="app.submissionEvaluation.evaluationFailed.configErrorDetails"
defaultMessage="This type of error usually occurs if the exercise is not configured properly. Please contact the author of the exercise."
/>
),
soft_config_error: (
<FormattedMessage
id="app.submissionEvaluation.evaluationFailed.softConfigErrorDetails"
defaultMessage="This type of error often occurs if the submission contains inapropriate files. Please consult the assignments specification to verify that you have submitted expected files and these files are properly named."
/>
),
};

const FailureReport = ({ failure }) => (
<>
<Callout variant="danger" icon={<EvaluationFailedIcon />}>
<span className="small float-right">
(<DateTime unixts={failure.createdAt} />)
</span>
<h4>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailedHeading"
defaultMessage="The evaluation has failed!"
/>
</h4>

{typeof failure === 'object' ? (
<>
<p>
{FAILURE_TYPES[failure.type] || (
<>
(
<FormattedMessage
id="app.submissionEvaluation.evaluationFailed.unknown"
defaultMessage="Unknown error type"
/>
) (<code>{failure.type}</code>)
</>
)}
</p>
{FAILURE_DETAILS[failure.type] ? (
<p className="small text-muted">
<InfoIcon gapRight />
{FAILURE_DETAILS[failure.type]}
</p>
) : null}
<hr />
<FormattedMessage id="app.submissionEvaluation.evaluationFailedMessage" defaultMessage="Backend message" />:
<InsetPanel className="py-2 px-3 mt-1">
<code>{failure.description}</code>
</InsetPanel>
</>
) : (
<p>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailedInternalError"
defaultMessage="Internal backend error."
/>
</p>
)}
</Callout>

{Boolean(typeof failure === 'object' && failure.resolvedAt && failure.resolutionNote) && (
<Callout variant="success" icon="fire-extinguisher">
<span className="small float-right">
(<DateTime unixts={failure.resolvedAt} />)
</span>
<h4>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailureResolved"
defaultMessage="The failure has been resolved by admin!"
/>
</h4>
<p>
<FormattedMessage
id="app.submissionEvaluation.evaluationFailureResolvedNote"
defaultMessage="Resolution note"
/>
: <em>{failure.resolutionNote}</em>
</p>
</Callout>
)}
</>
);

FailureReport.propTypes = {
failure: PropTypes.any,
};

export default FailureReport;
2 changes: 2 additions & 0 deletions src/components/SubmissionFailures/FailureReport/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import FailureReport from './FailureReport';
export default FailureReport;
9 changes: 9 additions & 0 deletions src/locales/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,15 @@
"app.submission.evaluation.title": "Podrobnosti odevzdaného řešení",
"app.submission.evaluation.title.testResults": "Výsledky testů",
"app.submissionEvaluation.confirmDeleteLastSubmission": "Toto je poslední vyhodnocení. Pokud jej smažete, může to způsobit změnu hodnocení odevzdaného řešení. Přejete si pokračovat?",
"app.submissionEvaluation.evaluationFailed.brokerReject": "Vyhodnocovací modul odmílt přijmout řešení k vyhodnocení.",
"app.submissionEvaluation.evaluationFailed.brokerRejectDetails": "Tento typ chyby nastává, když není možné zajistit vyhodnocení odevzdaného řešení. Důvodem může být chybná konfigurace úlohy, nebo jsou momentálně některé vyhodnocovací služby mimo provoz.",
"app.submissionEvaluation.evaluationFailed.configError": "Konfigurace úlohy nemohla být zkompilována do vyhodnocovacího plánu.",
"app.submissionEvaluation.evaluationFailed.configErrorDetails": "Tento typ chyby obvykle nastává, když je úloha špatně nakonfigurována. Prosíme, kontaktujte autora úlohy.",
"app.submissionEvaluation.evaluationFailed.evaluationFailure": "Vyhodnocování řešení selhalo za běhu.",
"app.submissionEvaluation.evaluationFailed.evaluationFailureDetails": "Tento typ chyby může být způsoben špatným nastavením úlohy nebo interní chybou vyhodnocovače. U složitějších úloh se také může stát, že došlo ke kolizi jmen zkompilovaných nebo odevzdaných souborů.",
"app.submissionEvaluation.evaluationFailed.softConfigError": "Vyhodnocovací plán nemohl být sestaven z důvodu problému s odevzdaným řešením.",
"app.submissionEvaluation.evaluationFailed.softConfigErrorDetails": "Tento typ chyby obvykle nastává pokud odevzdané řešení obsahuje nevhodné soubory. Prosíme, ověřte si v zadání úlohy, že odevzdané soubory odpovídají tomu, co zadání vyžaduje, a jsou správně pojmenovány.",
"app.submissionEvaluation.evaluationFailed.unknown": "Neznámý typ chyby",
"app.submissionEvaluation.evaluationFailedHeading": "Vyhodnocení selhalo!",
"app.submissionEvaluation.evaluationFailedInternalError": "Interní chyba vyhodnocovače.",
"app.submissionEvaluation.evaluationFailedMessage": "Zpráva z vyhodnocovače",
Expand Down
11 changes: 10 additions & 1 deletion src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,15 @@
"app.submission.evaluation.title": "Solution Detail",
"app.submission.evaluation.title.testResults": "Test Results",
"app.submissionEvaluation.confirmDeleteLastSubmission": "This is the last submission. If you delete it, you may alter the grading of this solution. Do you wish to proceed?",
"app.submissionEvaluation.evaluationFailed.brokerReject": "The backend rejected the evaluation job.",
"app.submissionEvaluation.evaluationFailed.brokerRejectDetails": "This type of error occurs when the backend cannot accept the evaluation job. The exercise configuration is not valid or the backend workers responsible for this type of submissions are currently offline.",
"app.submissionEvaluation.evaluationFailed.configError": "Exercise configuration could not be compiled in the evaluation execution plan.",
"app.submissionEvaluation.evaluationFailed.configErrorDetails": "This type of error usually occurs if the exercise is not configured properly. Please contact the author of the exercise.",
"app.submissionEvaluation.evaluationFailed.evaluationFailure": "The evaluation failed during processing.",
"app.submissionEvaluation.evaluationFailed.evaluationFailureDetails": "This type of error could be caused by invalid exercise configuration or by internal error of the backend worker. Complex exercises may also run into this error when names of the submitted or compiled files are clashing.",
"app.submissionEvaluation.evaluationFailed.softConfigError": "The evaluation execution plan could not be compiled due to problems with submission.",
"app.submissionEvaluation.evaluationFailed.softConfigErrorDetails": "This type of error often occurs if the submission contains inapropriate files. Please consult the assignments specification to verify that you have submitted expected files and these files are properly named.",
"app.submissionEvaluation.evaluationFailed.unknown": "Unknown error type",
"app.submissionEvaluation.evaluationFailedHeading": "The evaluation has failed!",
"app.submissionEvaluation.evaluationFailedInternalError": "Internal backend error.",
"app.submissionEvaluation.evaluationFailedMessage": "Backend message",
Expand Down Expand Up @@ -2058,4 +2067,4 @@
"recodex-judge-shuffle-all": "Unordered-tokens-and-rows judge",
"recodex-judge-shuffle-newline": "Unordered-tokens judge (ignoring ends of lines)",
"recodex-judge-shuffle-rows": "Unordered-rows judge"
}
}

0 comments on commit c5408d5

Please sign in to comment.