// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 // A workspace: its projects, and a form to create another (spec ยง3.1). The projects are listed // through `tenancy.project.list`, which reads them inside the workspace's own scope -- a workspace of // another organization, or one the person has no place in, is the not-found page. import { projectList, workspaceList } from "@conusai-kit/tenancy" import type { ReactElement } from "react" import { orFallback } from "../../../src/server/guard" import { holdsAtLeast, pageContext } from "../../../src/server/page" import { Breadcrumb } from "../../../src/ui/breadcrumb" import { ProcedureForm } from "../../../src/ui/procedure-form" import { PROJECT_MODULE_KEYS, projectHref } from "../../../src/ui/projects" export const dynamic = "force-dynamic" export default async function WorkspaceHome({ params, }: { params: Promise<{ org: string; workspace: string }> }): Promise { const { org, workspace } = await params const page = await pageContext() const { caller, i18n, path } = page const { name, projects } = await orFallback(path, async () => { const [{ projects }, { workspaces }] = await Promise.all([ caller.call(projectList, { org, workspace }), caller.call(workspaceList, { org }), ]) // `projectList` answers for the workspace's scope; the name is the list's own, so the page does // not need a procedure of its own to say it. return { projects, name: workspaces.find((entry) => entry.slug === workspace)?.name ?? workspace } }) const mayCreate = await holdsAtLeast(page, org, "editor") return ( <>

{i18n.message("workspace.title", { name })}

{i18n.message("workspace.projects")}

{projects.length === 0 ? (

{i18n.message("workspace.noProjects")}

) : ( {projects.map((project) => ( ))}
{i18n.message("app.name")} {i18n.message("workspace.module")}
{project.name} {project.moduleKey}
)} {mayCreate ? ( <>

{i18n.message("workspace.createProject")}