import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { Loader2, RefreshCw, Terminal } from "lucide-react"; import { Button } from "@/components/button"; import { Input } from "@/components/input"; import type { Host } from "@/types/ui-types"; import { getTailscaleDevices } from "./tailscale-api"; import { createQuickConnectHost } from "../../../src/ui/sidebar/quick-connect-host"; interface TailscaleDevice { id: string; name: string; hostname: string; addresses: string[]; os: string; lastSeen: string; } interface TailscaleDevicesPanelProps { onConnect: (host: Host, type: "terminal") => void; } function deviceIp(device: TailscaleDevice): string { return ( device.addresses.find((a) => a.startsWith("100.")) ?? device.addresses[0] ?? "" ); } export function TailscaleDevicesPanel({ onConnect, }: TailscaleDevicesPanelProps) { const { t } = useTranslation(); const [devices, setDevices] = useState([]); const [hasApiKey, setHasApiKey] = useState(true); const [loading, setLoading] = useState(true); const [error, setError] = useState(false); const [usernames, setUsernames] = useState>({}); function load() { setLoading(true); setError(false); getTailscaleDevices() .then((res) => { setDevices(res.devices); setHasApiKey(res.hasApiKey); }) .catch(() => setError(true)) .finally(() => setLoading(false)); } useEffect(load, []); function connect(device: TailscaleDevice) { const ip = deviceIp(device); if (!ip) return; const username = usernames[device.id]?.trim() || "root"; const host = createQuickConnectHost({ ip, port: 22, username, authType: "tailscale", }); onConnect(host, "terminal"); } return (
{t("nav.tailscale")}
{loading && (
{t("hosts.tailscaleLoadingDevices")}
)} {!loading && !hasApiKey && (

{t("hosts.tailscaleNoApiKey")}

)} {!loading && hasApiKey && error && (

{t("hosts.tailscaleDeviceLoadFailed")}

)} {!loading && hasApiKey && !error && devices.length === 0 && (

{t("hosts.tailscaleNoDevices")}

)} {!loading && hasApiKey && !error && devices.map((device) => { const ip = deviceIp(device); return (
{device.hostname || device.name} {ip} {device.os ? `ยท ${device.os}` : ""}
setUsernames((prev) => ({ ...prev, [device.id]: e.target.value, })) } onKeyDown={(e) => { if (e.key === "Enter") connect(device); }} className="h-7 text-xs" />
); })}
); } export default TailscaleDevicesPanel;