Initial commit — Proxmox SPICE Client (Electron)
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
/* global api */
|
||||
|
||||
const loadingEl = document.getElementById('loadingState');
|
||||
const listEl = document.getElementById('vmList');
|
||||
const emptyEl = document.getElementById('emptyState');
|
||||
const errorEl = document.getElementById('error');
|
||||
const noticeEl = document.getElementById('notice');
|
||||
const refreshBtn = document.getElementById('refreshBtn');
|
||||
|
||||
document.getElementById('logoutBtn').addEventListener('click', async () => {
|
||||
await api.proxmox.logout();
|
||||
});
|
||||
|
||||
refreshBtn.addEventListener('click', () => loadVMs());
|
||||
|
||||
// ── Load on mount ─────────────────────────────────────────
|
||||
|
||||
async function loadVMs() {
|
||||
clearMessages();
|
||||
listEl.classList.add('hidden');
|
||||
emptyEl.classList.add('hidden');
|
||||
loadingEl.classList.remove('hidden');
|
||||
|
||||
const result = await api.proxmox.getVMs();
|
||||
|
||||
loadingEl.classList.add('hidden');
|
||||
|
||||
if (!result.success) {
|
||||
showError(result.error || 'Fehler beim Laden der VMs.');
|
||||
return;
|
||||
}
|
||||
|
||||
const vms = result.vms;
|
||||
|
||||
if (vms.length === 0) {
|
||||
emptyEl.classList.remove('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto-connect when there is exactly one SPICE VM
|
||||
if (vms.length === 1) {
|
||||
showNotice(`Nur eine VM verfügbar — verbinde mit „${vms[0].name}" …`);
|
||||
await connectVM(vms[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
renderList(vms);
|
||||
}
|
||||
|
||||
loadVMs();
|
||||
|
||||
// ── Render ────────────────────────────────────────────────
|
||||
|
||||
function renderList(vms) {
|
||||
listEl.innerHTML = vms
|
||||
.map(
|
||||
(vm) => `
|
||||
<div class="vm-card" data-vmid="${vm.vmid}">
|
||||
<div class="vm-info">
|
||||
<div class="vm-name">${esc(vm.name)}</div>
|
||||
<div class="vm-meta">
|
||||
<span class="status-dot"></span>
|
||||
Läuft · Node: ${esc(vm.node)} · ID: ${vm.vmid}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="btn-connect"
|
||||
data-vmid="${vm.vmid}"
|
||||
data-node="${esc(vm.node)}"
|
||||
data-name="${esc(vm.name)}"
|
||||
>Verbinden</button>
|
||||
</div>
|
||||
`
|
||||
)
|
||||
.join('');
|
||||
|
||||
listEl.querySelectorAll('.btn-connect').forEach((btn) => {
|
||||
btn.addEventListener('click', () =>
|
||||
connectVM({ vmid: btn.dataset.vmid, node: btn.dataset.node, name: btn.dataset.name })
|
||||
);
|
||||
});
|
||||
|
||||
listEl.classList.remove('hidden');
|
||||
}
|
||||
|
||||
// ── Connect ───────────────────────────────────────────────
|
||||
|
||||
async function connectVM(vm) {
|
||||
clearMessages();
|
||||
setAllButtons(true, 'Verbinde…');
|
||||
|
||||
const result = await api.proxmox.connect(vm);
|
||||
|
||||
setAllButtons(false, 'Verbinden');
|
||||
|
||||
if (!result.success) {
|
||||
showError(result.error || 'Verbindung fehlgeschlagen.');
|
||||
} else {
|
||||
showNotice(`„${vm.name}" — SPICE-Sitzung gestartet.`);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────
|
||||
|
||||
function setAllButtons(disabled, label) {
|
||||
listEl.querySelectorAll('.btn-connect').forEach((b) => {
|
||||
b.disabled = disabled;
|
||||
b.textContent = label;
|
||||
});
|
||||
}
|
||||
|
||||
function showError(msg) {
|
||||
errorEl.textContent = msg;
|
||||
errorEl.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function showNotice(msg) {
|
||||
noticeEl.textContent = msg;
|
||||
noticeEl.classList.remove('hidden');
|
||||
setTimeout(() => noticeEl.classList.add('hidden'), 5000);
|
||||
}
|
||||
|
||||
function clearMessages() {
|
||||
errorEl.classList.add('hidden');
|
||||
noticeEl.classList.add('hidden');
|
||||
}
|
||||
|
||||
function esc(str) {
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
Reference in New Issue
Block a user