diff --git a/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx b/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx
index caa4796c0..f3b3a184d 100644
--- a/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx
+++ b/src/apps/admin/src/lib/components/ChallengeList/ChallengeList.tsx
@@ -261,15 +261,15 @@ const Actions: FC<{
{hasLegacyId && (
- Online Review
+ Review UI
)}
- {!hasLegacyId && Online Review}
+ {!hasLegacyId && Review UI}
diff --git a/src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx b/src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx
index 3643e2994..af9e8adf8 100644
--- a/src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx
+++ b/src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx
@@ -1,7 +1,8 @@
/**
* Challenge Details Content.
*/
-import { FC, ReactNode, useContext, useMemo } from 'react'
+import { FC, ReactNode, useCallback, useContext, useMemo } from 'react'
+import { toast } from 'react-toastify'
import { ActionLoading } from '~/apps/admin/src/lib'
@@ -185,6 +186,37 @@ export const ChallengeDetailsContent: FC = (props: Props) => {
isLoadingBool: isDownloadingSubmissionBool,
downloadSubmission,
}: useDownloadSubmissionProps = useDownloadSubmission()
+ const submissionsById = useMemo(() => {
+ const map = new Map()
+ props.submissions.forEach(submission => {
+ if (submission?.id) {
+ map.set(submission.id, submission)
+ }
+ })
+ return map
+ }, [props.submissions])
+ const handleSubmissionDownload = useCallback((submissionId: string) => {
+ const submission = submissionsById.get(submissionId)
+ if (submission && submission.isFileSubmission === false) {
+ const targetUrl = submission.url?.trim()
+ if (targetUrl) {
+ if (typeof window !== 'undefined') {
+ const openedWindow = window.open(targetUrl, '_blank', 'noopener,noreferrer')
+ if (openedWindow === null) {
+ toast.error('We could not open the submission URL. Check your pop-up blocker and try again.')
+ }
+ } else {
+ toast.error('Unable to open the submission URL from this environment.')
+ }
+ } else {
+ toast.error('Submission URL is not available for this entry.')
+ }
+
+ return
+ }
+
+ downloadSubmission(submissionId)
+ }, [downloadSubmission, submissionsById])
const {
isLoading: isLoadingProjectResult,
projectResults,
@@ -335,7 +367,7 @@ export const ChallengeDetailsContent: FC = (props: Props) => {
if (SUBMISSION_TAB_KEYS.has(selectedTabNormalized)) {
return renderSubmissionTab({
- downloadSubmission,
+ downloadSubmission: handleSubmissionDownload,
isActiveChallenge: props.isActiveChallenge,
isDownloadingSubmission,
isLoadingSubmission: props.isLoadingSubmission,
@@ -361,7 +393,7 @@ export const ChallengeDetailsContent: FC = (props: Props) => {
checkpointReviewMinimumPassingScore={props.checkpointReviewMinimumPassingScore}
isLoading={props.isLoadingSubmission}
isDownloading={isDownloadingSubmission}
- downloadSubmission={downloadSubmission}
+ downloadSubmission={handleSubmissionDownload}
mode={checkpointMode}
/>
)
@@ -373,7 +405,7 @@ export const ChallengeDetailsContent: FC = (props: Props) => {
isLoading={isLoadingProjectResult}
projectResults={projectResults}
isDownloading={isDownloadingSubmission}
- downloadSubmission={downloadSubmission}
+ downloadSubmission={handleSubmissionDownload}
/>
)
}
@@ -386,7 +418,7 @@ export const ChallengeDetailsContent: FC = (props: Props) => {
approvalMinimumPassingScore={props.approvalMinimumPassingScore}
isLoadingReview={props.isLoadingSubmission}
isDownloading={isDownloadingSubmission}
- downloadSubmission={downloadSubmission}
+ downloadSubmission={handleSubmissionDownload}
isActiveChallenge={props.isActiveChallenge}
/>
)
@@ -400,7 +432,7 @@ export const ChallengeDetailsContent: FC = (props: Props) => {
postMortemMinimumPassingScore={props.postMortemMinimumPassingScore}
isLoadingReview={props.isLoadingSubmission}
isDownloading={isDownloadingSubmission}
- downloadSubmission={downloadSubmission}
+ downloadSubmission={handleSubmissionDownload}
isActiveChallenge={props.isActiveChallenge}
columnLabel='Post-Mortem'
/>
@@ -415,7 +447,7 @@ export const ChallengeDetailsContent: FC = (props: Props) => {
postMortemMinimumPassingScore={props.postMortemMinimumPassingScore}
isLoadingReview={props.isLoadingSubmission}
isDownloading={isDownloadingSubmission}
- downloadSubmission={downloadSubmission}
+ downloadSubmission={handleSubmissionDownload}
isActiveChallenge={props.isActiveChallenge}
phaseIdFilter={props.selectedPhaseId}
/>
@@ -430,7 +462,7 @@ export const ChallengeDetailsContent: FC = (props: Props) => {
reviewMinimumPassingScore={props.reviewMinimumPassingScore}
isLoadingReview={props.isLoadingSubmission}
isDownloading={isDownloadingSubmission}
- downloadSubmission={downloadSubmission}
+ downloadSubmission={handleSubmissionDownload}
mappingReviewAppeal={props.mappingReviewAppeal}
isActiveChallenge={props.isActiveChallenge}
/>
diff --git a/src/apps/review/src/lib/models/BackendSubmission.model.ts b/src/apps/review/src/lib/models/BackendSubmission.model.ts
index ba4e43d14..5fb5476f5 100644
--- a/src/apps/review/src/lib/models/BackendSubmission.model.ts
+++ b/src/apps/review/src/lib/models/BackendSubmission.model.ts
@@ -48,6 +48,11 @@ export interface BackendSubmission {
* Indicates whether the submission is the latest for the member.
*/
isLatest?: boolean
+ /**
+ * Flag indicating whether the submission includes a downloadable file.
+ * When false the submission is represented only by a URL.
+ */
+ isFileSubmission?: boolean
}
/**
diff --git a/src/apps/review/src/lib/models/SubmissionInfo.model.ts b/src/apps/review/src/lib/models/SubmissionInfo.model.ts
index 73c04946d..3f0a9afb1 100644
--- a/src/apps/review/src/lib/models/SubmissionInfo.model.ts
+++ b/src/apps/review/src/lib/models/SubmissionInfo.model.ts
@@ -56,6 +56,10 @@ export interface SubmissionInfo {
* Submission type (e.g. CONTEST_SUBMISSION, CHECKPOINT_SUBMISSION).
*/
type?: string
+ /**
+ * Flag indicating whether the submission includes an uploaded file.
+ */
+ isFileSubmission?: boolean
}
/**
@@ -118,6 +122,7 @@ export function convertBackendSubmissionToSubmissionInfo(
return {
aggregateScore,
id: data.id,
+ isFileSubmission: data.isFileSubmission,
isLatest: data.isLatest,
isPassingReview,
memberId: data.memberId,
diff --git a/src/config/environments/default.env.ts b/src/config/environments/default.env.ts
index 9ee1c6c1d..9f5ef3615 100644
--- a/src/config/environments/default.env.ts
+++ b/src/config/environments/default.env.ts
@@ -118,20 +118,21 @@ export const ADMIN = {
DEFAULT_PAYMENT_TERMS: 1,
DIRECT_URL: 'https://www.topcoder-dev.com/direct',
ONLINE_REVIEW_URL: 'https://software.topcoder-dev.com/review',
+ REVIEW_UI_URL: 'https://review.topcoder-dev.com',
SUBMISSION_SCAN_TOPIC: 'submission.scan.complete',
WORK_MANAGER_URL: 'https://challenges.topcoder-dev.com',
}
const REVIEW_OPPORTUNITIES_URL_DEFAULT = getReactEnv(
'REVIEW_OPPORTUNITIES_URL',
- 'https://www-v6.topcoder-dev.com/challenges/?bucket=reviewOpportunities&'
+ 'https://www.topcoder-dev.com/challenges/?bucket=reviewOpportunities&'
+ 'tracks[DS]=true&tracks[Des]=true&tracks[Dev]=true&tracks[QA]=true',
)
export const REVIEW = {
- CHALLENGE_PAGE_URL: 'https://www-v6.topcoder-dev.com/challenges',
+ CHALLENGE_PAGE_URL: 'https://www.topcoder-dev.com/challenges',
OPPORTUNITIES_URL: REVIEW_OPPORTUNITIES_URL_DEFAULT,
- PROFILE_PAGE_URL: 'https://profiles-v6.topcoder-dev.com/profiles',
+ PROFILE_PAGE_URL: 'https://profiles.topcoder-dev.com/profiles',
}
const FILESTACK_SECURITY_POLICY = getReactEnv('FILESTACK_SECURITY_POLICY', undefined)
diff --git a/src/config/environments/global-config.model.ts b/src/config/environments/global-config.model.ts
index 0c5e8e953..6d1e07a84 100644
--- a/src/config/environments/global-config.model.ts
+++ b/src/config/environments/global-config.model.ts
@@ -62,6 +62,7 @@ export interface GlobalConfig {
DIRECT_URL: string
WORK_MANAGER_URL: string
ONLINE_REVIEW_URL: string
+ REVIEW_UI_URL: string
CHALLENGE_URL: string
AV_SCAN_SCORER_REVIEW_TYPE_ID: string
AGREE_ELECTRONICALLY: string
diff --git a/src/config/environments/prod.env.ts b/src/config/environments/prod.env.ts
index 8393ed4cc..ac75ed133 100644
--- a/src/config/environments/prod.env.ts
+++ b/src/config/environments/prod.env.ts
@@ -23,6 +23,7 @@ export const ADMIN = {
DEFAULT_PAYMENT_TERMS: 1,
DIRECT_URL: 'https://www.topcoder.com/direct',
ONLINE_REVIEW_URL: 'https://software.topcoder.com/review',
+ REVIEW_UI_URL: 'https://review.topcoder.com',
SUBMISSION_SCAN_TOPIC: 'submission.scan.complete',
WORK_MANAGER_URL: 'https://challenges.topcoder.com',
}