diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 8190894..ec80422 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -595,6 +595,7 @@ function AppContent() { provider?: "claude" | "opencode" | "cursor" | "github-copilot", evaluatorFilter?: EvaluatorFilter, concurrency?: number, + selectedEvaluators?: string[], ) => { setEvaluationMode("evaluating"); setApiError(null); @@ -609,6 +610,7 @@ function AppContent() { evaluatorFilter, undefined, concurrency, + selectedEvaluators, ); setCurrentJobId(response.jobId); setSSEUrl(response.sseUrl); @@ -622,6 +624,7 @@ function AppContent() { totalEvaluators: getFilteredEvaluatorCount( evaluatorFilter || "all", evaluators, + selectedEvaluators?.length, ), completedEvaluators: 0, percentage: 0, diff --git a/frontend/src/components/RepositoryUrlInput.tsx b/frontend/src/components/RepositoryUrlInput.tsx index 5b8c830..00c732b 100644 --- a/frontend/src/components/RepositoryUrlInput.tsx +++ b/frontend/src/components/RepositoryUrlInput.tsx @@ -1,10 +1,11 @@ -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import { useFeatureFlags } from "../contexts/FeatureFlagContext"; import type { ProviderName } from "../hooks/useEvaluationApi"; import { useEvaluatorsApi } from "../hooks/useEvaluatorsApi"; import { useProviderDetection } from "../hooks/useProviderDetection"; import { isValidGitUrl } from "../lib/url-validation"; import type { EvaluatorFilter } from "../types/evaluation"; +import type { IEvaluator } from "../types/evaluator"; interface IRepositoryUrlInputProps { onSubmit: ( @@ -13,6 +14,7 @@ interface IRepositoryUrlInputProps { provider: ProviderName, evaluatorFilter: EvaluatorFilter, concurrency: number, + selectedEvaluators?: string[], ) => Promise; isLoading: boolean; error?: string | null; @@ -44,23 +46,42 @@ export const RepositoryUrlInput: React.FC = ({ const [url, setUrl] = useState(""); const [concurrency, setConcurrency] = useState(3); const [totalEvaluators, setTotalEvaluators] = useState(17); // Default fallback - const [evaluatorFilter, setEvaluatorFilter] = - useState("all"); + const [evaluatorsList, setEvaluatorsList] = useState([]); + const [selectedEvaluatorIds, setSelectedEvaluatorIds] = useState>( + new Set(), + ); + const [evaluatorDropdownOpen, setEvaluatorDropdownOpen] = useState(false); + const dropdownRef = useRef(null); const [provider, setProvider] = useState("claude"); const [validationError, setValidationError] = useState(null); - // Fetch evaluators list on mount to get the total count + // Fetch evaluators list on mount to get the total count and details useEffect(() => { fetchEvaluatorsList() .then((list) => { - const total = list.length; - setTotalEvaluators(total); + setTotalEvaluators(list.length); + setEvaluatorsList(list); + setSelectedEvaluatorIds(new Set(list.map((e) => e.id))); }) .catch(() => { // Keep the fallback default }); }, [fetchEvaluatorsList]); + // Close dropdown on click outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) + ) { + setEvaluatorDropdownOpen(false); + } + }; + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + const validateUrl = useCallback((value: string): boolean => { if (!value.trim()) { setValidationError("Please enter a repository URL"); @@ -89,13 +110,19 @@ export const RepositoryUrlInput: React.FC = ({ try { // In cloud mode, use "random" sentinel to let backend pick an available provider const effectiveProvider = cloudMode ? "random" : provider; - const effectiveFilter = cloudMode ? "all" : evaluatorFilter; + const isAllSelected = + selectedEvaluatorIds.size === totalEvaluators || + selectedEvaluatorIds.size === 0; + const selectedArray = isAllSelected + ? undefined + : Array.from(selectedEvaluatorIds); await onSubmit( url.trim(), - totalEvaluators, + selectedArray ? selectedArray.length : totalEvaluators, effectiveProvider, - effectiveFilter, + "all", concurrency, + cloudMode ? undefined : selectedArray, ); } catch { // Error is handled by parent component @@ -105,7 +132,7 @@ export const RepositoryUrlInput: React.FC = ({ url, totalEvaluators, provider, - evaluatorFilter, + selectedEvaluatorIds, concurrency, validateUrl, onSubmit, @@ -246,7 +273,7 @@ export const RepositoryUrlInput: React.FC = ({ return (
-
+
{/* Text Content */}
@@ -294,37 +321,258 @@ export const RepositoryUrlInput: React.FC = ({
- {/* Options Row: Evaluator Filter and Provider - hidden in cloud mode */} + {/* Options Row: Evaluator Selector, Provider, Concurrency - hidden in cloud mode */} {!cloudMode && (
- {/* Evaluator Filter Selector */} -
-