Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -14,7 +14,7 @@ exports[`Snapshot match 1`] = `
</p>
</div>
<p>
Your submission has been received, and will be evaluated during Review phase.
Your submission has been received and may undergo AI-assisted review during Submission phase. Results will be available for inspection in the review app and final evaluation occurs during Review phase.
<a
className="src-shared-components-SubmissionManagement-ScreeningDetails-___styles__help-link___41Oxm"
href=""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,28 @@ exports[`Snapshot match 1`] = `
type="button"
/>
</Tooltip>
<Tooltip
align={Object {}}
className=""
content={[Function]}
defaultVisible={false}
id=""
onTooltipHover={[Function]}
placeArrow={[Function]}
position="top"
suppressDiv={false}
trigger={
Array [
"hover",
]
}
>
<button
className="src-shared-components-SubmissionManagement-Submission-___styles__download-artifacts-button___2lSi_"
onClick={[Function]}
type="button"
/>
</Tooltip>
<button
className="src-shared-components-SubmissionManagement-Submission-___styles__expand-icon___TDY6Y src-shared-components-SubmissionManagement-Submission-___styles__expanded___8pRX_"
onClick={[Function]}
Expand Down Expand Up @@ -232,6 +254,28 @@ exports[`Snapshot match 2`] = `
type="button"
/>
</Tooltip>
<Tooltip
align={Object {}}
className=""
content={[Function]}
defaultVisible={false}
id=""
onTooltipHover={[Function]}
placeArrow={[Function]}
position="top"
suppressDiv={false}
trigger={
Array [
"hover",
]
}
>
<button
className="src-shared-components-SubmissionManagement-Submission-___styles__download-artifacts-button___2lSi_"
onClick={[Function]}
type="button"
/>
</Tooltip>
<button
className="src-shared-components-SubmissionManagement-Submission-___styles__expand-icon___TDY6Y"
onClick={[Function]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ exports[`Matches shallow shapshot 1`] = `
className="src-shared-components-SubmissionManagement-SubmissionsTable-___styles__dev-details___2GC2b"
colSpan="6"
>
<div
className="src-shared-components-SubmissionManagement-SubmissionsTable-___styles__workflow-table___WCWMZ"
>
<TableWorkflowRuns
workflowRuns={null}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ correctness]
Passing null to workflowRuns might lead to runtime errors if TableWorkflowRuns does not handle null values gracefully. Consider providing a default value or ensuring TableWorkflowRuns can handle null inputs.

/>
</div>
<ScreeningDetails
helpPageUrl=""
onlineReviewUrl=""
Expand Down
3 changes: 3 additions & 0 deletions config/backup-default.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ module.exports = {
* object should be considered outdated, and updated as soon as possible. */
USER_GROUP_MAXAGE: 24 * 60 * 60 * 1000,

REVIEW_APP_URL: 'https://review.topcoder-dev.com',


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 style]
There are two consecutive blank lines here. While this is not a correctness issue, it could be considered a minor style inconsistency. Consider removing one of the blank lines to maintain a consistent style throughout the file.

/* Maximum time to wait before timeout on searching past challenges (seconds)
* when no result at all.
* Default: 30 seconds.
Expand Down
2 changes: 2 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ module.exports = {
* This value [seconds] specifies the maximum age after which a group data
* object should be considered outdated, and updated as soon as possible. */
USER_GROUP_MAXAGE: 24 * 60 * 60 * 1000,
REVIEW_APP_URL: 'https://review.topcoder-dev.com',


/* Maximum time to wait before timeout on searching past challenges (seconds)
* when no result at all.
Expand Down
3 changes: 3 additions & 0 deletions config/production.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ module.exports = {
REVIEW_TYPES_API_URL: '/reviewTypes',
REVIEW_SUMMATIONS_API_URL: '/reviewSummations',
},

REVIEW_APP_URL: 'https://review.topcoder.com',

/* Filestack configuration for uploading Submissions
* These are for the production back end */
FILESTACK: {
Expand Down
25 changes: 24 additions & 1 deletion src/shared/actions/page/submission_management.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
import _ from 'lodash';
import { redux } from 'topcoder-react-utils';
import { redux, config } from 'topcoder-react-utils';
import { services } from 'topcoder-react-lib';

const Api = services.api.default;

function loadAiWorkflowRunsInit() {}

function loadAiWorkflowRunsDone(tokenV3, submissionId, aiWorkflowId) {
const api = new Api(config.API.V6, tokenV3);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ security]
Consider validating tokenV3, submissionId, and aiWorkflowId before using them to ensure they are not undefined or null. This can prevent potential runtime errors or security issues.

const url = `/workflows/${aiWorkflowId}/runs?submissionId=${submissionId}`;

return api.get(url)
.then(res => res.json())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
The use of .then(res => res.json()) assumes that the response will always be JSON. Consider adding error handling for cases where the response might not be JSON, which could lead to runtime errors.

.then(data => ({
submissionId,
aiWorkflowId,
runs: data,
}))
.catch((err) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 maintainability]
Throwing the error directly without any additional context might make debugging difficult. Consider logging the error or adding more context to the error message.

throw err;
});
}

export default redux.createActions({
PAGE: {
SUBMISSION_MANAGEMENT: {
SHOW_DETAILS: _.identity,
CANCEL_DELETE: _.noop,
CONFIRM_DELETE: _.identity,
LOAD_AI_WORKFLOW_RUNS_INIT: loadAiWorkflowRunsInit,
LOAD_AI_WORKFLOW_RUNS_DONE: loadAiWorkflowRunsDone,
},
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default function ScreeningDetails(props) {
return {
title: '',
classname: '',
message: 'Your submission has been received, and will be evaluated during Review phase.',
message: 'Your submission has been received and may undergo AI-assisted review during Submission phase. Results will be available for inspection in the review app and final evaluation occurs during Review phase.',
};
};

Expand Down
23 changes: 21 additions & 2 deletions src/shared/components/SubmissionManagement/Submission/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import _ from 'lodash';
import moment from 'moment';
import React from 'react';
import { CHALLENGE_STATUS, COMPETITION_TRACKS, safeForDownload } from 'utils/tc';
import { config } from 'topcoder-react-utils';

import PT from 'prop-types';

Expand All @@ -25,10 +26,10 @@ import ArtifactsDownloadIcon from '../Icons/IconDownloadArtifacts.svg';
import ReviewRatingListIcon from '../Icons/IconReviewRatingList.svg';
import ExpandIcon from '../Icons/IconMinimalDown.svg';
import ScreeningStatus from '../ScreeningStatus';
import IconShare from '../Icons/IconShare.svg';

import './styles.scss';


export default function Submission(props) {
const {
challenge,
Expand All @@ -48,6 +49,11 @@ export default function Submission(props) {
const safeForDownloadCheck = safeForDownload(submissionObject.url);
const onDownloadArtifacts = onOpenDownloadArtifactsModal.bind(1, submissionObject.id);
const onOpenRatingsList = onOpenRatingsListModal.bind(1, submissionObject.id);
const onOpenReviewApp = () => {
if (!challenge || !challenge.id) return;
const url = `${config.REVIEW_APP_URL}/active-challenges/${challenge.id}/challenge-details?tab=submission`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ security]
Consider using encodeURIComponent for challenge.id when constructing the URL to ensure that any special characters are properly encoded. This can prevent potential issues with malformed URLs.

window.open(url, '_blank', 'noopener,noreferrer');
};

// Determine if a challenge is for Topcrowd so we can edit the UI accordingly
let isTopCrowdChallenge = false;
Expand Down Expand Up @@ -117,7 +123,20 @@ export default function Submission(props) {
: <span /> }
{ !isTopCrowdChallenge
? (
<Tooltip content={() => <div styleName="tooltip-content">Show Scores</div>}>
<Tooltip content={() => <div styleName="tooltip-content">View Review Info</div>}>
<button
onClick={() => onOpenReviewApp()}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
The button for opening the review app is only rendered if safeForDownloadCheck is true. Ensure that this condition is intentional and that the review app should only be accessible when the submission is safe for download.

type="button"
styleName="download-artifacts-button"
>
{safeForDownloadCheck === true && <IconShare />}
</button>
</Tooltip>
)
: <span />}
{ !isTopCrowdChallenge
? (
<Tooltip content={() => <div styleName="tooltip-content">Show scores</div>}>
<button
onClick={() => onOpenRatingsList()}
type="button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ $submission-space-50: $base-unit * 10;
.download-artifacts-button {
svg {
width: 24px;
fill: $color-turq-160;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default function SubmissionManagement(props) {
submissions,
loadingSubmissions,
showDetails,
submissionWorkflowRuns,
onDelete,
helpPageUrl,
onDownload,
Expand Down Expand Up @@ -182,6 +183,7 @@ export default function SubmissionManagement(props) {
<SubmissionsTable
challenge={challenge}
submissionObjects={submissions}
submissionWorkflowRuns={submissionWorkflowRuns}
showDetails={showDetails}
track={trackName}
status={challenge.status}
Expand Down Expand Up @@ -227,6 +229,7 @@ SubmissionManagement.defaultProps = {
SubmissionManagement.propTypes = {
challenge: PT.shape().isRequired,
showDetails: PT.shape().isRequired,
submissionWorkflowRuns: PT.shape().isRequired,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The submissionWorkflowRuns prop is defined as PT.shape().isRequired, but the shape is not specified. Consider defining the shape to ensure that the component receives the expected structure, which can prevent runtime errors and improve maintainability.

onDelete: PT.func,
onlineReviewUrl: PT.string,
helpPageUrl: PT.string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import ScreeningDetails from '../ScreeningDetails';
import DownloadArtifactsModal from '../DownloadArtifactsModal';
import Submission from '../Submission';
import RatingsListModal from '../RatingsListModal';
import TableWorkflowRuns from '../TableWorkflowRuns';

import './styles.scss';

Expand All @@ -35,6 +36,7 @@ export default function SubmissionsTable(props) {
const {
challenge,
submissionObjects,
submissionWorkflowRuns,
showDetails,
track,
onDelete,
Expand Down Expand Up @@ -92,12 +94,22 @@ export default function SubmissionsTable(props) {
/>
);
submissionsWithDetails.push(submission);
const workflowRunsForSubmission = submissionWorkflowRuns
&& submissionWorkflowRuns[subObject.id]
? submissionWorkflowRuns[subObject.id]
: null;

const submissionDetail = (
<tr key={subObject.id} styleName="submission-row">
{showDetails[subObject.id]
&& (
<td colSpan="6" styleName="dev-details">
<div styleName="workflow-table">
<TableWorkflowRuns
workflowRuns={workflowRunsForSubmission}
/>
</div>

<ScreeningDetails
screeningObject={subObject.screening}
helpPageUrl={helpPageUrl}
Expand Down Expand Up @@ -186,10 +198,12 @@ SubmissionsTable.defaultProps = {
onlineReviewUrl: '',
helpPageUrl: '',
getSubmissionScores: _.noop,
submissionWorkflowRuns: [],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ correctness]
The default value for submissionWorkflowRuns is set to an empty array, but its prop type is defined as a shape. This mismatch could lead to unexpected behavior. Consider setting the default value to an empty object {} to align with the prop type.

};

SubmissionsTable.propTypes = {
challenge: PT.shape().isRequired,
submissionWorkflowRuns: PT.shape(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The submissionWorkflowRuns prop type is defined as PT.shape(), which is not specific enough. Consider defining the shape of this object to ensure that the expected structure is enforced, improving maintainability and reducing potential runtime errors.

submissionObjects: PT.arrayOf(SubShape),
showDetails: PT.shape().isRequired,
track: PT.string.isRequired,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ $submission-space-50: $base-unit * 10;
border-top: 0;
padding-top: 0;

.workflow-table {
padding-left: 80px;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The padding-left value of 80px for .workflow-table might cause layout issues on smaller screens. Consider using a relative unit like % or em to ensure better responsiveness across different screen sizes.


@media (max-width: 768px) {
display: none;
}
}

.upload-artifact-btn {
@include roboto-medium;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from 'react';
import PT from 'prop-types';
import moment from 'moment-timezone';
import { config } from 'topcoder-react-utils';

import './styles.scss';

const TABLE_DATE_FORMAT = 'MMM DD YYYY, HH:mm A';

const getRunStatusText = (run) => {
if (!run) return '';

if (run.status === 'IN_PROGRESS' || run.status === 'QUEUED') return 'Pending';
if (run.status === 'FAILED') return 'Failed';
if (run.status === 'SUCCESS') {
const passingScore = run.workflow && run.workflow.scorecard
? run.workflow.scorecard.minimumPassingScore
: 0;
return run.score >= passingScore ? 'Passed' : 'Failed Score';
}

return run.status;
};

export default function TableWorkflowRuns(props) {
const { workflowRuns } = props;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ correctness]
The challengeId prop has been removed, but it is still referenced in the unchanged context of the code. Ensure that all references to challengeId are removed to prevent potential runtime errors.

if (!workflowRuns || Object.keys(workflowRuns).length === 0) {
return null;
}
return (
<div style={{ marginBottom: '15px' }}>
<table styleName="workflow-table">
<thead>
<tr>
<th>AI Reviewer</th>
<th>Review Date</th>
<th>Score</th>
<th>Result</th>
</tr>
</thead>
<tbody>
{Object.entries(workflowRuns).map(([workflowId, run]) => (
<tr key={workflowId}>
<td>{run.workflow.name}</td>
<td>{run.status === 'SUCCESS' && (
moment(run.completedAt)
.local()
.format(TABLE_DATE_FORMAT)
)}
</td>
<td>
{(() => {
if (run.status !== 'SUCCESS') return '-';
if (run.workflow.id) {
return (
<a
href={`${config.REVIEW_APP_URL}/scorecard/${run.workflow.scorecard.id}`}
target="_blank"
rel="noopener noreferrer"
>
{run.score}
</a>
);
}
return run.score;
})()}
</td>
<td>{getRunStatusText(run)}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}

TableWorkflowRuns.defaultProps = {
workflowRuns: [],
};

TableWorkflowRuns.propTypes = {
workflowRuns: PT.shape(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The workflowRuns prop type should be more specific. Instead of PT.shape(), consider defining the expected shape with PT.objectOf(PT.shape({ ... })) to improve type safety and clarity.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The workflowRuns prop type is defined as PT.shape(), which is too generic and does not specify the expected structure of the workflowRuns object. Consider defining a more specific shape to improve type safety and maintainability.

};
Loading
Loading