import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/src/components/ui/accordion"; import { Skeleton } from "@/src/components/ui/skeleton"; import { Button } from "@/src/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/src/components/ui/dropdown-menu"; import { api } from "@/src/utils/api"; import { useDatasetVersion } from "../hooks/useDatasetVersion"; import { Clock, MoreVertical, Copy, ExternalLink } from "lucide-react"; import { format, isToday, isYesterday, isWithinInterval, subDays, startOfDay, formatDistanceToNow, } from "date-fns"; import { cn } from "@/src/utils/tailwind"; import { showSuccessToast } from "@/src/features/notifications/showSuccessToast"; type DatasetVersionHistoryPanelProps = { projectId: string; datasetId: string; itemVersions?: Date[]; // Optional: versions where a specific item changed }; type GroupedVersions = { today: Date[]; yesterday: Date[]; last7Days: Date[]; last30Days: Date[]; older: Date[]; }; function groupVersionsByTime(versions: Date[]): GroupedVersions { const now = new Date(); const dayStart = startOfDay(now); const sevenDaysAgo = subDays(now, 7); const thirtyDaysAgo = subDays(now, 30); return { today: versions.filter((v) => isToday(v)), yesterday: versions.filter((v) => isYesterday(v)), last7Days: versions.filter( (v) => !isToday(v) && !isYesterday(v) && isWithinInterval(v, { start: sevenDaysAgo, end: dayStart }), ), last30Days: versions.filter( (v) => !isWithinInterval(v, { start: sevenDaysAgo, end: now }) && isWithinInterval(v, { start: thirtyDaysAgo, end: now }), ), older: versions.filter((v) => v < thirtyDaysAgo), }; } export function DatasetVersionHistoryPanel({ projectId, datasetId, itemVersions, }: DatasetVersionHistoryPanelProps) { const { selectedVersion, setSelectedVersion, resetToLatest } = useDatasetVersion(); const { data: versions, isLoading } = api.datasets.listDatasetVersions.useQuery({ projectId, datasetId, }); const copyVersionTimestamp = (version: Date) => { const isoTimestamp = version.toISOString(); navigator.clipboard.writeText(isoTimestamp); showSuccessToast({ title: "Copied!", description: `Version timestamp: ${isoTimestamp}`, }); }; const openDocumentation = () => { window.open( "https://langfuse.com/docs/datasets/dataset-versioning", "_blank", ); }; if (isLoading) { return (
); } if (!versions || versions.length === 0) { return (

No versions found

); } const latestVersion = versions[0]; const groupedVersions = groupVersionsByTime(versions); const renderVersionItem = (version: Date, index: number) => { const isLatest = index === 0 && version === latestVersion; const isSelected = selectedVersion?.getTime() === version.getTime() || (isLatest && !selectedVersion); // Check if this version has item-specific changes const isItemVersion = itemVersions?.some( (iv) => iv.getTime() === version.getTime(), ); return (
{ e.stopPropagation(); copyVersionTimestamp(version); }} > Copy version timestamp (UTC) { e.stopPropagation(); openDocumentation(); }} > How to use in experiments
); }; return (
{/* Header */}

Version History

{versions.length} version{versions.length !== 1 ? "s" : ""}

{/* Versions List */}
{/* Today */} {groupedVersions.today.length > 0 && ( Today ({groupedVersions.today.length})
{groupedVersions.today.map((v, i) => renderVersionItem(v, i))}
)} {/* Yesterday */} {groupedVersions.yesterday.length > 0 && ( Yesterday ({groupedVersions.yesterday.length})
{groupedVersions.yesterday.map((v) => renderVersionItem(v, versions.indexOf(v)), )}
)} {/* Last 7 Days */} {groupedVersions.last7Days.length > 0 && ( Last 7 Days ({groupedVersions.last7Days.length})
{groupedVersions.last7Days.map((v) => renderVersionItem(v, versions.indexOf(v)), )}
)} {/* Last 30 Days */} {groupedVersions.last30Days.length > 0 && ( Last 30 Days ({groupedVersions.last30Days.length})
{groupedVersions.last30Days.map((v) => renderVersionItem(v, versions.indexOf(v)), )}
)} {/* Older */} {groupedVersions.older.length > 0 && ( Older ({groupedVersions.older.length})
{groupedVersions.older.map((v) => renderVersionItem(v, versions.indexOf(v)), )}
)}
); }