Make the registry search live
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7cdb431fd4
commit
bb736e8258
8 files changed
+220
-77
No files matched your search
@@ -154,8 +154,18 @@ final class Anwendung
|
||||
$seiten = max(1, (int) ceil(count($treffer) / $proSeite));
|
||||
$seite = min($seiten, max(1, (int) ($_GET['seite'] ?? 1)));
|
||||
|
||||
$this->zeigen('uebersicht', [
|
||||
$namen = ['aktuell' => 'aktuell', 'veraltet' => 'veraltet', 'still' => 'ohne Meldung seit 48 h', 'unbekannt' => 'ohne Kundenzuordnung'];
|
||||
$von = [] === $treffer ? 0 : ($seite - 1) * $proSeite + 1;
|
||||
$bis = min(count($treffer), $seite * $proSeite);
|
||||
$trefferText = [] === $treffer ? 'Keine Treffer.' : sprintf('%d–%d von %d %s', $von, $bis, count($treffer), 1 === count($treffer) ? 'Installation' : 'Installationen')
|
||||
.(null !== $gewaehlt ? ' · Filter: '.$namen[$gewaehlt] : '')
|
||||
.('' !== $suche ? ' · Suche: „'.$suche.'“' : '');
|
||||
|
||||
// Die Live-Suche holt nur die Liste; ohne JavaScript kommt die ganze Seite.
|
||||
$teil = 'liste' === ($_GET['teil'] ?? null);
|
||||
$this->zeigen($teil ? '_liste' : 'uebersicht', [
|
||||
'titel' => 'Installationen',
|
||||
'trefferText' => $trefferText,
|
||||
'neueste' => $neueste,
|
||||
'installationen' => array_slice($treffer, ($seite - 1) * $proSeite, $proSeite),
|
||||
'treffer' => count($treffer),
|
||||
@@ -163,12 +173,10 @@ final class Anwendung
|
||||
'filter' => $gewaehlt,
|
||||
'seite' => $seite,
|
||||
'seiten' => $seiten,
|
||||
'von' => [] === $treffer ? 0 : ($seite - 1) * $proSeite + 1,
|
||||
'bis' => min(count($treffer), $seite * $proSeite),
|
||||
'zahlen' => $zahlen,
|
||||
// Verstummte bleiben außen vor: Sie holen den Auftrag womöglich nie ab. Wartende haben schon einen.
|
||||
'aktualisierbar' => array_values(array_filter($alle, static fn (array $i): bool => $i['kann_update'] && !$i['still'] && 'wartet' !== ($i['auftrag_zustand']['art'] ?? null))),
|
||||
]);
|
||||
], true, $teil);
|
||||
}
|
||||
|
||||
private function detail(Bestand $bestand, Fassungen $fassungen): void
|
||||
@@ -353,7 +361,7 @@ final class Anwendung
|
||||
|
||||
private function kopfzeilen(): void
|
||||
{
|
||||
header("Content-Security-Policy: default-src 'none'; style-src 'self'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none'; base-uri 'none'");
|
||||
header("Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; style-src 'self'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none'; base-uri 'none'");
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
header('Referrer-Policy: no-referrer');
|
||||
header('X-Robots-Tag: noindex, nofollow');
|
||||
@@ -361,9 +369,14 @@ final class Anwendung
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $daten */
|
||||
private function zeigen(string $vorlage, array $daten, bool $angemeldet = true): void
|
||||
private function zeigen(string $vorlage, array $daten, bool $angemeldet = true, bool $ohneRahmen = false): void
|
||||
{
|
||||
header('Content-Type: text/html; charset=UTF-8');
|
||||
if ($ohneRahmen) {
|
||||
echo (new Ansicht((string) ($_SESSION['csrf'] ?? '')))->vorlage($this->wurzel.'/app/vorlagen/'.$vorlage.'.php', $daten);
|
||||
|
||||
return;
|
||||
}
|
||||
$hinweis = $_SESSION['hinweis'] ?? null;
|
||||
unset($_SESSION['hinweis']);
|
||||
$v = new Ansicht((string) ($_SESSION['csrf'] ?? ''));
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php /** @var Zentrale\Ansicht $v */ ?>
|
||||
<div id="liste" tabindex="-1" data-treffer="<?= $v->e($trefferText) ?>">
|
||||
<?php if (0 === $zahlen['alle']) { ?>
|
||||
<div class="karte leer">
|
||||
<h2>Noch keine Meldung</h2>
|
||||
<p>Sobald eine KantSites-Installation ab Fassung 1.36.0 läuft, meldet sie sich hier – spätestens 15 Minuten nach dem ersten Besuch oder Cron-Aufruf.</p>
|
||||
</div>
|
||||
<?php } elseif (0 === $treffer) { ?>
|
||||
<div class="karte leer">
|
||||
<h2>Nichts gefunden</h2>
|
||||
<p>Keine Installation passt zu Suche und Filter. <a href="/">Alle anzeigen</a></p>
|
||||
</div>
|
||||
<?php } else { ?>
|
||||
<div class="tabelle-rahmen">
|
||||
<table class="tabelle">
|
||||
<caption class="unsichtbar">Gemeldete Installationen, Seite <?= $seite ?> von <?= $seiten ?></caption>
|
||||
<thead>
|
||||
<tr><th scope="col">Domain</th><th scope="col">Kunde</th><th scope="col">Fassung</th><th scope="col">Letzte Meldung</th><th scope="col">Zustand</th><th scope="col"><span class="unsichtbar">Aktion</span></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($installationen as $i) { ?>
|
||||
<tr>
|
||||
<th scope="row" data-label="Domain"><a href="/installation?id=<?= $v->e(rawurlencode($i['id'])) ?>"><?= $v->e($i['domain']) ?></a>
|
||||
<?php if (null !== $i['domain_vorher']) { ?><span class="klein">vorher <?= $v->e($i['domain_vorher']) ?></span><?php } ?></th>
|
||||
<td data-label="Kunde"><?= $i['unbekannt'] ? '<span class="marke-fremd">Unbekannt</span>' : $v->e($i['notiz']) ?></td>
|
||||
<td data-label="Fassung"><span class="fassung <?= $i['veraltet'] ? 'f-alt' : 'f-ok' ?>"><?= $v->e($i['fassung']) ?></span><?php if ('git' === $i['art']) { ?> <span class="klein">Git</span><?php } ?></td>
|
||||
<td data-label="Letzte Meldung"><span class="<?= $i['still'] ? 'still' : '' ?>"><?= $v->e($v->vor($i['alter'])) ?></span></td>
|
||||
<td data-label="Zustand">
|
||||
<?php if ($i['wartung']) { ?><span class="pille p-warn">Wartung</span> <?php } ?>
|
||||
<?php if (null !== $i['auftrag_zustand']) { ?><span class="pille p-<?= $v->e($i['auftrag_zustand']['art']) ?>"><?= $v->e($i['auftrag_zustand']['text']) ?></span><?php } elseif (!$i['wartung']) { ?><span class="klein">–</span><?php } ?>
|
||||
</td>
|
||||
<td class="aktion">
|
||||
<?php if ($i['kann_update'] && null !== $neueste && 'wartet' !== ($i['auftrag_zustand']['art'] ?? null)) { ?>
|
||||
<form method="post" action="/auftrag">
|
||||
<?= $v->csrf() ?>
|
||||
<input type="hidden" name="id" value="<?= $v->e($i['id']) ?>">
|
||||
<button type="submit" class="knopf knopf-klein">Auf <?= $v->e($neueste['version']) ?><span class="unsichtbar"> aktualisieren: <?= $v->e($i['domain']) ?></span></button>
|
||||
</form>
|
||||
<?php } ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php if ($seiten > 1) { ?>
|
||||
<nav class="seiten" aria-label="Seiten">
|
||||
<?php $basis = ['q' => $suche, 'filter' => $filter]; ?>
|
||||
<?php if ($seite > 1) { ?><a class="knopf knopf-leise" href="<?= $v->e($v->adresse([...$basis, 'seite' => $seite - 1])) ?>" rel="prev">← Zurück</a><?php } ?>
|
||||
<ul>
|
||||
<?php
|
||||
// Erste, letzte und zwei um die aktuelle; dazwischen Auslassungen.
|
||||
$zeigen = array_unique(array_filter([1, $seite - 2, $seite - 1, $seite, $seite + 1, $seite + 2, $seiten], static fn (int $n): bool => $n >= 1 && $n <= $seiten));
|
||||
sort($zeigen);
|
||||
$vorher = 0;
|
||||
foreach ($zeigen as $n) {
|
||||
if ($n > $vorher + 1) { ?><li aria-hidden="true">…</li><?php }
|
||||
$vorher = $n; ?>
|
||||
<li><?php if ($n === $seite) { ?><span aria-current="page"><span class="unsichtbar">Seite </span><?= $n ?></span><?php } else { ?><a href="<?= $v->e($v->adresse([...$basis, 'seite' => $n])) ?>"><span class="unsichtbar">Seite </span><?= $n ?></a><?php } ?></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
<?php if ($seite < $seiten) { ?><a class="knopf knopf-leise" href="<?= $v->e($v->adresse([...$basis, 'seite' => $seite + 1])) ?>" rel="next">Weiter →</a><?php } ?>
|
||||
</nav>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
</div>
|
||||
@@ -6,7 +6,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<title><?= $v->e($titel) ?> · KantSites Zentrale</title>
|
||||
<link rel="stylesheet" href="/app.css?v=1">
|
||||
<link rel="stylesheet" href="/app.css?v=3">
|
||||
<script src="/app.js?v=1" defer></script>
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%23173f6b'/%3E%3Cpath d='M9 8v16M9 16l9-8M12.5 13l7 11' stroke='%23fff' stroke-width='3.2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -43,76 +43,12 @@ $kacheln = [
|
||||
<?php if (null !== $filter) { ?><input type="hidden" name="filter" value="<?= $v->e($filter) ?>"><?php } ?>
|
||||
<label for="q">Suchen</label>
|
||||
<div class="suche-zeile">
|
||||
<input id="q" name="q" type="search" value="<?= $v->e($suche) ?>" placeholder="Domain, Kunde, Fassung oder IP" aria-describedby="treffer">
|
||||
<input id="q" name="q" type="search" value="<?= $v->e($suche) ?>" placeholder="Domain, Kunde, Fassung oder IP" autocomplete="off" aria-describedby="treffer" aria-controls="liste">
|
||||
<button type="submit" class="knopf">Suchen</button>
|
||||
<?php if ('' !== $suche || null !== $filter) { ?><a class="knopf knopf-leise" href="/">Zurücksetzen</a><?php } ?>
|
||||
<a class="knopf knopf-leise zuruecksetzen" href="/"<?= '' === $suche && null === $filter ? ' hidden' : '' ?>>Zurücksetzen</a>
|
||||
</div>
|
||||
<p class="klein" id="treffer" role="status">
|
||||
<?php if (0 === $treffer) { ?>Keine Treffer.<?php } else { ?><?= $von ?>–<?= $bis ?> von <?= $treffer ?> <?= 1 === $treffer ? 'Installation' : 'Installationen' ?><?= null !== $filter ? ' · Filter: '.$v->e($kacheln[$filter][1]) : '' ?><?= '' !== $suche ? ' · Suche: „'.$v->e($suche).'“' : '' ?><?php } ?>
|
||||
</p>
|
||||
<p class="klein" id="treffer" role="status"><?= $v->e($trefferText) ?></p>
|
||||
</form>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (0 === $zahlen['alle']) { ?>
|
||||
<div class="karte leer">
|
||||
<h2>Noch keine Meldung</h2>
|
||||
<p>Sobald eine KantSites-Installation ab Fassung 1.36.0 läuft, meldet sie sich hier – spätestens 15 Minuten nach dem ersten Besuch oder Cron-Aufruf.</p>
|
||||
</div>
|
||||
<?php } elseif (0 === $treffer) { ?>
|
||||
<div class="karte leer">
|
||||
<h2>Nichts gefunden</h2>
|
||||
<p>Keine Installation passt zu Suche und Filter. <a href="/">Alle anzeigen</a></p>
|
||||
</div>
|
||||
<?php } else { ?>
|
||||
<div class="tabelle-rahmen">
|
||||
<table class="tabelle">
|
||||
<caption class="unsichtbar">Gemeldete Installationen, Seite <?= $seite ?> von <?= $seiten ?></caption>
|
||||
<thead>
|
||||
<tr><th scope="col">Domain</th><th scope="col">Kunde</th><th scope="col">Fassung</th><th scope="col">Letzte Meldung</th><th scope="col">Zustand</th><th scope="col"><span class="unsichtbar">Aktion</span></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($installationen as $i) { ?>
|
||||
<tr>
|
||||
<th scope="row" data-label="Domain"><a href="/installation?id=<?= $v->e(rawurlencode($i['id'])) ?>"><?= $v->e($i['domain']) ?></a>
|
||||
<?php if (null !== $i['domain_vorher']) { ?><span class="klein">vorher <?= $v->e($i['domain_vorher']) ?></span><?php } ?></th>
|
||||
<td data-label="Kunde"><?= $i['unbekannt'] ? '<span class="marke-fremd">Unbekannt</span>' : $v->e($i['notiz']) ?></td>
|
||||
<td data-label="Fassung"><span class="fassung <?= $i['veraltet'] ? 'f-alt' : 'f-ok' ?>"><?= $v->e($i['fassung']) ?></span><?php if ('git' === $i['art']) { ?> <span class="klein">Git</span><?php } ?></td>
|
||||
<td data-label="Letzte Meldung"><span class="<?= $i['still'] ? 'still' : '' ?>"><?= $v->e($v->vor($i['alter'])) ?></span></td>
|
||||
<td data-label="Zustand">
|
||||
<?php if ($i['wartung']) { ?><span class="pille p-warn">Wartung</span> <?php } ?>
|
||||
<?php if (null !== $i['auftrag_zustand']) { ?><span class="pille p-<?= $v->e($i['auftrag_zustand']['art']) ?>"><?= $v->e($i['auftrag_zustand']['text']) ?></span><?php } elseif (!$i['wartung']) { ?><span class="klein">–</span><?php } ?>
|
||||
</td>
|
||||
<td class="aktion">
|
||||
<?php if ($i['kann_update'] && null !== $neueste && 'wartet' !== ($i['auftrag_zustand']['art'] ?? null)) { ?>
|
||||
<form method="post" action="/auftrag">
|
||||
<?= $v->csrf() ?>
|
||||
<input type="hidden" name="id" value="<?= $v->e($i['id']) ?>">
|
||||
<button type="submit" class="knopf knopf-klein">Auf <?= $v->e($neueste['version']) ?><span class="unsichtbar"> aktualisieren: <?= $v->e($i['domain']) ?></span></button>
|
||||
</form>
|
||||
<?php } ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php if ($seiten > 1) { ?>
|
||||
<nav class="seiten" aria-label="Seiten">
|
||||
<?php $basis = ['q' => $suche, 'filter' => $filter]; ?>
|
||||
<?php if ($seite > 1) { ?><a class="knopf knopf-leise" href="<?= $v->e($v->adresse([...$basis, 'seite' => $seite - 1])) ?>" rel="prev">← Zurück</a><?php } ?>
|
||||
<ul>
|
||||
<?php
|
||||
// Erste, letzte und zwei um die aktuelle; dazwischen Auslassungen.
|
||||
$zeigen = array_unique(array_filter([1, $seite - 2, $seite - 1, $seite, $seite + 1, $seite + 2, $seiten], static fn (int $n): bool => $n >= 1 && $n <= $seiten));
|
||||
sort($zeigen);
|
||||
$vorher = 0;
|
||||
foreach ($zeigen as $n) {
|
||||
if ($n > $vorher + 1) { ?><li aria-hidden="true">…</li><?php }
|
||||
$vorher = $n; ?>
|
||||
<li><?php if ($n === $seite) { ?><span aria-current="page"><span class="unsichtbar">Seite </span><?= $n ?></span><?php } else { ?><a href="<?= $v->e($v->adresse([...$basis, 'seite' => $n])) ?>"><span class="unsichtbar">Seite </span><?= $n ?></a><?php } ?></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
<?php if ($seite < $seiten) { ?><a class="knopf knopf-leise" href="<?= $v->e($v->adresse([...$basis, 'seite' => $seite + 1])) ?>" rel="next">Weiter →</a><?php } ?>
|
||||
</nav>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
<?php require __DIR__.'/_liste.php'; ?>
|
||||
Reference in new issue
Block a user