Quelltext des aktuellen Standes
<?php $this->layout('layouts/main', ['page_title' => $page_title, 'current_route' => $current_route, 'full_width' => true]); ?>
<style>
a { text-decoration:none; }
.af-body { padding:1.75rem 2.5rem 3rem; max-width:800px; }
.af-card { background:var(--color-bg); border:1px solid var(--gray-200); border-radius:0.25rem; margin-bottom:1.25rem; overflow:hidden; }
.af-card-header { padding:0.875rem 1.25rem; border-bottom:1px solid var(--gray-100); display:flex; align-items:center; justify-content:space-between; }
.af-card-title { font-size:0.78rem; font-weight:700; text-transform:uppercase; letter-spacing:0.07em; color:var(--gray-400); }
.af-card-body { padding:1.25rem; display:flex; flex-direction:column; gap:1rem; }
.af-grid { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }
/* Abstände liefern die Flex-/Grid-Gaps der Card – die Formulargruppe braucht keinen eigenen */
.af-card-body .form-group { margin-bottom:0; }
.af-textarea { min-height:80px; resize:vertical; }
/* Detail-Zeilen */
.af-detail-list { display:flex; flex-direction:column; gap:0.5rem; }
.af-detail-row { display:grid; grid-template-columns:1fr 1.5fr auto; gap:0.5rem; align-items:center; }
.af-detail-remove { background:none; border:none; color:var(--gray-400); cursor:pointer; padding:0.3rem; border-radius:0.25rem;
font-size:1rem; line-height:1; transition:color 0.1s; }
.af-detail-remove:hover { color:var(--red-600); }
.af-detail-suggestions { display:flex; flex-wrap:wrap; gap:0.35rem; margin-top:0.35rem; }
.af-detail-suggestion { font-size:0.72rem; padding:0.2rem 0.5rem; border-radius:9999px;
background:var(--blue-50); color:var(--color-primary-dark); cursor:pointer; border:none;
transition:background 0.1s; white-space:nowrap; }
.af-detail-suggestion:hover { background:var(--blue-100); }
.af-actions { display:flex; gap:0.75rem; align-items:center; padding-top:0.5rem; }
@media(max-width:768px) {
.af-body { padding:1.25rem 1rem 2rem; }
.af-grid { grid-template-columns:1fr; }
.af-detail-row { grid-template-columns:1fr 1fr auto; }
}
</style>
<div>
<!-- Content Header -->
<div class="content-header">
<div>
<h1><?= $address ? 'IP-Adresse bearbeiten' : 'IP-Adresse anlegen' ?></h1>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/"><?= $this->te('Home') ?></a></li>
<li class="breadcrumb-item"><a href="/ipam">IPAM</a></li>
<li class="breadcrumb-item"><a href="/ipam/subnets/<?= $subnet['id'] ?>"><?= $this->e($subnet['name']) ?></a></li>
<?php if ($address): ?>
<li class="breadcrumb-item"><a href="/ipam/addresses/<?= $address['id'] ?>"><?= $this->e($address['ip_address']) ?></a></li>
<li class="breadcrumb-item active"><?= $this->te('Bearbeiten') ?></li>
<?php else: ?>
<li class="breadcrumb-item active"><?= $this->te('Neue IP') ?></li>
<?php endif; ?>
</ol>
</div>
</div>
<div class="af-body">
<?php $action = $address
? '/ipam/addresses/' . $address['id']
: '/ipam/subnets/' . $subnet['id'] . '/addresses'; ?>
<form method="POST" action="<?= $action ?>">
<input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
<!-- Basis -->
<div class="af-card">
<div class="af-card-header"><span class="af-card-title"><?= $this->te('IP-Adresse') ?></span></div>
<div class="af-card-body">
<div class="af-grid">
<div class="form-group">
<label><?= $this->te('IP-Adresse') ?> <span class="text-danger">*</span></label>
<input class="form-control" type="text" name="ip_address" required
placeholder="192.168.1.10"
value="<?= $this->e($address['ip_address'] ?? $prefill_ip) ?>"
pattern="^(\d{1,3}\.){3}\d{1,3}$|^[0-9a-fA-F:]+$">
</div>
<div class="form-group">
<label><?= $this->te('Hostname') ?></label>
<input class="form-control" type="text" name="hostname"
placeholder="server01.intern"
value="<?= $this->e($address['hostname'] ?? '') ?>">
</div>
<div class="form-group">
<label for="f-0088-type"><?= $this->te('Typ') ?></label>
<select id="f-0088-type" class="form-control" name="type">
<?php foreach ($type_labels as $val => $lbl): ?>
<option value="<?= $val ?>" <?= ($address['type'] ?? 'other') === $val ? 'selected' : '' ?>><?= $lbl ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label for="f-0088-status"><?= $this->te('Status') ?></label>
<select id="f-0088-status" class="form-control" name="status">
<?php foreach ($status_labels as $val => $lbl): ?>
<option value="<?= $val ?>" <?= ($address['status'] ?? 'active') === $val ? 'selected' : '' ?>><?= $lbl ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label><?= $this->te('MAC-Adresse') ?></label>
<input class="form-control" type="text" name="mac_address"
placeholder="AA:BB:CC:DD:EE:FF"
value="<?= $this->e($address['mac_address'] ?? '') ?>">
</div>
<div class="form-group">
<label for="f-0088-asset_id"><?= $this->te('Verknüpftes Asset') ?></label>
<select id="f-0088-asset_id" class="form-control" name="asset_id">
<option value=""><?= $this->te('– automatisch per MAC / nicht verknüpft –') ?></option>
<?php foreach (($assets ?? []) as $a):
$label = $a['inventory_number'];
$extra = trim(($a['manufacturer_name'] ?? '') . ' ' . ($a['type_name'] ?? ''));
if ($extra !== '') { $label .= ' – ' . $extra; }
if (!empty($a['serial_number'])) { $label .= ' (S/N: ' . $a['serial_number'] . ')'; }
?>
<option value="<?= (int)$a['id'] ?>" <?= (int)($address['asset_id'] ?? 0) === (int)$a['id'] ? 'selected' : '' ?>><?= $this->e($label) ?></option>
<?php endforeach; ?>
</select>
<small style="color:var(--gray-500);font-size:0.78rem;"><?= $this->te('Leer lassen = automatische Zuordnung per MAC (falls aktiviert). Eine manuelle Auswahl hat Vorrang.') ?></small>
</div>
<div class="form-group">
<label><?= $this->te('Verantwortlich') ?></label>
<input class="form-control" type="text" name="responsible"
placeholder="<?= $this->te('Name oder Team') ?>"
value="<?= $this->e($address['responsible'] ?? '') ?>">
</div>
</div>
<div class="form-group">
<label><?= $this->te('Beschreibung') ?></label>
<textarea class="form-control af-textarea" name="description" placeholder="<?= $this->te('Kurze Beschreibung des Systems…') ?>"><?= $this->e($address['description'] ?? '') ?></textarea>
</div>
</div>
</div>
<!-- Details (Key-Value) -->
<div class="af-card">
<div class="af-card-header">
<span class="af-card-title"><?= $this->te('Details / Server-Infos') ?></span>
<button type="button" onclick="addDetailRow()" style="font-size:0.78rem;font-weight:600;color:var(--color-primary);background:none;border:none;cursor:pointer;padding:0;"><?= $this->te('+ Zeile hinzufügen') ?></button>
</div>
<div class="af-card-body">
<div style="display:grid;grid-template-columns:1fr 1.5fr auto;gap:0.5rem;margin-bottom:0.25rem;">
<span style="font-size:0.72rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:var(--gray-400);"><?= $this->te('Bezeichnung') ?></span>
<span style="font-size:0.72rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:var(--gray-400);"><?= $this->te('Wert') ?></span>
<span></span>
</div>
<div class="af-detail-list" id="detailList">
<?php foreach ($details as $d): ?>
<div class="af-detail-row">
<input type="text" name="detail_key[]" value="<?= $this->e($d['detail_key']) ?>" placeholder="<?= $this->te('z.B. Betriebssystem') ?>">
<input type="text" name="detail_val[]" value="<?= $this->e($d['detail_val'] ?? '') ?>" placeholder="<?= $this->te('Wert') ?>">
<button type="button" class="af-detail-remove" onclick="this.parentElement.remove()" title="<?= $this->te('Entfernen') ?>">×</button>
</div>
<?php endforeach; ?>
</div>
<!-- Schnell-Vorschläge -->
<div class="af-detail-suggestions" style="margin-top:0.75rem;">
<span style="font-size:0.72rem;color:var(--gray-400);margin-right:0.25rem;"><?= $this->te('Schnell hinzufügen:') ?></span>
<?php foreach (['Betriebssystem','OS-Version','CPU','RAM','Speicher','Dienste','Anwendungen','Virtualisierung','Backup','Cluster','Monitoring'] as $s): ?>
<button type="button" class="af-detail-suggestion" onclick="addDetailRow('<?= htmlspecialchars($s, ENT_QUOTES) ?>')"><?= $s ?></button>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="af-actions">
<button type="submit" class="btn btn-primary"><?= $this->te('Speichern') ?></button>
<a href="<?= $address ? '/ipam/addresses/' . $address['id'] : '/ipam/subnets/' . $subnet['id'] ?>" class="btn btn-default"><?= $this->te('Abbrechen') ?></a>
</div>
</form>
</div>
</div>
<script>
function addDetailRow(key) {
var row = document.createElement('div');
row.className = 'af-detail-row';
row.innerHTML = '<input type="text" name="detail_key[]" value="' + (key || '') + '" placeholder="z.B. Betriebssystem">'
+ '<input type="text" name="detail_val[]" placeholder="Wert">'
+ '<button type="button" class="af-detail-remove" onclick="this.parentElement.remove()" title="Entfernen">×</button>';
document.getElementById('detailList').appendChild(row);
row.querySelectorAll('input')[key ? 1 : 0].focus();
}
</script>