Consolidate all study-dependent routes and UI

- Remove global experiments and plugins routes; redirect to study-scoped
  pages
- Update sidebar navigation to separate platform-level and study-level
  items
- Add study filter to dashboard and stats queries
- Refactor participants, trials, analytics pages to use new header and
  breadcrumbs
- Update documentation for new route architecture and migration guide
- Remove duplicate experiment creation route
- Upgrade Next.js to 15.5.4 in package.json and bun.lock
This commit is contained in:
2025-09-24 13:41:29 -04:00
parent e0679f726e
commit cd7c657d5f
18 changed files with 961 additions and 775 deletions

View File

@@ -1,12 +1,9 @@
"use client";
import { FlaskConical, Plus } from "lucide-react";
import React from "react";
import { useBreadcrumbsEffect } from "~/components/ui/breadcrumb-provider";
import { Button } from "~/components/ui/button";
import { DataTable } from "~/components/ui/data-table";
import { ActionButton, PageHeader } from "~/components/ui/page-header";
import {
Select,
SelectContent,
@@ -50,21 +47,6 @@ export function ExperimentsDataTable() {
return () => clearInterval(interval);
}, [refetch, selectedStudyId]);
// Set breadcrumbs
useBreadcrumbsEffect([
{ label: "Dashboard", href: "/dashboard" },
{ label: "Studies", href: "/studies" },
...(selectedStudyId
? [
{
label: "Experiments",
href: `/studies/${selectedStudyId}`,
},
{ label: "Experiments" },
]
: [{ label: "Experiments" }]),
]);
// Transform experiments data (already filtered by studyId) to match columns
const experiments: Experiment[] = React.useMemo(() => {
if (!experimentsData) return [];
@@ -149,61 +131,34 @@ export function ExperimentsDataTable() {
if (error) {
return (
<div className="space-y-6">
<PageHeader
title="Experiments"
description="Design and manage experimental protocols for your HRI studies"
icon={FlaskConical}
actions={
<ActionButton href="/experiments/new">
<Plus className="mr-2 h-4 w-4" />
New Experiment
</ActionButton>
}
/>
<div className="rounded-lg border border-red-200 bg-red-50 p-6 text-center">
<div className="text-red-800">
<h3 className="mb-2 text-lg font-semibold">
Failed to Load Experiments
</h3>
<p className="mb-4">
{error.message ||
"An error occurred while loading your experiments."}
</p>
<Button onClick={() => refetch()} variant="outline">
Try Again
</Button>
</div>
<div className="rounded-lg border border-red-200 bg-red-50 p-6 text-center">
<div className="text-red-800">
<h3 className="mb-2 text-lg font-semibold">
Failed to Load Experiments
</h3>
<p className="mb-4">
{error.message ||
"An error occurred while loading your experiments."}
</p>
<Button onClick={() => refetch()} variant="outline">
Try Again
</Button>
</div>
</div>
);
}
return (
<div className="space-y-6">
<PageHeader
title="Experiments"
description="Design and manage experimental protocols for your HRI studies"
icon={FlaskConical}
actions={
<ActionButton href="/experiments/new">
<Plus className="mr-2 h-4 w-4" />
New Experiment
</ActionButton>
}
<div className="space-y-4">
<DataTable
columns={columns}
data={filteredExperiments}
searchKey="name"
searchPlaceholder="Search experiments..."
isLoading={isLoading}
loadingRowCount={5}
filters={filters}
/>
<div className="space-y-4">
<DataTable
columns={columns}
data={filteredExperiments}
searchKey="name"
searchPlaceholder="Search experiments..."
isLoading={isLoading}
loadingRowCount={5}
filters={filters}
/>
</div>
</div>
);
}