import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { Eye, EyeOff, Terminal } from "lucide-react"; import { Input } from "@/components/input"; import type { Host } from "@/types/ui-types"; import { getCredentials } from "@/api/credentials-api"; import { mapCredentials } from "./HostManagerData"; import { createQuickConnectHost } from "./quick-connect-host"; import { useHostProtocols } from "./host-protocols"; import { Select2 } from "@/components/select2"; import { resolveHostTabType } from "@/lib/host-connection-tabs"; import { useSshAuthProviders } from "@/hooks/useSshAuthProviders"; import { useSshAuthEditors } from "@/plugin-host/auth-registry"; import { useHostActions } from "./host-contributions"; // Core types Quick Connect draws its own fields for. const INLINE_AUTH_TYPES = new Set(["password", "key", "credential"]); interface QuickConnectPanelProps { onConnect: (host: Host, type: string) => void; } export function QuickConnectPanel({ onConnect }: QuickConnectPanelProps) { const { t } = useTranslation(); const [host, setHost] = useState(""); // "ssh", or the id of a plugin protocol offered in Quick Connect. const [protocol, setProtocol] = useState("ssh"); const [port, setPort] = useState("22"); const [domain, setDomain] = useState(""); const [username, setUsername] = useState("root"); const [authType, setAuthType] = useState("password"); const [authFields, setAuthFields] = useState>({}); const [password, setPassword] = useState(""); const [privateKey, setPrivateKey] = useState(""); const [showPassword, setShowPassword] = useState(false); const [credentialId, setCredentialId] = useState(""); const [credentials, setCredentials] = useState< { id: string; name: string; username: string }[] >([]); useEffect(() => { getCredentials() .then((res) => setCredentials(mapCredentials(res))) .catch(() => {}); }, []); // Every registered SSH auth type that works for a host that is never saved. const { providers } = useSshAuthProviders(); const authOptions = providers.filter( (option) => option.available && option.quickConnect, ); const authEditor = useSshAuthEditors().find( (editor) => editor.id === authType, ); const AuthEditor = INLINE_AUTH_TYPES.has(authType) ? undefined : authEditor?.component; const quickActions = useHostActions().filter( (action) => action.quickConnect && action.tabType, ); const pluginProtocols = useHostProtocols().filter( (entry) => entry.quickConnect, ); const selected = pluginProtocols.find((entry) => entry.id === protocol); const isDesktop = !!selected; const defaultPort = (id: string) => String(pluginProtocols.find((entry) => entry.id === id)?.defaultPort ?? 22); const switchProtocol = (next: string) => { // Keep a port the user typed; only swap the protocol default. if (port === defaultPort(protocol)) setPort(defaultPort(next)); setProtocol(next); }; // The tab comes from whichever plugin connects hosts of this protocol. const connect = (type?: string) => { if (!host) return; if (!isDesktop && !username) return; const hostConfig = createQuickConnectHost({ ip: host, port: parseInt(port) || parseInt(defaultPort(protocol)), username, authType: isDesktop ? "password" : authType, password, key: privateKey, credentialId, protocol: selected, domain: domain || undefined, authFields: INLINE_AUTH_TYPES.has(authType) ? undefined : authFields, }); const target = type ?? resolveHostTabType(hostConfig); if (target) onConnect(hostConfig, target); }; const connectDefault = () => connect(); return (
{["ssh", ...pluginProtocols.map((entry) => entry.id)].map( (type) => ( ), )}
setHost(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") connectDefault(); }} className="h-7 text-xs" />
setPort(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") connectDefault(); }} className="h-7 text-xs" />
{ if (username === "root") setUsername(""); }} onBlur={() => { if (username === "") setUsername("root"); }} onChange={(e) => setUsername(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") connectDefault(); }} className="h-7 text-xs" />
{!isDesktop && (
{authOptions.map((option) => ( ))}
)} {(isDesktop || authType === "password") && (
setPassword(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") connectDefault(); }} className="h-7 text-xs pr-8" />
)} {selected?.quickConnect?.showDomain && (
setDomain(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") connectDefault(); }} className="h-7 text-xs" />
)} {!isDesktop && authType === "key" && (