Begin plugins system

This commit is contained in:
2025-08-07 01:12:58 -04:00
parent 544207e9a2
commit 3a443d1727
53 changed files with 5873 additions and 2547 deletions

View File

@@ -63,7 +63,7 @@ export function ExperimentForm({ mode, experimentId }: ExperimentFormProps) {
resolver: zodResolver(experimentSchema),
defaultValues: {
status: "draft" as const,
studyId: selectedStudyId || "",
studyId: selectedStudyId ?? "",
},
});
@@ -84,13 +84,36 @@ export function ExperimentForm({ mode, experimentId }: ExperimentFormProps) {
// Set breadcrumbs
const breadcrumbs = [
{ label: "Dashboard", href: "/dashboard" },
{ label: "Experiments", href: "/experiments" },
...(mode === "edit" && experiment
{ label: "Studies", href: "/studies" },
...(selectedStudyId
? [
{ label: experiment.name, href: `/experiments/${experiment.id}` },
{ label: "Edit" },
{
label: experiment?.study?.name ?? "Study",
href: `/studies/${selectedStudyId}`,
},
{ label: "Experiments", href: "/experiments" },
...(mode === "edit" && experiment
? [
{
label: experiment.name,
href: `/experiments/${experiment.id}`,
},
{ label: "Edit" },
]
: [{ label: "New Experiment" }]),
]
: [{ label: "New Experiment" }]),
: [
{ label: "Experiments", href: "/experiments" },
...(mode === "edit" && experiment
? [
{
label: experiment.name,
href: `/experiments/${experiment.id}`,
},
{ label: "Edit" },
]
: [{ label: "New Experiment" }]),
]),
];
useBreadcrumbsEffect(breadcrumbs);
@@ -128,14 +151,14 @@ export function ExperimentForm({ mode, experimentId }: ExperimentFormProps) {
if (mode === "create") {
const newExperiment = await createExperimentMutation.mutateAsync({
...data,
estimatedDuration: data.estimatedDuration || undefined,
estimatedDuration: data.estimatedDuration ?? undefined,
});
router.push(`/experiments/${newExperiment.id}/designer`);
} else {
const updatedExperiment = await updateExperimentMutation.mutateAsync({
id: experimentId!,
...data,
estimatedDuration: data.estimatedDuration || undefined,
estimatedDuration: data.estimatedDuration ?? undefined,
});
router.push(`/experiments/${updatedExperiment.id}`);
}

File diff suppressed because it is too large Load Diff

View File

@@ -183,14 +183,16 @@ export const experimentsColumns: ColumnDef<Experiment>[] = [
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
onCheckedChange={(value: boolean) =>
table.toggleAllPageRowsSelected(!!value)
}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
onCheckedChange={(value: boolean) => row.toggleSelected(!!value)}
aria-label="Select row"
/>
),
@@ -231,12 +233,13 @@ export const experimentsColumns: ColumnDef<Experiment>[] = [
<DataTableColumnHeader column={column} title="Study" />
),
cell: ({ row }) => {
const study = row.getValue("study") as Experiment["study"];
const study = row.original.study;
if (!study?.id || !study?.name)
return <span className="text-muted-foreground">No study</span>;
return (
<Link
href={`/studies/${study.id}`}
className="block max-w-[140px] truncate text-sm hover:underline"
title={study.name}
className="text-primary hover:underline"
>
{study.name}
</Link>
@@ -250,8 +253,8 @@ export const experimentsColumns: ColumnDef<Experiment>[] = [
<DataTableColumnHeader column={column} title="Status" />
),
cell: ({ row }) => {
const status = row.getValue("status") as keyof typeof statusConfig;
const config = statusConfig[status];
const status = row.getValue("status");
const config = statusConfig[status as keyof typeof statusConfig];
return (
<Badge
@@ -264,7 +267,7 @@ export const experimentsColumns: ColumnDef<Experiment>[] = [
);
},
filterFn: (row, id, value: string[]) => {
return value.includes(row.getValue(id) as string);
return value.includes(row.getValue(id));
},
},
{
@@ -296,20 +299,23 @@ export const experimentsColumns: ColumnDef<Experiment>[] = [
<DataTableColumnHeader column={column} title="Owner" />
),
cell: ({ row }) => {
const owner = row.getValue("owner") as Experiment["owner"];
const owner = row.original.owner;
if (!owner) {
return <span className="text-muted-foreground">No owner</span>;
}
return (
<div className="max-w-[140px] space-y-1">
<div
className="truncate text-sm font-medium"
title={owner?.name ?? "Unknown"}
title={owner.name ?? "Unknown"}
>
{owner?.name ?? "Unknown"}
{owner.name ?? "Unknown"}
</div>
<div
className="text-muted-foreground truncate text-xs"
title={owner?.email}
title={owner.email ?? ""}
>
{owner?.email}
{owner.email ?? ""}
</div>
</div>
);

View File

@@ -46,10 +46,16 @@ export function ExperimentsDataTable() {
// Set breadcrumbs
useBreadcrumbsEffect([
{ label: "Dashboard", href: "/dashboard" },
{ label: "Studies", href: "/studies" },
...(activeStudy
? [{ label: activeStudy.title, href: `/studies/${activeStudy.id}` }]
: []),
{ label: "Experiments" },
? [
{
label: (activeStudy as { title: string; id: string }).title,
href: `/studies/${(activeStudy as { id: string }).id}`,
},
{ label: "Experiments" },
]
: [{ label: "Experiments" }]),
]);
// Transform experiments data to match the Experiment type expected by columns
@@ -101,7 +107,7 @@ export function ExperimentsDataTable() {
const filters = (
<div className="flex items-center space-x-2">
<Select value={statusFilter} onValueChange={setStatusFilter}>
<SelectTrigger className="w-[140px]">
<SelectTrigger className="h-8 w-[140px]">
<SelectValue placeholder="Status" />
</SelectTrigger>
<SelectContent>