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