"use client"; import { useMemo, useState } from "react"; import { IconButton, Stack, Switch, Tooltip, Typography } from "@mui/material"; import EditIcon from "@mui/icons-material/Edit"; import DeleteIcon from "@mui/icons-material/Delete"; import ContentCopyIcon from "@mui/icons-material/ContentCopy"; import type { AccessList } from "@/src/lib/models/access-lists"; import type { Certificate } from "@/src/lib/models/certificates"; import type { ProxyHost } from "@/src/lib/models/proxy-hosts"; import type { AuthentikSettings } from "@/src/lib/settings"; import { toggleProxyHostAction } from "./actions"; import { PageHeader } from "@/src/components/ui/PageHeader"; import { SearchField } from "@/src/components/ui/SearchField"; import { DataTable } from "@/src/components/ui/DataTable"; import { StatusChip } from "@/src/components/ui/StatusChip"; import { CreateHostDialog, EditHostDialog, DeleteHostDialog } from "@/src/components/proxy-hosts/HostDialogs"; type Props = { hosts: ProxyHost[]; certificates: Certificate[]; accessLists: AccessList[]; authentikDefaults: AuthentikSettings | null; }; export default function ProxyHostsClient({ hosts, certificates, accessLists, authentikDefaults }: Props) { const [createOpen, setCreateOpen] = useState(false); const [duplicateHost, setDuplicateHost] = useState(null); const [editHost, setEditHost] = useState(null); const [deleteHost, setDeleteHost] = useState(null); const [searchTerm, setSearchTerm] = useState(""); const filteredHosts = useMemo(() => { if (!searchTerm.trim()) return hosts; const search = searchTerm.toLowerCase(); return hosts.filter((host) => { // Search in name if (host.name.toLowerCase().includes(search)) return true; // Search in domains if (host.domains.some(domain => domain.toLowerCase().includes(search))) return true; // Search in upstreams if (host.upstreams.some(upstream => upstream.toLowerCase().includes(search))) return true; const certificate = host.certificate_id ? certificates.find(c => c.id === host.certificate_id) : null; const certName = certificate?.name ?? "Managed by Caddy (Auto)"; if (certName.toLowerCase().includes(search)) return true; return false; }); }, [hosts, certificates, searchTerm]); const handleToggleEnabled = async (id: number, enabled: boolean) => { await toggleProxyHostAction(id, enabled); }; const columns = [ { id: "name", label: "Name", render: (host: ProxyHost) => ( {host.name} ) }, { id: "domains", label: "Domains", render: (host: ProxyHost) => ( {host.domains[0]} {host.domains.length > 1 && ` +${host.domains.length - 1} more`} ) }, { id: "upstreams", label: "Upstreams", render: (host: ProxyHost) => ( {host.upstreams[0]} {host.upstreams.length > 1 && ` +${host.upstreams.length - 1} more`} ) }, { id: "status", label: "Status", render: (host: ProxyHost) => ( ) }, { id: "actions", label: "Actions", align: "right" as const, width: 150, render: (host: ProxyHost) => ( handleToggleEnabled(host.id, e.target.checked)} size="small" color="success" /> { setDuplicateHost(host); setCreateOpen(true); }} color="info" > setEditHost(host)} color="primary"> setDeleteHost(host)} color="error"> ) } ]; return ( setCreateOpen(true) }} /> setSearchTerm(e.target.value)} placeholder="Search hosts..." /> { setCreateOpen(false); // Clear duplicate host after dialog transition setTimeout(() => setDuplicateHost(null), 200); }} initialData={duplicateHost} certificates={certificates} accessLists={accessLists} authentikDefaults={authentikDefaults} /> {editHost && ( setEditHost(null)} certificates={certificates} accessLists={accessLists} /> )} {deleteHost && ( setDeleteHost(null)} /> )} ); }