import React, { useRef, useState, useEffect } from "react"; import { FormControl, FormDescription, FormField, FormItem, FormLabel, } from "@/components/ui/form.tsx"; import { Switch } from "@/components/ui/switch.tsx"; import { Input } from "@/components/ui/input.tsx"; import { Button } from "@/components/ui/button.tsx"; import { Alert, AlertDescription } from "@/components/ui/alert.tsx"; import type { HostTunnelTabProps } from "./shared/tab-types"; export function HostTunnelTab({ control, watch, setValue, getValues, sshConfigurations, editingHost, t, }: HostTunnelTabProps) { const [sshConfigDropdownOpen, setSshConfigDropdownOpen] = useState<{ [key: number]: boolean; }>({}); const sshConfigInputRefs = useRef<{ [key: number]: HTMLInputElement | null; }>({}); const sshConfigDropdownRefs = useRef<{ [key: number]: HTMLDivElement | null; }>({}); const getFilteredSshConfigs = (index: number) => { const value = watch(`tunnelConnections.${index}.endpointHost`); const currentHostId = editingHost?.id; let filtered = sshConfigurations; if (currentHostId) { const currentHostName = editingHost?.name; if (currentHostName) { filtered = sshConfigurations.filter( (config) => config !== currentHostName, ); } } else { const currentHostName = watch("name") || `${watch("username")}@${watch("ip")}`; filtered = sshConfigurations.filter( (config) => config !== currentHostName, ); } if (value) { filtered = filtered.filter((config) => config.toLowerCase().includes(value.toLowerCase()), ); } return filtered; }; const handleSshConfigClick = (config: string, index: number) => { setValue(`tunnelConnections.${index}.endpointHost`, config); setSshConfigDropdownOpen((prev) => ({ ...prev, [index]: false })); }; useEffect(() => { function handleSshConfigClickOutside(event: MouseEvent) { const openDropdowns = Object.keys(sshConfigDropdownOpen).filter( (key) => sshConfigDropdownOpen[parseInt(key)], ); openDropdowns.forEach((indexStr: string) => { const index = parseInt(indexStr); if ( sshConfigDropdownRefs.current[index] && !sshConfigDropdownRefs.current[index]?.contains( event.target as Node, ) && sshConfigInputRefs.current[index] && !sshConfigInputRefs.current[index]?.contains(event.target as Node) ) { setSshConfigDropdownOpen((prev) => ({ ...prev, [index]: false })); } }); } const hasOpenDropdowns = Object.values(sshConfigDropdownOpen).some( (open) => open, ); if (hasOpenDropdowns) { document.addEventListener("mousedown", handleSshConfigClickOutside); } else { document.removeEventListener("mousedown", handleSshConfigClickOutside); } return () => { document.removeEventListener("mousedown", handleSshConfigClickOutside); }; }, [sshConfigDropdownOpen]); return (
( {t("hosts.enableTunnel")} {t("hosts.enableTunnelDesc")} )} /> {watch("enableTunnel") && ( <> {t("hosts.sshpassRequired")}
{t("hosts.sshpassRequiredDesc")}{" "} sudo apt install sshpass {" "} {t("hosts.debianUbuntuEquivalent")}
{t("hosts.otherInstallMethods")}
• {t("hosts.centosRhelFedora")}{" "} sudo yum install sshpass {" "} {t("hosts.or")}{" "} sudo dnf install sshpass
• {t("hosts.macos")}{" "} brew install hudochenkov/sshpass/sshpass
• {t("hosts.windows")}
{t("hosts.sshServerConfigRequired")}
{t("hosts.sshServerConfigDesc")}
•{" "} GatewayPorts yes {" "} {t("hosts.gatewayPortsYes")}
•{" "} AllowTcpForwarding yes {" "} {t("hosts.allowTcpForwardingYes")}
•{" "} PermitRootLogin yes {" "} {t("hosts.permitRootLoginYes")}
{t("hosts.editSshConfig")}
( {t("hosts.tunnelConnections")}
{field.value.map((connection, index) => (

{t("hosts.connection")} {index + 1}

( {t("hosts.sourcePort")} {t("hosts.sourcePortDesc")} )} /> ( {t("hosts.endpointPort")} )} /> ( {t("hosts.endpointSshConfig")} { sshConfigInputRefs.current[index] = el; }} placeholder={t("placeholders.sshConfig")} className="min-h-[40px]" autoComplete="off" value={endpointHostField.value} onFocus={() => setSshConfigDropdownOpen((prev) => ({ ...prev, [index]: true, })) } onChange={(e) => { endpointHostField.onChange(e); setSshConfigDropdownOpen((prev) => ({ ...prev, [index]: true, })); }} onBlur={(e) => { endpointHostField.onChange( e.target.value.trim(), ); endpointHostField.onBlur(); }} /> {sshConfigDropdownOpen[index] && getFilteredSshConfigs(index).length > 0 && (
{ sshConfigDropdownRefs.current[index] = el; }} className="absolute top-full left-0 z-50 mt-1 w-full bg-canvas border border-input rounded-md shadow-lg max-h-40 overflow-y-auto thin-scrollbar p-1" >
{getFilteredSshConfigs(index).map( (config) => ( ), )}
)}
)} />

{t("hosts.tunnelForwardDescription", { sourcePort: watch(`tunnelConnections.${index}.sourcePort`) || "22", endpointPort: watch( `tunnelConnections.${index}.endpointPort`, ) || "224", })}

( {t("hosts.maxRetries")} {t("hosts.maxRetriesDescription")} )} /> ( {t("hosts.retryInterval")} {t("hosts.retryIntervalDescription")} )} /> ( {t("hosts.autoStartContainer")} {t("hosts.autoStartDesc")} )} />
))}
)} /> )}
); }