OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

infrastructure-rack-dialogs.php

36 KB
<?php
/**
 * Dialoge der Rack-Seite: Rack bearbeiten, Geraet einbauen und bearbeiten,
 * Verbindung anlegen, Verkabelung importieren, Ports beschriften.
 *
 * Aufruf nur fuer Aenderungsberechtigte:
 *   <?= $this->partial('infrastructure-rack-dialogs', [...]) ?>
 *
 * @var array                     $rack        Das Rack selbst (id, name, doc_page_id, ...).
 * @var int                       $height      Hoehe des Racks in HE.
 * @var string                    $numbering   'bottom_up' oder 'top_down'.
 * @var string                    $side        Angezeigte Seite ('front'/'rear') – Vorgabe beim Einbauen.
 * @var array                     $mounts      Geraete dieses Racks (fuer die Endpunkt-Auswahl).
 * @var array                     $targets     Racks der Umgebung mit ihren Geraeten (Endpunkt B).
 * @var list<array{0:int,1:string}> $docOptions Dokuseiten zur Auswahl.
 * @var float|null                $maxLoadKg   Hinterlegte Traglast.
 * @var int|null                  $maxPowerW   Hinterlegte Leistungsgrenze.
 */
?>
<!-- Modal: Rack bearbeiten -->
<div class="modal-overlay" id="inf-rack-modal" style="display:none;" onclick="if(event.target===this)this.style.display='none'">
    <div class="modal-card">
        <div class="modal-header"><h2><?= $this->te('Rack bearbeiten') ?></h2>
            <button aria-label="<?= $this->te('Schließen') ?>" type="button" class="modal-close" onclick="document.getElementById('inf-rack-modal').style.display='none'">&times;</button></div>
        <form method="POST" action="/infrastructure/racks/<?= (int)$rack['id'] ?>/update">
            <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
            <div class="modal-body">
                <div class="form-group">
                    <label for="f-f5d6-name"><?= $this->te('Name') ?> <span class="text-danger">*</span></label>
                    <input id="f-f5d6-name" type="text" name="name" class="form-control form-control-sm" value="<?= $this->e($rack['name']) ?>" required>
                </div>
                <div class="inf-form-row-2">
                    <div class="form-group"><label for="f-f5d6-height_u"><?= $this->te('Höhe (HE)') ?></label><input id="f-f5d6-height_u" type="number" name="height_u" class="form-control form-control-sm" value="<?= $height ?>" min="1" max="60"></div>
                    <div class="form-group"><label for="f-f5d6-numbering"><?= $this->te('Nummerierung') ?></label>
                        <select id="f-f5d6-numbering" name="numbering" class="form-control form-control-sm" data-searchable>
                            <option value="bottom_up" <?= $numbering === 'bottom_up' ? 'selected' : '' ?>><?= $this->te('von unten (1 unten)') ?></option>
                            <option value="top_down" <?= $numbering === 'top_down' ? 'selected' : '' ?>><?= $this->te('von oben (1 oben)') ?></option>
                        </select>
                    </div>
                </div>
                <div class="inf-form-row-2">
                    <div class="form-group"><label><?= $this->te('Max. Traglast (kg)') ?></label><input type="number" step="0.1" name="max_load_kg" class="form-control form-control-sm" value="<?= $maxLoadKg !== null ? $this->e(rtrim(rtrim(number_format($maxLoadKg, 1, '.', ''), '0'), '.')) : '' ?>" min="0" placeholder="<?= $this->te('optional') ?>"></div>
                    <div class="form-group"><label><?= $this->te('Max. Leistung (W)') ?></label><input type="number" name="max_power_watt" class="form-control form-control-sm" value="<?= $maxPowerW !== null ? (int)$maxPowerW : '' ?>" min="0" placeholder="<?= $this->te('optional') ?>"></div>
                    <div class="form-group">
                        <label for="f-f5d6-doc_page_id"><?= $this->te('Dokumentation') ?></label>
                        <?php
                        // Der hinterlegte Eintrag steht als einzige Option im Markup, damit der
                        // Wert auch ohne das Modul-Skript erhalten bleibt; der Rest kommt beim Oeffnen.
                        $rackDoc = (int)($rack['doc_page_id'] ?? 0);
                        $rackDocTitle = '';
                        foreach ($docOptions as $dp) { if ($dp[0] === $rackDoc) { $rackDocTitle = $dp[1]; break; } }
                        ?>
                        <select id="f-f5d6-doc_page_id" name="doc_page_id" class="form-control form-control-sm" data-searchable data-inf-fill="docPages">
                            <option value=""><?= $this->te('— keine —') ?></option>
                            <?php if ($rackDoc > 0 && $rackDocTitle !== ''): ?>
                            <option value="<?= $rackDoc ?>" selected><?= $this->e($rackDocTitle) ?></option>
                            <?php endif; ?>
                        </select>
                    </div>

                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" onclick="document.getElementById('inf-rack-modal').style.display='none'"><?= $this->te('Abbrechen') ?></button>
                <button type="submit" class="btn btn-primary"><?= $this->te('Speichern') ?></button>
            </div>
        </form>
    </div>
</div>

<!-- Modal: Gerät einbauen -->
<div class="modal-overlay" id="inf-mount-modal" style="display:none;" onclick="if(event.target===this)this.style.display='none'">
    <div class="modal-card">
        <div class="modal-header"><h2><?= $this->te('Gerät einbauen') ?></h2>
            <button aria-label="<?= $this->te('Schließen') ?>" type="button" class="modal-close" onclick="document.getElementById('inf-mount-modal').style.display='none'">&times;</button></div>
        <form method="POST" action="/infrastructure/racks/<?= (int)$rack['id'] ?>/mounts">
            <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
            <div class="modal-body">
                <div class="form-group">
                    <label for="inf-source"><?= $this->te('Quelle') ?></label>
                    <select name="source_type" class="form-control form-control-sm" id="inf-source" onchange="infSource(this.value)" data-searchable>
                        <option value="asset"><?= $this->te('Inventar-Gerät') ?></option>
                        <option value="unifi"><?= $this->te('UniFi-Gerät') ?></option>
                        <option value="passive"><?= $this->te('Passiv (Patchpanel, PDU …)') ?></option>
                    </select>
                </div>
                <div class="form-group" id="inf-f-asset">
                    <label for="f-f5d6-asset_id"><?= $this->te('Inventar-Gerät') ?></label>
                    <select id="f-f5d6-asset_id" name="asset_id" class="form-control form-control-sm" data-searchable data-inf-fill="assets">
                        <option value=""><?= $this->te('— wählen —') ?></option>
                    </select>
                </div>
                <div class="form-group" id="inf-f-unifi" style="display:none">
                    <label for="f-f5d6-unifi_mac"><?= $this->te('UniFi-Gerät') ?></label>
                    <select id="f-f5d6-unifi_mac" name="unifi_mac" class="form-control form-control-sm" onchange="infUnifiAutofill(this)" data-searchable data-inf-fill="unifi">
                        <option value=""><?= $this->te('— wählen —') ?></option>
                    </select>
                </div>
                <div class="form-group" id="inf-f-label" style="display:none">
                    <label><?= $this->te('Bezeichnung') ?></label>
                    <input type="text" name="label" class="form-control form-control-sm" placeholder="<?= $this->te('z. B. Patchpanel P-01') ?>">
                </div>
                <div class="form-group">
                    <label class="inf-check"><input type="checkbox" id="inf-add-usecolor" onchange="infToggleColor('add')"> <?= $this->te('Eigene Farbe (überschreibt Hell/Dunkel)') ?></label>
                    <div class="inf-color-row">
                        <input type="color" name="color" id="inf-add-color" value="#c0392b" disabled>
                        <span class="inf-hint"><?= $this->te('z. B. rot für WatchGuard-Firewalls – der Verlauf bleibt erhalten') ?></span>
                    </div>
                </div>
                <div class="inf-form-row">
                    <div class="form-group"><label for="inf-add-start"><?= $this->te('Start-HE') ?></label><input type="number" name="start_u" id="inf-add-start" class="form-control form-control-sm" value="1" min="1" max="<?= $height ?>"></div>
                    <div class="form-group"><label><?= $this->te('Höhe (HE)') ?></label><input type="number" name="height_u" class="form-control form-control-sm" value="1" min="1" max="20"></div>
                    <div class="form-group"><label for="inf-add-side"><?= $this->te('Seite') ?></label>
                        <select name="side" id="inf-add-side" class="form-control form-control-sm" data-searchable>
                            <option value="front" <?= $side === 'front' ? 'selected' : '' ?>><?= $this->te('Front') ?></option>
                            <option value="rear" <?= $side === 'rear' ? 'selected' : '' ?>><?= $this->te('Rück') ?></option>
                        </select>
                    </div>
                </div>
                <div class="inf-form-row-2">
                    <div class="form-group"><label for="inf-add-slot"><?= $this->te('Breite') ?></label>
                        <select name="slot" id="inf-add-slot" class="form-control form-control-sm" data-searchable>
                            <option value="full"><?= $this->te('Ganze Breite') ?></option>
                            <option value="left"><?= $this->te('Linke Hälfte') ?></option>
                            <option value="right"><?= $this->te('Rechte Hälfte') ?></option>
                        </select>
                    </div>
                    <div class="form-group"><label><?= $this->te('Tiefe') ?></label>
                        <label class="inf-check"><input type="checkbox" name="full_depth" id="inf-add-fulldepth" value="1" onchange="infAddDepth()"> <?= $this->te('Volle Tiefe (vorne & hinten)') ?></label>
                    </div>
                </div>
                <hr>
                <div class="form-group">
                    <label for="inf-portkind"><?= $this->te('Port-Darstellung') ?></label>
                    <select name="port_kind" class="form-control form-control-sm" id="inf-portkind" onchange="infPortKind(this.value)" data-searchable>
                        <option value="none"><?= $this->te('Keine (nur Blende)') ?></option>
                        <option value="switch"><?= $this->te('Switch (RJ45 + SFP)') ?></option>
                        <option value="firewall"><?= $this->te('Firewall (Ports + SFP)') ?></option>
                        <option value="patchpanel"><?= $this->te('Patchpanel') ?></option>
                        <option value="gateway"><?= $this->te('Gateway/Router (WAN/LAN)') ?></option>
                        <option value="server"><?= $this->te('Server (Laufwerke)') ?></option>
                        <option value="pbx"><?= $this->te('Telefonanlage (Anschlüsse)') ?></option>
                        <option value="pdu"><?= $this->te('PDU (Steckdosen)') ?></option>
                        <option value="ups"><?= $this->te('USV (Ausgänge)') ?></option>
                        <option value="generic"><?= $this->te('Generisch') ?></option>
                    </select>
                </div>
                <div id="inf-portcounts" style="display:none">
                    <div class="inf-form-row">
                        <div class="form-group" id="inf-add-pc-wrap"><label for="inf-add-pc" id="inf-add-pc-label"><?= $this->te('Ports') ?></label><input type="number" name="port_count" id="inf-add-pc" class="form-control form-control-sm" value="0" min="0" max="96"></div>
                        <div class="form-group" id="inf-add-sfp-wrap"><label for="inf-add-sfp">SFP</label><input type="number" name="sfp_count" id="inf-add-sfp" class="form-control form-control-sm" value="0" min="0" max="64"></div>
                        <div class="form-group" id="inf-add-qsfp-wrap"><label for="inf-add-qsfp">QSFP</label><input type="number" name="qsfp_count" id="inf-add-qsfp" class="form-control form-control-sm" value="0" min="0" max="32"></div>
                    </div>
                    <div class="form-group" id="inf-add-layout-wrap">
                        <label for="inf-add-layout"><?= $this->te('Port-Zählung') ?></label>
                        <select name="port_layout" id="inf-add-layout" class="form-control form-control-sm" data-searchable>
                            <option value="zebra"><?= $this->te('Senkrecht paarweise (1 oben, 2 darunter …)') ?></option>
                            <option value="rows"><?= $this->te('Zeilenweise (obere Reihe, dann untere)') ?></option>
                        </select>
                    </div>
                    <div id="inf-add-rear-wrap" style="display:none">
                        <div class="inf-subhead"><i class="fas fa-arrows-alt-h"></i> <?= $this->te('Ports auf der Rückseite') ?></div>
                        <div class="inf-form-row">
                            <div class="form-group" id="inf-add-rpc-wrap"><label for="f-f5d6-port_count_rear" id="inf-add-rpc-label"><?= $this->te('Ports hinten') ?></label><input id="f-f5d6-port_count_rear" type="number" name="port_count_rear" class="form-control form-control-sm" value="0" min="0" max="96"></div>
                            <div class="form-group" id="inf-add-rsfp-wrap"><label for="f-f5d6-sfp_count_rear"><?= $this->te('SFP hinten') ?></label><input id="f-f5d6-sfp_count_rear" type="number" name="sfp_count_rear" class="form-control form-control-sm" value="0" min="0" max="64"></div>
                            <div class="form-group" id="inf-add-rqsfp-wrap"><label for="f-f5d6-qsfp_count_rear"><?= $this->te('QSFP hinten') ?></label><input id="f-f5d6-qsfp_count_rear" type="number" name="qsfp_count_rear" class="form-control form-control-sm" value="0" min="0" max="32"></div>
                        </div>
                    </div>
                </div>
                <div class="inf-form-row-2">
                    <div class="form-group"><label><?= $this->te('Leistung (W)') ?></label><input type="number" name="power_watt" class="form-control form-control-sm" min="0" placeholder="<?= $this->te('optional') ?>"></div>
                    <div class="form-group"><label><?= $this->te('Gewicht (kg)') ?></label><input type="number" step="0.1" name="weight_kg" class="form-control form-control-sm" min="0" placeholder="<?= $this->te('optional') ?>"></div>
                    <div class="form-group"><label for="f-f5d6-power_feed"><?= $this->te('Stromeinspeisung') ?></label>
                        <select id="f-f5d6-power_feed" name="power_feed" class="form-control form-control-sm">
                            <option value="none"><?= $this->te('— nicht zugeordnet —') ?></option>
                            <option value="a"><?= $this->te('Nur A') ?></option>
                            <option value="b"><?= $this->te('Nur B') ?></option>
                            <option value="both"><?= $this->te('A und B (redundant)') ?></option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label><?= $this->te('Dokumentation') ?></label>
                        <select name="doc_page_id" class="form-control form-control-sm" data-searchable data-inf-fill="docPages">
                            <option value=""><?= $this->te('— keine —') ?></option>
                        </select>
                    </div>


                </div>
                <div class="form-group" id="inf-add-cap-wrap" style="display:none">
                    <label><?= $this->te('Nennleistung (W)') ?> <span class="text-muted"><?= $this->te('– Bezug für die Lastbilanz') ?></span></label>
                    <input type="number" name="capacity_watt" class="form-control form-control-sm" min="0" placeholder="z. B. 1500">
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" onclick="document.getElementById('inf-mount-modal').style.display='none'"><?= $this->te('Abbrechen') ?></button>
                <button type="submit" class="btn btn-primary"><?= $this->te('Einbauen') ?></button>
            </div>
        </form>
    </div>
</div>

<!-- Modal: Einbau bearbeiten (Identität bleibt, Verkabelung bleibt erhalten) -->
<div class="modal-overlay" id="inf-edit-modal" style="display:none;" onclick="if(event.target===this)this.style.display='none'">
    <div class="modal-card">
        <div class="modal-header"><h2><?= $this->te('Einbau bearbeiten') ?></h2>
            <button aria-label="<?= $this->te('Schließen') ?>" type="button" class="modal-close" onclick="document.getElementById('inf-edit-modal').style.display='none'">&times;</button></div>
        <form method="POST" id="inf-edit-form" action="">
            <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
            <div class="modal-body">
                <div class="form-group" id="inf-edit-f-label">
                    <label><?= $this->te('Bezeichnung') ?></label>
                    <input type="text" name="label" class="form-control form-control-sm" placeholder="<?= $this->te('Anzeigename (optional bei Inventar/UniFi)') ?>">
                </div>
                <div class="form-group">
                    <label class="inf-check"><input type="checkbox" id="inf-edit-usecolor" onchange="infToggleColor('edit')"> <?= $this->te('Eigene Farbe (überschreibt Hell/Dunkel)') ?></label>
                    <div class="inf-color-row">
                        <input type="color" name="color" id="inf-edit-color" value="#c0392b" disabled>
                        <span class="inf-hint"><?= $this->te('der dezente Verlauf bleibt erhalten') ?></span>
                    </div>
                </div>
                <div class="inf-form-row">
                    <div class="form-group"><label for="f-f5d6-start_u"><?= $this->te('Start-HE') ?></label><input id="f-f5d6-start_u" type="number" name="start_u" class="form-control form-control-sm" value="1" min="1" max="<?= $height ?>"></div>
                    <div class="form-group"><label><?= $this->te('Höhe (HE)') ?></label><input type="number" name="height_u" class="form-control form-control-sm" value="1" min="1" max="20"></div>
                    <div class="form-group"><label for="f-f5d6-side"><?= $this->te('Seite') ?></label><select id="f-f5d6-side" name="side" class="form-control form-control-sm" data-searchable><option value="front"><?= $this->te('Front') ?></option><option value="rear"><?= $this->te('Rück') ?></option></select></div>
                </div>
                <div class="inf-form-row-2">
                    <div class="form-group"><label for="f-f5d6-slot"><?= $this->te('Breite') ?></label>
                        <select id="f-f5d6-slot" name="slot" class="form-control form-control-sm" data-searchable>
                            <option value="full"><?= $this->te('Ganze Breite') ?></option>
                            <option value="left"><?= $this->te('Linke Hälfte') ?></option>
                            <option value="right"><?= $this->te('Rechte Hälfte') ?></option>
                        </select>
                    </div>
                    <div class="form-group"><label><?= $this->te('Tiefe') ?></label>
                        <label class="inf-check"><input type="checkbox" name="full_depth" id="inf-edit-fulldepth" value="1" onchange="infEditDepth()"> <?= $this->te('Volle Tiefe (vorne & hinten)') ?></label>
                    </div>
                </div>
                <div class="form-group">
                    <label for="f-f5d6-port_kind"><?= $this->te('Port-Darstellung') ?></label>
                    <select id="f-f5d6-port_kind" name="port_kind" class="form-control form-control-sm" onchange="infEditPortKind(this.value)" data-searchable>
                        <option value="none"><?= $this->te('Keine (nur Blende)') ?></option>
                        <option value="switch"><?= $this->te('Switch (RJ45 + SFP)') ?></option>
                        <option value="firewall"><?= $this->te('Firewall (Ports + SFP)') ?></option>
                        <option value="patchpanel"><?= $this->te('Patchpanel') ?></option>
                        <option value="gateway"><?= $this->te('Gateway/Router (WAN/LAN)') ?></option>
                        <option value="server"><?= $this->te('Server (Laufwerke)') ?></option>
                        <option value="pbx"><?= $this->te('Telefonanlage (Anschlüsse)') ?></option>
                        <option value="pdu"><?= $this->te('PDU (Steckdosen)') ?></option>
                        <option value="ups"><?= $this->te('USV (Ausgänge)') ?></option>
                        <option value="generic"><?= $this->te('Generisch') ?></option>
                    </select>
                </div>
                <div id="inf-edit-portcounts" style="display:none">
                    <div class="inf-form-row">
                        <div class="form-group" id="inf-edit-pc-wrap"><label for="f-f5d6-port_count" id="inf-edit-pc-label"><?= $this->te('Ports') ?></label><input id="f-f5d6-port_count" type="number" name="port_count" class="form-control form-control-sm" value="0" min="0" max="96"></div>
                        <div class="form-group" id="inf-edit-sfp-wrap"><label for="f-f5d6-sfp_count">SFP</label><input id="f-f5d6-sfp_count" type="number" name="sfp_count" class="form-control form-control-sm" value="0" min="0" max="64"></div>
                        <div class="form-group" id="inf-edit-qsfp-wrap"><label for="f-f5d6-qsfp_count">QSFP</label><input id="f-f5d6-qsfp_count" type="number" name="qsfp_count" class="form-control form-control-sm" value="0" min="0" max="32"></div>
                    </div>
                    <div class="form-group" id="inf-edit-layout-wrap">
                        <label for="f-f5d6-port_layout"><?= $this->te('Port-Zählung') ?></label>
                        <select id="f-f5d6-port_layout" name="port_layout" class="form-control form-control-sm" data-searchable>
                            <option value="zebra"><?= $this->te('Senkrecht paarweise (1 oben, 2 darunter …)') ?></option>
                            <option value="rows"><?= $this->te('Zeilenweise (obere Reihe, dann untere)') ?></option>
                        </select>
                    </div>
                    <div id="inf-edit-rear-wrap" style="display:none">
                        <div class="inf-subhead"><i class="fas fa-arrows-alt-h"></i> <?= $this->te('Ports auf der Rückseite') ?></div>
                        <div class="inf-form-row">
                            <div class="form-group" id="inf-edit-rpc-wrap"><label id="inf-edit-rpc-label"><?= $this->te('Ports hinten') ?></label><input type="number" name="port_count_rear" class="form-control form-control-sm" value="0" min="0" max="96"></div>
                            <div class="form-group" id="inf-edit-rsfp-wrap"><label><?= $this->te('SFP hinten') ?></label><input type="number" name="sfp_count_rear" class="form-control form-control-sm" value="0" min="0" max="64"></div>
                            <div class="form-group" id="inf-edit-rqsfp-wrap"><label><?= $this->te('QSFP hinten') ?></label><input type="number" name="qsfp_count_rear" class="form-control form-control-sm" value="0" min="0" max="32"></div>
                        </div>
                    </div>
                </div>
                <div class="inf-form-row-2">
                    <div class="form-group"><label><?= $this->te('Leistung (W)') ?></label><input type="number" name="power_watt" class="form-control form-control-sm" min="0" placeholder="<?= $this->te('optional') ?>"></div>
                    <div class="form-group"><label><?= $this->te('Gewicht (kg)') ?></label><input type="number" step="0.1" name="weight_kg" class="form-control form-control-sm" min="0" placeholder="<?= $this->te('optional') ?>"></div>
                    <div class="form-group"><label><?= $this->te('Stromeinspeisung') ?></label>
                        <select name="power_feed" class="form-control form-control-sm">
                            <option value="none"><?= $this->te('— nicht zugeordnet —') ?></option>
                            <option value="a"><?= $this->te('Nur A') ?></option>
                            <option value="b"><?= $this->te('Nur B') ?></option>
                            <option value="both"><?= $this->te('A und B (redundant)') ?></option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label><?= $this->te('Dokumentation') ?></label>
                        <select name="doc_page_id" class="form-control form-control-sm" data-searchable data-inf-fill="docPages">
                            <option value=""><?= $this->te('— keine —') ?></option>
                        </select>
                    </div>


                </div>
                <div class="form-group" id="inf-edit-cap-wrap" style="display:none">
                    <label><?= $this->te('Nennleistung (W)') ?> <span class="text-muted"><?= $this->te('– Bezug für die Lastbilanz') ?></span></label>
                    <input type="number" name="capacity_watt" class="form-control form-control-sm" min="0" placeholder="z. B. 1500">
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" onclick="document.getElementById('inf-edit-modal').style.display='none'"><?= $this->te('Abbrechen') ?></button>
                <button type="submit" class="btn btn-primary"><?= $this->te('Speichern') ?></button>
            </div>
        </form>
    </div>
</div>

<!-- Modal: Verbindung anlegen -->
<div class="modal-overlay" id="inf-conn-modal" style="display:none;" onclick="if(event.target===this)this.style.display='none'">
    <div class="modal-card">
        <div class="modal-header"><h2 id="inf-conn-title"><?= $this->te('Verbindung anlegen') ?></h2>
            <button aria-label="<?= $this->te('Schließen') ?>" type="button" class="modal-close" onclick="document.getElementById('inf-conn-modal').style.display='none'">&times;</button></div>
        <form method="POST" id="inf-conn-form" action="/infrastructure/racks/<?= (int)$rack['id'] ?>/connections">
            <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
            <div class="modal-body">
                <div class="inf-form-row-2">
                    <div class="form-group">
                        <label for="inf-a-mount"><?= $this->te('Gerät A') ?> <span class="text-danger">*</span></label>
                        <select name="a_mount_id" class="form-control form-control-sm" id="inf-a-mount" data-searchable>
                            <option value=""><?= $this->te('— wählen —') ?></option>
                            <?php foreach ($mounts as $m): ?>
                                <option value="<?= (int)$m['id'] ?>"><?= $this->te('{name} (HE {he})', ['name' => $m['name'], 'he' => (int)$m['start_u']]) ?></option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="form-group">
                        <label><?= $this->te('Port A') ?> <span class="text-danger">*</span></label>
                        <input type="text" name="a_port" class="form-control form-control-sm" list="inf-a-portlist" placeholder="<?= $this->te('z. B. 5, SFP1, WAN1') ?>">
                        <datalist id="inf-a-portlist"></datalist>
                    </div>
                </div>

                <div class="form-group">
                    <label for="inf-b-kind"><?= $this->te('Endpunkt B') ?></label>
                    <select class="form-control form-control-sm" id="inf-b-kind" name="b_kind" onchange="infBKind(this.value)" data-searchable>
                        <option value="mount"><?= $this->te('Gerät im System (auch anderes Rack/Standort)') ?></option>
                        <option value="external"><?= $this->te('Externes Ziel (frei)') ?></option>
                    </select>
                </div>

                <div id="inf-b-mount-wrap">
                    <div class="inf-form-row-2">
                        <div class="form-group">
                            <label for="inf-b-mount"><?= $this->te('Gerät B') ?></label>
                            <select name="b_mount_id" class="form-control form-control-sm" id="inf-b-mount" data-searchable onchange="infBPorts(this.value)">
                                <option value=""><?= $this->te('— wählen —') ?></option>
                                <?php foreach ($targets as $g): ?>
                                    <?php $ctx = ($g['location'] ? $g['location'] . ' › ' : '') . $g['rack']; ?>
                                    <?php foreach ($g['mounts'] as $tm): ?>
                                        <option value="<?= (int)$tm['id'] ?>"><?= $this->e($ctx . ' · ' . $tm['name']) ?></option>
                                    <?php endforeach; ?>
                                <?php endforeach; ?>
                            </select>
                        </div>
                        <div class="form-group">
                            <label><?= $this->te('Port B') ?></label>
                            <input type="text" name="b_port" class="form-control form-control-sm" list="inf-b-portlist" placeholder="<?= $this->te('z. B. 24, SFP1, Core-Uplink') ?>">
                            <datalist id="inf-b-portlist"></datalist>
                        </div>
                    </div>
                </div>

                <div id="inf-b-ext-wrap" style="display:none">
                    <div class="form-group">
                        <label><?= $this->te('Externes Ziel') ?></label>
                        <input type="text" name="b_external" class="form-control form-control-sm" placeholder="<?= $this->te('z. B. Provider-Übergabe, ISP-Modem') ?>">
                    </div>
                </div>

                <div class="inf-form-row-2">
                    <div class="form-group">
                        <label for="f-f5d6-cable_type"><?= $this->te('Kabeltyp') ?></label>
                        <select id="f-f5d6-cable_type" name="cable_type" class="form-control form-control-sm" data-searchable>
                            <option value="copper"><?= $this->te('Kupfer (Cat)') ?></option>
                            <option value="fiber"><?= $this->te('Fiber') ?></option>
                            <option value="dac">DAC</option>
                            <option value="wan">WAN/VPN</option>
                            <option value="power"><?= $this->te('Strom') ?></option>
                            <option value="other"><?= $this->te('Sonstige') ?></option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label><?= $this->te('Bezeichnung') ?></label>
                        <input type="text" name="label" class="form-control form-control-sm" placeholder="<?= $this->te('optional, z. B. DAC 1m') ?>">
                    </div>
                </div>

                <div class="inf-form-row-2">
                    <div class="form-group">
                        <label><?= $this->te('Länge (m)') ?></label>
                        <input type="number" step="0.1" min="0" name="length_m" class="form-control form-control-sm" placeholder="<?= $this->te('optional') ?>">
                    </div>
                    <div class="form-group">
                        <label class="inf-check"><input type="checkbox" id="inf-conn-usecolor" onchange="infToggleCableColor()"> <?= $this->te('Kabelfarbe') ?></label>
                        <div class="inf-color-row">
                            <input type="color" name="color" id="inf-conn-color" value="#3c8dbc" disabled>
                            <span class="inf-hint"><?= $this->te('hilft beim Wiederfinden im Rack') ?></span>
                        </div>
                    </div>
                </div>
                <div class="form-group">
                    <label for="f-f5d6-installed_on"><?= $this->te('Verlegt am') ?></label>
                    <input id="f-f5d6-installed_on" type="date" name="installed_on" class="form-control form-control-sm">
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" onclick="document.getElementById('inf-conn-modal').style.display='none'"><?= $this->te('Abbrechen') ?></button>
                <button type="submit" class="btn btn-primary"><?= $this->te('Speichern') ?></button>
            </div>
        </form>
    </div>
</div>



<!-- Modal: Einbauten aus CSV übernehmen -->
<div class="modal-overlay" id="inf-import-modal" style="display:none;" onclick="if(event.target===this)this.style.display='none'">
    <div class="modal-card">
        <form method="POST" action="/infrastructure/racks/<?= (int)$rack['id'] ?>/mounts/import" enctype="multipart/form-data">
            <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
            <div class="modal-header">
                <h2><?= $this->te('Einbauten aus CSV übernehmen') ?></h2>
                <button aria-label="<?= $this->te('Schließen') ?>" type="button" class="modal-close" onclick="document.getElementById('inf-import-modal').style.display='none'">&times;</button>
            </div>
            <div class="modal-body">
                <div class="form-group">
                    <label for="inf-import-file"><?= $this->te('CSV-Datei') ?> <span class="text-danger">*</span></label>
                    <input type="file" name="csv" id="inf-import-file" accept=".csv,text/csv" required class="form-control form-control-sm">
                </div>
                <p class="inf-hint" style="margin:0;">
                    <?= $this->t('Spalten, mit Semikolon getrennt:<br> <code>Bezeichnung;Start-HE;Höhe-HE;Seite;Port-Typ;Ports;SFP;Watt;kg</code><br> Beispiel: <code>Patchpanel EG;12;1;front;patchpanel;24;0;;3.2</code><br> Eine Kopfzeile wird erkannt und übersprungen. Zeilen auf belegten Positionen werden ausgelassen und danach benannt.') ?>
                </p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" onclick="document.getElementById('inf-import-modal').style.display='none'"><?= $this->te('Abbrechen') ?></button>
                <button type="submit" class="btn btn-primary"><?= $this->te('Übernehmen') ?></button>
            </div>
        </form>
    </div>
</div>

<!-- Modal: Ports beschriften -->
<div class="modal-overlay" id="inf-portlabel-modal" style="display:none;" onclick="if(event.target===this)this.style.display='none'">
    <div class="modal-card">
        <div class="modal-header"><h2 id="inf-portlabel-title"><?= $this->te('Ports beschriften') ?></h2>
            <button aria-label="<?= $this->te('Schließen') ?>" type="button" class="modal-close" onclick="document.getElementById('inf-portlabel-modal').style.display='none'">&times;</button></div>
        <form method="POST" id="inf-portlabel-form" action="">
            <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
            <div class="modal-body">
                <p class="inf-hint" style="margin:0 0 .6rem"><?= $this->te('Hinterlege je Port, wohin er führt (z. B. „Büro 1.02"). Leere Felder werden nicht gespeichert.') ?></p>
                <div id="inf-portlabel-body" class="inf-pl-grid"></div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" onclick="document.getElementById('inf-portlabel-modal').style.display='none'"><?= $this->te('Abbrechen') ?></button>
                <button type="submit" class="btn btn-primary"><?= $this->te('Speichern') ?></button>
            </div>
        </form>
    </div>
</div>