"use client"; import * as React from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { ArrowLeft, CheckCircle2, Database, Lock, RefreshCw, Server, ShieldAlert, ShieldCheck, XCircle, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { useWorkspace } from "@/providers/workspace-provider"; import { apiClient, ConnectionTestPayload, ConnectionTestResult, CreateConnectionPayload, } from "@/lib/api-client"; type EngineType = "postgresql" | "sqlite" | "mysql" | "mariadb"; interface EngineCard { id: EngineType; provider: string; name: string; badge: string; description: string; defaultPort: number | null; } const ENGINES: EngineCard[] = [ { id: "postgresql", provider: "generic", name: "PostgreSQL", badge: "Production Ready", description: "Connect to standard PostgreSQL 12–16+ instances.", defaultPort: 5432, }, { id: "postgresql", provider: "supabase", name: "Supabase PostgreSQL", badge: "Cloud Dialect", description: "Connect via direct port 5432 or transaction pooler port 6543.", defaultPort: 5432, }, { id: "mysql", provider: "generic", name: "MySQL", badge: "Production Ready", description: "Connect to MySQL 8.x network database instances.", defaultPort: 3306, }, { id: "mariadb", provider: "generic", name: "MariaDB", badge: "Production Ready", description: "Connect to MariaDB 10.x/11.x server deployments.", defaultPort: 3306, }, { id: "sqlite", provider: "generic", name: "SQLite (Contained)", badge: "Filesystem Isolated", description: "Inspect local or workspace-isolated SQLite embedded files.", defaultPort: null, }, ]; export default function NewConnectionPage() { const router = useRouter(); const { currentWorkspace } = useWorkspace(); const [selectedEngine, setSelectedEngine] = React.useState(ENGINES[0]); const [name, setName] = React.useState(""); const [database, setDatabase] = React.useState(""); const [host, setHost] = React.useState("localhost"); const [port, setPort] = React.useState("5432"); const [username, setUsername] = React.useState("postgres"); const [password, setPassword] = React.useState(""); const [sslMode, setSslMode] = React.useState("prefer"); // Diagnostics & submission const [testing, setTesting] = React.useState(false); const [testResult, setTestResult] = React.useState(null); const [saving, setSaving] = React.useState(false); const [error, setError] = React.useState(null); // Switch engine defaults const handleSelectEngine = (engine: EngineCard) => { setSelectedEngine(engine); setTestResult(null); setError(null); if (engine.id === "sqlite") { setHost(""); setPort(""); setUsername(""); setPassword(""); setDatabase("workspace/sample.db"); } else { setPort(String(engine.defaultPort || 5432)); if (engine.provider === "supabase") { setHost("db.xxxxxxxxxxxx.supabase.co"); setUsername("postgres"); setDatabase("postgres"); setSslMode("require"); } else if (engine.id === "mysql" || engine.id === "mariadb") { setHost("localhost"); setUsername("root"); setDatabase("app_db"); setSslMode("prefer"); } else { setHost("localhost"); setUsername("postgres"); setDatabase("postgres"); setSslMode("prefer"); } } }; const getTestPayload = (): ConnectionTestPayload => { return { engine: selectedEngine.id, database: database.trim(), host: selectedEngine.id !== "sqlite" ? host.trim() || undefined : undefined, port: selectedEngine.id !== "sqlite" && port ? parseInt(port, 10) : undefined, username: selectedEngine.id !== "sqlite" ? username.trim() || undefined : undefined, password: selectedEngine.id !== "sqlite" && password ? password : undefined, ssl_mode: sslMode, }; }; const handleTestConnection = async (e: React.FormEvent) => { e.preventDefault(); setError(null); setTestResult(null); setTesting(true); try { const payload = getTestPayload(); const res = await apiClient.testRawConnection(payload); setTestResult(res); } catch (err) { setTestResult({ success: false, latency_ms: 0, engine: selectedEngine.id, error_code: "NETWORK_ERROR", error_message: err instanceof Error ? err.message : "Diagnostic probe failed.", }); } finally { setTesting(false); } }; const handleSaveConnection = async (e: React.FormEvent) => { e.preventDefault(); if (!currentWorkspace?.id) { setError("Active workspace context required to save connection."); return; } if (!name.trim()) { setError("Please provide a connection name."); return; } if (!database.trim()) { setError("Please specify target database name."); return; } setSaving(true); setError(null); const payload: CreateConnectionPayload = { name: name.trim(), engine: selectedEngine.id, provider: selectedEngine.provider, database: database.trim(), host: selectedEngine.id !== "sqlite" ? host.trim() || undefined : undefined, port: selectedEngine.id !== "sqlite" && port ? parseInt(port, 10) : undefined, username: selectedEngine.id !== "sqlite" ? username.trim() || undefined : undefined, password: selectedEngine.id !== "sqlite" && password ? password : undefined, ssl_mode: sslMode, }; try { await apiClient.createConnection(currentWorkspace.id, payload); router.push("/connections"); } catch (err) { setError(err instanceof Error ? err.message : "Failed to persist database connection."); setSaving(false); } }; return (
{/* Breadcrumb / Back */}
{/* Header */}

Add Database Connection

Configure an authorized target database for deterministic structural introspection.

{/* Step 1: Engine Selection */}
{ENGINES.map((eng) => { const isSelected = selectedEngine.name === eng.name && selectedEngine.provider === eng.provider; return ( ); })}
{/* Security Notice */}
Read-Only & Credential Isolation Guarantees

DERA connectors enforce read-only transaction semantics. Passwords are never saved in browser storage or logged. The browser connects exclusively to the DERA API.

{/* Form Error */} {error && (
{error}
)} {/* Step 2: Connection Parameters Form */} 2. Connection Parameters ({selectedEngine.name}) Enter network coordinates and authentication credentials.
{/* Connection Name */}
setName(e.target.value)} placeholder="e.g. Production Analytics Database" className="h-9 text-xs" required />
{/* Network Engines Fields */} {selectedEngine.id !== "sqlite" ? ( <>
setHost(e.target.value)} placeholder="e.g. localhost or postgres.example.com" className="h-9 text-xs font-mono" required />
setPort(e.target.value)} placeholder="5432" className="h-9 text-xs font-mono" required />
setDatabase(e.target.value)} placeholder="e.g. postgres, analytics" className="h-9 text-xs font-mono" required />
setUsername(e.target.value)} placeholder="e.g. postgres, reader_user" className="h-9 text-xs font-mono" required />
setPassword(e.target.value)} placeholder="••••••••••••" className="h-9 text-xs font-mono" autoComplete="new-password" />
) : ( /* SQLite Contained Field */
setDatabase(e.target.value)} placeholder="e.g. workspace/chinook.db or :memory:" className="h-9 text-xs font-mono" required />

Path must reside within approved storage roots (e.g. workspace/ or demo/). Arbitrary server filesystem paths are rejected.

)} {/* Test Results Display */} {testResult && (
{testResult.success ? ( ) : ( )} {testResult.success ? `Verified in ${testResult.latency_ms}ms${ testResult.server_version ? ` — Server: ${testResult.server_version}` : "" }` : `Probe failed [${testResult.error_code || "ERROR"}]: ${testResult.error_message || "Unknown error"}`}
)} {/* Actions */}
); }