diff --git a/src/api.php b/src/api.php
index 516290e..a7f6902 100644
--- a/src/api.php
+++ b/src/api.php
@@ -2,6 +2,19 @@
// /home/docker/pve_dashboard/src/api.php
ini_set('display_errors', 0);
error_reporting(E_ALL);
+ini_set('log_errors', 1);
+ini_set('error_log', '/var/www/data/php_errors.log');
+
+set_error_handler(function($errno, $errstr, $errfile, $errline) {
+ error_log("Error [$errno]: $errstr in $errfile on line $errline");
+});
+
+set_exception_handler(function($e) {
+ error_log("Exception: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
+ http_response_code(500);
+ echo json_encode(['success' => false, 'error' => 'Backend Error: ' . $e->getMessage()]);
+ exit;
+});
require_once 'db.php';
header('Content-Type: application/json');
diff --git a/src/app.js b/src/app.js
index 20c3ab2..0c4ae75 100644
--- a/src/app.js
+++ b/src/app.js
@@ -68,7 +68,7 @@ if (!window.APP.isLoggedIn) {
}
// ---------------------------------------------------------
-// 4. MAIN APP LOGIC (Dashboard, API Polling, Modals)
+// 4. MAIN APP LOGIC
// ---------------------------------------------------------
if (window.APP.isLoggedIn && window.APP.nodeCount > 0) {
@@ -120,6 +120,7 @@ if (window.APP.isLoggedIn && window.APP.nodeCount > 0) {
}
});
document.querySelectorAll('[id^="nav-node-"]').forEach(el => el.classList.remove('text-white', 'font-bold'));
+ if(tab === 'pve') { window.fetchGlobalStats(); window.fetchTopVms(); window.fetchRecentJobs(); }
if(tab === 'pbs' && typeof window.fetchPbsStats === 'function') window.fetchPbsStats();
if(tab === 'pmg' && typeof window.fetchPmgStats === 'function') window.fetchPmgStats();
}
@@ -174,7 +175,7 @@ if (window.APP.isLoggedIn && window.APP.nodeCount > 0) {
res.vms.forEach(vm => {
const isRunning = vm.status === 'running'; const typeStr = vm.type === 'lxc' ? '📦 LXC' : '🖥️ QEMU';
const statusBadge = isRunning ? 'Online' : 'Offline';
- let actionButtons = isRunning ? `` : ``;
+ let actionButtons = isRunning ? `` : ``;
actionButtons += ``;
vmsBody.innerHTML += `
| ${vm.vmid} | ${vm.name} | ${typeStr} | ${statusBadge} | ${actionButtons} |
`;
});
@@ -185,14 +186,15 @@ if (window.APP.isLoggedIn && window.APP.nodeCount > 0) {
}
}
- // --- NEU: ROBUSTE DASHBOARD API POLLING FUNKTIONEN ---
+ // --- DASHBOARD API POLLING FUNKTIONEN ---
window.fetchGlobalStats = async function() {
const tabEl = document.getElementById('tab-pve');
- if(!tabEl || tabEl.classList.contains('hidden')) return;
+ // REPARIERT: Nur abbrechen, wenn das Element definitiv existiert und die Klasse hidden hat
+ if(tabEl && tabEl.classList.contains('hidden')) return;
try {
const response = await fetch('api.php?action=get_stats');
- const text = await response.text(); // Lese erst als Text, um PHP Fehler abzufangen
+ const text = await response.text();
try {
const res = JSON.parse(text);
@@ -243,16 +245,14 @@ if (window.APP.isLoggedIn && window.APP.nodeCount > 0) {
if(el && el.innerText.includes('Lade')) el.innerText = 'PHP Fehler';
}
} catch (err) {
- console.error("Network/Adblock Error:", err);
- const el = document.getElementById('stat-cpu-text');
- if(el && el.innerText.includes('Lade')) el.innerText = 'Blockiert!';
+ console.error("Network Error fetchGlobalStats:", err);
}
}
window.fetchTopVms = async function() {
const container = document.getElementById('top-vms-container');
const tabEl = document.getElementById('tab-pve');
- if(!container || !tabEl || tabEl.classList.contains('hidden')) return;
+ if(!container || (tabEl && tabEl.classList.contains('hidden'))) return;
try {
const response = await fetch('api.php?action=get_top_vms');
@@ -271,10 +271,7 @@ if (window.APP.isLoggedIn && window.APP.nodeCount > 0) {
console.error("PHP Error in fetchTopVms:", text);
container.innerHTML = 'PHP Fehler! (Siehe Konsole)
';
}
- } catch (err) {
- console.error("Network/Adblock Error (fetchTopVms):", err);
- container.innerHTML = 'Netzwerk blockiert! (Adblocker?)
';
- }
+ } catch (err) {}
}
window.fetchRecentJobs = async function() {
@@ -297,10 +294,7 @@ if (window.APP.isLoggedIn && window.APP.nodeCount > 0) {
console.error("PHP Error in fetchRecentJobs:", text);
container.innerHTML = 'PHP Fehler! (Siehe Konsole)
';
}
- } catch (err) {
- console.error("Network/Adblock Error (fetchRecentJobs):", err);
- container.innerHTML = 'Netzwerk blockiert! (Adblocker?)
';
- }
+ } catch (err) {}
}
// --- GRAPHS & MODALS ---
@@ -650,4 +644,19 @@ if (window.APP.isLoggedIn && window.APP.nodeCount > 0) {
window.openUpdateManager = async function() { const m = document.getElementById('updateManagerModal'); if(m) m.classList.remove('hidden'); const content = document.getElementById('updateManagerContent'); if(!content) return; content.innerHTML = 'Prüfe Updates...
'; try { const res = await (await fetch('api.php?action=get_update_details')).json(); if (res.success) { content.innerHTML = ''; if(res.data.length === 0) { content.innerHTML = '🎉 Alle Systeme sind auf dem neuesten Stand!
'; return; } res.data.forEach(node => { let pkgsHtml = ''; node.packages.forEach(p => { pkgsHtml += `${p.Title}${p.OldVersion} ➔ ${p.Version}
`; }); content.innerHTML += ` ${node.display_name} ${node.packages.length} Updates
${pkgsHtml}
`; }); } } catch(e) {} }
window.closeUpdateManager = function() { const m = document.getElementById('updateManagerModal'); if(m) m.classList.add('hidden'); if(typeof window.fetchUpdates === 'function') window.fetchUpdates(); }
window.triggerAptUpgrade = async function(nodeId, host) { if(!confirm(`Updates auf ${host} jetzt installieren?`)) return; const fd = new FormData(); fd.append('node_id', nodeId); fd.append('host', host); try { const res = await (await fetch('api.php?action=trigger_apt_upgrade', {method: 'POST', body: fd})).json(); if(res.success && res.upid) { window.openTaskLog(res.upid, nodeId, host); } else alert('Fehler: ' + res.error); } catch(e) {} }
+
+ // Initiale Intervall-Starts
+ setInterval(window.fetchGlobalStats, 10000);
+ setInterval(window.fetchTopVms, 10000);
+ setInterval(window.fetchRecentJobs, 15000);
+ setInterval(window.fetchUpdates, 60000);
+ setInterval(() => { if(typeof window.fetchPbsStats === 'function') window.fetchPbsStats(); }, 10000);
+ setInterval(() => { if(typeof window.fetchPmgStats === 'function') window.fetchPmgStats(); }, 10000);
+
+ // Initiale Aufrufe, um das Dashboard sofort zu füllen
+ setTimeout(() => {
+ window.fetchGlobalStats();
+ window.fetchTopVms();
+ window.fetchRecentJobs();
+ }, 1000);
}
\ No newline at end of file