import { DataTable } from "@/src/components/table/data-table"; import { DataTableToolbar } from "@/src/components/table/data-table-toolbar"; import { FilteredRunPills } from "@/src/components/table/filtered-run-pills"; import TableLink from "@/src/components/table/table-link"; import { type LangfuseColumnDef } from "@/src/components/table/types"; import { IOTableCell } from "@/src/components/ui/IOTableCell"; import useColumnVisibility from "@/src/features/column-visibility/hooks/useColumnVisibility"; import { getDatasetRunAggregateColumnProps } from "@/src/features/datasets/components/DatasetRunAggregateColumnHelpers"; import { useDatasetRunAggregateColumns } from "@/src/features/datasets/hooks/useDatasetRunAggregateColumns"; import { NumberParam } from "use-query-params"; import { useQueryParams, withDefault } from "use-query-params"; import { useState, useEffect } from "react"; import { api } from "@/src/utils/api"; import { Button } from "@/src/components/ui/button"; import { LayoutList } from "lucide-react"; import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger, } from "@/src/components/ui/dropdown-menu"; import { useRowHeightLocalStorage } from "@/src/components/table/data-table-row-height-switch"; import { useDetailPageLists } from "@/src/features/navigate-detail-pages/context"; import { DatasetCompareFieldsProvider, useDatasetCompareFields, } from "@/src/features/datasets/contexts/DatasetCompareFieldsContext"; import { useColumnFilterState } from "@/src/features/filters/hooks/useColumnFilterState"; import { type Prisma } from "@langfuse/shared"; import { type EnrichedDatasetRunItem } from "@langfuse/shared/src/server"; import { usePeekNavigation } from "@/src/components/table/peek/hooks/usePeekNavigation"; import { PeekViewTraceDetail } from "@/src/components/table/peek/peek-trace-detail"; export type DatasetCompareRunRowData = { id: string; input: Prisma.JsonValue; expectedOutput: Prisma.JsonValue; metadata: Prisma.JsonValue; // runs holds grouped column with individual run metrics runs?: Record; }; function DatasetCompareRunsTableInternal(props: { projectId: string; datasetId: string; runIds: string[]; localExperiments: { key: string; value: string }[]; }) { const { toggleField, isFieldSelected } = useDatasetCompareFields(); const [isFieldsDropdownOpen, setIsFieldsDropdownOpen] = useState(false); const { updateColumnFilters: updateRunFilters, getFiltersForColumnById: getFiltersForRun, convertToColumnFilterList, } = useColumnFilterState(); const { setDetailPageList } = useDetailPageLists(); const [rowHeight, setRowHeight] = useRowHeightLocalStorage( "datasetCompareRuns", "m", ); useEffect(() => { const allFilters = convertToColumnFilterList(); allFilters.forEach((filter) => { if (!props.runIds.includes(filter.runId)) { updateRunFilters(filter.runId, []); } }); }, [props.runIds, convertToColumnFilterList, updateRunFilters]); const [paginationState, setPaginationState] = useQueryParams({ pageIndex: withDefault(NumberParam, 0), pageSize: withDefault(NumberParam, 50), }); const datasetItemsWithRunData = api.datasets.datasetItemsWithRunData.useQuery( { projectId: props.projectId, datasetId: props.datasetId, runIds: props.runIds, filterByRun: convertToColumnFilterList(), page: paginationState.pageIndex, limit: paginationState.pageSize, }, ); const totalCountQuery = api.datasets.runItemCompareCount.useQuery({ projectId: props.projectId, datasetId: props.datasetId, runIds: props.runIds, filterByRun: convertToColumnFilterList(), }); const totalCount = totalCountQuery.data?.totalCount ?? null; useEffect(() => { if (datasetItemsWithRunData.isSuccess) { setDetailPageList( "datasetCompareRuns", datasetItemsWithRunData.data?.data.map((item) => ({ id: item.id, })), ); } // Note: setDetailPageList dependency is not stable as the context provider creates a new function on every render // eslint-disable-next-line react-hooks/exhaustive-deps }, [datasetItemsWithRunData.isSuccess, datasetItemsWithRunData.data]); const { closePeek, expandPeek } = usePeekNavigation({ queryParams: ["observation", "display", "timestamp"], expandConfig: { basePath: `/project/${props.projectId}/traces`, }, }); const { runAggregateColumns, isLoading: cellsLoading } = useDatasetRunAggregateColumns({ projectId: props.projectId, runIds: props.runIds, datasetId: props.datasetId, updateRunFilters, getFiltersForRun, }); const columns: LangfuseColumnDef[] = [ { accessorKey: "id", header: "Item id", id: "id", size: 90, enableHiding: true, defaultHidden: true, cell: ({ row }) => { const id: string = row.getValue("id"); return ( ); }, }, { accessorKey: "input", header: "Input", id: "input", size: 200, enableHiding: true, cell: ({ row }) => { const input = row.getValue( "input", ) as DatasetCompareRunRowData["input"]; return input !== null ? (
) : null; }, }, { accessorKey: "expectedOutput", header: "Expected Output", id: "expectedOutput", size: 200, enableHiding: true, cell: ({ row }) => { const expectedOutput = row.getValue( "expectedOutput", ) as DatasetCompareRunRowData["expectedOutput"]; return expectedOutput !== null ? (
) : null; }, }, { accessorKey: "metadata", header: "Metadata", id: "metadata", size: 200, enableHiding: true, defaultHidden: true, cell: ({ row }) => { const metadata = row.getValue( "metadata", ) as DatasetCompareRunRowData["metadata"]; return metadata !== null ? : null; }, }, { ...getDatasetRunAggregateColumnProps(cellsLoading), columns: runAggregateColumns, }, ]; const rows = datasetItemsWithRunData.data?.data.map((item) => ({ ...item, runs: item.runData, })) ?? []; const [columnVisibility, setColumnVisibility] = useColumnVisibility( "datasetCompareRunsColumnVisibility", columns, ); return ( <> setIsFieldsDropdownOpen(false)} > toggleField("output")} > Output toggleField("scores")} > Scores toggleField("resourceMetrics")} > Latency and cost } /> , tableDataUpdatedAt: datasetItemsWithRunData.dataUpdatedAt, closePeek, expandPeek, // openPeek is handled by DatasetAggregateTableCell's custom handleOpenPeek }} /> ); } export function DatasetCompareRunsTable(props: { projectId: string; datasetId: string; runIds: string[]; localExperiments: { key: string; value: string }[]; }) { return ( ); }