"use client"; import { type ColumnDef } from "@tanstack/react-table"; import { formatDistanceToNow } from "date-fns"; import { Copy, Edit, Eye, FlaskConical, MoreHorizontal, Play, TestTube, Trash2, } from "lucide-react"; import Link from "next/link"; import { toast } from "sonner"; import { Badge } from "~/components/ui/badge"; import { Button } from "~/components/ui/button"; import { Checkbox } from "~/components/ui/checkbox"; import { DataTableColumnHeader } from "~/components/ui/data-table-column-header"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "~/components/ui/dropdown-menu"; export type Experiment = { id: string; name: string; description: string | null; status: "draft" | "testing" | "ready" | "deprecated"; createdAt: Date; updatedAt: Date; studyId: string; study: { id: string; name: string; }; createdBy: string; owner: { name: string | null; email: string; }; _count?: { steps: number; trials: number; }; userRole?: "owner" | "researcher" | "wizard" | "observer"; canEdit?: boolean; canDelete?: boolean; }; const statusConfig = { draft: { label: "Draft", className: "bg-gray-100 text-gray-800 hover:bg-gray-200", description: "Experiment in preparation", }, testing: { label: "Testing", className: "bg-yellow-100 text-yellow-800 hover:bg-yellow-200", description: "Experiment being tested", }, ready: { label: "Ready", className: "bg-green-100 text-green-800 hover:bg-green-200", description: "Experiment ready for trials", }, deprecated: { label: "Deprecated", className: "bg-slate-100 text-slate-800 hover:bg-slate-200", description: "Experiment deprecated", }, }; function ExperimentActionsCell({ experiment }: { experiment: Experiment }) { const handleDelete = async () => { if ( window.confirm(`Are you sure you want to delete "${experiment.name}"?`) ) { try { // TODO: Implement delete experiment mutation toast.success("Experiment deleted successfully"); } catch { toast.error("Failed to delete experiment"); } } }; const handleCopyId = () => { void navigator.clipboard.writeText(experiment.id); toast.success("Experiment ID copied to clipboard"); }; const handleStartTrial = () => { // Navigate to new trial creation with this experiment pre-selected window.location.href = `/studies/${experiment.studyId}/trials/new?experimentId=${experiment.id}`; }; return ( Actions View Details Open Designer {experiment.canEdit && ( Edit Experiment )} {experiment.status === "ready" && ( Start New Trial )} View Trials Copy Experiment ID {experiment.canDelete && ( <> Delete Experiment )} ); } export const experimentsColumns: ColumnDef[] = [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" /> ), enableSorting: false, enableHiding: false, }, { accessorKey: "name", header: ({ column }) => ( ), cell: ({ row }) => { const experiment = row.original; return (
{experiment.name} {experiment.description && (

{experiment.description}

)}
); }, }, { accessorKey: "study", header: ({ column }) => ( ), cell: ({ row }) => { const study = row.getValue("study") as Experiment["study"]; return ( {study.name} ); }, enableSorting: false, }, { accessorKey: "status", header: ({ column }) => ( ), cell: ({ row }) => { const status = row.getValue("status") as keyof typeof statusConfig; const config = statusConfig[status]; return ( {config.label} ); }, filterFn: (row, id, value: string[]) => { return value.includes(row.getValue(id) as string); }, }, { id: "stats", header: "Statistics", cell: ({ row }) => { const experiment = row.original; const counts = experiment._count; return (
{counts?.steps ?? 0}
{counts?.trials ?? 0}
); }, enableSorting: false, enableHiding: false, }, { accessorKey: "owner", header: ({ column }) => ( ), cell: ({ row }) => { const owner = row.getValue("owner") as Experiment["owner"]; return (
{owner?.name ?? "Unknown"}
{owner?.email}
); }, enableSorting: false, }, { accessorKey: "createdAt", header: ({ column }) => ( ), cell: ({ row }) => { const date = row.getValue("createdAt"); return (
{formatDistanceToNow(date as Date, { addSuffix: true })}
); }, }, { accessorKey: "updatedAt", header: ({ column }) => ( ), cell: ({ row }) => { const date = row.getValue("updatedAt"); return (
{formatDistanceToNow(date as Date, { addSuffix: true })}
); }, }, { id: "actions", header: "Actions", cell: ({ row }) => , enableSorting: false, enableHiding: false, }, ];