fix(mentor): restore Add Project on mentoring rounds + gate mentor assignment
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m15s

Three related bugs around the mentoring-round Projects tab:

1. Add Project to Round was unreachable on MENTORING rounds — the table swap
   in the prior commit lost the button. Export AddProjectDialog from
   project-states-table and render it inside MentoringProjectsTable with an
   "Add" button in the filter row and a CTA in the empty state.
2. The "Assign Projects" quick action on the round overview linked to the
   global pool with an opaque filter; on MENTORING rounds it now switches
   to the Projects tab where the new Add Project button + auto-fill +
   per-team picker all live. Non-mentoring rounds keep the old behavior.
3. mentor.assign and mentor.bulkAssign now refuse projects that aren't
   enrolled in any MENTORING round (any status). The single-assign throws
   BAD_REQUEST with a guidance message; the bulk path filters them out and
   reports ineligibleProjectCount in the result so the UI can warn the
   admin instead of silently skipping.

Tests: the multi-mentor-assignment suite now sets up a MENTORING round +
ProjectRoundState for each project it tests against, matching the new gate.
This commit is contained in:
Matt
2026-05-26 15:20:01 +02:00
parent c4f7216bc1
commit 61dfc608cd
5 changed files with 183 additions and 27 deletions

View File

@@ -42,6 +42,37 @@ async function createUserWithRoles(
})
}
/**
* mentor.assign and mentor.bulkAssign now require the project to be enrolled
* in some MENTORING round. This helper sets up the minimum: one competition
* + one MENTORING round + one ProjectRoundState linking the project.
*/
async function attachToMentoringRound(programId: string, projectId: string) {
const compSlug = `comp-${uid()}`
const competition = await prisma.competition.create({
data: {
name: `Comp ${compSlug}`,
slug: compSlug,
programId,
status: 'ACTIVE',
},
})
const round = await prisma.round.create({
data: {
name: `Mentoring ${uid()}`,
slug: `mentoring-${uid()}`,
roundType: 'MENTORING',
sortOrder: 1,
status: 'ROUND_ACTIVE',
competitionId: competition.id,
},
})
await prisma.projectRoundState.create({
data: { roundId: round.id, projectId },
})
return { competitionId: competition.id, roundId: round.id }
}
describe('mentor.assign — stacking + per-team email idempotency', () => {
const programIds: string[] = []
const userIds: string[] = []
@@ -62,6 +93,7 @@ describe('mentor.assign — stacking + per-team email idempotency', () => {
const program = await createTestProgram({ name: `assign-stack-${uid()}` })
programIds.push(program.id)
const project = await createTestProject(program.id, { title: 'Stacking Project' })
await attachToMentoringRound(program.id, project.id)
const m1 = await createUserWithRoles('MENTOR', ['MENTOR'], { name: 'M1' })
const m2 = await createUserWithRoles('MENTOR', ['MENTOR'], { name: 'M2' })
@@ -93,6 +125,7 @@ describe('mentor.assign — stacking + per-team email idempotency', () => {
const program = await createTestProgram({ name: `assign-dup-${uid()}` })
programIds.push(program.id)
const project = await createTestProject(program.id, { title: 'Dup Project' })
await attachToMentoringRound(program.id, project.id)
const mentor = await createUserWithRoles('MENTOR', ['MENTOR'])
userIds.push(mentor.id)
@@ -114,7 +147,9 @@ describe('mentor.assign — stacking + per-team email idempotency', () => {
const program = await createTestProgram({ name: `assign-email-${uid()}` })
programIds.push(program.id)
const project1 = await createTestProject(program.id, { title: 'Project Alpha' })
await attachToMentoringRound(program.id, project1.id)
const project2 = await createTestProject(program.id, { title: 'Project Beta' })
await attachToMentoringRound(program.id, project2.id)
const mentor = await createUserWithRoles('MENTOR', ['MENTOR'])
userIds.push(mentor.id)
@@ -144,6 +179,7 @@ describe('mentor.assign — stacking + per-team email idempotency', () => {
const program = await createTestProgram({ name: `assign-comentor-${uid()}` })
programIds.push(program.id)
const project = await createTestProject(program.id, { title: 'Co-mentor Project' })
await attachToMentoringRound(program.id, project.id)
const m1 = await createUserWithRoles('MENTOR', ['MENTOR'], { name: 'Co-1' })
const m2 = await createUserWithRoles('MENTOR', ['MENTOR'], { name: 'Co-2' })
userIds.push(m1.id, m2.id)
@@ -169,6 +205,7 @@ describe('mentor.assign — stacking + per-team email idempotency', () => {
const program = await createTestProgram({ name: `assign-redrop-${uid()}` })
programIds.push(program.id)
const project = await createTestProject(program.id, { title: 'Re-assign Project' })
await attachToMentoringRound(program.id, project.id)
const mentor = await createUserWithRoles('MENTOR', ['MENTOR'])
userIds.push(mentor.id)