"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { SignInButton, SignedIn, SignedOut, useAuth } from "@clerk/nextjs"; import { CheckCircle2, RefreshCcw, XCircle } from "lucide-react"; 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 { getApiBaseUrl } from "@/lib/api-base"; const apiBase = getApiBaseUrl(); const DEFAULT_MAIN_SESSION_KEY = "agent:main:main"; const DEFAULT_WORKSPACE_ROOT = "~/.openclaw"; const validateGatewayUrl = (value: string) => { const trimmed = value.trim(); if (!trimmed) return "Gateway URL is required."; try { const url = new URL(trimmed); if (url.protocol !== "ws:" && url.protocol !== "wss:") { return "Gateway URL must start with ws:// or wss://."; } if (!url.port) { return "Gateway URL must include an explicit port."; } return null; } catch { return "Enter a valid gateway URL including port."; } }; export default function NewGatewayPage() { const { getToken, isSignedIn } = useAuth(); const router = useRouter(); const [name, setName] = useState(""); const [gatewayUrl, setGatewayUrl] = useState(""); const [gatewayToken, setGatewayToken] = useState(""); const [mainSessionKey, setMainSessionKey] = useState( DEFAULT_MAIN_SESSION_KEY ); const [workspaceRoot, setWorkspaceRoot] = useState(DEFAULT_WORKSPACE_ROOT); const [skyllEnabled, setSkyllEnabled] = useState(false); const [gatewayUrlError, setGatewayUrlError] = useState(null); const [gatewayCheckStatus, setGatewayCheckStatus] = useState< "idle" | "checking" | "success" | "error" >("idle"); const [gatewayCheckMessage, setGatewayCheckMessage] = useState( null ); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const canSubmit = Boolean(name.trim()) && Boolean(gatewayUrl.trim()) && Boolean(mainSessionKey.trim()) && Boolean(workspaceRoot.trim()) && gatewayCheckStatus === "success"; useEffect(() => { setGatewayCheckStatus("idle"); setGatewayCheckMessage(null); }, [gatewayToken]); const runGatewayCheck = async () => { const validationError = validateGatewayUrl(gatewayUrl); setGatewayUrlError(validationError); if (validationError) { setGatewayCheckStatus("error"); setGatewayCheckMessage(validationError); return; } if (!isSignedIn) return; setGatewayCheckStatus("checking"); setGatewayCheckMessage(null); try { const token = await getToken(); const params = new URLSearchParams({ gateway_url: gatewayUrl.trim(), }); if (gatewayToken.trim()) { params.set("gateway_token", gatewayToken.trim()); } if (mainSessionKey.trim()) { params.set("gateway_main_session_key", mainSessionKey.trim()); } const response = await fetch( `${apiBase}/api/v1/gateways/status?${params.toString()}`, { headers: { Authorization: token ? `Bearer ${token}` : "" }, } ); const data = await response.json(); if (!response.ok || !data?.connected) { setGatewayCheckStatus("error"); setGatewayCheckMessage(data?.error ?? "Unable to reach gateway."); return; } setGatewayCheckStatus("success"); setGatewayCheckMessage("Gateway reachable."); } catch (err) { setGatewayCheckStatus("error"); setGatewayCheckMessage( err instanceof Error ? err.message : "Unable to reach gateway." ); } }; const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); if (!isSignedIn) return; if (!name.trim()) { setError("Gateway name is required."); return; } const gatewayValidation = validateGatewayUrl(gatewayUrl); setGatewayUrlError(gatewayValidation); if (gatewayValidation) { setGatewayCheckStatus("error"); setGatewayCheckMessage(gatewayValidation); return; } if (!mainSessionKey.trim()) { setError("Main session key is required."); return; } if (!workspaceRoot.trim()) { setError("Workspace root is required."); return; } setIsLoading(true); setError(null); try { const token = await getToken(); const response = await fetch(`${apiBase}/api/v1/gateways`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: token ? `Bearer ${token}` : "", }, body: JSON.stringify({ name: name.trim(), url: gatewayUrl.trim(), token: gatewayToken.trim() || null, main_session_key: mainSessionKey.trim(), workspace_root: workspaceRoot.trim(), skyll_enabled: skyllEnabled, }), }); if (!response.ok) { throw new Error("Unable to create gateway."); } const created = (await response.json()) as { id: string }; router.push(`/gateways/${created.id}`); } catch (err) { setError(err instanceof Error ? err.message : "Something went wrong."); } finally { setIsLoading(false); } }; return (

Sign in to create a gateway.

Create gateway

Configure an OpenClaw gateway for mission control.

setName(event.target.value)} placeholder="Primary gateway" disabled={isLoading} />
{ setGatewayUrl(event.target.value); setGatewayUrlError(null); setGatewayCheckStatus("idle"); setGatewayCheckMessage(null); }} onBlur={runGatewayCheck} placeholder="ws://gateway:18789" disabled={isLoading} className={gatewayUrlError ? "border-red-500" : undefined} />
{gatewayUrlError ? (

{gatewayUrlError}

) : gatewayCheckMessage ? (

{gatewayCheckMessage}

) : null}
{ setGatewayToken(event.target.value); setGatewayCheckStatus("idle"); setGatewayCheckMessage(null); }} onBlur={runGatewayCheck} placeholder="Bearer token" disabled={isLoading} />
{ setMainSessionKey(event.target.value); setGatewayCheckStatus("idle"); setGatewayCheckMessage(null); }} placeholder={DEFAULT_MAIN_SESSION_KEY} disabled={isLoading} />
setWorkspaceRoot(event.target.value)} placeholder={DEFAULT_WORKSPACE_ROOT} disabled={isLoading} />
{error ?

{error}

: null}
); }