diff --git a/public/index.php b/public/index.php index 97e2ad3..3f4f743 100644 --- a/public/index.php +++ b/public/index.php @@ -142,19 +142,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($proj && hash_equals($proj['slug'], $confirmSlug)) { $pdo->beginTransaction(); - // 1. Delete associated activations $pdo->prepare('DELETE a FROM license_activations a JOIN license_licenses l ON a.license_id = l.id WHERE l.product_id = :id') ->execute([':id' => $id]); - // 2. Delete associated licenses $pdo->prepare('DELETE FROM license_licenses WHERE product_id = :id') ->execute([':id' => $id]); - // 3. Delete associated releases $pdo->prepare('DELETE FROM updateservice_releases WHERE product_slug = :slug') ->execute([':slug' => $proj['slug']]); - // 4. Delete project $delStmt = $pdo->prepare('DELETE FROM dc_projects WHERE id = :id'); $delStmt->execute([':id' => $id]); @@ -289,19 +285,21 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } } - // Edit Watchdog Monitor + // Edit Watchdog Monitor (Full Update) if ($action === 'edit_watchdog_monitor') { $oldSource = trim($_POST['old_source'] ?? ''); $newSource = trim($_POST['new_source'] ?? $oldSource); + $type = trim($_POST['type'] ?? 'host'); $group = trim($_POST['group_key'] ?? 'Default'); $parent = trim($_POST['parent_source'] ?? ''); + $os = trim($_POST['os'] ?? ''); $interval = (int)($_POST['interval'] ?? 60); $notes = trim($_POST['notes'] ?? ''); if ($oldSource && $newSource) { $monRepo = new MonitorRepo($pdo); - $monRepo->updateMonitor($oldSource, $newSource, 'default', $group, $parent, $notes, null, $interval); - $msg = "Monitor '{$newSource}' wurde aktualisiert."; + $monRepo->updateMonitor($oldSource, $newSource, 'default', $type, $group, $parent, $os, $notes, null, $interval); + $msg = "Monitor '{$newSource}' wurde erfolgreich aktualisiert."; } } @@ -330,11 +328,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($action === 'create_agent_token') { $source = trim($_POST['token_source'] ?? ''); $name = trim($_POST['token_name'] ?? ''); - if ($name) { - $tokMgr = new TokenManager($pdo); - $res = $tokMgr->createToken($source, $name); - $msg = "Agent-Token für '{$name}' generiert: {$res['raw_token']}"; + if (empty($name)) { + $name = "Token for " . ($source ?: 'General'); } + $tokMgr = new TokenManager($pdo); + $res = $tokMgr->createToken($source, $name); + $msg = "Agent-Token generiert: {$res['raw_token']}"; } // Revoke Agent Token @@ -392,6 +391,17 @@ $auditLogs = $pdo->query('SELECT * FROM license_audit_log ORDER BY created_at DE $monitorRepo = new MonitorRepo($pdo); $monitors = $monitorRepo->getAllMonitors(); +$tokenManager = new TokenManager($pdo); +$agentTokens = $tokenManager->getAllTokens(); + +// Map Active Tokens per Monitor Source +$tokensBySource = []; +foreach ($agentTokens as $tok) { + if (!$tok['revoked'] && !empty($tok['monitor_source'])) { + $tokensBySource[$tok['monitor_source']] = $tok; + } +} + // Flatten Tree for Hierarchy Rendering (Up to 3 levels: Hypervisor -> Host -> App) function buildMonitorTree(array $monitors): array { $childrenOf = []; @@ -449,9 +459,6 @@ foreach ($monitors as $m) { $eventLog = new EventLog($pdo); $recentEvents = $eventLog->getRecentEvents(100); -$tokenManager = new TokenManager($pdo); -$agentTokens = $tokenManager->getAllTokens(); - $updateMgr = new UpdateManager($pdo); $releases = $updateMgr->getReleases(); @@ -579,7 +586,7 @@ $baseUrl = $protocol . '://' . $host; .form-input { background: rgba(255,255,255,0.04); border: 1px solid var(--border-glass); border-radius: 10px; padding: 0.65rem 0.85rem; color: #fff; font-size: 0.875rem; outline: none; font-family: 'Manrope', system-ui; transition: border-color 0.2s; } .form-input:focus { border-color: var(--primary); } - /* Dropdown Option List Styling Fix (Readable text across all browsers) */ + /* Dropdown Option List Styling Fix (Readable dark text/bg across all operating systems & browsers) */ select.form-input option { background-color: #0e121c; color: #EDEFF5; @@ -591,10 +598,10 @@ $baseUrl = $protocol . '://' . $host; .alert-success { background: rgba(18,212,138,0.15); border: 1px solid rgba(18,212,138,0.3); color: #a7f3d0; } .alert-danger { background: rgba(246,70,93,0.15); border: 1px solid rgba(246,70,93,0.3); color: #fca5a5; } - /* Safety Modal */ + /* Modals */ .modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.75); backdrop-filter: blur(10px); display: none; align-items: center; justify-content: center; z-index: 200; } .modal-backdrop.active { display: flex; } - .modal-card { background: #0e121c; border: 1px solid rgba(246,70,93,0.3); border-radius: 18px; padding: 2rem; max-width: 500px; width: 90%; box-shadow: 0 20px 50px rgba(0,0,0,0.8); } + .modal-card { background: #0e121c; border: 1px solid var(--border-glass); border-radius: 18px; padding: 2rem; max-width: 550px; width: 90%; box-shadow: 0 20px 50px rgba(0,0,0,0.8); } .tab-content, .subtab-content { display: none; } .tab-content.active, .subtab-content.active { display: block; } @@ -865,6 +872,59 @@ $baseUrl = $protocol . '://' . $host; + + +
@@ -1159,7 +1219,7 @@ $baseUrl = $protocol . '://' . $host;
- +

🌳 Proxmox, Host & Worker System-Hierarchie (3 Ebenen)

@@ -1169,8 +1229,9 @@ $baseUrl = $protocol . '://' . $host; Hierarchie / Entity Source Typ Parent Entity + Agent Token Status - Parent Verknüpfen + Aktionen @@ -1179,6 +1240,8 @@ $baseUrl = $protocol . '://' . $host; $depth = (int)$m['depth']; $indentPx = $depth * 24; $isChild = ($depth > 0); + $hasToken = isset($tokensBySource[$m['source']]); + $tokenData = $hasToken ? $tokensBySource[$m['source']] : null; ?> @@ -1190,8 +1253,6 @@ $baseUrl = $protocol . '://' . $host;
- -
@@ -1199,7 +1260,6 @@ $baseUrl = $protocol . '://' . $host;
+ + + ... + +
+ + + + +
+ + + + + +
+ + + +
+ @@ -1216,10 +1297,10 @@ $baseUrl = $protocol . '://' . $host;
- +
-

🖥️ Monitor Anlegen / Bearbeiten

+

🖥️ Monitor Anlegen

@@ -1272,29 +1353,43 @@ $baseUrl = $protocol . '://' . $host;
-

⏱️ Uptime Monitor & CRUD Verwaltung

+

⏱️ Uptime Monitor & Vollständige Verwaltung

+ - - + - + + - - + - + @@ -1381,6 +1482,7 @@ $baseUrl = $protocol . '://' . $host; +
Monitor SourceTyp ParentGruppeIntervallAgent Token StatusZuletzt Gesehen Aktionen
s + + ... + + + + + + + + + + .ps1 .sh @@ -1353,7 +1448,12 @@ $baseUrl = $protocol . '://' . $host;
- +
@@ -1367,6 +1467,7 @@ $baseUrl = $protocol . '://' . $host;
Token ID BezeichnungGebundene Source Token Value Status Aktion
@@ -1699,6 +1801,22 @@ $baseUrl = $protocol . '://' . $host; document.getElementById('deleteProjectModal').classList.remove('active'); } + // Monitor Editing Functions + function openEditMonitorModal(m) { + document.getElementById('monEditOldSource').value = m.source; + document.getElementById('monEditNewSource').value = m.source; + document.getElementById('monEditType').value = m.type || 'host'; + document.getElementById('monEditParent').value = m.parent_source || ''; + document.getElementById('monEditGroup').value = m.group_key || 'Default'; + document.getElementById('monEditOs').value = m.os || ''; + document.getElementById('monEditInterval').value = m.expected_interval_sec || 60; + document.getElementById('editMonitorModal').classList.add('active'); + } + + function closeEditMonitorModal() { + document.getElementById('editMonitorModal').classList.remove('active'); + } + // License Editing Functions function openEditLicense(l) { switchMainTab('license', document.querySelector('.nav-link[onclick*="license"]')); diff --git a/src/Modules/Watchdog/MonitorRepo.php b/src/Modules/Watchdog/MonitorRepo.php index c91fe02..0887940 100644 --- a/src/Modules/Watchdog/MonitorRepo.php +++ b/src/Modules/Watchdog/MonitorRepo.php @@ -81,19 +81,31 @@ class MonitorRepo string $oldSource, string $newSource, string $instance, + ?string $type, ?string $groupKey, ?string $parentSource, + ?string $os, ?string $notes, ?string $url, ?int $intervalSec, ?string $icon = null, bool $isMuted = false ): bool { + // Cascade source renaming to children & agent tokens + if ($oldSource !== $newSource) { + $this->db->prepare('UPDATE watchdog_monitors SET parent_source = :new WHERE parent_source = :old') + ->execute([':new' => $newSource, ':old' => $oldSource]); + $this->db->prepare('UPDATE watchdog_agent_tokens SET monitor_source = :new WHERE monitor_source = :old') + ->execute([':new' => $newSource, ':old' => $oldSource]); + } + $stmt = $this->db->prepare(' UPDATE watchdog_monitors SET source = :new_source, + type = COALESCE(:type, type), group_key = :group_key, parent_source = :parent_source, + os = :os, notes = :notes, url = :url, expected_interval_sec = COALESCE(:interval, expected_interval_sec), @@ -105,8 +117,10 @@ class MonitorRepo return $stmt->execute([ ':new_source' => $newSource, + ':type' => !empty($type) ? $type : null, ':group_key' => !empty($groupKey) ? $groupKey : null, ':parent_source' => !empty($parentSource) ? $parentSource : null, + ':os' => !empty($os) ? $os : null, ':notes' => !empty($notes) ? $notes : null, ':url' => !empty($url) ? $url : null, ':interval' => $intervalSec, @@ -138,6 +152,15 @@ class MonitorRepo public function deleteMonitor(string $source, string $instance = 'default'): bool { + // 1. Unlink any children + $this->db->prepare('UPDATE watchdog_monitors SET parent_source = NULL WHERE parent_source = :s') + ->execute([':s' => $source]); + + // 2. Revoke agent tokens for this monitor + $this->db->prepare('UPDATE watchdog_agent_tokens SET revoked = 1 WHERE monitor_source = :s') + ->execute([':s' => $source]); + + // 3. Delete monitor $stmt = $this->db->prepare('DELETE FROM watchdog_monitors WHERE source = :s AND instance = :i'); return $stmt->execute([':s' => $source, ':i' => $instance]); }