diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page.tsx index 095899a8d..ca262df10 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page.tsx @@ -1,6 +1,12 @@ -import { AppId } from "@stackframe/stack-shared/dist/apps/apps-config"; +import { ALL_APPS, AppId } from "@stackframe/stack-shared/dist/apps/apps-config"; import AppDetailsModalPageClient from "./page-client"; +export const generateStaticParams = async () => { + return Object.keys(ALL_APPS).map(appId => ({ appId })); +}; + +export const dynamicParams = false; + export default async function AppDetailsModalPage({ params }: { params: Promise<{ appId: AppId }> }) { const appId = (await params).appId; diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/apps/[appId]/page.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/apps/[appId]/page.tsx index 5ed70bda9..824864e95 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/apps/[appId]/page.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/apps/[appId]/page.tsx @@ -1,6 +1,12 @@ -import { AppId } from "@stackframe/stack-shared/dist/apps/apps-config"; +import { ALL_APPS, AppId } from "@stackframe/stack-shared/dist/apps/apps-config"; import AppDetailsPageClient from "./page-client"; +export const generateStaticParams = async () => { + return Object.keys(ALL_APPS).map(appId => ({ appId })); +}; + +export const dynamicParams = false; + export default async function AppDetailsPage({ params }: { params: Promise<{ appId: AppId }> }) { const appId = (await params).appId; diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/apps/page.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/apps/page.tsx index 13a04925e..d65ccf033 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/apps/page.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/apps/page.tsx @@ -8,7 +8,7 @@ type Params = { projectId: string, }; -export default async function Page({ params }: { params: Promise }) { +export default async function Page() { return ( ); diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/layout.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/layout.tsx index 35398a1f0..d9d478213 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/layout.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/layout.tsx @@ -8,12 +8,12 @@ export default async function Layout( props: { children: React.ReactNode, modal?: React.ReactNode, params: Promise<{ projectId: string }> } ) { return ( - + {/* Pre-fetch the current URL to prevent request waterfalls */} - + }> {props.children} {props.modal} diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/sidebar-layout.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/sidebar-layout.tsx index ea850e0ee..caea6921c 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/sidebar-layout.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/sidebar-layout.tsx @@ -11,6 +11,7 @@ import { cn } from "@/lib/utils"; import { UserButton, useUser } from "@stackframe/stack"; import { ALL_APPS, type AppId } from "@stackframe/stack-shared/dist/apps/apps-config"; import { typedEntries } from "@stackframe/stack-shared/dist/utils/objects"; +import { runAsynchronously } from "@stackframe/stack-shared/dist/utils/promises"; import { getRelativePart } from "@stackframe/stack-shared/dist/utils/urls"; import { Breadcrumb, @@ -34,8 +35,7 @@ import { import { useTheme } from "next-themes"; import { usePathname } from "next/navigation"; import { Fragment, useEffect, useMemo, useRef, useState } from "react"; -import { useAdminApp } from "./use-admin-app"; -import { runAsynchronously } from "@stackframe/stack-shared/dist/utils/promises"; +import { useAdminApp, useProjectId } from "./use-admin-app"; type BreadcrumbItem = { item: React.ReactNode, href: string }; @@ -463,10 +463,11 @@ function HeaderBreadcrumb({ } } -export default function SidebarLayout(props: { projectId: string, children?: React.ReactNode }) { +export default function SidebarLayout(props: { children?: React.ReactNode }) { const [sidebarOpen, setSidebarOpen] = useState(false); const [companionExpanded, setCompanionExpanded] = useState(false); const { resolvedTheme, setTheme } = useTheme(); + const projectId = useProjectId(); return (
@@ -482,7 +483,7 @@ export default function SidebarLayout(props: { projectId: string, children?: Rea */}
- +
{/* Main Content Area */} @@ -490,7 +491,7 @@ export default function SidebarLayout(props: { projectId: string, children?: Rea {/* Header */}
- +
@@ -504,18 +505,18 @@ export default function SidebarLayout(props: { projectId: string, children?: Rea - setSidebarOpen(false)} /> + setSidebarOpen(false)} />
- +
diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/use-admin-app.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/use-admin-app.tsx index a9897afc7..5469e3f4f 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/use-admin-app.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/use-admin-app.tsx @@ -1,14 +1,15 @@ "use client"; import { StackAdminApp, useUser } from "@stackframe/stack"; -import { throwErr } from "@stackframe/stack-shared/dist/utils/errors"; -import { notFound } from "next/navigation"; +import { StackAssertionError, throwErr } from "@stackframe/stack-shared/dist/utils/errors"; +import { notFound, usePathname } from "next/navigation"; import React from "react"; const StackAdminAppContext = React.createContext | null>(null); -export function AdminAppProvider(props: { projectId: string, children: React.ReactNode }) { - const app = useAdminApp(props.projectId); +export function AdminAppProvider(props: { children: React.ReactNode }) { + const projectId = useProjectId(); + const app = useAdminApp(projectId); return ( {props.children} @@ -41,3 +42,12 @@ export function useAdminApp(projectId?: string) { return providedApp ?? throwErr("useAdminApp must be used within an AdminInterfaceProvider"); } } + +export function useProjectId() { + const pathname = usePathname(); + if (!pathname.startsWith("/projects/")) { + throw new StackAssertionError("useProjectId must be used within a project route"); + } + const projectId = pathname.split("/")[2]; + return projectId; +}