asdad
All checks were successful
Deploy / deploy-staging (push) Successful in 31s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-04-22 00:03:19 +02:00
parent 82ad817ad3
commit 1d948f0508
4 changed files with 248 additions and 6 deletions

View File

@@ -11,6 +11,9 @@
<div>
<h2 class="section-title">KEA DHCP Hosts</h2>
<p>Reservierungen und aktuelle Leases aus der KEA-Datenbank.</p>
<p class="muted kea-refresh-state" data-kea-refresh-state>
Automatische Aktualisierung alle 5 Sekunden.
</p>
</div>
<div class="setup-actions">
<a class="cta-button" href="/module/kea/groups">Gruppen verwalten</a>
@@ -34,23 +37,23 @@
<div class="stats">
<div class="stat-card">
<span class="stat-label">Einträge</span>
<span class="stat-value"><?= e((string)($stats['total'] ?? 0)) ?></span>
<span class="stat-value" data-kea-stat="total"><?= e((string)($stats['total'] ?? 0)) ?></span>
</div>
<div class="stat-card">
<span class="stat-label">Reservierungen</span>
<span class="stat-value"><?= e((string)($stats['reservations'] ?? 0)) ?></span>
<span class="stat-value" data-kea-stat="reservations"><?= e((string)($stats['reservations'] ?? 0)) ?></span>
</div>
<div class="stat-card">
<span class="stat-label">Leases</span>
<span class="stat-value"><?= e((string)($stats['leases'] ?? 0)) ?></span>
<span class="stat-value" data-kea-stat="leases"><?= e((string)($stats['leases'] ?? 0)) ?></span>
</div>
<div class="stat-card">
<span class="stat-label">Gruppen</span>
<span class="stat-value"><?= e((string)count($stats['groups'] ?? [])) ?></span>
<span class="stat-value" data-kea-stat="groups"><?= e((string)count($stats['groups'] ?? [])) ?></span>
</div>
<div class="stat-card">
<span class="stat-label">Freie Gruppen-IPs</span>
<span class="stat-value"><?= e((string)array_sum($stats['free_ips'] ?? [])) ?></span>
<span class="stat-value" data-kea-stat="free_ips"><?= e((string)array_sum($stats['free_ips'] ?? [])) ?></span>
</div>
</div>
@@ -78,7 +81,7 @@
<th>Aktion</th>
</tr>
</thead>
<tbody>
<tbody data-kea-host-rows>
<?php if (empty($hosts)): ?>
<tr>
<td colspan="10" class="kea-empty">
@@ -128,3 +131,98 @@
</div>
</div>
</section>
<script>
(() => {
const rowsTarget = document.querySelector('[data-kea-host-rows]');
const stateTarget = document.querySelector('[data-kea-refresh-state]');
if (!rowsTarget) {
return;
}
const setText = (selector, value) => {
const target = document.querySelector(selector);
if (target) {
target.textContent = String(value ?? '0');
}
};
const cell = (value, className = '') => {
const td = document.createElement('td');
if (className) {
td.className = className;
}
td.textContent = value || '-';
return td;
};
const renderRows = (rows) => {
rowsTarget.textContent = '';
if (!Array.isArray(rows) || rows.length === 0) {
const tr = document.createElement('tr');
const td = cell('Keine Reservierungen oder aktiven Leases gefunden.', 'kea-empty');
td.colSpan = 10;
tr.appendChild(td);
rowsTarget.appendChild(tr);
return;
}
for (const row of rows) {
const tr = document.createElement('tr');
const source = document.createElement('td');
const pill = document.createElement('span');
pill.className = 'pill';
pill.textContent = row.source === 'lease' ? 'Lease' : 'Reservierung';
source.appendChild(pill);
tr.appendChild(source);
tr.appendChild(cell(row.display_name));
tr.appendChild(cell(row.ipv4_address, 'mono'));
tr.appendChild(cell(row.dhcp_identifier, 'mono'));
tr.appendChild(cell(row.last_seen_at));
tr.appendChild(cell(row.lease_expires_at));
tr.appendChild(cell(row.real_name));
tr.appendChild(cell(row.location));
tr.appendChild(cell(row.group_name));
const action = document.createElement('td');
const link = document.createElement('a');
link.className = 'nav-link';
link.href = `/module/kea/edit?source=${encodeURIComponent(row.source || 'reservation')}&id=${encodeURIComponent(row.host_id || '0')}`;
link.textContent = 'Bearbeiten';
action.appendChild(link);
tr.appendChild(action);
rowsTarget.appendChild(tr);
}
};
const refresh = async () => {
try {
const response = await fetch('/module/kea/data', {
headers: {Accept: 'application/json'},
cache: 'no-store',
});
const payload = await response.json();
if (!response.ok || !payload.ok) {
throw new Error(payload.error || 'Aktualisierung fehlgeschlagen.');
}
setText('[data-kea-stat="total"]', payload.stats?.total);
setText('[data-kea-stat="reservations"]', payload.stats?.reservations);
setText('[data-kea-stat="leases"]', payload.stats?.leases);
setText('[data-kea-stat="groups"]', payload.stats?.groups);
setText('[data-kea-stat="free_ips"]', payload.stats?.free_ips);
renderRows(payload.rows);
if (stateTarget) {
stateTarget.textContent = `Automatische Aktualisierung aktiv. Zuletzt aktualisiert: ${payload.updated_at || '-'}`;
}
} catch (error) {
if (stateTarget) {
stateTarget.textContent = `Automatische Aktualisierung fehlgeschlagen: ${error.message}`;
}
}
};
window.setInterval(refresh, 5000);
})();
</script>