From 51096b7194e88343270acddcfa5f0ef6c4a69459 Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Wed, 24 Sep 2025 13:41:33 -0400 Subject: [PATCH] Add experiments and plugins pages for study dashboard --- .../studies/[id]/experiments/new/page.tsx | 21 +++++++ .../studies/[id]/experiments/page.tsx | 55 +++++++++++++++++++ .../studies/[id]/plugins/browse/page.tsx | 40 ++++++++++++++ .../(dashboard)/studies/[id]/plugins/page.tsx | 55 +++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 src/app/(dashboard)/studies/[id]/experiments/new/page.tsx create mode 100644 src/app/(dashboard)/studies/[id]/experiments/page.tsx create mode 100644 src/app/(dashboard)/studies/[id]/plugins/browse/page.tsx create mode 100644 src/app/(dashboard)/studies/[id]/plugins/page.tsx diff --git a/src/app/(dashboard)/studies/[id]/experiments/new/page.tsx b/src/app/(dashboard)/studies/[id]/experiments/new/page.tsx new file mode 100644 index 0000000..ad29fb8 --- /dev/null +++ b/src/app/(dashboard)/studies/[id]/experiments/new/page.tsx @@ -0,0 +1,21 @@ +"use client"; + +import { useParams } from "next/navigation"; +import { useEffect } from "react"; +import { ExperimentForm } from "~/components/experiments/ExperimentForm"; +import { useStudyContext } from "~/lib/study-context"; + +export default function NewStudyExperimentPage() { + const params = useParams(); + const studyId: string = typeof params.id === "string" ? params.id : ""; + const { setSelectedStudyId, selectedStudyId } = useStudyContext(); + + // Sync selected study (unified study-context) + useEffect(() => { + if (studyId && selectedStudyId !== studyId) { + setSelectedStudyId(studyId); + } + }, [studyId, selectedStudyId, setSelectedStudyId]); + + return ; +} diff --git a/src/app/(dashboard)/studies/[id]/experiments/page.tsx b/src/app/(dashboard)/studies/[id]/experiments/page.tsx new file mode 100644 index 0000000..f6faf49 --- /dev/null +++ b/src/app/(dashboard)/studies/[id]/experiments/page.tsx @@ -0,0 +1,55 @@ +"use client"; + +import { useParams } from "next/navigation"; +import { Suspense, useEffect } from "react"; +import { FlaskConical, Plus } from "lucide-react"; +import { ExperimentsDataTable } from "~/components/experiments/experiments-data-table"; +import { PageHeader } from "~/components/ui/page-header"; +import { Button } from "~/components/ui/button"; +import { useBreadcrumbsEffect } from "~/components/ui/breadcrumb-provider"; +import { useStudyContext } from "~/lib/study-context"; +import { useSelectedStudyDetails } from "~/hooks/useSelectedStudyDetails"; + +export default function StudyExperimentsPage() { + const params = useParams(); + const studyId: string = typeof params.id === "string" ? params.id : ""; + const { setSelectedStudyId, selectedStudyId } = useStudyContext(); + const { study } = useSelectedStudyDetails(); + + // Set breadcrumbs + useBreadcrumbsEffect([ + { label: "Dashboard", href: "/dashboard" }, + { label: "Studies", href: "/studies" }, + { label: study?.name ?? "Study", href: `/studies/${studyId}` }, + { label: "Experiments" }, + ]); + + // Sync selected study (unified study-context) + useEffect(() => { + if (studyId && selectedStudyId !== studyId) { + setSelectedStudyId(studyId); + } + }, [studyId, selectedStudyId, setSelectedStudyId]); + + return ( +
+ + + + Create Experiment + + + } + /> + + Loading experiments...
}> + + + + ); +} diff --git a/src/app/(dashboard)/studies/[id]/plugins/browse/page.tsx b/src/app/(dashboard)/studies/[id]/plugins/browse/page.tsx new file mode 100644 index 0000000..3c31e30 --- /dev/null +++ b/src/app/(dashboard)/studies/[id]/plugins/browse/page.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { useParams } from "next/navigation"; +import { Suspense, useEffect } from "react"; +import { PluginStoreBrowse } from "~/components/plugins/plugin-store-browse"; +import { ManagementPageLayout } from "~/components/ui/page-layout"; +import { useStudyContext } from "~/lib/study-context"; +import { useSelectedStudyDetails } from "~/hooks/useSelectedStudyDetails"; + +export default function StudyPluginBrowsePage() { + const params = useParams(); + const studyId: string = typeof params.id === "string" ? params.id : ""; + const { setSelectedStudyId, selectedStudyId } = useStudyContext(); + const { study } = useSelectedStudyDetails(); + + // Sync selected study (unified study-context) + useEffect(() => { + if (studyId && selectedStudyId !== studyId) { + setSelectedStudyId(studyId); + } + }, [studyId, selectedStudyId, setSelectedStudyId]); + + return ( + + Loading plugin store...}> + + + + ); +} diff --git a/src/app/(dashboard)/studies/[id]/plugins/page.tsx b/src/app/(dashboard)/studies/[id]/plugins/page.tsx new file mode 100644 index 0000000..00f90ed --- /dev/null +++ b/src/app/(dashboard)/studies/[id]/plugins/page.tsx @@ -0,0 +1,55 @@ +"use client"; + +import { useParams } from "next/navigation"; +import { Suspense, useEffect } from "react"; +import { Puzzle, Plus } from "lucide-react"; +import { PluginsDataTable } from "~/components/plugins/plugins-data-table"; +import { PageHeader } from "~/components/ui/page-header"; +import { Button } from "~/components/ui/button"; +import { useBreadcrumbsEffect } from "~/components/ui/breadcrumb-provider"; +import { useStudyContext } from "~/lib/study-context"; +import { useSelectedStudyDetails } from "~/hooks/useSelectedStudyDetails"; + +export default function StudyPluginsPage() { + const params = useParams(); + const studyId: string = typeof params.id === "string" ? params.id : ""; + const { setSelectedStudyId, selectedStudyId } = useStudyContext(); + const { study } = useSelectedStudyDetails(); + + // Set breadcrumbs + useBreadcrumbsEffect([ + { label: "Dashboard", href: "/dashboard" }, + { label: "Studies", href: "/studies" }, + { label: study?.name ?? "Study", href: `/studies/${studyId}` }, + { label: "Plugins" }, + ]); + + // Sync selected study (unified study-context) + useEffect(() => { + if (studyId && selectedStudyId !== studyId) { + setSelectedStudyId(studyId); + } + }, [studyId, selectedStudyId, setSelectedStudyId]); + + return ( +
+ + + + Browse Plugin Store + + + } + /> + + Loading plugins...
}> + + + + ); +}