PM-4477 Show failed submission in appeals response#1557
PM-4477 Show failed submission in appeals response#1557himaniraghav3 wants to merge 2 commits intodevfrom
Conversation
src/apps/review/src/lib/components/TableAppealsResponse/TableAppealsResponse.tsx
Outdated
Show resolved
Hide resolved
| if (canViewAsSubmitter) { | ||
| // For reviewer-only rows, use existing filter | ||
| const reviewerOnlyRows = aggregatedRows.filter(row => matchesReviewer(row) && !matchesSubmitter(row)) | ||
|
|
||
| // For submitter rows, include both aggregated and non-aggregated submissions | ||
| // Apply restrictToLatest filtering to respect submission limits | ||
| const submissionsForSubmitterRows = restrictToLatest && hasLatestFlag | ||
| ? (filteredChallengeSubmissions ?? []).filter(submission => submission.isLatest) | ||
| : (filteredChallengeSubmissions ?? []) | ||
|
|
||
| const submitterRows = submissionsForSubmitterRows | ||
| .filter(submission => { | ||
| const memberId = submission.memberId | ||
| if (!memberId || !ownedMemberIds.has(memberId)) { | ||
| return false | ||
| } | ||
|
|
||
| const submissionType = submission.type?.toUpperCase() | ||
| return !submissionType || submissionType === 'CONTEST_SUBMISSION' | ||
| }) | ||
| .map(submission => { | ||
| // Use aggregated data if available, otherwise create minimal aggregated structure | ||
| const aggregatedRow = aggregatedRows.find(row => row.id === submission.id) | ||
| if (aggregatedRow) { | ||
| return aggregatedRow | ||
| } | ||
|
|
||
| // Create minimal aggregated structure for non-reviewed submissions | ||
| // This ensures buildSubmissionReviewerRows creates at least one row | ||
| const submitterHandle = submission.userInfo?.memberHandle | ||
| ?? submission.review?.submitterHandle | ||
| ?? undefined | ||
| const submitterColor = submission.userInfo?.handleColor | ||
| ?? submission.review?.submitterHandleColor | ||
| ?? undefined | ||
|
|
||
| // Build review details array from all reviewInfos or single review | ||
| const allReviewInfos = submission.reviewInfos && submission.reviewInfos.length > 0 | ||
| ? submission.reviewInfos | ||
| : submission.review | ||
| ? [submission.review] | ||
| : [] | ||
|
|
||
| const reviewDetails = allReviewInfos | ||
| .map((reviewInfo: any) => { | ||
| const reviewId = reviewInfo.id | ||
| const appealInfo = reviewId ? mappingReviewAppeal[reviewId] : undefined | ||
| const totalAppeals = appealInfo?.totalAppeals ?? 0 | ||
| const finishedAppeals = appealInfo?.finishAppeals ?? 0 | ||
|
|
||
| // Resolve review date from multiple sources | ||
| const reviewDateString = reviewInfo.reviewDateString | ||
| ?? reviewInfo.updatedAtString | ||
| ?? (reviewInfo as any).createdAtString | ||
| ?? (reviewInfo as any).reviewedAt | ||
|
|
||
| return { | ||
| // Review detail with reviewer information from reviewInfo | ||
| finalScore: reviewInfo.finalScore, | ||
| finishedAppeals, | ||
| resourceId: reviewInfo.resourceId, | ||
| reviewDateString, | ||
| reviewerHandle: reviewInfo.reviewerHandle ?? undefined, | ||
| reviewerHandleColor: reviewInfo.reviewerHandleColor, | ||
| reviewInfo: { | ||
| ...reviewInfo, | ||
| reviewDateString, | ||
| }, | ||
| totalAppeals, | ||
| unresolvedAppeals: totalAppeals - finishedAppeals, | ||
| } | ||
| }) | ||
| .reverse() | ||
|
|
||
| // Get latest review date from reviewDetails | ||
| const latestReviewDate = reviewDetails.length > 0 | ||
| ? reviewDetails[0]?.reviewDateString | ||
| : undefined | ||
|
|
||
| return { | ||
| ...submission, | ||
| aggregated: { | ||
| id: submission.id, | ||
| latestReviewDateString: latestReviewDate, | ||
| reviews: reviewDetails, | ||
| submission, | ||
| submitterHandle, | ||
| submitterHandleColor: submitterColor, | ||
| }, | ||
| } | ||
| }) | ||
|
|
||
| // Combine submitter rows and reviewer-only rows | ||
| return [...reviewerOnlyRows, ...submitterRows] | ||
| } |
There was a problem hiding this comment.
🔴 Submitter rows dropped when filteredChallengeSubmissions is empty
The new canViewAsSubmitter code block (line 277) sources submitter rows exclusively from filteredChallengeSubmissions, which derives from challengeInfo?.submissions (TableAppealsResponse.tsx:166-177). When challengeInfo is undefined (the default context value per ChallengeDetailContext.ts:12) or has no submissions, filteredChallengeSubmissions is [], so submissionsForSubmitterRows is also [] and submitterRows will be empty. Meanwhile, reviewerOnlyRows at line 279 explicitly excludes any row where matchesSubmitter(row) is true. The combined result [...reviewerOnlyRows, ...submitterRows] therefore drops all submitter-owned rows that exist in aggregatedRows.
The old code at line 373 (aggregatedRows.filter(row => matchesSubmitter(row) || matchesReviewer(row))) would correctly return submitter-matching rows from aggregatedRows regardless of filteredChallengeSubmissions being empty. This regression means submitters may see no rows during loading or when challenge submission data is incomplete.
Prompt for agents
In src/apps/review/src/lib/components/TableAppealsResponse/TableAppealsResponse.tsx, the canViewAsSubmitter block (lines 277-371) sources submitter rows from filteredChallengeSubmissions. When that array is empty (e.g. challengeInfo?.submissions not yet loaded), submitter rows are dropped because they are excluded from reviewerOnlyRows via !matchesSubmitter(row) but never appear in submitterRows.
Fix: Add a fallback so that when filteredChallengeSubmissions is empty (or has no valid IDs), submitter rows should still come from aggregatedRows. For example, at line 283, before computing submissionsForSubmitterRows, check if filteredChallengeSubmissions is empty. If it is, fall back to the old behavior:
if (!filteredChallengeSubmissions || filteredChallengeSubmissions.length === 0) {
return aggregatedRows.filter(row => matchesSubmitter(row) || matchesReviewer(row))
}
Alternatively, ensure that submitterRows is computed from aggregatedRows as a base and only augmented with additional entries from filteredChallengeSubmissions for non-reviewed submissions.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if (canViewAsSubmitter) { | ||
| // For reviewer-only rows, use existing filter | ||
| const reviewerOnlyRows = aggregatedRows.filter(row => matchesReviewer(row) && !matchesSubmitter(row)) | ||
|
|
||
| // For submitter rows, include both aggregated and non-aggregated submissions | ||
| // Apply restrictToLatest filtering to respect submission limits | ||
| const submissionsForSubmitterRows = restrictToLatest && hasLatestFlag | ||
| ? (filteredChallengeSubmissions ?? []).filter(submission => submission.isLatest) | ||
| : (filteredChallengeSubmissions ?? []) | ||
|
|
||
| const submitterRows = submissionsForSubmitterRows | ||
| .filter(submission => { | ||
| const memberId = submission.memberId | ||
| if (!memberId || !ownedMemberIds.has(memberId)) { | ||
| return false | ||
| } | ||
|
|
||
| const submissionType = submission.type?.toUpperCase() | ||
| return !submissionType || submissionType === 'CONTEST_SUBMISSION' | ||
| }) | ||
| .map(submission => { | ||
| // Use aggregated data if available, otherwise create minimal aggregated structure | ||
| const aggregatedRow = aggregatedRows.find(row => row.id === submission.id) | ||
| if (aggregatedRow) { | ||
| return aggregatedRow | ||
| } | ||
|
|
||
| // Create minimal aggregated structure for non-reviewed submissions | ||
| // This ensures buildSubmissionReviewerRows creates at least one row | ||
| const submitterHandle = submission.userInfo?.memberHandle | ||
| ?? submission.review?.submitterHandle | ||
| ?? undefined | ||
| const submitterColor = submission.userInfo?.handleColor | ||
| ?? submission.review?.submitterHandleColor | ||
| ?? undefined | ||
|
|
||
| // Build review details array from all reviewInfos or single review | ||
| const allReviewInfos = submission.reviewInfos && submission.reviewInfos.length > 0 | ||
| ? submission.reviewInfos | ||
| : submission.review | ||
| ? [submission.review] | ||
| : [] | ||
|
|
||
| const reviewDetails = allReviewInfos | ||
| .map((reviewInfo: any) => { | ||
| const reviewId = reviewInfo.id | ||
| const appealInfo = reviewId ? mappingReviewAppeal[reviewId] : undefined | ||
| const totalAppeals = appealInfo?.totalAppeals ?? 0 | ||
| const finishedAppeals = appealInfo?.finishAppeals ?? 0 | ||
|
|
||
| // Resolve review date from multiple sources | ||
| const reviewDateString = reviewInfo.reviewDateString | ||
| ?? reviewInfo.updatedAtString | ||
| ?? (reviewInfo as any).createdAtString | ||
| ?? (reviewInfo as any).reviewedAt | ||
|
|
||
| return { | ||
| // Review detail with reviewer information from reviewInfo | ||
| finalScore: reviewInfo.finalScore, | ||
| finishedAppeals, | ||
| resourceId: reviewInfo.resourceId, | ||
| reviewDateString, | ||
| reviewerHandle: reviewInfo.reviewerHandle ?? undefined, | ||
| reviewerHandleColor: reviewInfo.reviewerHandleColor, | ||
| reviewInfo: { | ||
| ...reviewInfo, | ||
| reviewDateString, | ||
| }, | ||
| totalAppeals, | ||
| unresolvedAppeals: totalAppeals - finishedAppeals, | ||
| } | ||
| }) | ||
| .reverse() | ||
|
|
||
| // Get latest review date from reviewDetails | ||
| const latestReviewDate = reviewDetails.length > 0 | ||
| ? reviewDetails[0]?.reviewDateString | ||
| : undefined | ||
|
|
||
| return { | ||
| ...submission, | ||
| aggregated: { | ||
| id: submission.id, | ||
| latestReviewDateString: latestReviewDate, | ||
| reviews: reviewDetails, | ||
| submission, | ||
| submitterHandle, | ||
| submitterHandleColor: submitterColor, | ||
| }, | ||
| } | ||
| }) | ||
|
|
||
| // Combine submitter rows and reviewer-only rows | ||
| return [...reviewerOnlyRows, ...submitterRows] | ||
| } |
|
I'll create a new one. This one got too crowded and out of control |
Related JIRA Ticket:
https://topcoder.atlassian.net/browse/PM-4477
What's in this PR?
Show failed submissions in the Appeals Response phase