tfrere commited on
Commit
edf1655
·
1 Parent(s): 8b0d0d3
client/src/components/LeaderboardFilters/LeaderboardFilters.jsx CHANGED
@@ -95,23 +95,212 @@ const LeaderboardFilters = ({ allSections = [] }) => {
95
  selectedCategories,
96
  setSelectedCategories,
97
  searchQuery,
 
98
  } = useLeaderboard();
99
 
100
  const [inputValue, setInputValue] = useState(searchQuery || "");
101
  const [totalArenaCount, setTotalArenaCount] = useState(0);
102
  const debouncedSearch = useDebounce(inputValue, 200);
103
 
104
- // Calculate section counts based on arena filter
105
  const sectionCounts = useMemo(() => {
106
  const counts = new Map();
107
- allSections.forEach(({ id, data = [] }) => {
108
- const filteredData = arenaOnly
109
- ? data.filter((board) => board.tags?.includes("judge:humans"))
110
- : data;
111
- counts.set(id, filteredData.length);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  });
 
113
  return counts;
114
- }, [allSections, arenaOnly]);
 
 
 
 
 
 
115
 
116
  // Update the search query after debounce
117
  React.useEffect(() => {
 
95
  selectedCategories,
96
  setSelectedCategories,
97
  searchQuery,
98
+ selectedLanguage,
99
  } = useLeaderboard();
100
 
101
  const [inputValue, setInputValue] = useState(searchQuery || "");
102
  const [totalArenaCount, setTotalArenaCount] = useState(0);
103
  const debouncedSearch = useDebounce(inputValue, 200);
104
 
105
+ // Calculate section counts based on all active filters
106
  const sectionCounts = useMemo(() => {
107
  const counts = new Map();
108
+
109
+ // Get all filtered leaderboards first
110
+ const allLeaderboards = Array.from(
111
+ new Set(
112
+ allSections.reduce((acc, section) => {
113
+ return [...acc, ...(section.data || [])];
114
+ }, [])
115
+ )
116
+ );
117
+
118
+ // Apply current filters except the category being counted
119
+ let baseFiltered = allLeaderboards;
120
+
121
+ // Apply arena filter if active
122
+ if (arenaOnly) {
123
+ baseFiltered = baseFiltered.filter((board) =>
124
+ board.tags?.includes("judge:humans")
125
+ );
126
+ }
127
+
128
+ // Apply search filter if active
129
+ if (searchQuery) {
130
+ const query = searchQuery.toLowerCase();
131
+ const tagMatch = query.match(/^(\w+):(\w+)$/);
132
+
133
+ if (tagMatch) {
134
+ const [_, category, value] = tagMatch;
135
+ const searchTag = `${category}:${value}`.toLowerCase();
136
+ baseFiltered = baseFiltered.filter((board) => {
137
+ const allTags = [...(board.tags || []), ...(board.editor_tags || [])];
138
+ return allTags.some((tag) => tag.toLowerCase() === searchTag);
139
+ });
140
+ } else {
141
+ baseFiltered = baseFiltered.filter((board) =>
142
+ board.card_data?.title?.toLowerCase().includes(query)
143
+ );
144
+ }
145
+ }
146
+
147
+ // Apply language filters if active
148
+ if (selectedLanguage.size > 0) {
149
+ baseFiltered = baseFiltered.filter((board) =>
150
+ Array.from(selectedLanguage).some((lang) =>
151
+ board.tags?.some(
152
+ (tag) => tag.toLowerCase() === `language:${lang.toLowerCase()}`
153
+ )
154
+ )
155
+ );
156
+ }
157
+
158
+ // Apply category filters if active, but exclude the category being counted
159
+ const applyCategoryFilters = (board, excludedCategory) => {
160
+ if (selectedCategories.size === 0) return true;
161
+
162
+ const tags = board.tags || [];
163
+ return Array.from(selectedCategories)
164
+ .filter((category) => category !== excludedCategory)
165
+ .every((category) => {
166
+ switch (category) {
167
+ case "agentic":
168
+ return tags.includes("modality:agent");
169
+ case "text":
170
+ return tags.includes("modality:text");
171
+ case "image":
172
+ return tags.includes("modality:image");
173
+ case "video":
174
+ return tags.includes("modality:video");
175
+ case "code":
176
+ return tags.includes("eval:code");
177
+ case "math":
178
+ return tags.includes("eval:math");
179
+ case "reasoning":
180
+ return tags.includes("eval:reasoning");
181
+ case "hallucination":
182
+ return tags.includes("eval:hallucination");
183
+ case "rag":
184
+ return tags.includes("eval:rag");
185
+ case "language":
186
+ return tags.some((tag) => tag.startsWith("language:"));
187
+ case "vision":
188
+ return tags.some(
189
+ (tag) => tag === "modality:video" || tag === "modality:image"
190
+ );
191
+ case "threeD":
192
+ return tags.includes("modality:3d");
193
+ case "audio":
194
+ return tags.includes("modality:audio");
195
+ case "financial":
196
+ return tags.includes("domain:financial");
197
+ case "medical":
198
+ return tags.includes("domain:medical");
199
+ case "legal":
200
+ return tags.includes("domain:legal");
201
+ case "biology":
202
+ return tags.includes("domain:biology");
203
+ case "commercial":
204
+ return tags.includes("domain:commercial");
205
+ case "translation":
206
+ return tags.includes("domain:translation");
207
+ case "chemistry":
208
+ return tags.includes("domain:chemistry");
209
+ case "safety":
210
+ return tags.includes("eval:safety");
211
+ case "performance":
212
+ return tags.includes("eval:performance");
213
+ case "uncategorized":
214
+ return !tags.some(
215
+ (tag) =>
216
+ CATEGORIZATION_TAGS.includes(tag) ||
217
+ tag.startsWith("language:")
218
+ );
219
+ default:
220
+ return false;
221
+ }
222
+ });
223
+ };
224
+
225
+ // Now calculate counts for each section based on the filtered boards
226
+ allSections.forEach(({ id, title }) => {
227
+ let sectionBoards = baseFiltered
228
+ .filter((board) => applyCategoryFilters(board, id))
229
+ .filter((board) => {
230
+ const tags = board.tags || [];
231
+ switch (id) {
232
+ case "agentic":
233
+ return tags.includes("modality:agent");
234
+ case "text":
235
+ return tags.includes("modality:text");
236
+ case "image":
237
+ return tags.includes("modality:image");
238
+ case "video":
239
+ return tags.includes("modality:video");
240
+ case "code":
241
+ return tags.includes("eval:code");
242
+ case "math":
243
+ return tags.includes("eval:math");
244
+ case "reasoning":
245
+ return tags.includes("eval:reasoning");
246
+ case "hallucination":
247
+ return tags.includes("eval:hallucination");
248
+ case "rag":
249
+ return tags.includes("eval:rag");
250
+ case "language":
251
+ return tags.some((tag) => tag.startsWith("language:"));
252
+ case "vision":
253
+ return tags.some(
254
+ (tag) => tag === "modality:video" || tag === "modality:image"
255
+ );
256
+ case "threeD":
257
+ return tags.includes("modality:3d");
258
+ case "audio":
259
+ return tags.includes("modality:audio");
260
+ case "financial":
261
+ return tags.includes("domain:financial");
262
+ case "medical":
263
+ return tags.includes("domain:medical");
264
+ case "legal":
265
+ return tags.includes("domain:legal");
266
+ case "biology":
267
+ return tags.includes("domain:biology");
268
+ case "commercial":
269
+ return tags.includes("domain:commercial");
270
+ case "translation":
271
+ return tags.includes("domain:translation");
272
+ case "chemistry":
273
+ return tags.includes("domain:chemistry");
274
+ case "safety":
275
+ return tags.includes("eval:safety");
276
+ case "performance":
277
+ return tags.includes("eval:performance");
278
+ case "uncategorized":
279
+ return !tags.some(
280
+ (tag) =>
281
+ CATEGORIZATION_TAGS.includes(tag) ||
282
+ tag.startsWith("language:")
283
+ );
284
+ default:
285
+ return false;
286
+ }
287
+ });
288
+
289
+ // Only count approved leaderboards
290
+ sectionBoards = sectionBoards.filter(
291
+ (board) => board.approval_status === "approved"
292
+ );
293
+ counts.set(id, sectionBoards.length);
294
  });
295
+
296
  return counts;
297
+ }, [
298
+ allSections,
299
+ arenaOnly,
300
+ searchQuery,
301
+ selectedLanguage,
302
+ selectedCategories,
303
+ ]);
304
 
305
  // Update the search query after debounce
306
  React.useEffect(() => {
client/src/components/LeaderboardSection/components/LanguageList.jsx CHANGED
@@ -126,7 +126,7 @@ const LanguageList = ({
126
  }}
127
  >
128
  {familyLanguages.map((lang) => {
129
- const isActive = selectedLanguage === lang;
130
  const count = filteredLanguageStats.get(lang) || 0;
131
 
132
  return (
@@ -135,7 +135,7 @@ const LanguageList = ({
135
  label={capitalize(lang)}
136
  count={count}
137
  isActive={isActive}
138
- onClick={() => onLanguageSelect(isActive ? null : lang)}
139
  colors={LANGUAGE_COLORS}
140
  />
141
  );
 
126
  }}
127
  >
128
  {familyLanguages.map((lang) => {
129
+ const isActive = selectedLanguage.has(lang);
130
  const count = filteredLanguageStats.get(lang) || 0;
131
 
132
  return (
 
135
  label={capitalize(lang)}
136
  count={count}
137
  isActive={isActive}
138
+ onClick={() => onLanguageSelect(lang)}
139
  colors={LANGUAGE_COLORS}
140
  />
141
  );
client/src/context/LeaderboardContext.jsx CHANGED
@@ -63,7 +63,7 @@ export const LeaderboardProvider = ({ children }) => {
63
  new Set(params.categories || [])
64
  );
65
  const [selectedLanguage, setSelectedLanguage] = useState(
66
- params.language || null
67
  );
68
  const [expandedSections, setExpandedSections] = useState(
69
  new Set(params.categories || [])
@@ -78,7 +78,10 @@ export const LeaderboardProvider = ({ children }) => {
78
  categories: Array.from(selectedCategories),
79
  search: searchQuery,
80
  arena: arenaOnly ? "true" : null,
81
- language: selectedLanguage,
 
 
 
82
  languageExpanded: isLanguageExpanded ? "true" : null,
83
  });
84
  }, [
@@ -116,13 +119,21 @@ export const LeaderboardProvider = ({ children }) => {
116
 
117
  // On réinitialise la langue sélectionnée seulement si on désélectionne "language"
118
  if (categoryId === "language") {
119
- setSelectedLanguage(null);
120
  }
121
  }, []);
122
 
123
  // Wrapper pour la sélection de langue
124
  const handleLanguageSelection = useCallback((language) => {
125
- setSelectedLanguage((prev) => (prev === language ? null : language));
 
 
 
 
 
 
 
 
126
  }, []);
127
 
128
  // Filter leaderboards based on search query and arena toggle, ignoring category selection
@@ -175,12 +186,13 @@ export const LeaderboardProvider = ({ children }) => {
175
 
176
  let filtered = filterLeaderboardsForCount(boards);
177
 
178
- // Filter by selected language if any
179
- if (selectedLanguage) {
180
  filtered = filtered.filter((board) =>
181
- board.tags?.some(
182
- (tag) =>
183
- tag.toLowerCase() === `language:${selectedLanguage.toLowerCase()}`
 
184
  )
185
  );
186
  }
@@ -621,7 +633,7 @@ export const LeaderboardProvider = ({ children }) => {
621
  setSearchQuery("");
622
  setArenaOnly(false);
623
  setSelectedCategories(new Set());
624
- setSelectedLanguage(null);
625
  setExpandedSections(new Set());
626
  setIsLanguageExpanded(false);
627
  }, []);
 
63
  new Set(params.categories || [])
64
  );
65
  const [selectedLanguage, setSelectedLanguage] = useState(
66
+ params.language ? new Set(params.language.split(",")) : new Set()
67
  );
68
  const [expandedSections, setExpandedSections] = useState(
69
  new Set(params.categories || [])
 
78
  categories: Array.from(selectedCategories),
79
  search: searchQuery,
80
  arena: arenaOnly ? "true" : null,
81
+ language:
82
+ selectedLanguage.size > 0
83
+ ? Array.from(selectedLanguage).join(",")
84
+ : null,
85
  languageExpanded: isLanguageExpanded ? "true" : null,
86
  });
87
  }, [
 
119
 
120
  // On réinitialise la langue sélectionnée seulement si on désélectionne "language"
121
  if (categoryId === "language") {
122
+ setSelectedLanguage(new Set());
123
  }
124
  }, []);
125
 
126
  // Wrapper pour la sélection de langue
127
  const handleLanguageSelection = useCallback((language) => {
128
+ setSelectedLanguage((prev) => {
129
+ const newSet = new Set(prev);
130
+ if (newSet.has(language)) {
131
+ newSet.delete(language);
132
+ } else {
133
+ newSet.add(language);
134
+ }
135
+ return newSet;
136
+ });
137
  }, []);
138
 
139
  // Filter leaderboards based on search query and arena toggle, ignoring category selection
 
186
 
187
  let filtered = filterLeaderboardsForCount(boards);
188
 
189
+ // Filter by selected languages if any
190
+ if (selectedLanguage.size > 0) {
191
  filtered = filtered.filter((board) =>
192
+ Array.from(selectedLanguage).some((lang) =>
193
+ board.tags?.some(
194
+ (tag) => tag.toLowerCase() === `language:${lang.toLowerCase()}`
195
+ )
196
  )
197
  );
198
  }
 
633
  setSearchQuery("");
634
  setArenaOnly(false);
635
  setSelectedCategories(new Set());
636
+ setSelectedLanguage(new Set());
637
  setExpandedSections(new Set());
638
  setIsLanguageExpanded(false);
639
  }, []);