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 (
sudo apt install sshpass
{" "}
{t("hosts.debianUbuntuEquivalent")}
sudo yum install sshpass
{" "}
{t("hosts.or")}{" "}
sudo dnf install sshpass
brew install hudochenkov/sshpass/sshpass
GatewayPorts yes
{" "}
{t("hosts.gatewayPortsYes")}
AllowTcpForwarding yes
{" "}
{t("hosts.allowTcpForwardingYes")}
PermitRootLogin yes
{" "}
{t("hosts.permitRootLoginYes")}
{t("hosts.tunnelForwardDescription", { sourcePort: watch(`tunnelConnections.${index}.sourcePort`) || "22", endpointPort: watch( `tunnelConnections.${index}.endpointPort`, ) || "224", })}