feat(gateway): refactor gateway form and connection check logic

This commit is contained in:
Abhimanyu Saharan
2026-02-08 23:26:57 +05:30
parent cdda147feb
commit 03317f0baf
4 changed files with 341 additions and 378 deletions

View File

@@ -0,0 +1,174 @@
import type { FormEvent } from "react";
import { CheckCircle2, RefreshCcw, XCircle } from "lucide-react";
import type { GatewayCheckStatus } from "@/lib/gateway-form";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
type GatewayFormProps = {
name: string;
gatewayUrl: string;
gatewayToken: string;
mainSessionKey: string;
workspaceRoot: string;
gatewayUrlError: string | null;
gatewayCheckStatus: GatewayCheckStatus;
gatewayCheckMessage: string | null;
errorMessage: string | null;
isLoading: boolean;
canSubmit: boolean;
mainSessionKeyPlaceholder: string;
workspaceRootPlaceholder: string;
cancelLabel: string;
submitLabel: string;
submitBusyLabel: string;
onSubmit: (event: FormEvent<HTMLFormElement>) => void;
onCancel: () => void;
onRunGatewayCheck: () => Promise<void>;
onNameChange: (next: string) => void;
onGatewayUrlChange: (next: string) => void;
onGatewayTokenChange: (next: string) => void;
onMainSessionKeyChange: (next: string) => void;
onWorkspaceRootChange: (next: string) => void;
};
export function GatewayForm({
name,
gatewayUrl,
gatewayToken,
mainSessionKey,
workspaceRoot,
gatewayUrlError,
gatewayCheckStatus,
gatewayCheckMessage,
errorMessage,
isLoading,
canSubmit,
mainSessionKeyPlaceholder,
workspaceRootPlaceholder,
cancelLabel,
submitLabel,
submitBusyLabel,
onSubmit,
onCancel,
onRunGatewayCheck,
onNameChange,
onGatewayUrlChange,
onGatewayTokenChange,
onMainSessionKeyChange,
onWorkspaceRootChange,
}: GatewayFormProps) {
return (
<form
onSubmit={onSubmit}
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Gateway name <span className="text-red-500">*</span>
</label>
<Input
value={name}
onChange={(event) => onNameChange(event.target.value)}
placeholder="Primary gateway"
disabled={isLoading}
/>
</div>
<div className="grid gap-6 md:grid-cols-2">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Gateway URL <span className="text-red-500">*</span>
</label>
<div className="relative">
<Input
value={gatewayUrl}
onChange={(event) => onGatewayUrlChange(event.target.value)}
onBlur={onRunGatewayCheck}
placeholder="ws://gateway:18789"
disabled={isLoading}
className={gatewayUrlError ? "border-red-500" : undefined}
/>
<button
type="button"
onClick={() => void onRunGatewayCheck()}
className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600"
aria-label="Check gateway connection"
>
{gatewayCheckStatus === "checking" ? (
<RefreshCcw className="h-4 w-4 animate-spin" />
) : gatewayCheckStatus === "success" ? (
<CheckCircle2 className="h-4 w-4 text-emerald-500" />
) : gatewayCheckStatus === "error" ? (
<XCircle className="h-4 w-4 text-red-500" />
) : (
<RefreshCcw className="h-4 w-4" />
)}
</button>
</div>
{gatewayUrlError ? (
<p className="text-xs text-red-500">{gatewayUrlError}</p>
) : gatewayCheckMessage ? (
<p
className={
gatewayCheckStatus === "success"
? "text-xs text-emerald-600"
: "text-xs text-red-500"
}
>
{gatewayCheckMessage}
</p>
) : null}
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Gateway token
</label>
<Input
value={gatewayToken}
onChange={(event) => onGatewayTokenChange(event.target.value)}
onBlur={onRunGatewayCheck}
placeholder="Bearer token"
disabled={isLoading}
/>
</div>
</div>
<div className="grid gap-6 md:grid-cols-2">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Main session key <span className="text-red-500">*</span>
</label>
<Input
value={mainSessionKey}
onChange={(event) => onMainSessionKeyChange(event.target.value)}
placeholder={mainSessionKeyPlaceholder}
disabled={isLoading}
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Workspace root <span className="text-red-500">*</span>
</label>
<Input
value={workspaceRoot}
onChange={(event) => onWorkspaceRootChange(event.target.value)}
placeholder={workspaceRootPlaceholder}
disabled={isLoading}
/>
</div>
</div>
{errorMessage ? <p className="text-sm text-red-500">{errorMessage}</p> : null}
<div className="flex justify-end gap-3">
<Button type="button" variant="ghost" onClick={onCancel} disabled={isLoading}>
{cancelLabel}
</Button>
<Button type="submit" disabled={isLoading || !canSubmit}>
{isLoading ? submitBusyLabel : submitLabel}
</Button>
</div>
</form>
);
}