feat: clickable status badges, observer status alignment, CSV export all
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m36s
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m36s
- Admin projects: status summary badges are clickable to filter by round state with ring highlight, opacity fade, and clear button - Add roundStates filter param to project.list backend query (filters by latest round state per project, consistent with counts) - Observer status dropdown now uses ProjectRoundState values (Pending/In Progress/Completed/Passed/Rejected/Withdrawn) - Observer status derived from latest ProjectRoundState instead of stale Project.status - Observer CSV export fetches all matching projects, not just current page - Add PENDING and PASSED styles to StatusBadge component Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -231,7 +231,7 @@ export function EvaluationPanel({ roundId, programId }: { roundId: string; progr
|
||||
{projects
|
||||
.filter((p) => {
|
||||
const s = p.observerStatus ?? p.status
|
||||
return s !== 'NOT_REVIEWED' && s !== 'SUBMITTED'
|
||||
return s !== 'PENDING'
|
||||
})
|
||||
.slice(0, 6)
|
||||
.map((p) => (
|
||||
|
||||
@@ -141,11 +141,19 @@ export function ObserverProjectsContent() {
|
||||
{ refetchInterval: 30_000 },
|
||||
)
|
||||
|
||||
const utils = trpc.useUtils()
|
||||
const handleRequestCsvData = useCallback(async () => {
|
||||
setCsvLoading(true)
|
||||
try {
|
||||
const allData = await new Promise<typeof projectsData>((resolve) => {
|
||||
resolve(projectsData)
|
||||
const allData = await utils.analytics.getAllProjects.fetch({
|
||||
roundId: roundFilter !== 'all' ? roundFilter : undefined,
|
||||
search: debouncedSearch || undefined,
|
||||
status: statusFilter !== 'all' ? statusFilter : undefined,
|
||||
sortBy,
|
||||
sortDir,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
exportAll: true,
|
||||
})
|
||||
|
||||
if (!allData?.projects) {
|
||||
@@ -158,7 +166,7 @@ export function ObserverProjectsContent() {
|
||||
teamName: p.teamName ?? '',
|
||||
country: p.country ?? '',
|
||||
roundName: p.roundName ?? '',
|
||||
status: p.status,
|
||||
status: p.observerStatus ?? p.status,
|
||||
averageScore: p.averageScore !== null ? p.averageScore.toFixed(2) : '',
|
||||
evaluationCount: p.evaluationCount,
|
||||
}))
|
||||
@@ -174,7 +182,7 @@ export function ObserverProjectsContent() {
|
||||
setCsvLoading(false)
|
||||
return undefined
|
||||
}
|
||||
}, [projectsData])
|
||||
}, [utils, roundFilter, debouncedSearch, statusFilter, sortBy, sortDir])
|
||||
|
||||
const SortIcon = ({ column }: { column: 'title' | 'score' | 'evaluations' }) => {
|
||||
if (sortBy !== column)
|
||||
@@ -251,13 +259,12 @@ export function ObserverProjectsContent() {
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All Statuses</SelectItem>
|
||||
<SelectItem value="SUBMITTED">Submitted</SelectItem>
|
||||
<SelectItem value="NOT_REVIEWED">Not Reviewed</SelectItem>
|
||||
<SelectItem value="UNDER_REVIEW">Under Review</SelectItem>
|
||||
<SelectItem value="REVIEWED">Reviewed</SelectItem>
|
||||
<SelectItem value="SEMIFINALIST">Semi-finalist</SelectItem>
|
||||
<SelectItem value="FINALIST">Finalist</SelectItem>
|
||||
<SelectItem value="PENDING">Pending</SelectItem>
|
||||
<SelectItem value="IN_PROGRESS">In Progress</SelectItem>
|
||||
<SelectItem value="COMPLETED">Completed</SelectItem>
|
||||
<SelectItem value="PASSED">Passed</SelectItem>
|
||||
<SelectItem value="REJECTED">Rejected</SelectItem>
|
||||
<SelectItem value="WITHDRAWN">Withdrawn</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
@@ -28,9 +28,11 @@ const STATUS_STYLES: Record<string, { variant: BadgeProps['variant']; className?
|
||||
NOT_REVIEWED: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200 dark:text-slate-400' },
|
||||
REVIEWED: { variant: 'default', className: 'bg-emerald-500/10 text-emerald-700 border-emerald-200 dark:text-emerald-400' },
|
||||
|
||||
// Evaluation statuses
|
||||
// Round state statuses
|
||||
PENDING: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200 dark:text-slate-400' },
|
||||
IN_PROGRESS: { variant: 'default', className: 'bg-blue-500/10 text-blue-700 border-blue-200 dark:text-blue-400' },
|
||||
COMPLETED: { variant: 'default', className: 'bg-emerald-500/10 text-emerald-700 border-emerald-200 dark:text-emerald-400' },
|
||||
PASSED: { variant: 'default', className: 'bg-green-500/10 text-green-700 border-green-200 dark:text-green-400' },
|
||||
|
||||
// User statuses
|
||||
NONE: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-500 border-slate-200 dark:text-slate-400' },
|
||||
|
||||
Reference in New Issue
Block a user