Skip to content
Closed
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 @@ -272,15 +272,117 @@ export const TableAppealsResponse: FC<TableAppealsResponseProps> = (props: Table
return reviews.some(review => review.resourceId && myReviewerResourceIds.has(review.resourceId))
}

// For submitters, also include submissions that don't have aggregated reviews (e.g., failed submissions)
// but exist in the submissions data. This allows failed submissions to appear in Appeals Response tab.
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]
}
Comment on lines +277 to +371
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 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.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@himaniraghav3 please check and fix.


return aggregatedRows.filter(row => matchesSubmitter(row) || matchesReviewer(row))
}, [
aggregatedRows,
canRender,
canViewAllAppeals,
canViewAsReviewer,
canViewAsSubmitter,
filteredChallengeSubmissions,
hasLatestFlag,
mappingReviewAppeal,
myReviewerResourceIds,
ownedMemberIds,
restrictToLatest,
submitterCanViewAllRows,
])

Expand Down Expand Up @@ -505,6 +607,7 @@ export const TableAppealsResponse: FC<TableAppealsResponseProps> = (props: Table
canRespondToAppeals,
isAppealsResponsePhaseOpen,
scoreVisibilityConfig,
props.aiReviewers,
])

const columnsMobile = useMemo<MobileTableColumn<SubmissionReviewerRow>[][]>(
Expand Down
Loading