"use client"; export const dynamic = "force-dynamic"; import { useState } from "react"; import { useParams, useRouter } from "next/navigation"; import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ApiError } from "@/api/mutator"; import { type getGatewayApiV1GatewaysGatewayIdGetResponse, useGetGatewayApiV1GatewaysGatewayIdGet, useUpdateGatewayApiV1GatewaysGatewayIdPatch, } from "@/api/generated/gateways/gateways"; import { type getMyMembershipApiV1OrganizationsMeMemberGetResponse, useGetMyMembershipApiV1OrganizationsMeMemberGet, } from "@/api/generated/organizations/organizations"; import type { GatewayUpdate } from "@/api/generated/model"; import { GatewayForm } from "@/components/gateways/GatewayForm"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; import { DEFAULT_MAIN_SESSION_KEY, DEFAULT_WORKSPACE_ROOT, checkGatewayConnection, type GatewayCheckStatus, validateGatewayUrl, } from "@/lib/gateway-form"; export default function EditGatewayPage() { const { isSignedIn } = useAuth(); const router = useRouter(); const params = useParams(); const gatewayIdParam = params?.gatewayId; const gatewayId = Array.isArray(gatewayIdParam) ? gatewayIdParam[0] : gatewayIdParam; const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet< getMyMembershipApiV1OrganizationsMeMemberGetResponse, ApiError >({ query: { enabled: Boolean(isSignedIn), refetchOnMount: "always", retry: false, }, }); const member = membershipQuery.data?.status === 200 ? membershipQuery.data.data : null; const isAdmin = member ? ["owner", "admin"].includes(member.role) : false; const [name, setName] = useState(undefined); const [gatewayUrl, setGatewayUrl] = useState(undefined); const [gatewayToken, setGatewayToken] = useState( undefined, ); const [mainSessionKey, setMainSessionKey] = useState( undefined, ); const [workspaceRoot, setWorkspaceRoot] = useState( undefined, ); const [gatewayUrlError, setGatewayUrlError] = useState(null); const [gatewayCheckStatus, setGatewayCheckStatus] = useState("idle"); const [gatewayCheckMessage, setGatewayCheckMessage] = useState( null, ); const [error, setError] = useState(null); const gatewayQuery = useGetGatewayApiV1GatewaysGatewayIdGet< getGatewayApiV1GatewaysGatewayIdGetResponse, ApiError >(gatewayId ?? "", { query: { enabled: Boolean(isSignedIn && isAdmin && gatewayId), refetchOnMount: "always", retry: false, }, }); const updateMutation = useUpdateGatewayApiV1GatewaysGatewayIdPatch({ mutation: { onSuccess: (result) => { if (result.status === 200) { router.push(`/gateways/${result.data.id}`); } }, onError: (err) => { setError(err.message || "Something went wrong."); }, }, }); const loadedGateway = gatewayQuery.data?.status === 200 ? gatewayQuery.data.data : null; const resolvedName = name ?? loadedGateway?.name ?? ""; const resolvedGatewayUrl = gatewayUrl ?? loadedGateway?.url ?? ""; const resolvedGatewayToken = gatewayToken ?? loadedGateway?.token ?? ""; const resolvedMainSessionKey = mainSessionKey ?? loadedGateway?.main_session_key ?? DEFAULT_MAIN_SESSION_KEY; const resolvedWorkspaceRoot = workspaceRoot ?? loadedGateway?.workspace_root ?? DEFAULT_WORKSPACE_ROOT; const isLoading = gatewayQuery.isLoading || updateMutation.isPending; const errorMessage = error ?? gatewayQuery.error?.message ?? null; const canSubmit = Boolean(resolvedName.trim()) && Boolean(resolvedGatewayUrl.trim()) && Boolean(resolvedMainSessionKey.trim()) && Boolean(resolvedWorkspaceRoot.trim()) && gatewayCheckStatus === "success"; const runGatewayCheck = async () => { const validationError = validateGatewayUrl(resolvedGatewayUrl); setGatewayUrlError(validationError); if (validationError) { setGatewayCheckStatus("error"); setGatewayCheckMessage(validationError); return; } if (!isSignedIn) return; setGatewayCheckStatus("checking"); setGatewayCheckMessage(null); const { ok, message } = await checkGatewayConnection({ gatewayUrl: resolvedGatewayUrl, gatewayToken: resolvedGatewayToken, mainSessionKey: resolvedMainSessionKey, }); setGatewayCheckStatus(ok ? "success" : "error"); setGatewayCheckMessage(message); }; const handleSubmit = (event: React.FormEvent) => { event.preventDefault(); if (!isSignedIn || !gatewayId) return; if (!resolvedName.trim()) { setError("Gateway name is required."); return; } const gatewayValidation = validateGatewayUrl(resolvedGatewayUrl); setGatewayUrlError(gatewayValidation); if (gatewayValidation) { setGatewayCheckStatus("error"); setGatewayCheckMessage(gatewayValidation); return; } if (!resolvedMainSessionKey.trim()) { setError("Main session key is required."); return; } if (!resolvedWorkspaceRoot.trim()) { setError("Workspace root is required."); return; } setError(null); const payload: GatewayUpdate = { name: resolvedName.trim(), url: resolvedGatewayUrl.trim(), token: resolvedGatewayToken.trim() || null, main_session_key: resolvedMainSessionKey.trim(), workspace_root: resolvedWorkspaceRoot.trim(), }; updateMutation.mutate({ gatewayId, data: payload }); }; return (

Sign in to edit a gateway.

{resolvedName.trim() ? `Edit gateway — ${resolvedName.trim()}` : "Edit gateway"}

Update connection settings for this OpenClaw gateway.

{!isAdmin ? (
Only organization owners and admins can edit gateways.
) : ( router.push("/gateways")} onRunGatewayCheck={runGatewayCheck} onNameChange={setName} onGatewayUrlChange={(next) => { setGatewayUrl(next); setGatewayUrlError(null); setGatewayCheckStatus("idle"); setGatewayCheckMessage(null); }} onGatewayTokenChange={(next) => { setGatewayToken(next); setGatewayCheckStatus("idle"); setGatewayCheckMessage(null); }} onMainSessionKeyChange={(next) => { setMainSessionKey(next); setGatewayCheckStatus("idle"); setGatewayCheckMessage(null); }} onWorkspaceRootChange={setWorkspaceRoot} /> )}
); }