"use client"; export const dynamic = "force-dynamic"; import { useMemo, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ApiError } from "@/api/mutator"; import { useCreateBoardApiV1BoardsPost } from "@/api/generated/boards/boards"; import { type listBoardGroupsApiV1BoardGroupsGetResponse, useListBoardGroupsApiV1BoardGroupsGet, } from "@/api/generated/board-groups/board-groups"; import { type listGatewaysApiV1GatewaysGetResponse, useListGatewaysApiV1GatewaysGet, } from "@/api/generated/gateways/gateways"; import { useOrganizationMembership } from "@/lib/use-organization-membership"; import type { BoardGroupRead } from "@/api/generated/model"; import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice"; import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import SearchableSelect from "@/components/ui/searchable-select"; const slugify = (value: string) => value .toLowerCase() .trim() .replace(/[^a-z0-9]+/g, "-") .replace(/(^-|-$)/g, "") || "board"; export default function NewBoardPage() { const router = useRouter(); const { isSignedIn } = useAuth(); const { isAdmin } = useOrganizationMembership(isSignedIn); const [name, setName] = useState(""); const [gatewayId, setGatewayId] = useState(""); const [boardGroupId, setBoardGroupId] = useState("none"); const [error, setError] = useState(null); const gatewaysQuery = useListGatewaysApiV1GatewaysGet< listGatewaysApiV1GatewaysGetResponse, ApiError >(undefined, { query: { enabled: Boolean(isSignedIn && isAdmin), refetchOnMount: "always", retry: false, }, }); const groupsQuery = useListBoardGroupsApiV1BoardGroupsGet< listBoardGroupsApiV1BoardGroupsGetResponse, ApiError >(undefined, { query: { enabled: Boolean(isSignedIn && isAdmin), refetchOnMount: "always", retry: false, }, }); const createBoardMutation = useCreateBoardApiV1BoardsPost({ mutation: { onSuccess: (result) => { if (result.status === 200) { router.push(`/boards/${result.data.id}/edit?onboarding=1`); } }, onError: (err) => { setError(err.message || "Something went wrong."); }, }, }); const gateways = useMemo(() => { if (gatewaysQuery.data?.status !== 200) return []; return gatewaysQuery.data.data.items ?? []; }, [gatewaysQuery.data]); const groups = useMemo(() => { if (groupsQuery.data?.status !== 200) return []; return groupsQuery.data.data.items ?? []; }, [groupsQuery.data]); const displayGatewayId = gatewayId || gateways[0]?.id || ""; const isLoading = gatewaysQuery.isLoading || groupsQuery.isLoading || createBoardMutation.isPending; const errorMessage = error ?? gatewaysQuery.error?.message ?? groupsQuery.error?.message ?? null; const isFormReady = Boolean(name.trim() && displayGatewayId); const gatewayOptions = useMemo( () => gateways.map((gateway) => ({ value: gateway.id, label: gateway.name })), [gateways], ); const groupOptions = useMemo( () => [ { value: "none", label: "No group" }, ...groups.map((group) => ({ value: group.id, label: group.name })), ], [groups], ); const handleSubmit = (event: React.FormEvent) => { event.preventDefault(); if (!isSignedIn) return; const trimmedName = name.trim(); const resolvedGatewayId = displayGatewayId; if (!trimmedName) { setError("Board name is required."); return; } if (!resolvedGatewayId) { setError("Select a gateway before creating a board."); return; } setError(null); createBoardMutation.mutate({ data: { name: trimmedName, slug: slugify(trimmedName), gateway_id: resolvedGatewayId, board_group_id: boardGroupId === "none" ? null : boardGroupId, }, }); }; return (

Create board

Boards organize tasks and agents by mission context.

{!isAdmin ? ( ) : (
setName(event.target.value)} placeholder="e.g. Release operations" disabled={isLoading} />

Optional. Groups increase cross-board visibility.

{gateways.length === 0 ? (

No gateways available. Create one in{" "} Gateways {" "} to continue.

) : null} {errorMessage ? (

{errorMessage}

) : null}
)}
); }