fix: ranking dashboard respects threshold advancement mode
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
- Header shows "Score >= X advance" instead of "Top N" in threshold mode - Cutoff line placed after last project meeting threshold, not at fixed count - Projects advancing determined by avg score vs threshold, not position Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -362,6 +362,8 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
|||||||
const config = roundData.configJson as Record<string, unknown>
|
const config = roundData.configJson as Record<string, unknown>
|
||||||
const advConfig = config.advancementConfig as Record<string, unknown> | undefined
|
const advConfig = config.advancementConfig as Record<string, unknown> | undefined
|
||||||
return {
|
return {
|
||||||
|
advanceMode: (config.advanceMode as string) ?? 'count',
|
||||||
|
advanceScoreThreshold: (config.advanceScoreThreshold as number) ?? undefined,
|
||||||
startupAdvanceCount: (advConfig?.startupCount ?? config.startupAdvanceCount ?? 0) as number,
|
startupAdvanceCount: (advConfig?.startupCount ?? config.startupAdvanceCount ?? 0) as number,
|
||||||
conceptAdvanceCount: (advConfig?.conceptCount ?? config.conceptAdvanceCount ?? 0) as number,
|
conceptAdvanceCount: (advConfig?.conceptCount ?? config.conceptAdvanceCount ?? 0) as number,
|
||||||
}
|
}
|
||||||
@@ -785,11 +787,15 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
|||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">
|
<CardTitle className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">
|
||||||
{categoryLabels[category]}
|
{categoryLabels[category]}
|
||||||
{evalConfig && (category === 'STARTUP' ? evalConfig.startupAdvanceCount : evalConfig.conceptAdvanceCount) > 0 && (
|
{evalConfig && evalConfig.advanceMode === 'threshold' && evalConfig.advanceScoreThreshold != null ? (
|
||||||
|
<span className="ml-2 text-xs font-normal normal-case">
|
||||||
|
(Score ≥ {evalConfig.advanceScoreThreshold} advance)
|
||||||
|
</span>
|
||||||
|
) : evalConfig && (category === 'STARTUP' ? evalConfig.startupAdvanceCount : evalConfig.conceptAdvanceCount) > 0 ? (
|
||||||
<span className="ml-2 text-xs font-normal normal-case">
|
<span className="ml-2 text-xs font-normal normal-case">
|
||||||
(Top {category === 'STARTUP' ? evalConfig.startupAdvanceCount : evalConfig.conceptAdvanceCount} advance)
|
(Top {category === 'STARTUP' ? evalConfig.startupAdvanceCount : evalConfig.conceptAdvanceCount} advance)
|
||||||
</span>
|
</span>
|
||||||
)}
|
) : null}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@@ -810,11 +816,24 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
|||||||
<AnimatePresence initial={false}>
|
<AnimatePresence initial={false}>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{localOrder[category].map((projectId, index) => {
|
{localOrder[category].map((projectId, index) => {
|
||||||
const advanceCount = category === 'STARTUP'
|
const isThresholdMode = evalConfig?.advanceMode === 'threshold' && evalConfig.advanceScoreThreshold != null
|
||||||
|
const advanceCount = isThresholdMode ? 0 : (category === 'STARTUP'
|
||||||
? (evalConfig?.startupAdvanceCount ?? 0)
|
? (evalConfig?.startupAdvanceCount ?? 0)
|
||||||
: (evalConfig?.conceptAdvanceCount ?? 0)
|
: (evalConfig?.conceptAdvanceCount ?? 0))
|
||||||
const isAdvancing = advanceCount > 0 && index < advanceCount
|
// In threshold mode, check if this project's avg score meets the threshold
|
||||||
const isCutoffRow = advanceCount > 0 && index === advanceCount - 1
|
const entry = rankingMap.get(projectId)
|
||||||
|
const projectAvg = entry?.avgGlobalScore ?? 0
|
||||||
|
const threshold = evalConfig?.advanceScoreThreshold ?? 0
|
||||||
|
const isAdvancing = isThresholdMode
|
||||||
|
? projectAvg >= threshold
|
||||||
|
: (advanceCount > 0 && index < advanceCount)
|
||||||
|
// Show cutoff line: in threshold mode, after last project above threshold
|
||||||
|
const nextProjectId = localOrder[category][index + 1]
|
||||||
|
const nextEntry = nextProjectId ? rankingMap.get(nextProjectId) : null
|
||||||
|
const nextAvg = nextEntry?.avgGlobalScore ?? 0
|
||||||
|
const isCutoffRow = isThresholdMode
|
||||||
|
? (projectAvg >= threshold && nextAvg < threshold)
|
||||||
|
: (advanceCount > 0 && index === advanceCount - 1)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={projectId}>
|
<React.Fragment key={projectId}>
|
||||||
@@ -839,7 +858,7 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
|||||||
<div className="flex items-center gap-2 py-1">
|
<div className="flex items-center gap-2 py-1">
|
||||||
<div className="flex-1 border-t-2 border-dashed border-emerald-400/60" />
|
<div className="flex-1 border-t-2 border-dashed border-emerald-400/60" />
|
||||||
<span className="text-xs font-medium text-emerald-600 dark:text-emerald-400 whitespace-nowrap">
|
<span className="text-xs font-medium text-emerald-600 dark:text-emerald-400 whitespace-nowrap">
|
||||||
Advancement cutoff — Top {advanceCount}
|
Advancement cutoff — {isThresholdMode ? `Score ≥ ${threshold}` : `Top ${advanceCount}`}
|
||||||
</span>
|
</span>
|
||||||
<div className="flex-1 border-t-2 border-dashed border-emerald-400/60" />
|
<div className="flex-1 border-t-2 border-dashed border-emerald-400/60" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user