import { Sidebar, SidebarContent, SidebarFooter, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider } from "@/components/ui/sidebar.tsx"; import {Button} from "@/components/ui/button.tsx"; import {ChevronUp, Menu, User2} from "lucide-react"; import React, {useState, useEffect, useMemo, useCallback} from "react"; import {Separator} from "@/components/ui/separator.tsx"; import {FolderCard} from "@/ui/Mobile/Navigation/Hosts/FolderCard.tsx"; import {getSSHHosts} from "@/ui/main-axios.ts"; import {useTranslation} from "react-i18next"; import {Input} from "@/components/ui/input.tsx"; import {DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger} from "@radix-ui/react-dropdown-menu"; interface SSHHost { id: number; name: string; ip: string; port: number; username: string; folder: string; tags: string[]; pin: boolean; authType: string; password?: string; key?: string; keyPassword?: string; keyType?: string; enableTerminal: boolean; enableTunnel: boolean; enableFileManager: boolean; defaultPath: string; tunnelConnections: any[]; createdAt: string; updatedAt: string; } interface LeftSidebarProps { isSidebarOpen: boolean; setIsSidebarOpen: (type: boolean) => void; onHostConnect: () => void; disabled?: boolean; username?: string | null; } function handleLogout() { document.cookie = 'jwt=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; window.location.reload(); } export function LeftSidebar({isSidebarOpen, setIsSidebarOpen, onHostConnect, disabled, username}: LeftSidebarProps) { const {t} = useTranslation(); const [hosts, setHosts] = useState([]); const [hostsLoading, setHostsLoading] = useState(false); const [hostsError, setHostsError] = useState(null); const prevHostsRef = React.useRef([]); const [search, setSearch] = useState(""); const [debouncedSearch, setDebouncedSearch] = useState(""); const fetchHosts = useCallback(async () => { try { const newHosts = await getSSHHosts(); const prevHosts = prevHostsRef.current; if (JSON.stringify(newHosts) !== JSON.stringify(prevHosts)) { setHosts(newHosts); prevHostsRef.current = newHosts; } } catch (err: any) { setHostsError(t('leftSidebar.failedToLoadHosts')); } }, [t]); useEffect(() => { fetchHosts(); const interval = setInterval(fetchHosts, 300000); return () => clearInterval(interval); }, [fetchHosts]); useEffect(() => { const handleHostsChanged = () => { fetchHosts(); }; window.addEventListener('ssh-hosts:changed', handleHostsChanged as EventListener); return () => window.removeEventListener('ssh-hosts:changed', handleHostsChanged as EventListener); }, [fetchHosts]); useEffect(() => { const handler = setTimeout(() => setDebouncedSearch(search), 200); return () => clearTimeout(handler); }, [search]); const filteredHosts = useMemo(() => { if (!debouncedSearch.trim()) return hosts; const q = debouncedSearch.trim().toLowerCase(); return hosts.filter(h => { const searchableText = [ h.name || '', h.username, h.ip, h.folder || '', ...(h.tags || []), ].join(' ').toLowerCase(); return searchableText.includes(q); }); }, [hosts, debouncedSearch]); const hostsByFolder = useMemo(() => { const map: Record = {}; filteredHosts.forEach(h => { const folder = h.folder && h.folder.trim() ? h.folder : t('leftSidebar.noFolder'); if (!map[folder]) map[folder] = []; map[folder].push(h); }); return map; }, [filteredHosts, t]); const sortedFolders = useMemo(() => { const folders = Object.keys(hostsByFolder); folders.sort((a, b) => { if (a === t('leftSidebar.noFolder')) return 1; if (b === t('leftSidebar.noFolder')) return -1; return a.localeCompare(b); }); return folders; }, [hostsByFolder, t]); const getSortedHosts = useCallback((arr: SSHHost[]) => { const pinned = arr.filter(h => h.pin).sort((a, b) => (a.name || '').localeCompare(b.name || '')); const rest = arr.filter(h => !h.pin).sort((a, b) => (a.name || '').localeCompare(b.name || '')); return [...pinned, ...rest]; }, []); return (
Termix
setSearch(e.target.value)} placeholder={t('placeholders.searchHostsAny')} className="w-full h-8 text-sm border-2 !bg-[#222225] border-[#303032] rounded-md" autoComplete="off" />
{hostsError && (
{t('leftSidebar.failedToLoadHosts')}
)} {hostsLoading && (
{t('hosts.loadingHosts')}
)} {sortedFolders.map((folder) => ( ))}
{username ? username : t('common.logout')} {t('common.logout')}
) }