import { StatusBadge } from "@/src/components/layouts/status-badge"; import { DataTable } from "@/src/components/table/data-table"; import { useRowHeightLocalStorage } from "@/src/components/table/data-table-row-height-switch"; import { DataTableToolbar } from "@/src/components/table/data-table-toolbar"; import { DataTableControlsProvider, DataTableControls, } from "@/src/components/table/data-table-controls"; import { ResizableFilterLayout } from "@/src/components/table/resizable-filter-layout"; import TableLink from "@/src/components/table/table-link"; import { type LangfuseColumnDef } from "@/src/components/table/types"; import { IOTableCell } from "@/src/components/ui/IOTableCell"; import useColumnOrder from "@/src/features/column-visibility/hooks/useColumnOrder"; import useColumnVisibility from "@/src/features/column-visibility/hooks/useColumnVisibility"; import { useSidebarFilterState } from "@/src/features/filters/hooks/useSidebarFilterState"; import { evalLogFilterConfig } from "@/src/features/filters/config/eval-logs-config"; import { type RouterOutputs, api } from "@/src/utils/api"; import { safeExtract } from "@/src/utils/map-utils"; import { type Prisma } from "@langfuse/shared"; import { createColumnHelper } from "@tanstack/react-table"; import { useQueryParams, withDefault, NumberParam } from "use-query-params"; export type JobExecutionRow = { status: string; scoreName?: string; scoreValue?: number; scoreComment?: string; scoreMetadata?: Prisma.JsonValue; startTime?: string; endTime?: string; traceId?: string; sessionId?: string; executionTraceId?: string; templateId: string; evaluatorId: string; error?: string; }; export default function EvalLogTable({ projectId, jobConfigurationId, }: { projectId: string; jobConfigurationId?: string; }) { const [rowHeight, setRowHeight] = useRowHeightLocalStorage("evalLogs", "s"); const [paginationState, setPaginationState] = useQueryParams({ pageIndex: withDefault(NumberParam, 0), pageSize: withDefault(NumberParam, 50), }); const queryFilter = useSidebarFilterState( evalLogFilterConfig, {}, // No dynamic options needed - status options are in column definition projectId, false, ); const logs = api.evals.getLogs.useQuery({ page: paginationState.pageIndex, limit: paginationState.pageSize, filter: queryFilter.filterState, jobConfigurationId, projectId, }); const totalCount = logs.data?.totalCount ?? null; const columnHelper = createColumnHelper(); const columns = [ columnHelper.accessor("status", { header: "Status", id: "status", cell: (row) => { const status = row.getValue(); return ; }, }), columnHelper.accessor("startTime", { id: "startTime", header: "Start Time", enableHiding: true, }), columnHelper.accessor("endTime", { id: "endTime", header: "End Time", enableHiding: true, }), columnHelper.accessor("scoreName", { header: "Score Name", id: "scoreName", enableHiding: true, }), columnHelper.accessor("scoreValue", { header: "Score Value", id: "scoreValue", enableHiding: true, cell: (row) => { const value = row.getValue(); if (value === undefined) { return undefined; } return value % 1 === 0 ? value : value.toFixed(4); }, }), columnHelper.accessor("scoreComment", { header: "Score Comment", id: "scoreComment", enableHiding: true, cell: (row) => { const value = row.getValue(); return ( value !== undefined && ( ) ); }, }), columnHelper.accessor("error", { id: "error", header: "Error", enableHiding: true, cell: (row) => { const value = row.getValue(); return ( value !== undefined && ( ) ); }, }), columnHelper.accessor("traceId", { id: "traceId", header: "Target Trace", cell: (row) => { const traceId = row.getValue(); return traceId ? ( ) : undefined; }, }), columnHelper.accessor("sessionId", { id: "sessionId", header: "Session", enableHiding: true, cell: (row) => { const sessionId = row.getValue(); return sessionId ? ( ) : undefined; }, }), columnHelper.accessor("executionTraceId", { id: "executionTraceId", header: "Execution Trace", enableHiding: true, cell: (row) => { const traceId = row.getValue(); return traceId ? ( ) : undefined; }, }), columnHelper.accessor("templateId", { id: "templateId", header: "Template", cell: (row) => { const templateId = row.getValue(); return templateId ? ( ) : undefined; }, }), ] as LangfuseColumnDef[]; if (!jobConfigurationId) { columns.push( columnHelper.accessor("evaluatorId", { id: "evaluatorId", header: "Evaluator", cell: (row) => { const evaluatorId = row.getValue(); return evaluatorId ? ( ) : undefined; }, }) as LangfuseColumnDef, ); } const [columnVisibility, setColumnVisibility] = useColumnVisibility("evalLogColumnVisibility", columns); const [columnOrder, setColumnOrder] = useColumnOrder( "evalLogColumnOrder", columns, ); const convertToTableRow = ( jobConfig: RouterOutputs["evals"]["getLogs"]["data"][number], ): JobExecutionRow => { return { status: jobConfig.status, scoreName: jobConfig.score?.name ?? undefined, scoreValue: jobConfig.score?.value ?? undefined, scoreComment: jobConfig.score?.comment ?? undefined, scoreMetadata: jobConfig.score?.metadata ?? undefined, startTime: jobConfig.startTime?.toLocaleString() ?? undefined, endTime: jobConfig.endTime?.toLocaleString() ?? undefined, traceId: jobConfig.jobInputTraceId ?? undefined, sessionId: jobConfig.sessionId ?? undefined, executionTraceId: jobConfig.executionTraceId ?? undefined, templateId: jobConfig.jobTemplateId ?? "", evaluatorId: jobConfig.jobConfigurationId, error: jobConfig.error ?? undefined, }; }; return (
convertToTableRow(t), ), } } pagination={{ totalCount, onChange: setPaginationState, state: paginationState, }} columnVisibility={columnVisibility} onColumnVisibilityChange={setColumnVisibility} columnOrder={columnOrder} onColumnOrderChange={setColumnOrder} />
); }