import { HoverCard, HoverCardContent, HoverCardTrigger, } from "@/src/components/ui/hover-card"; import { type CategoricalAggregate, type AggregatedScoreData, } from "@langfuse/shared"; import { numberFormatter } from "@/src/utils/numbers"; import { cn } from "@/src/utils/tailwind"; import { BracesIcon, MessageCircleMore, Copy, Check } from "lucide-react"; import { JSONView } from "@/src/components/ui/CodeJsonViewer"; import { api } from "@/src/utils/api"; import useProjectIdFromURL from "@/src/hooks/useProjectIdFromURL"; import { Skeleton } from "@/src/components/ui/skeleton"; import React from "react"; import { copyTextToClipboard } from "@/src/utils/clipboard"; import { Button } from "@/src/components/ui/button"; const COLOR_MAP = new Map([ ["True", "bg-light-green p-0.5 text-dark-green"], ["False", "bg-light-red p-0.5 text-dark-red"], ]); const COLLAPSE_CATEGORICAL_SCORES_AFTER = 2; const ScoreValueCounts = ({ valueCounts, wrap, }: { valueCounts: CategoricalAggregate["valueCounts"]; wrap: boolean; }) => { return valueCounts.map(({ value, count }, index) => (
{value} {`: ${numberFormatter(count, 0)}`} {!wrap && index < valueCounts.length - 1 && ( {";"} )}
)); }; export const ScoresTableCell = ({ aggregate, displayFormat, wrap = true, hasMetadata, }: { aggregate: AggregatedScoreData; displayFormat: "smart" | "aggregate"; wrap?: boolean; hasMetadata?: boolean; }) => { const projectId = useProjectIdFromURL(); const [copied, setCopied] = React.useState(false); const handleCopy = async (e: React.MouseEvent) => { e.stopPropagation(); if (aggregate.comment) { await copyTextToClipboard(aggregate.comment); setCopied(true); setTimeout(() => setCopied(false), 2000); } }; if (displayFormat === "smart" && aggregate.values.length === 1 && projectId) { const value = aggregate.type === "NUMERIC" ? aggregate.average.toFixed(4) : aggregate.values[0]; return ( {value} {aggregate.comment && (

{aggregate.comment}

)} {hasMetadata && !!aggregate.id && ( )}
); } if (aggregate.type === "NUMERIC") { return ( {`Ø ${aggregate.average.toFixed(4)}`} ); } return (
{aggregate.valueCounts.length > COLLAPSE_CATEGORICAL_SCORES_AFTER ? (
) : (
)}
); }; function AggregateScoreMetadataPeek({ scoreId, projectId, }: { scoreId: string; projectId: string; }) { const [isOpen, setIsOpen] = React.useState(false); const { data: metadata } = api.scores.getScoreMetadataById.useQuery( { projectId, id: scoreId, }, { enabled: !!projectId && !!scoreId && isOpen, trpc: { context: { skipBatch: true, }, }, refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false, staleTime: Infinity, }, ); const metadataLoaded = metadata && Object.keys(metadata).length > 0; return ( {metadataLoaded ? ( ) : ( )} ); }