import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@openstatus/ui/components/ui/tooltip"; import { useEffect, useRef, useState } from "react"; import { Pill } from "@/components/common/pill"; import { cn } from "@/lib/utils"; /** Sorted `[key, value]` pairs with empty values dropped; `[]` for non-objects. */ export function getMetadataEntries(value: unknown): [string, string][] { if (!value || typeof value !== "object" || Array.isArray(value)) return []; return Object.entries(value) .filter((entry): entry is [string, string] => { return typeof entry[1] === "string" && entry[1].trim().length > 0; }) .sort(([a], [b]) => a.localeCompare(b)); } export function TableCellMetadata({ value, maxEntries, className, ...props }: React.ComponentProps<"div"> & { value: unknown; /** Collapse the rest into a `+n` chip with the full list in a tooltip. */ maxEntries?: number; }) { const entries = getMetadataEntries(value); if (entries.length === 0) { return (
-
); } const visible = maxEntries ? entries.slice(0, maxEntries) : entries; const hidden = maxEntries ? entries.slice(maxEntries) : []; return (
{visible.map(([key, val]) => ( ))} {hidden.length > 0 ? ( +{hidden.length} {hidden.map(([key, val]) => (
{key}: {val}
))}
) : null}
); } function MetadataPill({ label, value }: { label: string; value: string }) { const ref = useRef(null); const [isTruncated, setIsTruncated] = useState(false); useEffect(() => { if (ref.current) { setIsTruncated(ref.current.scrollWidth > ref.current.clientWidth); } }, [value]); const pill = ( {value} } variant="outline" /> ); if (!isTruncated) return pill; return ( event.preventDefault()} asChild>
{pill}
{label}: {value}
); }