import { useEffect, useState, type ComponentType } from "react"; import { Boxes, HardDrive, Server } from "lucide-react"; import { useHosts, useTranslation, type HostEditorSectionProps, type StandaloneViewProps, type TabProps, type TermixApp, } from "@termix/plugin-sdk/frontend"; import { ComponentSlot, DropdownMenuItem } from "@termix/plugin-sdk/ui"; import type { SSHHostWithStatus } from "@/main-axios"; import { ProxmoxDiscoverDialog } from "./ProxmoxDiscoverDialog"; import { HostProxmoxTab } from "./HostProxmoxTab"; import { ProxmoxStatsTab } from "./stats/ProxmoxStatsTab"; import ProxmoxStatsApp from "./stats/ProxmoxStatsApp"; import { HostProxmoxStatsTab } from "./stats/HostProxmoxStatsTab"; import type { SSHHost } from "@/types"; interface DiscoverRequest { hostId?: number; defaultCredentialId?: number | null; defaultAuthType?: string; } type Opener = (request: DiscoverRequest) => void; // The Proxmox fields are this plugin's host settings, saved with the host // through form.pluginSettings.proxmox. function ProxmoxHostSection({ form, updateForm }: HostEditorSectionProps) { const values = (form.pluginSettings?.proxmox ?? {}) as Record< string, unknown >; const setField = (key: string, value: unknown) => updateForm((current) => { const all = (current.pluginSettings ?? {}) as Record< string, Record >; return { ...current, pluginSettings: { ...all, proxmox: { ...(all.proxmox ?? {}), [key]: value }, }, }; }); const sectionForm = { enableProxmox: values.enableProxmox === true, proxmoxConfig: values.proxmoxConfig ?? null, enableProxmoxStats: values.enableProxmoxStats === true, proxmoxStatsConfig: values.proxmoxStatsConfig ?? { pollInterval: 60, nodeName: null, }, }; return ( <> [0]["form"]} setField={setField as Parameters[0]["setField"]} /> [0]["form"]} setField={ setField as Parameters[0]["setField"] } /> {/* Other plugins add Proxmox-related settings here. */} ); } function ProxmoxStatsTabView({ sshHost, label, isVisible }: TabProps) { return ( ); } function ProxmoxStatsStandalone({ hostId }: StandaloneViewProps) { return ; } export function activate(app: TermixApp): void { // The dialog lives in the hosts panel; the menu item and host action open // it through this, created per activation. const openers = new Set(); const openDiscover: Opener = (request) => { for (const open of openers) open(request); }; function DiscoverDialogHost({ hosts, onHostsChanged, }: { hosts: SSHHostWithStatus[]; onHostsChanged: (hosts: SSHHostWithStatus[]) => void; }) { const [request, setRequest] = useState(null); useEffect(() => { openers.add(setRequest); return () => { openers.delete(setRequest); }; }, []); if (!request) return null; return ( setRequest(null)} hosts={hosts} onHostsChanged={onHostsChanged} preselectedHostId={request.hostId} defaultCredentialId={request.defaultCredentialId ?? null} defaultAuthType={request.defaultAuthType} /> ); } function ImportMenuItem() { const { t } = useTranslation(); const { hosts } = useHosts(); return ( openDiscover({})} disabled={!hosts.some((host) => host.enableProxmox)} > {t("hosts.proxmoxImportTitle")} ); } app.registerSlotContribution("hosts.panel", { actionId: "proxmox.discoverDialog", titleKey: "hosts.proxmoxImportTitle", kind: "component", component: DiscoverDialogHost as unknown as ComponentType< Record >, }); app.registerSlotContribution("hosts.importMenu", { actionId: "proxmox.import", titleKey: "hosts.proxmoxImportTitle", kind: "component", component: ImportMenuItem as ComponentType>, }); app.registerHostAction({ id: "proxmox-discover", titleKey: "hosts.proxmoxDiscoverAction", icon: Boxes, kind: "open", order: 90, when: (host) => !!host.enableProxmox, run: (host) => { const config = host.proxmoxConfig as | { defaultCredentialId?: number | null; defaultAuthType?: string } | undefined; openDiscover({ hostId: Number(host.id), defaultCredentialId: config?.defaultCredentialId ?? null, defaultAuthType: config?.defaultAuthType ?? undefined, }); }, }); app.registerHostEditorSection({ id: "proxmox", group: "ssh", titleKey: "hosts.tabProxmox", icon: Server, order: 50, component: ProxmoxHostSection, }); app.registerTab("proxmox-stats", ProxmoxStatsTabView, { icon: HardDrive, titleKey: "nav.proxmoxStats", requiresHost: true, noHostMessageKey: "proxmoxStats.noHostSelected", standalone: ProxmoxStatsStandalone, preload: () => import("./stats/ProxmoxStatsTab"), }); app.registerHostAction({ id: "proxmox-stats", titleKey: "nav.proxmoxStats", icon: HardDrive, kind: "open", order: 60, tabType: "proxmox-stats", copyUrlView: "proxmox-stats", when: (host) => host.enableProxmoxStats === true, }); }