import React, { useState, useEffect, useRef } from "react"; import { HostManagerViewer } from "@/ui/desktop/apps/host-manager/hosts/HostManagerViewer.tsx"; import { Tabs, TabsContent, TabsList, TabsTrigger, } from "@/components/ui/tabs.tsx"; import { Separator } from "@/components/ui/separator.tsx"; import { HostManagerEditor } from "@/ui/desktop/apps/host-manager/hosts/HostManagerEditor.tsx"; import { CredentialsManager } from "@/ui/desktop/apps/host-manager/credentials/CredentialsManager.tsx"; import { CredentialEditor } from "@/ui/desktop/apps/host-manager/credentials/CredentialEditor.tsx"; import { useSidebar } from "@/components/ui/sidebar.tsx"; import { useTranslation } from "react-i18next"; import { exportSSHHostWithCredentials } from "@/ui/main-axios.ts"; import type { SSHHost, HostManagerProps } from "../../../types/index"; export function HostManager({ isTopbarOpen, initialTab = "hosts", hostConfig, _updateTimestamp, rightSidebarOpen = false, rightSidebarWidth = 400, currentTabId, updateTab, }: HostManagerProps): React.ReactElement { const { t } = useTranslation(); const [activeTab, setActiveTab] = useState( initialTab === "host_viewer" || initialTab === "add_host" ? "hosts" : initialTab === "credentials" || initialTab === "add_credential" ? "credentials" : initialTab, ); const [editingHost, setEditingHost] = useState( hostConfig || null, ); const [isAddingHost, setIsAddingHost] = useState(false); const [isAddingCredential, setIsAddingCredential] = useState(false); useEffect(() => {}, [editingHost]); const [editingCredential, setEditingCredential] = useState<{ id: number; name?: string; username: string; } | null>(null); const { state: sidebarState } = useSidebar(); const ignoreNextHostConfigChangeRef = useRef(false); const lastProcessedHostIdRef = useRef(undefined); useEffect(() => { const handleAddHostEvent = () => { setActiveTab("hosts"); setEditingHost(null); setIsAddingHost(true); setIsAddingCredential(false); }; const handleAddCredentialEvent = () => { setActiveTab("credentials"); setEditingCredential(null); setIsAddingCredential(true); setIsAddingHost(false); }; window.addEventListener("host-manager:add-host", handleAddHostEvent); window.addEventListener( "host-manager:add-credential", handleAddCredentialEvent, ); return () => { window.removeEventListener("host-manager:add-host", handleAddHostEvent); window.removeEventListener( "host-manager:add-credential", handleAddCredentialEvent, ); }; }, []); useEffect(() => { if (_updateTimestamp !== undefined) { const normalizedTab = initialTab === "host_viewer" || initialTab === "add_host" ? "hosts" : initialTab === "credentials" || initialTab === "add_credential" ? "credentials" : initialTab; if (initialTab && normalizedTab !== activeTab) { setActiveTab(normalizedTab); } if (hostConfig && hostConfig.id !== lastProcessedHostIdRef.current) { lastProcessedHostIdRef.current = hostConfig.id; setIsAddingHost(false); exportSSHHostWithCredentials(hostConfig.id) .then((fullHost) => setEditingHost({ ...hostConfig, ...fullHost } as SSHHost), ) .catch(() => setEditingHost(hostConfig)); } else if (!hostConfig && editingHost) { setEditingHost(null); setIsAddingHost(false); } } else { if (initialTab) { const normalizedTab = initialTab === "host_viewer" || initialTab === "add_host" ? "hosts" : initialTab === "credentials" || initialTab === "add_credential" ? "credentials" : initialTab; setActiveTab(normalizedTab); } if (hostConfig && hostConfig.id !== lastProcessedHostIdRef.current) { lastProcessedHostIdRef.current = hostConfig.id; setIsAddingHost(false); exportSSHHostWithCredentials(hostConfig.id) .then((fullHost) => setEditingHost({ ...hostConfig, ...fullHost } as SSHHost), ) .catch(() => setEditingHost(hostConfig)); } } }, [_updateTimestamp, initialTab, hostConfig]); const handleEditHost = async (host: SSHHost) => { setIsAddingHost(false); lastProcessedHostIdRef.current = host.id; try { const fullHost = await exportSSHHostWithCredentials(host.id); setEditingHost({ ...host, ...fullHost } as SSHHost); } catch { setEditingHost(host); } }; const handleAddHost = () => { setEditingHost(null); setIsAddingHost(true); lastProcessedHostIdRef.current = undefined; }; const handleFormSubmit = (savedHost?: SSHHost) => { ignoreNextHostConfigChangeRef.current = true; const isUpdatingHost = Boolean(editingHost?.id && savedHost?.id); if (isUpdatingHost) { setEditingHost((current) => ({ ...current, ...savedHost }) as SSHHost); setIsAddingHost(false); lastProcessedHostIdRef.current = savedHost.id; if (updateTab && currentTabId !== undefined) { updateTab(currentTabId, { hostConfig: savedHost }); } return; } const savedHostId = savedHost?.id || editingHost?.id; setEditingHost(null); setIsAddingHost(false); setTimeout(() => { lastProcessedHostIdRef.current = savedHostId; }, 500); }; const handleEditCredential = (credential: { id: number; name?: string; username: string; }) => { setEditingCredential(credential); setIsAddingCredential(false); }; const handleAddCredential = () => { setEditingCredential(null); setIsAddingCredential(true); }; const handleCredentialFormSubmit = () => { setEditingCredential(null); setIsAddingCredential(false); }; const handleTabChange = (value: string) => { if (activeTab !== value) { setEditingHost(null); setEditingCredential(null); setIsAddingHost(false); setIsAddingCredential(false); lastProcessedHostIdRef.current = undefined; if (updateTab && currentTabId !== undefined) { updateTab(currentTabId, { hostConfig: null }); } } setActiveTab(value); if (updateTab && currentTabId !== undefined) { updateTab(currentTabId, { initialTab: value }); } }; const topMarginPx = isTopbarOpen ? 74 : 26; const leftMarginPx = sidebarState === "collapsed" ? 26 : 8; const bottomMarginPx = 8; return (
{t("hosts.hosts")} {t("credentials.credentials")} {editingHost !== null || isAddingHost ? (
{ setEditingHost(null); setIsAddingHost(false); lastProcessedHostIdRef.current = undefined; }} />
) : ( )}
{editingCredential !== null || isAddingCredential ? (
{ setEditingCredential(null); setIsAddingCredential(false); }} />
) : (
)}
); }