import React, { useEffect, useState } from "react"; import { createRoot } from "react-dom/client"; import { clearToken, createTemplate, deactivateTemplate, getMe, getToken, listInstances, listTemplates, login, register, } from "./api"; import "./styles.css"; function App() { const [mode, setMode] = useState("login"); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [message, setMessage] = useState(""); const [user, setUser] = useState(null); const [templates, setTemplates] = useState([]); const [instances, setInstances] = useState([]); const [templateForm, setTemplateForm] = useState({ name: "", description: "", guest_type: "vm", source_vmid: "", source_template: "", cores: 1, memory_mb: 1024, disk_gb: 10, }); async function loadPanel() { const [templateData, instanceData] = await Promise.all([ listTemplates(), listInstances(), ]); setTemplates(templateData); setInstances(instanceData); } useEffect(() => { if (!getToken()) return; Promise.all([getMe(), loadPanel()]).then(([currentUser]) => { setUser(currentUser); }).catch(() => clearToken()); }, []); async function handleSubmit(event) { event.preventDefault(); setMessage(""); try { if (mode === "register") { await register(email, password); setMessage("Регистрация завершена. Теперь войдите."); setMode("login"); return; } await login(email, password); const currentUser = await getMe(); setUser(currentUser); await loadPanel(); setMessage(`Вы вошли как ${currentUser.role}.`); } catch (error) { setMessage(error.message); } } async function handleCreateTemplate(event) { event.preventDefault(); setMessage(""); try { const payload = { ...templateForm, cores: Number(templateForm.cores), memory_mb: Number(templateForm.memory_mb), disk_gb: Number(templateForm.disk_gb), source_vmid: templateForm.guest_type === "vm" ? Number(templateForm.source_vmid) : null, source_template: templateForm.guest_type === "lxc" ? templateForm.source_template : null, }; await createTemplate(payload); setMessage("Шаблон создан."); setTemplateForm({ ...templateForm, name: "", description: "" }); await loadPanel(); } catch (error) { setMessage(error.message); } } async function handleDeactivate(id) { if (!window.confirm("Деактивировать этот шаблон?")) return; try { await deactivateTemplate(id); await loadPanel(); setMessage("Шаблон деактивирован."); } catch (error) { setMessage(error.message); } } function logout() { clearToken(); setUser(null); setTemplates([]); setInstances([]); } if (!user) { return (

Proxmox VPS Panel

{mode === "login" ? "Вход" : "Регистрация"}

{message &&

{message}

}
); } return (
Proxmox VPS Panel{user.email} · {user.role}
{message &&

{message}

}

Мои инстансы

{instances.length === 0 ?

Инстансов пока нет.

: (
{instances.map((item) => (
{item.name} {item.guest_type.toUpperCase()} · VMID {item.vmid ?? "не назначен"} {item.status} · {item.node}
))}
)}

Доступные шаблоны

{templates.length === 0 ?

Шаблонов пока нет.

: (
{templates.map((item) => (
{item.name} {item.guest_type.toUpperCase()} · {item.cores} CPU · {item.memory_mb} MB · {item.disk_gb} GB {user.role === "admin" && }
))}
)}
{user.role === "admin" &&

Создать шаблон

{templateForm.guest_type === "vm" ? ( ) : ( )}
}
); } createRoot(document.getElementById("root")).render();