Files
proxmox-unified-console/src/modals.php
T
2026-08-23 19:36:19 +02:00

123 lines
37 KiB
PHP

<!-- /home/docker/pve_dashboard/src/modals.php -->
<div id="nodeManagerModal" class="fixed inset-0 bg-black/80 hidden z-50 flex items-center justify-center backdrop-blur-sm"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-4xl overflow-hidden flex flex-col max-h-[85vh]"><div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg"><h2 class="text-xl font-bold text-white flex items-center gap-2">Node Verwaltung</h2><button onclick="closeNodeManager()" class="text-gray-400 hover:text-white transition-colors"></button></div><div class="p-6 overflow-y-auto flex-1"><div class="mb-8"><div class="flex justify-between items-center mb-4"><h3 class="text-white font-bold">Verbundene Systeme</h3><button onclick="toggleAddNodeForm()" class="bg-proxmox/20 text-proxmox hover:bg-proxmox hover:text-white px-3 py-1.5 rounded-lg text-sm font-medium transition-colors">+ Server hinzufügen</button></div><div class="bg-darkbg rounded-lg border border-darkborder overflow-hidden"><table class="w-full text-left text-sm text-gray-400"><thead class="bg-darkcard border-b border-darkborder text-xs uppercase"><tr><th class="px-4 py-3">Name</th><th class="px-4 py-3">Typ</th><th class="px-4 py-3">IP-Adresse</th><th class="px-4 py-3 text-right">Aktion</th></tr></thead><tbody id="nodeTableBody" class="divide-y divide-darkborder"></tbody></table></div></div><div id="addNodeFormContainer" class="hidden bg-darkbg p-5 rounded-lg border border-darkborder"><h3 class="text-white font-bold mb-4 border-b border-darkborder pb-2">Neues System anbinden</h3><form id="addNewNodeForm" class="grid grid-cols-2 gap-4"><div><label class="block text-xs font-medium text-gray-500 mb-1">System Typ</label><select id="newNodeType" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white"><option value="pve">Proxmox VE (PVE)</option><option value="pbs">Backup Server (PBS)</option><option value="pmg">Mail Gateway (PMG)</option></select></div><div><label class="block text-xs font-medium text-gray-500 mb-1">Anzeigename</label><input type="text" id="newNodeName" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white" required></div><div><label class="block text-xs font-medium text-gray-500 mb-1">IP-Adresse</label><input type="text" id="newNodeIp" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white" required></div><div><label class="block text-xs font-medium text-gray-500 mb-1">Benutzername</label><input type="text" id="newNodeUser" value="root@pam" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white" required></div><div><label class="block text-xs font-medium text-gray-500 mb-1">Passwort</label><input type="password" id="newNodePass" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white" required></div><div class="col-span-2 mt-2"><button type="submit" class="w-full bg-proxmox hover:bg-orange-600 text-white font-bold py-2.5 rounded">Verbinden</button></div></form></div></div></div></div>
<div id="userManagerModal" class="fixed inset-0 bg-black/80 hidden z-50 flex items-center justify-center backdrop-blur-sm"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-4xl overflow-hidden flex flex-col max-h-[90vh]"><div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg"><h2 class="text-xl font-bold text-white flex items-center gap-2">Benutzer & Rollen</h2><button onclick="closeUserManager()" class="text-gray-400 hover:text-white transition-colors"></button></div><div class="p-6 overflow-y-auto flex-1 flex flex-col lg:flex-row gap-8"><div class="flex-1"><h3 class="text-white font-bold mb-4">Aktive Accounts</h3><div class="bg-darkbg rounded-lg border border-darkborder overflow-hidden"><table class="w-full text-left text-sm text-gray-400"><thead class="bg-darkcard border-b border-darkborder text-xs uppercase"><tr><th class="px-4 py-3">Benutzer</th><th class="px-4 py-3">Rolle</th><th class="px-4 py-3 text-right">Aktion</th></tr></thead><tbody id="userTableBody" class="divide-y divide-darkborder"></tbody></table></div></div><div class="flex-1 bg-darkbg p-5 rounded-lg border border-darkborder"><h3 class="text-white font-bold mb-4 border-b border-darkborder pb-2">Neuen Benutzer anlegen</h3><form id="addNewUserForm" class="space-y-4"><div class="grid grid-cols-2 gap-4"><div><label class="block text-xs font-medium text-gray-500 mb-1">Benutzername</label><input type="text" id="newUsername" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white" required></div><div><label class="block text-xs font-medium text-gray-500 mb-1">Passwort</label><input type="password" id="newUserPass" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white" required></div></div><div><label class="block text-xs font-medium text-gray-500 mb-1">Rolle</label><select id="newUserRole" onchange="handleRoleChange()" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white"><option value="viewer">Viewer</option><option value="vm_manager">VM Manager</option><option value="admin">Admin</option></select></div><div id="vmPermissionsBlock" class="hidden border border-darkborder rounded p-3 bg-darkcard/50"><p class="text-xs font-bold text-gray-400 mb-2">VMs erlauben:</p><div id="vmCheckboxList" class="max-h-40 overflow-y-auto space-y-1 text-sm text-gray-300"></div></div><button type="submit" class="w-full bg-proxmox hover:bg-orange-600 text-white font-bold py-2.5 rounded mt-4">Anlegen</button></form></div></div></div></div>
<div id="vmManagerModal" class="fixed inset-0 bg-black/80 hidden z-[60] flex items-center justify-center backdrop-blur-sm"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-5xl overflow-hidden flex flex-col max-h-[90vh]"><div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg"><div class="flex items-center gap-4"><h2 class="text-xl font-bold text-white flex items-center gap-2"><svg class="w-6 h-6 text-proxmox" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"></path></svg> Virtuelle Maschinen & LXC</h2><button onclick="openCreateVm()" class="bg-proxmox/20 text-proxmox hover:bg-proxmox hover:text-white px-3 py-1 rounded text-xs font-bold border border-proxmox/50">+ Neue VM</button></div><button onclick="closeVmManager()" class="text-gray-400 hover:text-white transition-colors"></button></div><div class="p-6 overflow-y-auto flex-1"><div class="bg-darkbg rounded-lg border border-darkborder overflow-hidden"><table class="w-full text-left text-sm text-gray-400"><thead class="bg-darkcard border-b border-darkborder text-xs uppercase"><tr><th class="px-4 py-3">ID / Name</th><th class="px-4 py-3">Host / Typ</th><th class="px-4 py-3">Ressourcen</th><th class="px-4 py-3 text-center">Status</th><th class="px-4 py-3 text-right">Aktionen</th></tr></thead><tbody id="vmTableBody" class="divide-y divide-darkborder"></tbody></table></div></div></div></div>
<div id="createVmModal" class="fixed inset-0 bg-black/80 hidden z-[80] flex items-center justify-center backdrop-blur-sm"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-md overflow-hidden flex flex-col"><div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg"><h2 class="text-xl font-bold text-white"> Neue VM erstellen</h2><button onclick="closeCreateVm()" class="text-gray-400 hover:text-white transition-colors"></button></div><div class="p-6"><form id="createVmForm" class="space-y-4"><div><label class="block text-xs font-medium text-gray-500 mb-1">Ziel-Host (PVE Node)</label><select id="createVmHost" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm focus:border-proxmox"><option value="">Lade Hosts...</option></select></div><div><label class="block text-xs font-medium text-gray-500 mb-1">Name der VM</label><input type="text" id="createVmName" placeholder="z.B. webserver-01" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm" required></div><div class="grid grid-cols-2 gap-4"><div><label class="block text-xs font-medium text-gray-500 mb-1">RAM (MB)</label><input type="number" id="createVmRam" value="2048" step="512" min="512" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm" required></div><div><label class="block text-xs font-medium text-gray-500 mb-1">CPU Cores</label><input type="number" id="createVmCores" value="2" min="1" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm" required></div></div><button type="submit" class="w-full bg-proxmox hover:bg-orange-600 text-white font-bold py-3 rounded mt-4 transition-colors">Freie ID suchen & Erstellen</button></form></div></div></div>
<div id="vmSettingsModal" class="fixed inset-0 bg-black/80 hidden z-[70] flex items-center justify-center backdrop-blur-sm"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-4xl overflow-hidden flex flex-col max-h-[90vh]"><div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg"><h2 class="text-xl font-bold text-white flex items-center gap-2"><span id="settingsModalTitle">Einstellungen</span></h2><button onclick="closeVmSettings()" class="text-gray-400 hover:text-white transition-colors text-2xl"></button></div><div class="p-6 overflow-y-auto space-y-6 flex-1"><input type="hidden" id="setVmid"><input type="hidden" id="setHost"><input type="hidden" id="setType"><input type="hidden" id="setNodeId"><input type="hidden" id="setRawNet0"><input type="hidden" id="setPrimaryDisk"><div class="grid grid-cols-1 lg:grid-cols-2 gap-6"><div class="space-y-6"><div class="bg-darkbg p-5 rounded-lg border border-darkborder"><h3 class="text-white font-bold mb-4">💻 Ressourcen</h3><div class="grid grid-cols-2 gap-4"><div><label class="block text-xs font-medium text-gray-500 mb-1">RAM (MB)</label><input type="number" id="setMemory" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white text-sm"></div><div><label class="block text-xs font-medium text-gray-500 mb-1">CPU Cores</label><input type="number" id="setCores" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white text-sm"></div></div><button onclick="saveHardwareSettings()" class="mt-4 bg-proxmox hover:bg-orange-600 text-white font-bold py-2 px-4 rounded text-sm transition-colors">Speichern</button></div><div class="bg-darkbg p-5 rounded-lg border border-darkborder"><h3 class="text-white font-bold mb-4">🌐 Netzwerkverwaltung</h3><div class="flex items-center gap-3 mb-6 border-b border-darkborder pb-4"><span id="netStatusBadge" class="px-2 py-1 rounded text-xs font-bold text-gray-400 bg-gray-500/20">Lade...</span><button id="btnToggleNet" onclick="toggleNetwork()" class="bg-darkcard border border-darkborder hover:border-proxmox text-white font-bold py-1.5 px-4 rounded text-sm transition-colors">Lade...</button></div><div><h4 class="text-gray-400 font-bold mb-2 text-xs uppercase">Zusätzliche NIC</h4><div class="flex items-end gap-3"><div class="flex-1"><label class="block text-xs font-medium text-gray-500 mb-1">Bridge Name (z.B. vmbr0)</label><input type="text" id="addNicBridge" value="vmbr0" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white text-sm"></div><button onclick="addNic()" class="bg-proxmox hover:bg-orange-600 text-white font-bold py-2 px-4 rounded text-sm">+ Hinzufügen</button></div></div></div><div class="bg-darkbg p-5 rounded-lg border border-darkborder border-l-4 border-l-blue-500"><h3 class="text-white font-bold mb-4">💾 Festplatte erweitern</h3><div class="flex items-end gap-4"><div class="flex-1"><label class="block text-xs font-medium text-gray-500 mb-1">Um wie viel GB? (Disk: <span id="diskLabelName" class="text-proxmox">Lade...</span>)</label><input type="number" id="addDiskGb" min="1" placeholder="z.B. 10" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white text-sm"></div><button onclick="expandDisk()" class="bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-6 rounded text-sm transition-colors">Erweitern</button></div></div></div><div class="space-y-6"><div class="bg-darkbg p-5 rounded-lg border border-darkborder border-l-4 border-l-emerald-500"><h3 class="text-white font-bold mb-4">📸 Sicherung & Snapshots</h3><div class="flex items-end gap-3 mb-4"><div class="flex-1"><label class="block text-xs font-medium text-gray-500 mb-1">Neuer Snapshot Name</label><input type="text" id="newSnapName" placeholder="z.B. pre-update" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white text-sm"></div><button onclick="createSnapshot()" class="bg-emerald-600 hover:bg-emerald-500 text-white font-bold py-2 px-4 rounded text-sm transition-colors">+ Snapshot</button></div><div class="space-y-2 mt-4 max-h-40 overflow-y-auto" id="snapshotListContainer"><div class="text-gray-500 text-sm italic">Lade Snapshots...</div></div></div><div class="bg-darkbg p-5 rounded-lg border border-darkborder border-l-4 border-l-pbs"><h3 class="text-white font-bold mb-4">🛡️ Backup Archive (vzdump)</h3><div class="flex items-end gap-3 mb-4 border-b border-darkborder pb-4"><div class="flex-1"><label class="block text-xs font-medium text-gray-500 mb-1">Ziel-Storage für manuelles Backup</label><select id="backupTargetStorage" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white text-sm"><option value="">Lade Storages...</option></select></div><button onclick="createBackup()" class="bg-pbs hover:bg-purple-500 text-white font-bold py-2 px-4 rounded text-sm transition-colors">Jetzt sichern</button></div><h4 class="text-xs font-bold text-gray-400 mb-2 uppercase tracking-wider">Verfügbare Backups (Klick = Wiederherstellen)</h4><div class="space-y-2 max-h-40 overflow-y-auto" id="backupListContainer"><div class="text-gray-500 text-sm italic">Lade Backup-Archive...</div></div></div><div class="bg-red-900/10 p-5 rounded-lg border border-red-900/30"><h3 class="text-red-500 font-bold mb-2">⚠️ Gefahrenzone</h3><button onclick="destroyVm()" class="w-full bg-red-900/50 hover:bg-red-600 text-red-200 hover:text-white border border-red-800 hover:border-red-600 font-bold py-2 rounded transition-colors">VM Endgültig Löschen</button></div></div></div></div></div></div>
<div id="nodeTopologyModal" class="fixed inset-0 bg-black/80 hidden z-[65] flex items-center justify-center backdrop-blur-sm"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-6xl overflow-hidden flex flex-col max-h-[90vh]"><div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg"><h2 class="text-xl font-bold text-white flex items-center gap-2"><svg class="w-6 h-6 text-proxmox" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path></svg> Cluster Topologie</h2><button onclick="closeNodeTopology()" class="text-gray-400 hover:text-white"></button></div><div class="p-6 overflow-y-auto flex-1 bg-darkbg"><div id="nodeTopologyContainer" class="space-y-6"></div></div></div></div>
<div id="liveGraphModal" class="fixed inset-0 bg-black/90 hidden z-[90] flex items-center justify-center backdrop-blur-md"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-6xl overflow-hidden flex flex-col max-h-[90vh]"><div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg"><h2 class="text-xl font-bold text-white flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-green-500 animate-pulse"></span><span id="graphModalTitle">Live Performance</span></h2><button onclick="closeLiveGraph()" class="text-gray-400 hover:text-white transition-colors"></button></div><div class="p-6 bg-darkbg overflow-y-auto"><div class="grid grid-cols-1 lg:grid-cols-2 gap-6"><div class="bg-darkcard border border-darkborder rounded-xl p-4 shadow-lg"><h3 class="text-white font-bold mb-3 text-sm">System: CPU & RAM (%)</h3><div class="relative w-full h-[250px]"><canvas id="perfChart"></canvas></div></div><div class="bg-darkcard border border-darkborder rounded-xl p-4 shadow-lg"><h3 class="text-white font-bold mb-3 text-sm">Netzwerk: RX / TX (MB/s)</h3><div class="relative w-full h-[250px]"><canvas id="netChart"></canvas></div></div></div><p class="text-center text-xs text-gray-500 mt-4">Metriken werden live im 2-Sekunden-Takt abgefragt.</p></div></div></div>
<div id="pbsDatastoreModal" class="fixed inset-0 bg-black/80 hidden z-[70] flex items-center justify-center backdrop-blur-sm"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-7xl overflow-hidden flex flex-col max-h-[95vh]"><div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg"><h2 class="text-xl font-bold text-white flex items-center gap-2"><svg class="w-6 h-6 text-pbs" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2"></path></svg> <span id="pbsModalTitle">Datastore</span></h2><button onclick="closePbsDatastore()" class="text-gray-400 hover:text-white transition-colors text-2xl"></button></div><div class="p-6 overflow-y-auto space-y-6 flex-1 bg-darkbg"><input type="hidden" id="pbsNodeId"><input type="hidden" id="pbsStoreName"><div class="grid grid-cols-1 xl:grid-cols-3 gap-6"><div class="bg-darkcard border border-darkborder rounded-xl p-5 shadow-lg flex flex-col h-[350px]"><h3 class="text-white font-bold mb-4 flex justify-between items-center">🗄️ Gespeicherte Backups</h3><div id="pbsBackupsContainer" class="space-y-2 overflow-y-auto flex-1 pr-2">Lade...</div></div><div class="bg-darkcard border border-darkborder rounded-xl p-5 shadow-lg flex flex-col h-[350px]"><h3 class="text-white font-bold mb-4">🧹 Verify & Garbage Collection</h3><div id="pbsVerifyGcContainer" class="space-y-2 overflow-y-auto flex-1 pr-2">Lade...</div></div><div class="bg-darkcard border border-darkborder rounded-xl p-5 shadow-lg flex flex-col h-[350px] border-l-4 border-l-blue-500"><h3 class="text-white font-bold mb-4">🔄 Eingerichtete Sync Jobs</h3><div id="pbsSyncContainer" class="space-y-2 overflow-y-auto flex-1 pr-2">Lade...</div></div></div><div class="bg-darkcard border border-darkborder rounded-xl p-5 shadow-lg mt-6"><h3 class="text-white font-bold mb-4">📋 Letzte 100 PBS Jobs (Historie)</h3><div class="max-h-60 overflow-y-auto pr-2"><table class="w-full text-left text-sm text-gray-400"><thead class="bg-darkbg border-b border-darkborder text-xs uppercase sticky top-0"><tr><th class="px-4 py-2">Start</th><th class="px-4 py-2">Job Typ</th><th class="px-4 py-2">Status</th><th class="px-4 py-2">Dauer</th><th class="px-4 py-2 text-right">Log</th></tr></thead><tbody id="pbsJobsTable" class="divide-y divide-darkborder"></tbody></table></div></div></div></div></div>
<div id="taskLogModal" class="fixed inset-0 bg-black/90 hidden z-[100] flex items-center justify-center backdrop-blur-sm"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-5xl overflow-hidden flex flex-col h-[85vh]"><div class="p-4 border-b border-darkborder flex justify-between items-center bg-darkbg"><h2 class="text-lg font-bold text-white flex items-center gap-2">📄 Task Log Viewer</h2><button onclick="closeTaskLog()" class="text-gray-400 hover:text-white transition-colors text-2xl"></button></div><div class="p-4 bg-black flex-1 overflow-y-auto"><pre id="taskLogContent" class="text-xs text-green-400 font-mono whitespace-pre-wrap">Lade Log...</pre></div></div></div>
<div id="pmgManagerModal" class="fixed inset-0 bg-black/80 hidden z-[75] flex items-center justify-center backdrop-blur-sm"><div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-7xl overflow-hidden flex flex-col h-[95vh]"><div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg"><h2 class="text-xl font-bold text-white flex items-center gap-2"><svg class="w-6 h-6 text-pmg" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path></svg> <span id="pmgModalTitle">Mail Gateway</span></h2><button onclick="closePmgManager()" class="text-gray-400 hover:text-white transition-colors text-2xl"></button></div><div class="flex border-b border-darkborder bg-darkbg px-5 pt-4"><button onclick="switchPmgTab('spam')" id="btn-pmg-spam" class="px-4 py-2 border-b-2 border-pmg text-white font-bold">🛡️ Quarantäne</button><button onclick="switchPmgTab('tracking')" id="btn-pmg-tracking" class="px-4 py-2 border-b-2 border-transparent text-gray-400 hover:text-white font-bold transition-colors">🔎 Tracking Center</button><button onclick="switchPmgTab('queues')" id="btn-pmg-queues" class="px-4 py-2 border-b-2 border-transparent text-gray-400 hover:text-white font-bold transition-colors">📨 Mail Queues</button><button onclick="switchPmgTab('settings')" id="btn-pmg-settings" class="px-4 py-2 border-b-2 border-transparent text-gray-400 hover:text-white font-bold transition-colors ml-auto">⚙️ Einstellungen</button></div><div class="p-6 overflow-y-auto flex-1 bg-darkbg"><input type="hidden" id="pmgNodeId"><input type="hidden" id="pmgHostName"><input type="hidden" id="pmgInternalName"><div id="pmg-tab-spam" class="h-full flex flex-col"><div class="flex justify-between items-center mb-4"><h3 class="text-white font-bold">Zurückgehaltene Mails</h3><button onclick="loadPmgSpamQueue(document.getElementById('pmgNodeId').value)" class="text-xs bg-darkcard border border-darkborder hover:border-pmg text-white px-3 py-1.5 rounded transition-colors">🔄 Aktualisieren</button></div><div class="overflow-y-auto flex-1 bg-darkcard border border-darkborder rounded-lg relative"><table class="w-full text-left text-sm text-gray-400"><thead class="bg-darkbg border-b border-darkborder text-xs uppercase sticky top-0 z-10"><tr><th class="px-4 py-3">Datum</th><th class="px-4 py-3">Absender</th><th class="px-4 py-3">Empfänger</th><th class="px-4 py-3">Betreff</th><th class="px-4 py-3 text-center">Score</th><th class="px-4 py-3 text-right">Aktion</th></tr></thead><tbody id="pmgSpamTable" class="divide-y divide-darkborder"></tbody></table></div></div><div id="pmg-tab-tracking" class="hidden h-full flex flex-col"><div class="flex gap-4 mb-4 items-end"><div class="flex-1"><label class="block text-xs font-medium text-gray-500 mb-1">Nach E-Mail Adresse filtern (Letzte 24h)</label><input type="text" id="pmgTrackingFilter" placeholder="z.B. spammer@evil.com oder user@firma.de" class="w-full bg-darkcard border border-darkborder rounded p-2 text-white text-sm" onkeydown="if(event.key === 'Enter') loadPmgTracking()"></div><button onclick="loadPmgTracking()" class="bg-pmg hover:bg-blue-600 text-white font-bold py-2 px-6 rounded text-sm transition-colors">Suchen</button></div><div class="overflow-y-auto flex-1 bg-darkcard border border-darkborder rounded-lg relative"><table class="w-full text-left text-sm text-gray-400"><thead class="bg-darkbg border-b border-darkborder text-xs uppercase sticky top-0 z-10"><tr><th class="px-4 py-3">Zeit</th><th class="px-4 py-3">Absender</th><th class="px-4 py-3">Empfänger</th><th class="px-4 py-3">Status</th></tr></thead><tbody id="pmgTrackingTable" class="divide-y divide-darkborder"></tbody></table></div></div><div id="pmg-tab-queues" class="hidden h-full flex flex-col"><div class="flex justify-between items-center mb-4"><h3 class="text-white font-bold">Aktuelle Postfix Warteschlangen</h3><button onclick="loadPmgQueues()" class="text-xs bg-darkcard border border-darkborder hover:border-pmg text-white px-3 py-1.5 rounded transition-colors">🔄 Aktualisieren</button></div><div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6" id="pmgQueuesSummary"><div class="bg-darkcard border border-darkborder rounded-xl p-5 text-center animate-pulse"><p class="text-gray-500">Lade...</p></div></div><div class="overflow-y-auto flex-1 bg-darkcard border border-darkborder rounded-lg relative"><table class="w-full text-left text-sm text-gray-400"><thead class="bg-darkbg border-b border-darkborder text-xs uppercase sticky top-0 z-10"><tr><th class="px-4 py-3">Queue</th><th class="px-4 py-3">Zeit</th><th class="px-4 py-3">Absender</th><th class="px-4 py-3">Empfänger</th><th class="px-4 py-3">Grund</th></tr></thead><tbody id="pmgQueueTable" class="divide-y divide-darkborder"></tbody></table></div></div><div id="pmg-tab-settings" class="hidden h-full flex flex-col overflow-y-auto"><div class="grid grid-cols-1 lg:grid-cols-2 gap-6 pb-10"><div class="bg-darkcard border border-darkborder rounded-xl p-5 shadow-lg border-l-4 border-l-pmg h-fit"><h3 class="text-white font-bold mb-4 text-lg">⚙️ Mail Proxy Konfiguration</h3><div class="space-y-4"><div><label class="block text-xs font-bold text-gray-400 uppercase mb-1">Default Relay (Ziel für saubere Mails)</label><input type="text" id="pmgCfgRelay" class="w-full bg-darkbg border border-darkborder focus:border-pmg rounded p-2 text-white font-mono text-sm" placeholder="z.B. 192.168.1.10"></div><div class="grid grid-cols-2 gap-4"><div><label class="block text-xs font-bold text-gray-400 uppercase mb-1">Externer Port (IN)</label><input type="number" id="pmgCfgExtPort" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white font-mono text-sm"></div><div><label class="block text-xs font-bold text-gray-400 uppercase mb-1">Interner Port (OUT)</label><input type="number" id="pmgCfgIntPort" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white font-mono text-sm"></div></div><div class="grid grid-cols-2 gap-4"><div><label class="block text-xs font-bold text-gray-400 uppercase mb-1">TLS</label><select id="pmgCfgTls" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm"><option value="1">Aktiviert</option><option value="0">Deaktiviert</option></select></div><div><label class="block text-xs font-bold text-gray-400 uppercase mb-1">TLS Logging</label><select id="pmgCfgTlsLog" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm"><option value="1">Aktiviert</option><option value="0">Deaktiviert</option></select></div></div><button onclick="savePmgConfig()" class="w-full bg-pmg hover:bg-blue-600 text-white font-bold py-2.5 rounded transition-colors mt-2">Proxy Config speichern</button></div></div><div class="space-y-6"><div class="bg-darkcard border border-darkborder rounded-xl p-5 shadow-lg"><h3 class="text-white font-bold mb-4 text-lg">🌍 Relay Domains</h3><div class="flex gap-2 mb-3"><input type="text" id="pmgNewDomain" placeholder="z.B. firma.de" class="flex-1 bg-darkbg border border-darkborder rounded p-2 text-white text-sm"><button onclick="addPmgDomain()" class="bg-proxmox hover:bg-orange-600 text-white font-bold px-4 rounded text-sm">Hinzufügen</button></div><div id="pmgDomainsContainer" class="space-y-1 max-h-40 overflow-y-auto"><p class="text-gray-500 text-sm">Lade Domains...</p></div></div><div class="bg-darkcard border border-darkborder rounded-xl p-5 shadow-lg"><h3 class="text-white font-bold mb-4 text-lg">🛜 Trusted Networks (Outbound)</h3><div class="flex gap-2 mb-3"><input type="text" id="pmgNewNetwork" placeholder="z.B. 192.168.1.0/24" class="flex-1 bg-darkbg border border-darkborder rounded p-2 text-white text-sm"><button onclick="addPmgNetwork()" class="bg-proxmox hover:bg-orange-600 text-white font-bold px-4 rounded text-sm">Hinzufügen</button></div><div id="pmgNetworksContainer" class="space-y-1 max-h-40 overflow-y-auto"><p class="text-gray-500 text-sm">Lade Netzwerke...</p></div></div></div><div class="bg-darkcard border border-darkborder rounded-xl p-5 shadow-lg border-l-4 border-l-emerald-500 lg:col-span-2"><h3 class="text-white font-bold mb-4 text-lg">🔒 SSL Zertifikate</h3><div class="grid grid-cols-1 lg:grid-cols-2 gap-8"><div><h4 class="text-xs font-bold text-gray-400 uppercase mb-3 border-b border-darkborder pb-1">Installierte Zertifikate</h4><div id="pmgSslContainer" class="space-y-3"><p class="text-gray-500 text-sm">Lade Zertifikate...</p></div></div><div class="bg-darkbg p-4 rounded border border-darkborder"><h4 class="text-xs font-bold text-emerald-500 uppercase mb-3 border-b border-darkborder pb-1">Neues Zertifikat installieren</h4><div class="space-y-3"><div><label class="block text-xs font-medium text-gray-500 mb-1">Private Key (.key)</label><textarea id="pmgSslKey" rows="3" class="w-full bg-darkcard border border-darkborder rounded p-2 text-green-400 font-mono text-xs" placeholder="-----BEGIN PRIVATE KEY-----..."></textarea></div><div><label class="block text-xs font-medium text-gray-500 mb-1">Zertifikat (.pem / .crt inkl. Chain)</label><textarea id="pmgSslCert" rows="4" class="w-full bg-darkcard border border-darkborder rounded p-2 text-blue-400 font-mono text-xs" placeholder="-----BEGIN CERTIFICATE-----..."></textarea></div><button onclick="uploadPmgSsl()" class="w-full bg-emerald-600 hover:bg-emerald-500 text-white font-bold py-2 rounded transition-colors text-sm">Zertifikat hochladen & Dienste neustarten</button></div></div></div></div></div></div></div></div></div>
<!-- NEU: CRON / SCHEDULER MODAL -->
<div id="cronManagerModal" class="fixed inset-0 bg-black/80 hidden z-50 flex items-center justify-center backdrop-blur-sm">
<div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-5xl overflow-hidden flex flex-col max-h-[90vh]">
<div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg">
<h2 class="text-xl font-bold text-white flex items-center gap-2">⏱️ Task Scheduler & Automatisierung</h2>
<button onclick="closeCronManager()" class="text-gray-400 hover:text-white transition-colors"></button>
</div>
<div class="p-6 overflow-y-auto flex-1 flex flex-col gap-6 bg-darkbg">
<div class="bg-darkcard p-5 rounded-xl border border-darkborder shadow-lg">
<h3 class="text-white font-bold mb-4 border-b border-darkborder pb-2">Neuen Cron-Job anlegen</h3>
<form id="addCronJobForm" class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div><label class="block text-xs font-medium text-gray-500 mb-1">Name / Beschreibung</label><input type="text" id="cronName" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm" placeholder="z.B. Nächtlicher Reboot" required></div>
<div><label class="block text-xs font-medium text-gray-500 mb-1">Ziel-Host (PVE)</label><select id="cronNodeId" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm" required><option value="">Lade Hosts...</option></select></div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label class="block text-xs font-medium text-gray-500 mb-1">Aktion</label>
<select id="cronAction" onchange="checkCronAction()" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm" required>
<option value="reboot_node">Ganzen Server neustarten</option>
<option value="start_vm">VM Starten</option>
<option value="stop_vm">VM Stoppen</option>
<option value="reboot_vm">VM Neustarten</option>
</select>
</div>
<div id="cronVmBlock" class="hidden">
<label class="block text-xs font-medium text-gray-500 mb-1">Ziel VM-ID</label>
<input type="number" id="cronTargetVmid" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm" placeholder="z.B. 100">
</div>
<div>
<label class="block text-xs font-medium text-gray-500 mb-1">Zeitplan (Cron-Format)</label>
<input type="text" id="cronSchedule" value="0 3 * * *" class="w-full bg-darkbg border border-darkborder rounded p-2 text-proxmox font-mono text-sm font-bold" required title="Minute Stunde Tag Monat Wochentag">
<p class="text-[10px] text-gray-500 mt-1">Beispiel: "0 3 * * *" = Jeden Tag um 03:00 Uhr.</p>
</div>
</div>
<button type="submit" class="bg-proxmox hover:bg-orange-600 text-white font-bold py-2 px-6 rounded transition-colors text-sm w-full md:w-auto">Job Speichern</button>
</form>
</div>
<div class="bg-darkcard border border-darkborder rounded-xl shadow-lg flex-1 overflow-hidden flex flex-col">
<table class="w-full text-left text-sm text-gray-400">
<thead class="bg-darkbg border-b border-darkborder text-xs uppercase sticky top-0">
<tr><th class="px-4 py-3">Status</th><th class="px-4 py-3">Beschreibung</th><th class="px-4 py-3">Host / Ziel</th><th class="px-4 py-3">Cron</th><th class="px-4 py-3">Letzter Lauf</th><th class="px-4 py-3 text-right">Löschen</th></tr>
</thead>
<tbody id="cronTableBody" class="divide-y divide-darkborder"></tbody>
</table>
</div>
</div>
</div>
</div>
<!-- NEU: AUDIT LOG MODAL -->
<div id="auditLogModal" class="fixed inset-0 bg-black/80 hidden z-[100] flex items-center justify-center backdrop-blur-sm">
<div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-5xl overflow-hidden flex flex-col max-h-[90vh]">
<div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg">
<h2 class="text-xl font-bold text-white flex items-center gap-2">
<svg class="w-6 h-6 text-proxmox" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
Aktivitäten-Protokoll (Audit Log)
</h2>
<button onclick="closeAuditLog()" class="text-gray-400 hover:text-white transition-colors"></button>
</div>
<div class="p-6 overflow-y-auto flex-1 bg-darkbg">
<div class="bg-darkcard border border-darkborder rounded-xl shadow-lg flex-1 overflow-hidden flex flex-col">
<table class="w-full text-left text-sm text-gray-400">
<thead class="bg-darkbg border-b border-darkborder text-xs uppercase sticky top-0">
<tr><th class="px-4 py-3">Datum / Uhrzeit</th><th class="px-4 py-3">Benutzer</th><th class="px-4 py-3">Aktion</th><th class="px-4 py-3">Ziel / Details</th></tr>
</thead>
<tbody id="auditLogTableBody" class="divide-y divide-darkborder"></tbody>
</table>
</div>
</div>
</div>
</div>
<!-- NEU: PASSWORT ÄNDERN MODAL -->
<div id="passwordModal" class="fixed inset-0 bg-black/80 hidden z-[100] flex items-center justify-center backdrop-blur-sm">
<div class="bg-darkcard border border-darkborder rounded-xl shadow-2xl w-full max-w-sm overflow-hidden flex flex-col">
<div class="p-5 border-b border-darkborder flex justify-between items-center bg-darkbg">
<h2 class="text-lg font-bold text-white flex items-center gap-2">🔑 Passwort ändern</h2>
<button onclick="closePasswordModal()" class="text-gray-400 hover:text-white transition-colors text-xl"></button>
</div>
<div class="p-6">
<form id="changePasswordForm" class="space-y-4">
<div>
<label class="block text-xs font-medium text-gray-500 mb-1">Aktuelles Passwort</label>
<input type="password" id="oldPassword" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm focus:border-proxmox" required>
</div>
<div>
<label class="block text-xs font-medium text-gray-500 mb-1">Neues Passwort</label>
<input type="password" id="newPassword" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm focus:border-proxmox" required>
</div>
<div>
<label class="block text-xs font-medium text-gray-500 mb-1">Neues Passwort bestätigen</label>
<input type="password" id="newPasswordConfirm" class="w-full bg-darkbg border border-darkborder rounded p-2 text-white text-sm focus:border-proxmox" required>
</div>
<button type="submit" class="w-full bg-proxmox hover:bg-orange-600 text-white font-bold py-2.5 rounded mt-2 transition-colors">Passwort aktualisieren</button>
</form>
</div>
</div>
</div>