Add background filtering jobs, improved date picker, AI reasoning display

- Implement background job system for AI filtering to avoid HTTP timeouts
- Add FilteringJob model to track progress of long-running filtering operations
- Add real-time progress polling for filtering operations on round details page
- Create custom DateTimePicker component with calendar popup (no year picker hassle)
- Fix round date persistence bug (refetchOnWindowFocus was resetting form state)
- Integrate filtering controls into round details page for filtering rounds
- Display AI reasoning for flagged/filtered projects in results table
- Add onboarding system scaffolding (schema, routes, basic UI)
- Allow setting round dates in the past for manual overrides

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 19:48:41 +01:00
parent 8be740a4fb
commit e2782b2b19
24 changed files with 3692 additions and 443 deletions

View File

@@ -35,16 +35,17 @@ import {
} from '@/components/ui/form'
import { RoundTypeSettings } from '@/components/forms/round-type-settings'
import { ArrowLeft, Loader2, AlertCircle } from 'lucide-react'
import { DateTimePicker } from '@/components/ui/datetime-picker'
const createRoundSchema = z.object({
programId: z.string().min(1, 'Please select a program'),
name: z.string().min(1, 'Name is required').max(255),
requiredReviews: z.number().int().min(1).max(10),
votingStartAt: z.string().optional(),
votingEndAt: z.string().optional(),
votingStartAt: z.date().nullable().optional(),
votingEndAt: z.date().nullable().optional(),
}).refine((data) => {
if (data.votingStartAt && data.votingEndAt) {
return new Date(data.votingEndAt) > new Date(data.votingStartAt)
return data.votingEndAt > data.votingStartAt
}
return true
}, {
@@ -75,8 +76,8 @@ function CreateRoundContent() {
programId: programIdParam || '',
name: '',
requiredReviews: 3,
votingStartAt: '',
votingEndAt: '',
votingStartAt: null,
votingEndAt: null,
},
})
@@ -87,8 +88,8 @@ function CreateRoundContent() {
roundType,
requiredReviews: data.requiredReviews,
settingsJson: roundSettings,
votingStartAt: data.votingStartAt ? new Date(data.votingStartAt) : undefined,
votingEndAt: data.votingEndAt ? new Date(data.votingEndAt) : undefined,
votingStartAt: data.votingStartAt ?? undefined,
votingEndAt: data.votingEndAt ?? undefined,
})
}
@@ -246,7 +247,11 @@ function CreateRoundContent() {
<FormItem>
<FormLabel>Start Date & Time</FormLabel>
<FormControl>
<Input type="datetime-local" {...field} />
<DateTimePicker
value={field.value}
onChange={field.onChange}
placeholder="Select start date & time"
/>
</FormControl>
<FormMessage />
</FormItem>
@@ -260,7 +265,11 @@ function CreateRoundContent() {
<FormItem>
<FormLabel>End Date & Time</FormLabel>
<FormControl>
<Input type="datetime-local" {...field} />
<DateTimePicker
value={field.value}
onChange={field.onChange}
placeholder="Select end date & time"
/>
</FormControl>
<FormMessage />
</FormItem>
@@ -269,8 +278,7 @@ function CreateRoundContent() {
</div>
<p className="text-sm text-muted-foreground">
Leave empty to set the voting window later. The round will need to be
activated before jury members can submit evaluations.
Leave empty to set the voting window later. Past dates are allowed.
</p>
</CardContent>
</Card>