From 11321b81b877c46804d3be4086f025ee00579903 Mon Sep 17 00:00:00 2001 From: Justin Gasper Date: Fri, 31 Oct 2025 14:20:03 +1100 Subject: [PATCH 1/3] Remove OR link from system-admin app --- .../src/lib/components/ChallengeList/ChallengeList.tsx | 6 +++--- src/config/environments/default.env.ts | 1 + src/config/environments/global-config.model.ts | 1 + src/config/environments/prod.env.ts | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) 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/config/environments/default.env.ts b/src/config/environments/default.env.ts index 9ee1c6c1d..d115b9756 100644 --- a/src/config/environments/default.env.ts +++ b/src/config/environments/default.env.ts @@ -118,6 +118,7 @@ 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', } 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', } From 8d1f45fb5ae21693d52dfcec9d8aa4c616d0458b Mon Sep 17 00:00:00 2001 From: Justin Gasper Date: Fri, 31 Oct 2025 14:21:13 +1100 Subject: [PATCH 2/3] Remove v6 paths --- src/config/environments/default.env.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/environments/default.env.ts b/src/config/environments/default.env.ts index d115b9756..9f5ef3615 100644 --- a/src/config/environments/default.env.ts +++ b/src/config/environments/default.env.ts @@ -125,14 +125,14 @@ export const ADMIN = { 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) From 95c7aeee3e7b0fb34253337041a1c980cbd00c57 Mon Sep 17 00:00:00 2001 From: Justin Gasper Date: Fri, 31 Oct 2025 21:31:49 +1100 Subject: [PATCH 3/3] Handle isFileSubmission flag for URL submissions for TG --- .../ChallengeDetailsContent.tsx | 48 +++++++++++++++---- .../src/lib/models/BackendSubmission.model.ts | 5 ++ .../src/lib/models/SubmissionInfo.model.ts | 5 ++ 3 files changed, 50 insertions(+), 8 deletions(-) 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,