Admin UI audit round 2: fix 28 display bugs across 23 files
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m51s

HIGH fixes (broken features / wrong data):
- H1: Fix roundAssignments → projectRoundStates in project router (7 occurrences)
- H2: Fix deliberation results panel blank table (wrong field names)
- H3: Fix deliberation participant names blank (wrong data path)
- H4: Fix awards "Evaluated" stat duplicating "Eligible" count
- H5: Fix cross-round comparison enabled at 1 round (backend requires 2)
- H6: Fix setState during render anti-pattern (6 occurrences)
- H7: Fix round detail jury member count always showing 0
- H8: Remove 4 invalid status values from observer dashboard filter
- H9: Fix filtering progress bar always showing 100%

MEDIUM fixes (misleading display):
- M1: Filter special-award rounds from competition timeline
- M2: Exclude special-award rounds from distinct project count
- M3: Fix MENTORING pipeline node hardcoded "0 mentored"
- M4: Fix DELIB_LOCKED badge using red for success state
- M5: Add status label maps to deliberation session detail
- M6: Humanize deliberation category + tie-break method displays
- M8: Rename setStageId → setRoundId, "Select Stage" → "Select Round"
- M9: Add missing INVITED/ACTIVE/SUSPENDED to members status labels
- M10: Add ROUND_DRAFT/ACTIVE/CLOSED/ARCHIVED to StatusBadge
- M11: Fix unsent messages showing "Scheduled" instead of "Draft"
- M12: Rename misleading totalEvaluations → totalAssignments
- M13: Rename "Stage" column to "Program" in projects page

LOW fixes (cosmetic / edge-case):
- L1: Use unfiltered rounds array for active round detection
- L2: Use all rounds length for new round sort order
- L3: Filter special-award rounds from header count
- L4: Fix single-underscore replace in award status badges
- L5: Fix score bucket boundary gaps (4.99 dropped between buckets)
- L6: Title-case LIVE_FINAL pipeline metric status
- L7: Fix roundType.replace only replacing first underscore
- L8: Remove duplicate severity sort in smart-actions component

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt
2026-02-19 11:11:00 +01:00
parent ae1685179c
commit 51e18870b6
23 changed files with 170 additions and 111 deletions

View File

@@ -754,14 +754,14 @@ export const analyticsRouter = router({
const scores = evaluationScores.map((e) => e.globalScore!).filter((s) => s != null)
const scoreDistribution = [
{ label: '9-10', min: 9, max: 10 },
{ label: '7-8', min: 7, max: 8.99 },
{ label: '5-6', min: 5, max: 6.99 },
{ label: '3-4', min: 3, max: 4.99 },
{ label: '1-2', min: 1, max: 2.99 },
{ label: '9-10', min: 9, max: Infinity },
{ label: '7-8', min: 7, max: 9 },
{ label: '5-6', min: 5, max: 7 },
{ label: '3-4', min: 3, max: 5 },
{ label: '1-2', min: 1, max: 3 },
].map((b) => ({
label: b.label,
count: scores.filter((s) => s >= b.min && s <= b.max).length,
count: scores.filter((s) => s >= b.min && s < b.max).length,
}))
return {
@@ -770,7 +770,7 @@ export const analyticsRouter = router({
projectCount,
jurorCount,
submittedEvaluations,
totalEvaluations: totalAssignments,
totalAssignments,
completionRate,
scoreDistribution,
}

View File

@@ -123,7 +123,7 @@ export const competitionRouter = router({
}
// Count distinct projects across all rounds (not sum of per-round states)
const roundIds = competition.rounds.map((r) => r.id)
const roundIds = competition.rounds.filter((r) => !r.specialAwardId).map((r) => r.id)
const distinctProjectCount = roundIds.length > 0
? await ctx.prisma.projectRoundState.findMany({
where: { roundId: { in: roundIds } },

View File

@@ -146,7 +146,24 @@ export const deliberationRouter = router({
aggregate: adminProcedure
.input(z.object({ sessionId: z.string() }))
.query(async ({ ctx, input }) => {
return aggregateVotes(input.sessionId, ctx.prisma)
const result = await aggregateVotes(input.sessionId, ctx.prisma)
// Enrich rankings with project titles
const projectIds = result.rankings.map((r) => r.projectId)
const projects = projectIds.length > 0
? await ctx.prisma.project.findMany({
where: { id: { in: projectIds } },
select: { id: true, title: true, teamName: true },
})
: []
const projectMap = new Map(projects.map((p) => [p.id, p]))
return {
...result,
rankings: result.rankings.map((r) => ({
...r,
projectTitle: projectMap.get(r.projectId)?.title ?? 'Unknown Project',
teamName: projectMap.get(r.projectId)?.teamName ?? '',
})),
}
}),
/**

View File

@@ -89,19 +89,19 @@ export const projectRouter = router({
// Filter by program
if (programId) where.programId = programId
// Filter by round (via RoundAssignment join)
// Filter by round (via ProjectRoundState)
if (roundId) {
where.roundAssignments = { some: { roundId } }
where.projectRoundStates = { some: { roundId } }
}
// Exclude projects already in a specific round
if (excludeInRoundId) {
where.roundAssignments = { none: { roundId: excludeInRoundId } }
where.projectRoundStates = { none: { roundId: excludeInRoundId } }
}
// Filter by unassigned (not in any round)
if (unassignedOnly) {
where.roundAssignments = { none: {} }
where.projectRoundStates = { none: {} }
}
// Status filter
@@ -223,13 +223,13 @@ export const projectRouter = router({
if (programId) where.programId = programId
if (roundId) {
where.roundAssignments = { some: { roundId } }
where.projectRoundStates = { some: { roundId } }
}
if (excludeInRoundId) {
where.roundAssignments = { none: { roundId: excludeInRoundId } }
where.projectRoundStates = { none: { roundId: excludeInRoundId } }
}
if (unassignedOnly) {
where.roundAssignments = { none: {} }
where.projectRoundStates = { none: {} }
}
if (statuses?.length) where.status = { in: statuses }
if (tags && tags.length > 0) where.tags = { hasSome: tags }
@@ -1102,7 +1102,7 @@ export const projectRouter = router({
const where: Record<string, unknown> = {
programId,
roundAssignments: { none: {} }, // Projects not assigned to any round
projectRoundStates: { none: {} }, // Projects not assigned to any round
}
if (search) {

View File

@@ -102,12 +102,17 @@ export const specialAwardRouter = router({
}
}
// Count eligible projects
const eligibleCount = await ctx.prisma.awardEligibility.count({
where: { awardId: input.id, eligible: true },
})
// Count eligible projects and total assessed
const [eligibleCount, totalAssessed] = await Promise.all([
ctx.prisma.awardEligibility.count({
where: { awardId: input.id, eligible: true },
}),
ctx.prisma.awardEligibility.count({
where: { awardId: input.id },
}),
])
return { ...award, competition, eligibleCount }
return { ...award, competition, eligibleCount, totalAssessed }
}),
// ─── Admin Mutations ────────────────────────────────────────────────────