Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,24 @@ describe('getSubmissionTestProgress', () => {
status: 'FAILED',
});
});

it('surfaces cancelled scoring runs superseded by a newer submission', () => {
expect(getSubmissionTestProgress({
reviewSummations: [
{
metadata: {
testProcess: 'provisional',
testProgress: 1,
testStatus: 'CANCELLED',
},
},
],
})).toEqual({
process: 'provisional',
progressPercent: '100%',
status: 'CANCELLED',
});
});
});

describe('isActiveTestStatus', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe('getSubmissionStatus', () => {
})).toEqual({
hasReviewSummation: false,
isAccepted: false,
isCancelled: false,
isFailed: true,
});
});
Expand All @@ -28,6 +29,30 @@ describe('getSubmissionStatus', () => {
})).toEqual({
hasReviewSummation: false,
isAccepted: false,
isCancelled: false,
isFailed: false,
});
});

it('reports cancelled scoring runs instead of leaving them in preparing state', () => {
expect(getSubmissionStatus({
status: 'ACTIVE',
submissionId: 'submission-1',
reviewSummations: [
{
submissionId: 'submission-1',
isProvisional: true,
metadata: {
testProcess: 'provisional',
testProgress: 1,
testStatus: 'CANCELLED',
},
},
],
})).toEqual({
hasReviewSummation: true,
isAccepted: true,
isCancelled: true,
isFailed: false,
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,13 @@ class SubmissionsDetailView extends React.Component {
const { onCancel, submission, onSortChange } = this.props;
let { finalScore } = submission;
const { sortedSubmissions } = this.state;
const { isAccepted, isFailed } = getSubmissionStatus(submission);
const { isAccepted, isCancelled, isFailed } = getSubmissionStatus(submission);
let finalStatusStyleName = 'status-in-queue';
let finalStatusLabel = 'Preparing';
if (isAccepted) {
if (isCancelled) {
finalStatusStyleName = 'status-cancelled';
finalStatusLabel = 'Cancelled';
} else if (isAccepted) {
finalStatusStyleName = 'status-complete';
finalStatusLabel = 'Complete';
} else if (isFailed) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@ button.header-sort {
font-weight: 500;
}

.status-cancelled {
font-size: 14px;
color: #767676;
font-weight: 500;
}

.mobile-header {
display: none;
font-weight: 600;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import DateSortIcon from 'assets/images/icon-date-sort.svg';
import SortIcon from 'assets/images/icon-sort.svg';
import Tooltip from 'components/Tooltip';
import IconFail from '../../icons/failed.svg';
import IconTestCancelled from '../../icons/cancelled.svg';
import IconTestInProgress from '../../icons/clock.svg';
import IconTestSuccess from '../../icons/check-mark.svg';
import DownloadIcon from '../../../SubmissionManagement/Icons/IconSquareDownload.svg';
Expand Down Expand Up @@ -127,17 +128,19 @@ function normalizeTestProcess(value) {
*/
function normalizeTestStatus(value) {
const normalized = _.toUpper(_.toString(value || '').trim());
if (['FAILED', 'IN PROGRESS', 'SUCCESS'].indexOf(normalized) >= 0) {
if (['CANCELLED', 'FAILED', 'IN PROGRESS', 'SUCCESS'].indexOf(normalized) >= 0) {
return normalized;
}
return undefined;
}

/**
* Returns whether a Marathon Match test status still represents active testing.
* Returns whether a Marathon Match test status produced no score to display.
* Running tests have no score yet, and a run cancelled because the member
* submitted a newer solution never produces one.
*
* @param {String} status normalized test status from review summation metadata.
* @returns {Boolean} true when scoring should remain hidden until testing completes.
* @returns {Boolean} true when scoring should stay hidden for the submission.
*/
export function isActiveTestStatus(status) {
const normalized = normalizeTestStatus(status);
Expand Down Expand Up @@ -257,6 +260,17 @@ function renderTestStatusIcon(status) {
</span>
);
}
if (status === 'CANCELLED') {
return (
<span
aria-label="Test status: CANCELLED"
role="img"
styleName="test-status-icon test-status-cancelled"
>
<IconTestCancelled />
</span>
);
}
return null;
}

Expand Down Expand Up @@ -662,10 +676,15 @@ class SubmissionsListView extends React.Component {
} else {
provisionalScore = 'N/A';
}
const { isAccepted, isFailed } = getSubmissionStatus(mySubmission);
const {
isAccepted, isCancelled, isFailed,
} = getSubmissionStatus(mySubmission);
let statusStyleName = 'queue';
let statusLabel = 'Preparing';
if (isAccepted) {
if (isCancelled) {
statusStyleName = 'cancelled';
statusLabel = 'Cancelled';
} else if (isAccepted) {
statusStyleName = 'accepted';
statusLabel = 'Accepted';
} else if (isFailed) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@
line-height: 22px;
}

.cancelled {
color: #767676;

@include roboto-medium;

font-weight: 500;
font-size: 14px;
line-height: 22px;
}

.h2 {
@include roboto-bold;

Expand Down Expand Up @@ -395,6 +405,10 @@ button.column-1-1,
color: #ef476f;
}

.test-status-cancelled {
color: #767676;
}

.icon-search {
margin-left: 17px;
}
Expand Down
4 changes: 4 additions & 0 deletions src/shared/components/challenge-detail/icons/cancelled.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 20 additions & 2 deletions src/shared/utils/challenge-detail/submission-status.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ function hasFailedSubmissionStatus(submission) {
return status === 'failed' || status === 'failure';
}

/**
* Returns whether a review summation reports a cancelled Marathon Match test run.
* Marathon Match scoring is cancelled when the member submits a newer solution
* while an earlier scorer is still running.
*
* @param {Object} summation review summation attached to a submission attempt.
* @returns {Boolean} true when the summation test status is cancelled.
*/
function hasCancelledTestStatus(summation) {
const status = _.toUpper(_.toString(_.get(summation, 'metadata.testStatus', '')).trim());
return status === 'CANCELLED';
}

export function getSubmissionReviewSummations(submission) {
return collectReviewSummations(submission);
}
Expand All @@ -58,10 +71,12 @@ export function getSubmissionReviewSummations(submission) {
* Builds display status flags for a challenge submission attempt.
* Review summations indicate accepted scoring; when no accepted summation is
* present, failed scan or submission states should display as failed instead of
* staying in the generic preparing state.
* staying in the generic preparing state. Cancelled scoring runs take precedence
* so a superseded Marathon Match submission is never shown as still preparing.
*
* @param {Object} submission submission attempt shown in challenge details.
* @returns {{hasReviewSummation: Boolean, isAccepted: Boolean, isFailed: Boolean}} status flags.
* @returns {{hasReviewSummation: Boolean, isAccepted: Boolean, isCancelled: Boolean,
* isFailed: Boolean}} status flags.
*/
export function getSubmissionStatus(submission) {
const targetIdRaw = _.get(submission, 'submissionId', _.get(submission, 'id', null));
Expand Down Expand Up @@ -93,12 +108,15 @@ export function getSubmissionStatus(submission) {
return hasFlag || type === 'provisional' || type === 'final';
});

const isCancelled = reviewSummations.some(hasCancelledTestStatus);

const isFailed = !isAccepted
&& (hasVirusScanFailure(submission) || hasFailedSubmissionStatus(submission));

return {
hasReviewSummation,
isAccepted,
isCancelled,
isFailed,
};
}
Expand Down
Loading