From 20372a932da56943212eb1ab700fa84e10fbe0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Tue, 14 Oct 2025 11:02:23 +0530 Subject: [PATCH] Add filtering to Model Performance Matrix --- client/src/pages/PuzzleFeedback.tsx | 118 +++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 4 deletions(-) diff --git a/client/src/pages/PuzzleFeedback.tsx b/client/src/pages/PuzzleFeedback.tsx index d57d2dd3b..c1ead92e6 100644 --- a/client/src/pages/PuzzleFeedback.tsx +++ b/client/src/pages/PuzzleFeedback.tsx @@ -31,7 +31,7 @@ import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Badge } from '@/components/ui/badge'; -import { Loader2, Grid3X3, CheckCircle, XCircle, Copy, Lightbulb, Users, MessageSquare, Brain, Settings, Database, BarChart3 } from 'lucide-react'; +import { Loader2, Grid3X3, CheckCircle, XCircle, Copy, Lightbulb, Users, MessageSquare, Brain, Settings, Database, BarChart3, Search, Filter } from 'lucide-react'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { PuzzleGrid } from '@/components/puzzle/PuzzleGrid'; import { AnalysisResultCard } from '@/components/puzzle/AnalysisResultCard'; @@ -40,6 +40,7 @@ import { ClickablePuzzleBadge } from '@/components/ui/ClickablePuzzleBadge'; import { usePuzzleListAnalysis } from '@/hooks/usePuzzleListAnalysis'; import type { ExplanationData } from '@/types/puzzle'; import { formatPuzzleDisplay } from '@shared/utils/puzzleNames'; +import { Checkbox } from '@/components/ui/checkbox'; const LAST_MODEL_STORAGE_KEY = 'puzzleFeedback:lastModel'; const LAST_CUSTOM_MODEL_STORAGE_KEY = 'puzzleFeedback:lastCustomModel'; @@ -76,6 +77,12 @@ export default function PuzzleFeedback() { const [puzzleListInput, setPuzzleListInput] = useState(''); const { analyzePuzzleList, data: puzzleAnalysisData, isLoading: isAnalyzing, isError: analysisError, error: analysisErrorDetails } = usePuzzleListAnalysis(); + // Matrix filter state + const [modelSearchFilter, setModelSearchFilter] = useState(''); + const [showCorrect, setShowCorrect] = useState(true); + const [showIncorrect, setShowIncorrect] = useState(true); + const [showNotAttempted, setShowNotAttempted] = useState(true); + // Set page title React.useEffect(() => { document.title = puzzleId ? `Test Solution - ${formatPuzzleDisplay(puzzleId)}` : 'Test Your Solution'; @@ -415,6 +422,24 @@ export default function PuzzleFeedback() { model.puzzleStatuses.some(status => status.status !== 'not_attempted') ); + // Apply filters to get filtered models count + const filteredModels = activeModels.filter((model) => { + // Filter by model name search + if (modelSearchFilter && !model.modelName.toLowerCase().includes(modelSearchFilter.toLowerCase())) { + return false; + } + + // Filter by status visibility + const hasCorrect = model.puzzleStatuses.some(p => p.status === 'correct'); + const hasIncorrect = model.puzzleStatuses.some(p => p.status === 'incorrect'); + const hasNotAttempted = model.puzzleStatuses.some(p => p.status === 'not_attempted'); + + // Show model if it has at least one status that's enabled + return (showCorrect && hasCorrect) || + (showIncorrect && hasIncorrect) || + (showNotAttempted && hasNotAttempted); + }); + // Calculate per-puzzle metrics const puzzleMetrics = puzzleAnalysisData.puzzleResults.map(puzzle => { const totalModels = activeModels.length; @@ -502,7 +527,7 @@ export default function PuzzleFeedback() { Model Performance Matrix - {activeModels.length} active / {puzzleAnalysisData.summary.totalModels} total + {filteredModels.length} shown / {activeModels.length} active / {puzzleAnalysisData.summary.totalModels} total

@@ -510,6 +535,67 @@ export default function PuzzleFeedback() {

+ {/* Filter Controls */} +
+
+ + setModelSearchFilter(e.target.value)} + className="h-7 text-xs flex-1" + /> + +
+
+
+ + Show: +
+
+ setShowCorrect(checked === true)} + /> + +
+
+ setShowIncorrect(checked === true)} + /> + +
+
+ setShowNotAttempted(checked === true)} + /> + +
+
+
@@ -531,7 +617,30 @@ export default function PuzzleFeedback() { - {activeModels.map((model) => { + {filteredModels.length === 0 ? ( + + + + ) : ( + filteredModels.map((model) => { const correctCount = model.puzzleStatuses.filter(p => p.status === 'correct').length; const incorrectCount = model.puzzleStatuses.filter(p => p.status === 'incorrect').length; const attemptedCount = correctCount + incorrectCount; @@ -554,7 +663,8 @@ export default function PuzzleFeedback() { ))} ); - })} + }) + )}
+
+ +

No models match the current filters

+ +
+