import { Button, Input, Modal } from "../ui"; import { Field, SectionHeader, ToggleRow } from "./formUi"; import { ipv6Hint, type UpstreamForm, type UpstreamProbeResult } from "./shared"; import { tl, useI18n } from "../../lib/i18n"; export interface UpstreamDialogProps { open: boolean; editing: boolean; form: UpstreamForm; testing: boolean; probe: UpstreamProbeResult | null; onPatch: (patch: Partial) => void; onTest: () => void; onClose: () => void; onSubmit: () => void; } type ProbeState = "ok" | "fail" | "pending"; function ProbeRow({ state, label, detail }: { state: ProbeState; label: string; detail?: string }) { const dot = state === "ok" ? "bg-green-500" : state === "fail" ? "bg-red-500" : "bg-gray-300 dark:bg-gray-600"; const text = state === "ok" ? "text-green-600 dark:text-green-400" : state === "fail" ? "text-red-600 dark:text-red-400" : "text-gray-400"; return (
{label} {detail ? {detail} : null}
); } function authMethodLabel(method?: string): string { if (method === "none") return tl("免鉴权"); if (method === "username_password") return tl("用户名密码"); return method || ""; } function ProbeResultPanel({ probe }: { probe: UpstreamProbeResult }) { const { t } = useI18n(); const reachable = !!probe.reachable; const handshakeOk = !!probe.handshakeOk; const udpOk = !!probe.udpAssociateOk; const handshakeState: ProbeState = !reachable ? "pending" : handshakeOk ? "ok" : "fail"; const udpState: ProbeState = !handshakeOk ? "pending" : udpOk ? "ok" : "fail"; return (
{probe.relayAddr ? (
{t("UDP 中继地址:")}{probe.relayAddr}
) : null} {probe.hint ?
{probe.hint}
: null} {probe.error ?
{probe.error}
: null}
); } export function UpstreamDialog({ open, editing, form, testing, probe, onPatch, onTest, onClose, onSubmit }: UpstreamDialogProps) { const { t } = useI18n(); return ( } >
onPatch({ id: e.target.value })} /> onPatch({ name: e.target.value })} />
onPatch({ addr: e.target.value })} />
{t("VoWiFi 通过此 Socks5 代理连接运营商,实现跨区域本地 VoWiFi。")} {ipv6Hint()} {t("。点下方「检测连通性」可在保存前验证 Socks5 握手与 UDP Associate。")}
onPatch({ enabled: v })} />
onPatch({ username: e.target.value })} /> onPatch({ password: e.target.value })} />
{t("编辑已有代理时留空会保持原密码不变。")}
{probe ? (
) : null}
); }