feat(mentor): round-level auto-fill toolbar on Projects tab (§C)

Adds an 'Auto-fill remaining' button above ProjectStatesTable on the
MENTORING round Projects tab. Calls mentor.autoAssignBulkForRound,
respecting the round's configJson.eligibility:
  - requested_only / all_advancing: enabled, count from new
    round.getProjectsNeedingMentor query
  - admin_selected: disabled with explanatory copy

Plan: docs/superpowers/plans/2026-04-28-pr4-mentor-assignment-ux.md
This commit is contained in:
Matt
2026-04-28 14:58:32 +02:00
parent ddae34c8f5
commit 2b07c12c18
2 changed files with 99 additions and 0 deletions

View File

@@ -215,6 +215,35 @@ export const roundRouter = router({
)
}),
/**
* Count projects in a MENTORING round eligible for mentor auto-fill
* (i.e., no mentorAssignment, scoped by configJson.eligibility).
* Used by the Auto-fill remaining toolbar on the round Projects tab.
*/
getProjectsNeedingMentor: adminProcedure
.input(z.object({ roundId: z.string() }))
.query(async ({ ctx, input }) => {
const round = await ctx.prisma.round.findUniqueOrThrow({
where: { id: input.roundId },
select: { roundType: true, configJson: true },
})
if (round.roundType !== 'MENTORING') return { count: 0 }
const config = (round.configJson ?? {}) as Record<string, unknown>
const eligibility = (config.eligibility as string) ?? 'requested_only'
if (eligibility === 'admin_selected') return { count: 0 }
const count = await ctx.prisma.projectRoundState.count({
where: {
roundId: input.roundId,
project: {
mentorAssignment: null,
...(eligibility === 'requested_only' ? { wantsMentorship: true } : {}),
},
},
})
return { count }
}),
/**
* Delete a round
*/