- Introduce default MITM router base URL and update related components to handle it.

- Add input for MITM router base URL in MitmServerCard component.
This commit is contained in:
decolua
2026-04-04 11:25:58 +07:00
parent 2e740ad7e4
commit d84489dba4
11 changed files with 559 additions and 266 deletions
@@ -3,6 +3,8 @@
import { useState, useEffect } from "react";
import { Card, Button, Badge, Input } from "@/shared/components";
const DEFAULT_MITM_ROUTER_BASE = "http://localhost:20128";
/**
* Shared MITM infrastructure card — manages SSL cert + server start/stop.
* DNS per-tool is handled separately in MitmToolCard.
@@ -15,6 +17,7 @@ export default function MitmServerCard({ apiKeys, cloudEnabled, onStatusChange }
const [selectedApiKey, setSelectedApiKey] = useState("");
const [pendingAction, setPendingAction] = useState(null);
const [modalError, setModalError] = useState(null);
const [mitmRouterBaseUrl, setMitmRouterBaseUrl] = useState(DEFAULT_MITM_ROUTER_BASE);
const isWindows = typeof navigator !== "undefined" && navigator.userAgent?.includes("Windows");
const isAdmin = status?.isAdmin !== false;
@@ -35,6 +38,9 @@ export default function MitmServerCard({ apiKeys, cloudEnabled, onStatusChange }
if (res.ok) {
const data = await res.json();
setStatus(data);
if (data.mitmRouterBaseUrl) {
setMitmRouterBaseUrl(data.mitmRouterBaseUrl);
}
onStatusChange?.(data);
}
} catch {
@@ -68,7 +74,11 @@ export default function MitmServerCard({ apiKeys, cloudEnabled, onStatusChange }
await fetch("/api/cli-tools/antigravity-mitm", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ apiKey: keyToUse, sudoPassword: password }),
body: JSON.stringify({
apiKey: keyToUse,
sudoPassword: password,
mitmRouterBaseUrl: mitmRouterBaseUrl.trim() || DEFAULT_MITM_ROUTER_BASE,
}),
});
} else {
await fetch("/api/cli-tools/antigravity-mitm", {
@@ -137,25 +147,44 @@ export default function MitmServerCard({ apiKeys, cloudEnabled, onStatusChange }
</p>
</div>
{/* API Key selector (only when stopped) */}
{!isRunning && (
{/* Base URL + API Key — same row pattern as Claude Code / cli-tools */}
<div className="flex flex-col gap-2">
<div className="flex items-center gap-2">
<span className="text-xs text-text-muted shrink-0">API Key</span>
{apiKeys?.length > 0 ? (
<select
value={selectedApiKey}
onChange={(e) => setSelectedApiKey(e.target.value)}
className="flex-1 px-2 py-1 bg-surface rounded text-xs border border-border focus:outline-none focus:ring-1 focus:ring-primary/50"
>
{apiKeys.map((key) => <option key={key.id} value={key.key}>{key.key}</option>)}
</select>
) : (
<span className="text-xs text-text-muted">
{cloudEnabled ? "No API keys — create one in Keys page" : "sk_9router (default)"}
</span>
)}
<span className="w-32 shrink-0 text-sm font-semibold text-text-main text-right">9Router Base URL</span>
<span className="material-symbols-outlined text-text-muted text-[14px]">arrow_forward</span>
<input
type="text"
value={mitmRouterBaseUrl}
onChange={(e) => setMitmRouterBaseUrl(e.target.value)}
placeholder={DEFAULT_MITM_ROUTER_BASE}
disabled={isRunning}
className="flex-1 min-w-0 px-2 py-1.5 bg-surface rounded border border-border text-xs text-text-main focus:outline-none focus:ring-1 focus:ring-primary/50 disabled:opacity-50"
/>
</div>
)}
{!isRunning && (
<div className="flex items-center gap-2">
<span className="w-32 shrink-0 text-sm font-semibold text-text-main text-right">API Key</span>
<span className="material-symbols-outlined text-text-muted text-[14px]">arrow_forward</span>
{apiKeys?.length > 0 ? (
<select
value={selectedApiKey}
onChange={(e) => setSelectedApiKey(e.target.value)}
className="flex-1 min-w-0 px-2 py-1.5 bg-surface rounded text-xs border border-border text-text-main focus:outline-none focus:ring-1 focus:ring-primary/50"
>
{apiKeys.map((key) => (
<option key={key.id} value={key.key}>
{key.key}
</option>
))}
</select>
) : (
<span className="flex-1 px-2 py-1.5 text-xs text-text-muted">
{cloudEnabled ? "No API keys — create one in Keys page" : "sk_9router (default)"}
</span>
)}
</div>
)}
</div>
{/* Action buttons */}
<div className="flex items-center gap-2 flex-wrap" data-i18n-skip="true">