diff --git a/frontend/src/TemplateManager.jsx b/frontend/src/TemplateManager.jsx new file mode 100644 index 0000000..8ab8708 --- /dev/null +++ b/frontend/src/TemplateManager.jsx @@ -0,0 +1,125 @@ +import React, { useEffect, useState } from "react"; +import { + createTemplate, + deactivateTemplate, + listProxmoxTemplates, + listTemplates, +} from "./api"; + +const empty = { + name: "", + description: "", + guest_type: "vm", + source_vmid: "", + source_template: "", + cores: 1, + memory_mb: 1024, + disk_gb: 10, +}; + +export default function TemplateManager() { + const [templates, setTemplates] = useState([]); + const [discovered, setDiscovered] = useState(null); + const [form, setForm] = useState(empty); + const [message, setMessage] = useState(""); + const [busy, setBusy] = useState(false); + + async function refresh() { + setTemplates(await listTemplates()); + } + + async function findTemplates() { + setBusy(true); + setMessage("Ищем шаблоны на Proxmox..."); + try { + setDiscovered(await listProxmoxTemplates()); + setMessage("Шаблоны Proxmox найдены."); + } catch (error) { + setMessage(error.message); + } finally { + setBusy(false); + } + } + + async function importTemplate(payload) { + setBusy(true); + try { + await createTemplate(payload); + await refresh(); + setMessage("Шаблон импортирован в каталог панели."); + } catch (error) { + setMessage(error.message); + } finally { + setBusy(false); + } + } + + async function submit(event) { + event.preventDefault(); + setBusy(true); + try { + await createTemplate({ + ...form, + source_vmid: form.source_vmid ? Number(form.source_vmid) : null, + source_template: form.source_template || null, + cores: Number(form.cores), + memory_mb: Number(form.memory_mb), + disk_gb: Number(form.disk_gb), + }); + setForm(empty); + await refresh(); + setMessage("Шаблон создан."); + } catch (error) { + setMessage(error.message); + } finally { + setBusy(false); + } + } + + async function remove(id) { + if (!window.confirm("Деактивировать шаблон?")) return; + await deactivateTemplate(id); + await refresh(); + } + + useEffect(() => { refresh().catch((error) => setMessage(error.message)); }, []); + + return
+

Шаблоны VPS

+ {message &&

{message}

} + +

Найти шаблоны на Proxmox

+ + + {discovered &&
+

VM-шаблоны

+ {discovered.vm_templates?.map((vm) =>
+ {vm.vmid} — {vm.name} + {vm.cores} vCPU · {vm.memory_mb} MB + +
)} + +

LXC-шаблоны

+ {discovered.lxc_templates?.map((lxc) =>
+ {lxc.name} + {lxc.source_kind === "vmid" ? `CTID ${lxc.vmid}` : `${lxc.storage} · ${lxc.size_mb} MB`} + +
)} +
} + +

Добавить вручную

+
+ + + {form.guest_type === "vm" ? : } + +
+ +
+ +

Активные шаблоны

+
{templates.map((template) =>
{template.name}{template.guest_type.toUpperCase()} · {template.cores} CPU · {template.memory_mb} MB · {template.disk_gb} GB
)}
+
; +}