diff --git a/components/PerformanceList/index.tsx b/components/PerformanceList/index.tsx index 6ba1c98a..8f1a87fc 100644 --- a/components/PerformanceList/index.tsx +++ b/components/PerformanceList/index.tsx @@ -6,31 +6,35 @@ import { ExplorerTooltip } from "@components/ExplorerTooltip"; import Link from "next/link"; import { useMemo } from "react"; import QRCode from "qrcode.react"; -import { useAllScoreData, useEnsData } from "hooks"; +import { useEnsData } from "hooks"; import { OrchestratorsQueryResult } from "apollo"; import numeral from "numeral"; import { Pipeline } from "@lib/api/types/get-available-pipelines"; import { Region } from "@lib/api/types/get-regions"; +import { AllPerformanceMetrics } from "@lib/api/types/get-performance"; const EmptyData = () => ; const PerformanceList = ({ - data, + orchestratorIds, pageSize = 20, region, pipeline, model, + performanceMetrics = null, + isLoadingMetrics = false, }: { pageSize: number; region: Region["id"]; pipeline: Pipeline["id"] | null; model: string | null; - data: Pick< + performanceMetrics?: AllPerformanceMetrics | null; + isLoadingMetrics?: boolean; + orchestratorIds: Pick< NonNullable["transcoders"][number], "id" >[]; }) => { - const {isValidating, data: allScores} = useAllScoreData(pipeline, model); const isAIData = pipeline !== null && model !== null; const scoreAccessor = `scores.${region}`;//total score const successRateAccessor = `successRates.${region}`;//success rate @@ -53,8 +57,8 @@ const PerformanceList = ({ }; const mergedData = useMemo( - () => data.map((o) => ({ ...o, ...allScores?.[o?.id] })), - [allScores, data] + () => orchestratorIds.map((o) => ({ ...o, ...performanceMetrics?.[o?.id] })), + [performanceMetrics, orchestratorIds] ); //tanstack v7's numberic sorting function incorrectly treats 0, null, and undefined as 0 (the same value). @@ -215,11 +219,8 @@ const PerformanceList = ({ defaultCanSort: true, sortType: sortTypeFn, Cell: ({ value }) => { - if ( - isValidating - ) { - return ; - } + if (isLoadingMetrics) return ; + return ( {typeof value === "undefined" || value === null ? @@ -251,9 +252,8 @@ const PerformanceList = ({ accessor: `${successRateAccessor}`, sortType: sortTypeFn, Cell: ({ value }) => { - if (isValidating) { - return ; - } + if (isLoadingMetrics) return ; + return ( {typeof value === "undefined" || value === null ? @@ -286,9 +286,8 @@ const PerformanceList = ({ accessor: `${roundTripScoreAccessor}`, sortType: sortTypeFn, Cell: ({ value }) => { - if (isValidating) { - return ; - } + if (isLoadingMetrics) return ; + return ( {typeof value === "undefined" || value === null ? @@ -302,7 +301,7 @@ const PerformanceList = ({ }, }, ], - [region, isValidating] + [region, isLoadingMetrics] ); return ( diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 4985563f..e5c4edd6 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -6,10 +6,10 @@ import { EnsIdentity } from "@lib/api/types/get-ens"; import { Box, Container, Flex, Heading } from "@livepeer/design-system"; import { ChevronDownIcon } from "@modulz/radix-icons"; import Head from "next/head"; -import { useState } from "react"; +import { useState, useMemo } from "react"; import { getApollo, OrchestratorsQueryResult } from "../apollo"; import { Pipeline } from "@lib/api/types/get-available-pipelines"; -import { useRegionsData } from "hooks/useSwr"; +import { useRegionsData, useAllScoreData } from "hooks/useSwr"; import { Region } from "@lib/api/types/get-regions"; type PageProps = { @@ -25,6 +25,36 @@ const LeaderboardPage = ({ orchestratorIds }: PageProps) => { const [selectedModel, setSelectedModel] = useState(null); const knownRegions = useRegionsData(); const [region, setRegion] = useState("GLOBAL"); + const { data: allScores, isValidating } = useAllScoreData(selectedPipeline, selectedModel); + + // Filter regions to only show those with data. + const availableRegions = useMemo(() => { + if (!knownRegions?.regions) return []; + + const pipelineType = selectedPipeline ? "ai" : "transcoding"; + + // If no scores loaded yet, just filter by pipeline type. + if (!allScores) { + return knownRegions.regions.filter((r) => r.type === pipelineType); + } + + // Collect regions that have score data. + const regionsWithData = new Set(); + Object.values(allScores).forEach((orchestratorData) => { + if (orchestratorData?.scores) { + Object.entries(orchestratorData.scores).forEach(([regionKey, value]) => { + if (value != null) { + regionsWithData.add(regionKey); + } + }); + } + }); + + // Filter regions based on pipeline type and data availability. + return knownRegions.regions.filter( + (r) => r.type === pipelineType && regionsWithData.has(r.id) + ); + }, [knownRegions?.regions, allScores, selectedPipeline]); return ( <> @@ -99,9 +129,7 @@ const LeaderboardPage = ({ orchestratorIds }: PageProps) => { appearance: "none", }} > - {knownRegions?.regions - .filter((r) => r.type === (selectedPipeline?"ai":"transcoding")) - .map((region) => { + {availableRegions.map((region) => { return ( {region.name} ) @@ -137,11 +165,13 @@ const LeaderboardPage = ({ orchestratorIds }: PageProps) => {