Spaces:
Running
Running
Last commit not found
import React, { useState, useEffect, useMemo } from "react"; | |
import { | |
Box, | |
CircularProgress, | |
Typography, | |
Chip, | |
Tooltip, | |
} from "@mui/material"; | |
import SearchOffIcon from "@mui/icons-material/SearchOff"; | |
import WarningAmberIcon from "@mui/icons-material/WarningAmber"; | |
import Logo from "../../components/Logo/Logo"; | |
import PageTitle from "../../components/PageTitle/PageTitle"; | |
import LeaderboardSection from "../../components/LeaderboardSection"; | |
import LeaderboardFilters from "../../components/LeaderboardFilters/LeaderboardFilters"; | |
import API_URLS from "../../config/api"; | |
import { | |
LeaderboardProvider, | |
useLeaderboard, | |
} from "../../context/LeaderboardContext"; | |
import EmptyState from "../../components/LeaderboardSection/components/EmptyState"; | |
const LeaderboardPageContent = () => { | |
const [loading, setLoading] = useState(true); | |
const [showUncategorized, setShowUncategorized] = useState(false); | |
const { | |
setLeaderboards, | |
filterLeaderboards, | |
sections, | |
allSections, | |
sectionsSortedByCount, | |
searchQuery, | |
arenaOnly, | |
selectedCategories, | |
leaderboards, | |
} = useLeaderboard(); | |
// Vérifier si on a uniquement une recherche textuelle active ou arena only | |
const isOnlyTextSearch = | |
(searchQuery || arenaOnly) && selectedCategories.size === 0; | |
// Obtenir tous les leaderboards uniques de toutes les sections | |
const allUniqueLeaderboards = useMemo(() => { | |
if (!allSections) return []; | |
return Array.from( | |
new Set( | |
allSections.reduce((acc, section) => { | |
return [...acc, ...(section.data || [])]; | |
}, []) | |
) | |
); | |
}, [allSections]); | |
// Calculer le nombre de leaderboards non catégorisés | |
const uncategorizedLeaderboards = useMemo(() => { | |
if (!leaderboards || leaderboards.length === 0) return []; | |
return leaderboards.filter( | |
(board) => | |
board.approval_status === "approved" && | |
!board.tags?.some( | |
(tag) => | |
tag.startsWith("modality:") || | |
tag.startsWith("eval:") || | |
tag.startsWith("domain:") || | |
tag.startsWith("language:") | |
) | |
); | |
}, [leaderboards]); | |
// Filtrer tous les leaderboards pour la recherche textuelle ou arena only | |
const searchResults = useMemo(() => { | |
if (!isOnlyTextSearch) return []; | |
return filterLeaderboards(allUniqueLeaderboards); | |
}, [isOnlyTextSearch, filterLeaderboards, allUniqueLeaderboards]); | |
useEffect(() => { | |
fetch(API_URLS.leaderboards) | |
.then((res) => { | |
if (!res.ok) { | |
throw new Error(`Failed to fetch leaderboards: ${res.status}`); | |
} | |
return res.json(); | |
}) | |
.then((data) => { | |
// Les données sont directement dans le format attendu depuis le dataset HF | |
setLeaderboards(data); | |
setLoading(false); | |
}) | |
.catch((error) => { | |
console.error("Error fetching leaderboards:", error); | |
setLoading(false); | |
}); | |
}, [setLeaderboards]); | |
// Check if any leaderboards are found after filtering | |
const totalFilteredLeaderboards = sections.reduce( | |
(total, { data }) => total + filterLeaderboards(data).length, | |
0 | |
); | |
const hasLeaderboards = totalFilteredLeaderboards > 0; | |
const isFiltering = searchQuery || arenaOnly; | |
return ( | |
<Box | |
sx={{ | |
width: "100%", | |
ph: 2, | |
display: "flex", | |
flexDirection: "column", | |
}} | |
> | |
<Box | |
sx={{ display: "flex", justifyContent: "center", pt: 6, mb: -4, pb: 0 }} | |
> | |
<Logo /> | |
</Box> | |
<Box | |
sx={{ | |
display: "flex", | |
flexDirection: "column", | |
alignItems: "center", | |
textAlign: "center", | |
mb: 0, | |
mt: 6, | |
gap: 2, | |
}} | |
> | |
<PageTitle /> | |
<Typography variant="h6" color="text.secondary"> | |
<span style={{ fontWeight: 600 }}>Discover</span> and{" "} | |
<span style={{ fontWeight: 600 }}>explore</span> all leaderboards from | |
the <span style={{ fontWeight: 600 }}>Hugging Face community</span> | |
</Typography> | |
{uncategorizedLeaderboards.length > 0 && ( | |
<Tooltip | |
title={`${uncategorizedLeaderboards.length} leaderboards approuvés n'ont pas de catégorie et ne sont pas affichés dans les sections`} | |
> | |
<Chip | |
icon={<WarningAmberIcon />} | |
label={`${uncategorizedLeaderboards.length} leaderboards non catégorisés`} | |
color="warning" | |
variant="outlined" | |
sx={{ mt: 1 }} | |
onClick={() => { | |
console.log("=== LEADERBOARDS NON CATÉGORISÉS ==="); | |
console.table( | |
uncategorizedLeaderboards.map((board) => ({ | |
id: board.id, | |
uid: board.uid, | |
title: board.card_data?.title || "Sans titre", | |
tags: (board.tags || []).join(", "), | |
url: board.card_data?.url || "", | |
})) | |
); | |
setShowUncategorized(!showUncategorized); | |
}} | |
/> | |
</Tooltip> | |
)} | |
</Box> | |
{loading ? ( | |
<Box sx={{ display: "flex", justifyContent: "center", mt: 4 }}> | |
<CircularProgress /> | |
</Box> | |
) : ( | |
<Box | |
sx={{ | |
width: "100%", | |
maxWidth: "1200px", | |
mx: "auto", | |
mt: 4, | |
}} | |
> | |
<LeaderboardFilters allSections={allSections} /> | |
{/* Section pour les leaderboards non catégorisés */} | |
{showUncategorized && uncategorizedLeaderboards.length > 0 && ( | |
<Box | |
sx={{ | |
mb: 4, | |
p: 2, | |
border: "1px dashed", | |
borderColor: "warning.main", | |
borderRadius: 2, | |
bgcolor: (theme) => theme.palette.warning.light + "20", | |
}} | |
> | |
<LeaderboardSection | |
id="uncategorized" | |
title={`Leaderboards non catégorisés (${uncategorizedLeaderboards.length})`} | |
leaderboards={uncategorizedLeaderboards} | |
filteredLeaderboards={uncategorizedLeaderboards} | |
showEmptyState={false} | |
/> | |
</Box> | |
)} | |
{isOnlyTextSearch ? ( | |
// Vue spéciale pour la recherche textuelle | |
searchResults.length > 0 ? ( | |
<Box key="search-results"> | |
<LeaderboardSection | |
id="search-results" | |
title={ | |
searchQuery | |
? `All leaderboards matching "${searchQuery}"${ | |
arenaOnly ? " (Arena only)" : "" | |
}` | |
: "All Arena leaderboards" | |
} | |
leaderboards={allUniqueLeaderboards} | |
filteredLeaderboards={searchResults} | |
/> | |
</Box> | |
) : ( | |
// Message d'erreur pour la recherche textuelle sans résultats | |
<Box key="search-results"> | |
<LeaderboardSection | |
id="search-results" | |
title={ | |
searchQuery | |
? `All leaderboards matching "${searchQuery}"${ | |
arenaOnly ? " (Arena only)" : "" | |
}` | |
: "All Arena leaderboards" | |
} | |
leaderboards={allUniqueLeaderboards} | |
filteredLeaderboards={[]} | |
showEmptyState={true} | |
/> | |
</Box> | |
) | |
) : selectedCategories.size > 0 ? ( | |
// Si des catégories sont sélectionnées | |
selectedCategories.size === 1 ? ( | |
// Si une seule catégorie est sélectionnée, on affiche sa section | |
sections | |
.filter(({ id }) => selectedCategories.has(id)) | |
.map(({ id, title, data }) => { | |
const filteredLeaderboards = filterLeaderboards(data); | |
// Ajouter le terme de recherche au titre si présent | |
const sectionTitle = searchQuery | |
? `${title} matching "${searchQuery}"` | |
: title; | |
// Toujours afficher la section, même si elle est vide | |
return ( | |
<Box key={id} id={id}> | |
<LeaderboardSection | |
id={id} | |
title={sectionTitle} | |
leaderboards={data} | |
filteredLeaderboards={filteredLeaderboards} | |
showEmptyState={true} // Toujours afficher l'état vide sous le header | |
/> | |
</Box> | |
); | |
}) | |
) : ( | |
// Si plusieurs catégories sont sélectionnées, on les agrège | |
(() => { | |
// Agréger les données de toutes les sections sélectionnées | |
const selectedSections = sections.filter(({ id }) => | |
selectedCategories.has(id) | |
); | |
// Créer un titre combiné avec le terme de recherche si présent | |
const combinedTitle = selectedSections | |
.map(({ title }) => title) | |
.join(" + "); | |
const finalTitle = searchQuery | |
? `${combinedTitle} matching "${searchQuery}"` | |
: combinedTitle; | |
// Agréger les leaderboards | |
const combinedData = selectedSections.reduce( | |
(acc, { data }) => [...acc, ...data], | |
[] | |
); | |
// Filtrer les doublons par ID | |
const uniqueData = Array.from( | |
new Map(combinedData.map((item) => [item.id, item])).values() | |
); | |
const filteredLeaderboards = filterLeaderboards(uniqueData); | |
return ( | |
<Box key="combined"> | |
<LeaderboardSection | |
id="combined" | |
title={finalTitle} | |
leaderboards={uniqueData} | |
filteredLeaderboards={filteredLeaderboards} | |
showEmptyState={true} // Toujours afficher l'état vide sous le header | |
/> | |
</Box> | |
); | |
})() | |
) | |
) : ( | |
// Si aucune catégorie n'est sélectionnée, on affiche toutes les sections avec des résultats | |
// triées par nombre de leaderboards | |
(hasLeaderboards || !isFiltering) && | |
sectionsSortedByCount.map(({ id, title, data }) => { | |
const filteredLeaderboards = filterLeaderboards(data); | |
if (filteredLeaderboards.length === 0) return null; | |
return ( | |
<Box key={id} id={id}> | |
<LeaderboardSection | |
id={id} | |
title={title} | |
leaderboards={data} | |
filteredLeaderboards={filteredLeaderboards} | |
/> | |
</Box> | |
); | |
}) | |
)} | |
</Box> | |
)} | |
</Box> | |
); | |
}; | |
const LeaderboardPage = () => { | |
return ( | |
<LeaderboardProvider> | |
<LeaderboardPageContent /> | |
</LeaderboardProvider> | |
); | |
}; | |
export default LeaderboardPage; | |