import { ChevronRight } from "lucide-react" import { useState } from "react" import type { DType } from "@/client" import { Marquee } from "@/components/Common/Marquee" import { cn, si } from "@/lib/utils" /** * How much of a structured value is worth unfolding in a side panel. * * The cap sits on the `pre` itself rather than on a `ScrollArea`: that one * sizes its viewport in percent, which resolves to the content's own height * against a box that has only a maximum, so a long value spills out of the * panel or popover and paints over whatever is below it. */ const MAX_HEIGHT = "max-h-48" function count(n: number, one: string, many = `${one}s`): string { return `${n} ${n === 1 ? one : many}` } /** Whether this is an artifact reference rather than data of its own. */ function isArtifact(value: Record): boolean { return typeof value.digest === "string" && value.digest.startsWith("sha256:") } /** * What a structured value *is*, in the space a value would have taken. * * The shape is what you want while wiring — that this port carries a record of * three fields, or a checkpoint of sixty kilobytes — and the contents are what * you want once something looks wrong. Serialising the whole thing into a line * answers the second question badly and the first one not at all. */ function summarize(value: object, dtype?: DType): string { if (Array.isArray(value)) { return `${dtype ?? "list"} · ${count(value.length, "item")}` } const record = value as Record if (isArtifact(record)) { const name = typeof record.name === "string" && record.name ? record.name : "" const size = typeof record.size === "number" ? `${si(record.size)}B` : "" // The media type when there is one: what kind of bytes these are is the // first thing worth knowing about a frame or a clip, and it is what the // port's own type was declared against. const media = typeof record.media_type === "string" && record.media_type && record.media_type !== "application/octet-stream" ? record.media_type : "artifact" return [media, name, size].filter(Boolean).join(" · ") } if (Array.isArray(record.lines)) { const points = record.lines.reduce( (total: number, line: unknown) => total + (Array.isArray((line as { points?: unknown[] })?.points) ? ((line as { points: unknown[] }).points.length as number) : 0), 0, ) return `series · ${count(record.lines.length, "line")}, ${count(points, "point")}` } return `${dtype ?? "record"} · ${count(Object.keys(record).length, "field")}` } /** * What a message is carrying: its shape at rest, its contents on request. * * A scalar simply reads, scrolling itself when it is longer than the room it * was given. Anything structured shows what it is and unfolds when asked — * which is what keeps a panel four hundred pixels wide from being pushed open * by one checkpoint reference. */ export function ValuePreview({ value, dtype, defaultOpen = false, className, }: { value: unknown dtype?: DType /** Start unfolded, where there is room for it — an inspector, not a row. */ defaultOpen?: boolean className?: string }) { const [open, setOpen] = useState(defaultOpen) const structured = value !== null && typeof value === "object" if (!structured) { return ( ) } return (