@@ -8,12 +8,13 @@ import { useForm, FormProvider } from "react-hook-form"
88import { zodResolver } from "@hookform/resolvers/zod"
99import fuzzysort from "fuzzysort"
1010import { toast } from "sonner"
11- import { X , Rocket , Check , ChevronsUpDown , SlidersHorizontal , Book , CircleCheck } from "lucide-react"
11+ import { X , Rocket , Check , ChevronsUpDown , SlidersHorizontal , Book , CircleCheck , Users } from "lucide-react"
1212
1313import { globalSettingsSchema , providerSettingsSchema , EVALS_SETTINGS , getModelId } from "@roo-code/types"
1414
1515import { createRun } from "@/actions/runs"
1616import { getExercises } from "@/actions/exercises"
17+ import { getExerciseGroups } from "@/actions/exercise-groups"
1718import {
1819 createRunSchema ,
1920 type CreateRun ,
@@ -70,6 +71,7 @@ export function NewRun() {
7071
7172 const models = useOpenRouterModels ( )
7273 const exercises = useQuery ( { queryKey : [ "getExercises" ] , queryFn : ( ) => getExercises ( ) } )
74+ const exerciseGroups = useQuery ( { queryKey : [ "getExerciseGroups" ] , queryFn : ( ) => getExerciseGroups ( ) } )
7375
7476 const form = useForm < CreateRun > ( {
7577 resolver : zodResolver ( createRunSchema ) ,
@@ -178,6 +180,18 @@ export function NewRun() {
178180 [ clearErrors , setValue ] ,
179181 )
180182
183+ const onSelectExerciseGroup = useCallback (
184+ ( groupName : string ) => {
185+ const group = exerciseGroups . data ?. find ( ( g ) => g . name === groupName )
186+ if ( group ) {
187+ setValue ( "suite" , "partial" )
188+ setValue ( "exercises" , group . exercises )
189+ toast . success ( `Selected "${ groupName } " exercise group with ${ group . exercises . length } exercises` )
190+ }
191+ } ,
192+ [ exerciseGroups . data , setValue ] ,
193+ )
194+
181195 return (
182196 < >
183197 < FormProvider { ...form } >
@@ -309,13 +323,37 @@ export function NewRun() {
309323 </ TabsList >
310324 </ Tabs >
311325 { suite === "partial" && (
312- < MultiSelect
313- options = { exercises . data ?. map ( ( path ) => ( { value : path , label : path } ) ) || [ ] }
314- onValueChange = { ( value ) => setValue ( "exercises" , value ) }
315- placeholder = "Select"
316- variant = "inverted"
317- maxCount = { 4 }
318- />
326+ < >
327+ { exerciseGroups . data && exerciseGroups . data . length > 0 && (
328+ < div className = "flex flex-wrap gap-2 mt-2 mb-2" >
329+ < div className = "text-sm text-muted-foreground flex items-center gap-1" >
330+ < Users className = "size-4" />
331+ Predefined groups:
332+ </ div >
333+ { exerciseGroups . data . map ( ( group ) => (
334+ < Button
335+ key = { group . name }
336+ type = "button"
337+ variant = "outline"
338+ size = "sm"
339+ onClick = { ( ) => onSelectExerciseGroup ( group . name ) }
340+ className = "text-xs" >
341+ { group . name } ({ group . exercises . length } )
342+ </ Button >
343+ ) ) }
344+ </ div >
345+ ) }
346+ < MultiSelect
347+ options = {
348+ exercises . data ?. map ( ( path ) => ( { value : path , label : path } ) ) || [ ]
349+ }
350+ onValueChange = { ( value ) => setValue ( "exercises" , value ) }
351+ placeholder = "Select"
352+ variant = "inverted"
353+ maxCount = { 4 }
354+ defaultValue = { form . watch ( "exercises" ) || [ ] }
355+ />
356+ </ >
319357 ) }
320358 < FormMessage />
321359 </ FormItem >
0 commit comments