OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

vm_form.php

13 KB
<?php
$this->layout('layouts/main', [
    'page_title'    => $page_title,
    'current_route' => 'vms',
    'full_width'    => true,
]);

$vm         = $vm         ?? null;
$hosts      = $hosts      ?? [];
$can_manage = $can_manage ?? false;
$isEdit     = $vm !== null;
?>

<div class="vmf-wrap">

    <div class="content-header">
        <div>
            <h1><?= $this->e($page_title) ?></h1>
            <ol class="breadcrumb">
                <li class="breadcrumb-item"><a href="/"><?= $this->te('Home') ?></a></li>
                <li class="breadcrumb-item"><a href="/vms"><?= $this->te('Virtualisierung') ?></a></li>
                <?php if ($isEdit): ?>
                    <li class="breadcrumb-item"><a href="/vms/<?= $vm['id'] ?>"><?= $this->e($vm['name']) ?></a></li>
                    <li class="breadcrumb-item active"><?= $this->te('Bearbeiten') ?></li>
                <?php else: ?>
                    <li class="breadcrumb-item active"><?= $this->te('Neue VM') ?></li>
                <?php endif; ?>
            </ol>
        </div>
    </div>

    <form action="<?= $this->e($form_action) ?>" method="POST" class="vmf-layout">
        <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">

        <!-- Hauptspalte -->
        <div class="vmf-main">

            <section class="vmf-card">
                <h2 class="vmf-section-head">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
                    <?= $this->te('Stammdaten') ?>
                </h2>
                <div class="vmf-card-body">
                    <div class="vmf-row-2">
                        <div class="vmf-field">
                            <label for="vmf_name"><?= $this->te('Name') ?> <span class="vmf-req">*</span></label>
                            <input type="text" id="vmf_name" name="name" required maxlength="255"
                                   value="<?= $this->e($vm['name'] ?? '') ?>"
                                   placeholder="<?= $this->te('z.B. web-server-01') ?>">
                        </div>
                        <div class="vmf-field">
                            <label for="vmf_status"><?= $this->te('Status') ?></label>
                            <select id="vmf_status" name="status">
                                <option value="running"  <?= ($vm['status'] ?? 'running') === 'running'  ? 'selected' : '' ?>><?= $this->te('Laufend') ?></option>
                                <option value="stopped"  <?= ($vm['status'] ?? '') === 'stopped'  ? 'selected' : '' ?>><?= $this->te('Gestoppt') ?></option>
                                <option value="paused"   <?= ($vm['status'] ?? '') === 'paused'   ? 'selected' : '' ?>><?= $this->te('Pausiert') ?></option>
                                <option value="error"    <?= ($vm['status'] ?? '') === 'error'    ? 'selected' : '' ?>><?= $this->te('Fehler') ?></option>
                            </select>
                        </div>
                    </div>
                    <div class="vmf-row-2">
                        <div class="vmf-field">
                            <label for="vmf_ip"><?= $this->te('IP-Adresse') ?></label>
                            <input type="text" id="vmf_ip" name="ip_address" maxlength="45"
                                   value="<?= $this->e($vm['ip_address'] ?? '') ?>"
                                   placeholder="z.B. 192.168.1.100">
                            <span class="vmf-hint"><?= $this->te('Wird automatisch in IPAM eingetragen, wenn ein Subnetz passt.') ?></span>
                        </div>
                        <div class="vmf-field">
                            <label for="vmf_os"><?= $this->te('Betriebssystem') ?></label>
                            <input type="text" id="vmf_os" name="os" maxlength="255"
                                   value="<?= $this->e($vm['os'] ?? '') ?>"
                                   placeholder="<?= $this->te('z.B. Ubuntu 22.04 LTS') ?>">
                        </div>
                    </div>
                    <div class="vmf-field">
                        <label for="vmf_host"><?= $this->te('Host') ?></label>
                        <select id="vmf_host" name="host_id">
                            <option value=""><?= $this->te('Kein Host zugewiesen') ?></option>
                            <?php foreach ($hosts as $h): ?>
                                <option value="<?= $h['id'] ?>" <?= ($vm['host_id'] ?? '') == $h['id'] ? 'selected' : '' ?>>
                                    <?= $this->e($h['name']) ?>
                                    <?php if (!empty($h['hypervisor'])): ?>(<?= $this->e($h['hypervisor']) ?>)<?php endif; ?>
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="vmf-field">
                        <label for="vmf_purpose"><?= $this->te('Zweck / Verwendungszweck') ?></label>
                        <textarea id="vmf_purpose" name="purpose" rows="3"
                                  placeholder="<?= $this->te('Wofür wird diese VM genutzt?') ?>"><?= $this->e($vm['purpose'] ?? '') ?></textarea>
                    </div>
                </div>
            </section>

            <section class="vmf-card">
                <h2 class="vmf-section-head">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><rect x="2" y="3" width="20" height="14" rx="2"/><polyline points="8 21 12 17 16 21"/></svg>
                    <?= $this->te('Ressourcen') ?>
                </h2>
                <div class="vmf-card-body">
                    <div class="vmf-row-3">
                        <div class="vmf-field">
                            <label for="vmf_cpu"><?= $this->te('vCPU-Kerne') ?></label>
                            <input type="number" id="vmf_cpu" name="cpu_cores" min="1" max="1024"
                                   value="<?= $this->e($vm['cpu_cores'] ?? '') ?>"
                                   placeholder="z.B. 4">
                        </div>
                        <div class="vmf-field">
                            <label for="vmf_ram"><?= $this->t('RAM (GB)') ?></label>
                            <input type="number" id="vmf_ram" name="ram_gb" min="0" step="0.5"
                                   value="<?= $this->e($vm['ram_gb'] ?? '') ?>"
                                   placeholder="z.B. 8">
                        </div>
                        <div class="vmf-field">
                            <label for="vmf_disk"><?= $this->te('Speicher (GB)') ?></label>
                            <input type="number" id="vmf_disk" name="storage_gb" min="0" step="1"
                                   value="<?= $this->e($vm['storage_gb'] ?? '') ?>"
                                   placeholder="z.B. 100">
                        </div>
                    </div>
                </div>
            </section>

            <section class="vmf-card">
                <h2 class="vmf-section-head">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
                    <?= $this->te('Notizen') ?>
                </h2>
                <div class="vmf-card-body">
                    <div class="vmf-field">
                        <label for="vmf_notes"><?= $this->te('Interne Notizen') ?></label>
                        <textarea id="vmf_notes" name="notes" rows="4"
                                  placeholder="<?= $this->te('Interne Anmerkungen, Konfigurationshinweise…') ?>"><?= $this->e($vm['notes'] ?? '') ?></textarea>
                    </div>
                </div>
            </section>

        </div><!-- /vmf-main -->

        <!-- Sidebar -->
        <aside class="vmf-sidebar">

            <?php if (!empty($hosts)): ?>
            <section class="vmf-card">
                <h2 class="vmf-section-head">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/></svg>
                    <?= $this->te('Verfügbare Hosts') ?>
                </h2>
                <div class="vmf-card-body">
                    <ul class="vmf-host-list">
                        <?php foreach ($hosts as $h): ?>
                        <li class="vmf-host-item <?= ($vm['host_id'] ?? '') == $h['id'] ? 'vmf-host-selected' : '' ?>">
                            <span class="vmf-host-name"><?= $this->e($h['name']) ?></span>
                            <span class="vmf-host-info">
                                <?= $h['cpu_cores'] ? (int)$h['cpu_cores'] . ' CPU' : '' ?>
                                <?= $h['ram_gb'] ? '· ' . number_format((float)$h['ram_gb'], 0) . ' GB RAM' : '' ?>
                            </span>
                        </li>
                        <?php endforeach; ?>
                    </ul>
                </div>
            </section>
            <?php endif; ?>

            <div class="vmf-actions">
                <button type="submit" class="btn btn-primary">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15"><polyline points="20 6 9 17 4 12"/></svg>
                    <?= $isEdit ? 'Änderungen speichern' : 'VM erstellen' ?>
                </button>
                <a href="<?= $isEdit ? '/vms/' . $vm['id'] : '/vms' ?>" class="btn btn-default"><?= $this->te('Abbrechen') ?></a>
            </div>

        </aside>
    </form>

</div>

<style>
/* ====================================================
   VM-Formular  ·  Prefix: vmf-
   ==================================================== */
.vmf-wrap { display:flex; flex-direction:column; }

.vmf-layout { display:grid; grid-template-columns:1fr 320px; gap:1.5rem; padding:1.5rem 1rem 3rem; background:var(--gray-50); }

.vmf-main { display:flex; flex-direction:column; gap:1.25rem; }
.vmf-sidebar { display:flex; flex-direction:column; gap:1rem; }

.vmf-card { background:var(--color-bg); border-radius:0.25rem; box-shadow:0 1px 3px rgba(0,0,0,0.06); overflow:hidden; }
.vmf-section-head {
    display:flex; align-items:center; gap:0.5rem;
    font-size:0.8rem; font-weight:700; color:var(--gray-700);
    text-transform:uppercase; letter-spacing:0.04em;
    padding:0.875rem 1.25rem; border-bottom:1px solid var(--gray-100); margin:0;
    background:var(--gray-50);
}
.vmf-section-head svg { color:var(--gray-400); flex-shrink:0; }
.vmf-card-body { padding:1.25rem; display:flex; flex-direction:column; gap:0.875rem; }

.vmf-field { display:flex; flex-direction:column; gap:0.35rem; }
.vmf-field label { font-size:0.8rem; font-weight:600; color:var(--gray-700); }
.vmf-field input, .vmf-field select, .vmf-field textarea {
    width:100%; padding:0.5rem 0.75rem; border:1px solid var(--gray-300);
    border-radius:0.25rem; font-size:0.875rem; color:var(--gray-900);
    background:var(--color-bg); transition:border-color .15s;
    font-family:inherit;
}
.vmf-field input:focus, .vmf-field select:focus, .vmf-field textarea:focus {
    outline:none; border-color:var(--color-primary); box-shadow:0 0 0 2px rgba(var(--color-primary-rgb), 0.15);
}
.vmf-field textarea { resize:vertical; }
.vmf-hint { font-size:0.75rem; color:var(--gray-400); }
.vmf-req { color:var(--red-600); }

.vmf-row-2 { display:grid; grid-template-columns:1fr 1fr; gap:0.875rem; }
.vmf-row-3 { display:grid; grid-template-columns:1fr 1fr 1fr; gap:0.875rem; }

/* Host List */
.vmf-host-list { margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:0.375rem; }
.vmf-host-item {
    padding:0.5rem 0.75rem; border-radius:0.25rem; border:1px solid var(--gray-100);
    background:var(--gray-50); font-size:0.8rem;
}
.vmf-host-selected { border-color:var(--color-primary); background:var(--blue-50); }
.vmf-host-name { display:block; font-weight:500; color:var(--gray-700); }
.vmf-host-info { font-size:0.72rem; color:var(--gray-400); }

/* Actions */
.vmf-actions { display:flex; flex-direction:column; gap:0.5rem; }

@media (max-width:1100px) { .vmf-layout { grid-template-columns:1fr 280px; } }
@media (max-width:900px)  { .vmf-layout { grid-template-columns:1fr; padding:1rem; } .vmf-sidebar { position:static; } }
@media (max-width:640px)  { .vmf-row-2, .vmf-row-3 { grid-template-columns:1fr; } }
</style>