dsfdsf
This commit is contained in:
@@ -3,7 +3,10 @@
|
|||||||
"title": "KEA DHCP",
|
"title": "KEA DHCP",
|
||||||
"description": "Verwaltung von KEA DHCP Hosts und Reservierungen.",
|
"description": "Verwaltung von KEA DHCP Hosts und Reservierungen.",
|
||||||
"actions": [
|
"actions": [
|
||||||
{ "label": "Gruppen verwalten", "href": "/module/kea/groups", "variant": "secondary" },
|
|
||||||
{ "label": "Setup", "href": "/modules/setup/kea", "variant": "secondary" }
|
{ "label": "Setup", "href": "/modules/setup/kea", "variant": "secondary" }
|
||||||
|
],
|
||||||
|
"tabs": [
|
||||||
|
{ "label": "Hosts", "href": "/module/kea", "match_prefixes": ["/module/kea", "/module/kea/edit"] },
|
||||||
|
{ "label": "Gruppen", "href": "/module/kea/groups", "match_prefixes": ["/module/kea/groups"] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,21 +3,6 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"schema_version": 3,
|
"schema_version": 3,
|
||||||
"description": "Verwaltung von KEA DHCP Hosts und Reservierungen.",
|
"description": "Verwaltung von KEA DHCP Hosts und Reservierungen.",
|
||||||
"menu": [
|
|
||||||
{ "label": "Hosts", "href": "/module/kea" },
|
|
||||||
{ "label": "Gruppen", "href": "/module/kea/groups" },
|
|
||||||
{ "label": "Setup", "href": "/modules/setup/kea" }
|
|
||||||
],
|
|
||||||
"sidebar": {
|
|
||||||
"enabled": true,
|
|
||||||
"collapsible": true,
|
|
||||||
"default": "collapsed",
|
|
||||||
"items": [
|
|
||||||
{ "label": "Hosts", "href": "/module/kea" },
|
|
||||||
{ "label": "Gruppen", "href": "/module/kea/groups" },
|
|
||||||
{ "label": "Setup", "href": "/modules/setup/kea" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"setup": {
|
"setup": {
|
||||||
"fields": [
|
"fields": [
|
||||||
{ "name": "db.driver", "label": "KEA DB Driver", "type": "text", "required": true, "help": "Standard-KEA-Datenbank, die auch vom KEA-Dienst selbst genutzt wird." },
|
{ "name": "db.driver", "label": "KEA DB Driver", "type": "text", "required": true, "help": "Standard-KEA-Datenbank, die auch vom KEA-Dienst selbst genutzt wird." },
|
||||||
|
|||||||
@@ -101,17 +101,22 @@ $metadata = is_array($host['metadata'] ?? null) ? $host['metadata'] : [];
|
|||||||
$selectedGroup = (string)($metadata['group_name'] ?? '');
|
$selectedGroup = (string)($metadata['group_name'] ?? '');
|
||||||
$selectedIp = (string)($metadata['desired_ip'] ?? '');
|
$selectedIp = (string)($metadata['desired_ip'] ?? '');
|
||||||
?>
|
?>
|
||||||
<section class="kea-page">
|
<?= module_shell_header('kea', [
|
||||||
<div class="section-head">
|
'title' => 'KEA Eintrag bearbeiten',
|
||||||
|
]) ?>
|
||||||
|
<div class="module-flow kea-page">
|
||||||
|
<section class="module-box">
|
||||||
|
<div class="module-box-head">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="section-title">KEA Eintrag bearbeiten</h2>
|
<h2 class="module-box-title">KEA Eintrag bearbeiten</h2>
|
||||||
<p>Zusatzdaten werden separat von der KEA-Datenbank gespeichert.</p>
|
<p>Zusatzdaten werden separat von der KEA-Datenbank gespeichert.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="setup-actions">
|
<div class="setup-actions">
|
||||||
<a class="nav-link" href="/module/kea/groups">Gruppen verwalten</a>
|
<a class="module-button module-button--secondary" href="/module/kea/groups">Gruppen verwalten</a>
|
||||||
<a class="nav-link" href="/module/kea">Zurueck</a>
|
<a class="module-button module-button--secondary" href="/module/kea">Zurueck</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<?php if ($error): ?>
|
<?php if ($error): ?>
|
||||||
<div class="kea-message kea-message--error" role="alert">
|
<div class="kea-message kea-message--error" role="alert">
|
||||||
@@ -125,11 +130,11 @@ $selectedIp = (string)($metadata['desired_ip'] ?? '');
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="kea-panel">
|
<section class="module-box kea-panel">
|
||||||
<div class="kea-panel__head">
|
<div class="module-box-head kea-panel__head">
|
||||||
<div>
|
<div>
|
||||||
<span class="pill"><?= ($source === 'lease') ? 'Lease' : 'Reservierung' ?></span>
|
<span class="pill"><?= ($source === 'lease') ? 'Lease' : 'Reservierung' ?></span>
|
||||||
<h3><?= e((string)($host['hostname'] ?: 'Unbekannt')) ?></h3>
|
<h2 class="module-box-title"><?= e((string)($host['hostname'] ?: 'Unbekannt')) ?></h2>
|
||||||
<p class="muted">
|
<p class="muted">
|
||||||
IP <?= e((string)($host['ipv4_address'] ?? '')) ?> · MAC <?= e((string)($host['dhcp_identifier'] ?? '')) ?>
|
IP <?= e((string)($host['ipv4_address'] ?? '')) ?> · MAC <?= e((string)($host['dhcp_identifier'] ?? '')) ?>
|
||||||
</p>
|
</p>
|
||||||
@@ -190,13 +195,13 @@ $selectedIp = (string)($metadata['desired_ip'] ?? '');
|
|||||||
<a class="nav-link" href="/module/kea">Abbrechen</a>
|
<a class="nav-link" href="/module/kea">Abbrechen</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<div class="kea-panel">
|
<section class="module-box kea-panel">
|
||||||
<div class="kea-panel__head">
|
<div class="module-box-head kea-panel__head">
|
||||||
<div>
|
<div>
|
||||||
<span class="pill">Pruefungen</span>
|
<span class="pill">Pruefungen</span>
|
||||||
<h3>Gerätechecks</h3>
|
<h2 class="module-box-title">Gerätechecks</h2>
|
||||||
<p class="muted">Pruefergebnisse werden in der Nexus-DHCP-Datenbank gespeichert und koennen spaeter fuer Reports genutzt werden.</p>
|
<p class="muted">Pruefergebnisse werden in der Nexus-DHCP-Datenbank gespeichert und koennen spaeter fuer Reports genutzt werden.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -224,7 +229,7 @@ $selectedIp = (string)($metadata['desired_ip'] ?? '');
|
|||||||
<p class="muted">Vorbereitet fuer spaetere HTTP/Port-Erkennung. Noch nicht automatisch aktiv, damit keine ungewollten Scans laufen.</p>
|
<p class="muted">Vorbereitet fuer spaetere HTTP/Port-Erkennung. Noch nicht automatisch aktiv, damit keine ungewollten Scans laufen.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
<script>
|
<script>
|
||||||
(() => {
|
(() => {
|
||||||
const ipsByGroup = <?= json_encode($availableIpsByGroup, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
|
const ipsByGroup = <?= json_encode($availableIpsByGroup, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
|
||||||
@@ -257,4 +262,5 @@ $selectedIp = (string)($metadata['desired_ip'] ?? '');
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</section>
|
</div>
|
||||||
|
<?= module_shell_footer() ?>
|
||||||
|
|||||||
@@ -75,14 +75,19 @@ $matrixForGroup = static function (array $group) use ($usedIpLookup): array {
|
|||||||
return $dots;
|
return $dots;
|
||||||
};
|
};
|
||||||
?>
|
?>
|
||||||
<section class="kea-page">
|
<?= module_shell_header('kea', [
|
||||||
<div class="section-head">
|
'title' => 'KEA Gruppen',
|
||||||
|
]) ?>
|
||||||
|
<div class="module-flow kea-page">
|
||||||
|
<section class="module-box">
|
||||||
|
<div class="module-box-head">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="section-title">KEA Gruppen</h2>
|
<h2 class="module-box-title">KEA Gruppen</h2>
|
||||||
<p>Gruppen und IP-Bereiche fuer DHCP-Reservierungen.</p>
|
<p>Gruppen und IP-Bereiche fuer DHCP-Reservierungen.</p>
|
||||||
</div>
|
</div>
|
||||||
<a class="nav-link" href="/module/kea">Zurueck</a>
|
<a class="module-button module-button--secondary" href="/module/kea">Zurueck</a>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<?php if ($error): ?>
|
<?php if ($error): ?>
|
||||||
<div class="kea-message kea-message--error" role="alert">
|
<div class="kea-message kea-message--error" role="alert">
|
||||||
@@ -93,11 +98,11 @@ $matrixForGroup = static function (array $group) use ($usedIpLookup): array {
|
|||||||
<div class="kea-message kea-message--success"><?= e($notice) ?></div>
|
<div class="kea-message kea-message--success"><?= e($notice) ?></div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="kea-panel">
|
<section class="module-box kea-panel">
|
||||||
<div class="kea-panel__head">
|
<div class="module-box-head kea-panel__head">
|
||||||
<div>
|
<div>
|
||||||
<span class="pill">Gruppe</span>
|
<span class="pill">Gruppe</span>
|
||||||
<h3>Gruppe anlegen</h3>
|
<h2 class="module-box-title">Gruppe anlegen</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" class="kea-edit-form">
|
<form method="post" class="kea-edit-form">
|
||||||
@@ -123,13 +128,13 @@ $matrixForGroup = static function (array $group) use ($usedIpLookup): array {
|
|||||||
<button class="cta-button" type="submit">Gruppe speichern</button>
|
<button class="cta-button" type="submit">Gruppe speichern</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<div class="kea-panel">
|
<section class="module-box kea-panel">
|
||||||
<div class="kea-panel__head">
|
<div class="module-box-head kea-panel__head">
|
||||||
<div>
|
<div>
|
||||||
<span class="pill">IP-Bereich</span>
|
<span class="pill">IP-Bereich</span>
|
||||||
<h3>Bereich zuweisen</h3>
|
<h2 class="module-box-title">Bereich zuweisen</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" class="kea-edit-form">
|
<form method="post" class="kea-edit-form">
|
||||||
@@ -155,13 +160,13 @@ $matrixForGroup = static function (array $group) use ($usedIpLookup): array {
|
|||||||
<button class="cta-button" type="submit">Bereich speichern</button>
|
<button class="cta-button" type="submit">Bereich speichern</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<div class="kea-panel">
|
<section class="module-box-table kea-panel">
|
||||||
<div class="kea-panel__head">
|
<div class="module-box-head kea-panel__head">
|
||||||
<div>
|
<div>
|
||||||
<span class="pill">Uebersicht</span>
|
<span class="pill">Uebersicht</span>
|
||||||
<h3>Gruppen und freie IPs</h3>
|
<h2 class="module-box-title">Gruppen und freie IPs</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="kea-table-wrap">
|
<div class="kea-table-wrap">
|
||||||
@@ -217,5 +222,6 @@ $matrixForGroup = static function (array $group) use ($usedIpLookup): array {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
<?= module_shell_footer() ?>
|
||||||
|
|||||||
@@ -10,16 +10,18 @@
|
|||||||
'title' => 'KEA DHCP Hosts',
|
'title' => 'KEA DHCP Hosts',
|
||||||
'description' => 'Reservierungen und aktuelle Leases aus der KEA-Datenbank.',
|
'description' => 'Reservierungen und aktuelle Leases aus der KEA-Datenbank.',
|
||||||
]) ?>
|
]) ?>
|
||||||
<section class="kea-page">
|
<div class="module-flow kea-page">
|
||||||
<div class="section-head">
|
<section class="module-box">
|
||||||
|
<div class="module-box-head">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="section-title">KEA DHCP Hosts</h2>
|
<h2 class="module-box-title">KEA DHCP Hosts</h2>
|
||||||
<p>Reservierungen und aktuelle Leases aus der KEA-Datenbank.</p>
|
<p>Reservierungen und aktuelle Leases aus der KEA-Datenbank.</p>
|
||||||
<p class="muted kea-refresh-state" data-kea-refresh-state>
|
<p class="muted kea-refresh-state" data-kea-refresh-state>
|
||||||
Automatische Aktualisierung alle 5 Sekunden.
|
Automatische Aktualisierung alle 5 Sekunden.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<?php if ($error): ?>
|
<?php if ($error): ?>
|
||||||
<div class="kea-message kea-message--error" role="alert">
|
<div class="kea-message kea-message--error" role="alert">
|
||||||
@@ -34,34 +36,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
||||||
<div class="stats">
|
<div class="module-box-grid module-box-grid--stats stats">
|
||||||
<div class="stat-card">
|
<section class="module-box-soft stat-card">
|
||||||
<span class="stat-label">Einträge</span>
|
<span class="stat-label">Einträge</span>
|
||||||
<span class="stat-value" data-kea-stat="total"><?= e((string)($stats['total'] ?? 0)) ?></span>
|
<span class="stat-value" data-kea-stat="total"><?= e((string)($stats['total'] ?? 0)) ?></span>
|
||||||
</div>
|
</section>
|
||||||
<div class="stat-card">
|
<section class="module-box-soft stat-card">
|
||||||
<span class="stat-label">Reservierungen</span>
|
<span class="stat-label">Reservierungen</span>
|
||||||
<span class="stat-value" data-kea-stat="reservations"><?= e((string)($stats['reservations'] ?? 0)) ?></span>
|
<span class="stat-value" data-kea-stat="reservations"><?= e((string)($stats['reservations'] ?? 0)) ?></span>
|
||||||
</div>
|
</section>
|
||||||
<div class="stat-card">
|
<section class="module-box-soft stat-card">
|
||||||
<span class="stat-label">Leases</span>
|
<span class="stat-label">Leases</span>
|
||||||
<span class="stat-value" data-kea-stat="leases"><?= e((string)($stats['leases'] ?? 0)) ?></span>
|
<span class="stat-value" data-kea-stat="leases"><?= e((string)($stats['leases'] ?? 0)) ?></span>
|
||||||
</div>
|
</section>
|
||||||
<div class="stat-card">
|
<section class="module-box-soft stat-card">
|
||||||
<span class="stat-label">Gruppen</span>
|
<span class="stat-label">Gruppen</span>
|
||||||
<span class="stat-value" data-kea-stat="groups"><?= e((string)count($stats['groups'] ?? [])) ?></span>
|
<span class="stat-value" data-kea-stat="groups"><?= e((string)count($stats['groups'] ?? [])) ?></span>
|
||||||
</div>
|
</section>
|
||||||
<div class="stat-card">
|
<section class="module-box-soft stat-card">
|
||||||
<span class="stat-label">Freie Gruppen-IPs</span>
|
<span class="stat-label">Freie Gruppen-IPs</span>
|
||||||
<span class="stat-value" data-kea-stat="free_ips"><?= 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>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="kea-panel">
|
<section class="module-box-table kea-panel">
|
||||||
<div class="kea-panel__head">
|
<div class="module-box-head kea-panel__head">
|
||||||
<div>
|
<div>
|
||||||
<span class="pill">Inventar</span>
|
<span class="pill">Inventar</span>
|
||||||
<h3>Registrierte Geräte</h3>
|
<h2 class="module-box-title">Registrierte Geräte</h2>
|
||||||
<p class="muted">Zusatzdaten werden in der separaten Nexus-DHCP-Datenbank gespeichert.</p>
|
<p class="muted">Zusatzdaten werden in der separaten Nexus-DHCP-Datenbank gespeichert.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -129,8 +131,8 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
<script>
|
<script>
|
||||||
(() => {
|
(() => {
|
||||||
const rowsTarget = document.querySelector('[data-kea-host-rows]');
|
const rowsTarget = document.querySelector('[data-kea-host-rows]');
|
||||||
|
|||||||
@@ -99,51 +99,6 @@
|
|||||||
overflow-x: clip;
|
overflow-x: clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mining-checker-app .mc-grid-bg[data-module-theme="custom"] {
|
|
||||||
--mc-bg: #09111f;
|
|
||||||
--mc-surface: rgba(8, 15, 29, 0.76);
|
|
||||||
--mc-surface-strong: rgba(15, 23, 42, 0.94);
|
|
||||||
--mc-line: rgba(148, 163, 184, 0.18);
|
|
||||||
--mc-line-strong: rgba(255, 255, 255, 0.12);
|
|
||||||
--mc-text: #e5eef8;
|
|
||||||
--mc-text-muted: #a7b5c8;
|
|
||||||
--mc-accent: #3dd9c4;
|
|
||||||
--mc-accent-strong: #7dd3fc;
|
|
||||||
color: var(--mc-text);
|
|
||||||
background:
|
|
||||||
linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px),
|
|
||||||
linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px),
|
|
||||||
radial-gradient(circle at top left, rgba(13, 148, 136, 0.16), transparent 26%),
|
|
||||||
radial-gradient(circle at top right, rgba(59, 130, 246, 0.18), transparent 22%),
|
|
||||||
linear-gradient(180deg, #04111d 0%, #0f172a 42%, #111827 100%);
|
|
||||||
background-size: 24px 24px, 24px 24px, auto, auto, auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mining-checker-app .mc-grid-bg[data-module-theme="custom"][data-module-accent="logo"] {
|
|
||||||
--mc-accent: #ed1671;
|
|
||||||
--mc-accent-strong: #06a9c8;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mining-checker-app .mc-grid-bg[data-module-theme="custom"][data-module-accent="pink"] {
|
|
||||||
--mc-accent: #ed1671;
|
|
||||||
--mc-accent-strong: #f6aa21;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mining-checker-app .mc-grid-bg[data-module-theme="custom"][data-module-accent="cyan"] {
|
|
||||||
--mc-accent: #06a9c8;
|
|
||||||
--mc-accent-strong: #8bc53f;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mining-checker-app .mc-grid-bg[data-module-theme="custom"][data-module-accent="orange"] {
|
|
||||||
--mc-accent: #f6aa21;
|
|
||||||
--mc-accent-strong: #ed1671;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mining-checker-app .mc-grid-bg[data-module-theme="custom"][data-module-accent="green"] {
|
|
||||||
--mc-accent: #8bc53f;
|
|
||||||
--mc-accent-strong: #06a9c8;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mining-checker-app .mc-shell {
|
#mining-checker-app .mc-shell {
|
||||||
width: min(1360px, calc(100% - 24px));
|
width: min(1360px, calc(100% - 24px));
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|||||||
@@ -12,6 +12,23 @@
|
|||||||
const fxBaseUrl = root.dataset.fxUrl || 'https://currencyapi.net';
|
const fxBaseUrl = root.dataset.fxUrl || 'https://currencyapi.net';
|
||||||
const fxCurrenciesUrl = root.dataset.fxCurrenciesUrl || fxBaseUrl;
|
const fxCurrenciesUrl = root.dataset.fxCurrenciesUrl || fxBaseUrl;
|
||||||
const fxApiKeyMask = root.dataset.fxApiKeyMask || '';
|
const fxApiKeyMask = root.dataset.fxApiKeyMask || '';
|
||||||
|
const configuredSections = (() => {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(root.dataset.sectionsJson || '[]');
|
||||||
|
if (!Array.isArray(parsed)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return parsed
|
||||||
|
.map((section) => {
|
||||||
|
const key = section && typeof section.key === 'string' ? section.key.trim() : '';
|
||||||
|
const label = section && typeof section.label === 'string' ? section.label.trim() : '';
|
||||||
|
return key && label ? [key, label] : null;
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
})();
|
||||||
const initialDebugMode = (() => {
|
const initialDebugMode = (() => {
|
||||||
try {
|
try {
|
||||||
return window.localStorage.getItem('mining-checker-debug-enabled') === '1';
|
return window.localStorage.getItem('mining-checker-debug-enabled') === '1';
|
||||||
@@ -292,8 +309,6 @@
|
|||||||
report_currency: 'EUR',
|
report_currency: 'EUR',
|
||||||
crypto_currency: 'DOGE',
|
crypto_currency: 'DOGE',
|
||||||
fx_max_age_hours: 3,
|
fx_max_age_hours: 3,
|
||||||
module_theme_mode: 'inherit',
|
|
||||||
module_theme_accent: 'teal',
|
|
||||||
preferred_currencies: ['DOGE', 'USD', 'EUR'],
|
preferred_currencies: ['DOGE', 'USD', 'EUR'],
|
||||||
cost_plans: [],
|
cost_plans: [],
|
||||||
currencies: [],
|
currencies: [],
|
||||||
@@ -585,8 +600,6 @@
|
|||||||
report_currency: 'EUR',
|
report_currency: 'EUR',
|
||||||
crypto_currency: 'DOGE',
|
crypto_currency: 'DOGE',
|
||||||
fx_max_age_hours: 3,
|
fx_max_age_hours: 3,
|
||||||
module_theme_mode: 'inherit',
|
|
||||||
module_theme_accent: 'teal',
|
|
||||||
});
|
});
|
||||||
const [moduleAuthForm, setModuleAuthForm] = useState({
|
const [moduleAuthForm, setModuleAuthForm] = useState({
|
||||||
required: true,
|
required: true,
|
||||||
@@ -1017,8 +1030,6 @@
|
|||||||
report_currency: normalized.settings.report_currency || 'EUR',
|
report_currency: normalized.settings.report_currency || 'EUR',
|
||||||
crypto_currency: normalized.settings.crypto_currency || 'DOGE',
|
crypto_currency: normalized.settings.crypto_currency || 'DOGE',
|
||||||
fx_max_age_hours: normalized.settings.fx_max_age_hours || 3,
|
fx_max_age_hours: normalized.settings.fx_max_age_hours || 3,
|
||||||
module_theme_mode: normalized.settings.module_theme_mode || 'inherit',
|
|
||||||
module_theme_accent: normalized.settings.module_theme_accent || 'teal',
|
|
||||||
});
|
});
|
||||||
setFxSelection(Array.isArray(normalized.settings.preferred_currencies) && normalized.settings.preferred_currencies.length
|
setFxSelection(Array.isArray(normalized.settings.preferred_currencies) && normalized.settings.preferred_currencies.length
|
||||||
? normalized.settings.preferred_currencies
|
? normalized.settings.preferred_currencies
|
||||||
@@ -1243,8 +1254,6 @@
|
|||||||
report_currency: settingsForm.report_currency || 'EUR',
|
report_currency: settingsForm.report_currency || 'EUR',
|
||||||
crypto_currency: settingsForm.crypto_currency || 'DOGE',
|
crypto_currency: settingsForm.crypto_currency || 'DOGE',
|
||||||
fx_max_age_hours: settingsForm.fx_max_age_hours || 3,
|
fx_max_age_hours: settingsForm.fx_max_age_hours || 3,
|
||||||
module_theme_mode: settingsForm.module_theme_mode || 'inherit',
|
|
||||||
module_theme_accent: settingsForm.module_theme_accent || 'teal',
|
|
||||||
preferred_currencies: Array.isArray(currentSettings.preferred_currencies)
|
preferred_currencies: Array.isArray(currentSettings.preferred_currencies)
|
||||||
? currentSettings.preferred_currencies
|
? currentSettings.preferred_currencies
|
||||||
: fxSelection,
|
: fxSelection,
|
||||||
@@ -1806,7 +1815,7 @@
|
|||||||
setCookie('mining_checker_report_currency', '', 0);
|
setCookie('mining_checker_report_currency', '', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabs = [
|
const tabs = configuredSections.length ? configuredSections : [
|
||||||
['overview', 'Ueberblick'],
|
['overview', 'Ueberblick'],
|
||||||
['measurements', 'Messpunkte'],
|
['measurements', 'Messpunkte'],
|
||||||
['currencies', 'Waehrungen'],
|
['currencies', 'Waehrungen'],
|
||||||
@@ -1871,17 +1880,8 @@
|
|||||||
const debugConsoleText = debugEntries
|
const debugConsoleText = debugEntries
|
||||||
.map((entry) => `${entry.time} · ${entry.type}\n${JSON.stringify(entry, null, 2)}`)
|
.map((entry) => `${entry.time} · ${entry.type}\n${JSON.stringify(entry, null, 2)}`)
|
||||||
.join('\n\n');
|
.join('\n\n');
|
||||||
const moduleThemeMode = ['inherit', 'custom'].includes(String(currentSettings.module_theme_mode || ''))
|
|
||||||
? String(currentSettings.module_theme_mode)
|
|
||||||
: 'inherit';
|
|
||||||
const moduleThemeAccent = ['teal', 'logo', 'pink', 'cyan', 'orange', 'green'].includes(String(currentSettings.module_theme_accent || ''))
|
|
||||||
? String(currentSettings.module_theme_accent)
|
|
||||||
: 'teal';
|
|
||||||
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
className: 'mc-grid-bg',
|
className: 'mc-grid-bg',
|
||||||
'data-module-theme': moduleThemeMode,
|
|
||||||
'data-module-accent': moduleThemeAccent,
|
|
||||||
}, [
|
}, [
|
||||||
h('div', { key: 'shell', className: 'mc-shell mc-stack' }, [
|
h('div', { key: 'shell', className: 'mc-shell mc-stack' }, [
|
||||||
h('header', { key: 'header', className: 'mc-hero' }, [
|
h('header', { key: 'header', className: 'mc-hero' }, [
|
||||||
@@ -2949,20 +2949,6 @@
|
|||||||
selectField('Standard-FIAT-Währung', settingsForm.report_currency || 'EUR', selectableFiatCurrencies.map((currency) => currency.code), (value) => setSettingsForm({ ...settingsForm, report_currency: value })),
|
selectField('Standard-FIAT-Währung', settingsForm.report_currency || 'EUR', selectableFiatCurrencies.map((currency) => currency.code), (value) => setSettingsForm({ ...settingsForm, report_currency: value })),
|
||||||
selectField('Standard-Krypto-Währung', settingsForm.crypto_currency || 'DOGE', selectableCryptoCurrencies.map((currency) => currency.code), (value) => setSettingsForm({ ...settingsForm, crypto_currency: value })),
|
selectField('Standard-Krypto-Währung', settingsForm.crypto_currency || 'DOGE', selectableCryptoCurrencies.map((currency) => currency.code), (value) => setSettingsForm({ ...settingsForm, crypto_currency: value })),
|
||||||
inputField('FX maximal in Stunden wiederverwenden', 'number', String(settingsForm.fx_max_age_hours || 3), (value) => setSettingsForm({ ...settingsForm, fx_max_age_hours: value }), '0.25'),
|
inputField('FX maximal in Stunden wiederverwenden', 'number', String(settingsForm.fx_max_age_hours || 3), (value) => setSettingsForm({ ...settingsForm, fx_max_age_hours: value }), '0.25'),
|
||||||
selectField('Modul-Layout', settingsForm.module_theme_mode || 'inherit', [
|
|
||||||
{ value: 'inherit', label: 'Wie Main-Site' },
|
|
||||||
{ value: 'custom', label: 'Custom' },
|
|
||||||
], (value) => setSettingsForm({ ...settingsForm, module_theme_mode: value })),
|
|
||||||
settingsForm.module_theme_mode === 'custom'
|
|
||||||
? selectField('Custom-Farbschema', settingsForm.module_theme_accent || 'teal', [
|
|
||||||
{ value: 'teal', label: 'Mining Teal' },
|
|
||||||
{ value: 'logo', label: 'Logo Mix' },
|
|
||||||
{ value: 'pink', label: 'Pink' },
|
|
||||||
{ value: 'cyan', label: 'Cyan' },
|
|
||||||
{ value: 'orange', label: 'Orange' },
|
|
||||||
{ value: 'green', label: 'Gruen' },
|
|
||||||
], (value) => setSettingsForm({ ...settingsForm, module_theme_accent: value }))
|
|
||||||
: null,
|
|
||||||
h('button', {
|
h('button', {
|
||||||
type: 'submit',
|
type: 'submit',
|
||||||
className: 'mc-button mc-button--primary',
|
className: 'mc-button mc-button--primary',
|
||||||
|
|||||||
16
modules/mining-checker/design.json
Normal file
16
modules/mining-checker/design.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"eyebrow": "Modul",
|
||||||
|
"title": "Mining-Checker",
|
||||||
|
"description": "Erfassung, OCR-Auswertung und Analyse von DOGE-Mining-Messwerten als eingebettetes Modul.",
|
||||||
|
"actions": [
|
||||||
|
{ "label": "Setup", "href": "/modules/setup/mining-checker", "variant": "secondary" }
|
||||||
|
],
|
||||||
|
"sections": [
|
||||||
|
{ "key": "overview", "label": "Ueberblick" },
|
||||||
|
{ "key": "measurements", "label": "Messpunkte" },
|
||||||
|
{ "key": "currencies", "label": "Waehrungen" },
|
||||||
|
{ "key": "mining", "label": "Mining" },
|
||||||
|
{ "key": "dashboards", "label": "Dashboards" },
|
||||||
|
{ "key": "settings", "label": "Settings" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
require_once dirname(__DIR__) . '/bootstrap.php';
|
require_once dirname(__DIR__) . '/bootstrap.php';
|
||||||
|
|
||||||
$moduleConfig = require dirname(__DIR__) . '/config/module.php';
|
$moduleConfig = require dirname(__DIR__) . '/config/module.php';
|
||||||
|
$design = module_design('mining-checker');
|
||||||
$defaultProjectKey = (string) ($moduleConfig['default_project_key'] ?? 'doge-main');
|
$defaultProjectKey = (string) ($moduleConfig['default_project_key'] ?? 'doge-main');
|
||||||
$fxConfig = (array) ($moduleConfig['fx'] ?? []);
|
$fxConfig = (array) ($moduleConfig['fx'] ?? []);
|
||||||
$fxProvider = (string) ($fxConfig['provider'] ?? 'currencyapi');
|
$fxProvider = (string) ($fxConfig['provider'] ?? 'currencyapi');
|
||||||
@@ -13,20 +14,28 @@ $fxApiKey = (string) ($fxConfig['api_key'] ?? '');
|
|||||||
$fxApiKeyMasked = $fxApiKey === ''
|
$fxApiKeyMasked = $fxApiKey === ''
|
||||||
? ''
|
? ''
|
||||||
: (strlen($fxApiKey) <= 10 ? $fxApiKey : substr($fxApiKey, 0, 6) . '...' . substr($fxApiKey, -4));
|
: (strlen($fxApiKey) <= 10 ? $fxApiKey : substr($fxApiKey, 0, 6) . '...' . substr($fxApiKey, -4));
|
||||||
|
$sectionsJson = json_encode(is_array($design['sections'] ?? null) ? $design['sections'] : [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
$moduleCss = file_get_contents(dirname(__DIR__) . '/assets/css/app.css') ?: '';
|
$moduleCss = file_get_contents(dirname(__DIR__) . '/assets/css/app.css') ?: '';
|
||||||
$moduleJs = file_get_contents(dirname(__DIR__) . '/assets/js/app.js') ?: '';
|
$moduleJs = file_get_contents(dirname(__DIR__) . '/assets/js/app.js') ?: '';
|
||||||
$moduleJs = str_replace('</script>', '<\/script>', $moduleJs);
|
$moduleJs = str_replace('</script>', '<\/script>', $moduleJs);
|
||||||
?>
|
?>
|
||||||
<div class="module-host-card mining-checker-host">
|
<?= module_shell_header('mining-checker', [
|
||||||
|
'title' => 'DOGE Mining-Checker',
|
||||||
|
]) ?>
|
||||||
|
<div class="module-flow">
|
||||||
|
<div class="module-box mining-checker-host">
|
||||||
<div id="mining-checker-app"
|
<div id="mining-checker-app"
|
||||||
data-default-project-key="<?= e($defaultProjectKey) ?>"
|
data-default-project-key="<?= e($defaultProjectKey) ?>"
|
||||||
data-api-base="/api/mining-checker/v1"
|
data-api-base="/api/mining-checker/v1"
|
||||||
data-fx-provider="<?= e($fxProvider) ?>"
|
data-fx-provider="<?= e($fxProvider) ?>"
|
||||||
data-fx-url="<?= e($fxBaseUrl) ?>"
|
data-fx-url="<?= e($fxBaseUrl) ?>"
|
||||||
data-fx-currencies-url="<?= e($fxCurrenciesUrl) ?>"
|
data-fx-currencies-url="<?= e($fxCurrenciesUrl) ?>"
|
||||||
data-fx-api-key-mask="<?= e($fxApiKeyMasked) ?>"></div>
|
data-fx-api-key-mask="<?= e($fxApiKeyMasked) ?>"
|
||||||
|
data-sections-json="<?= e(is_string($sectionsJson) ? $sectionsJson : '[]') ?>"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<style><?= $moduleCss ?></style>
|
<style><?= $moduleCss ?></style>
|
||||||
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
||||||
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
||||||
<script><?= $moduleJs ?></script>
|
<script><?= $moduleJs ?></script>
|
||||||
|
<?= module_shell_footer() ?>
|
||||||
|
|||||||
14
modules/pi_control/design.json
Normal file
14
modules/pi_control/design.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"eyebrow": "Modul",
|
||||||
|
"title": "Pi Control",
|
||||||
|
"description": "Verwaltung und Steuerung von Raspberry Pis per SSH, Presets und Konsole.",
|
||||||
|
"actions": [
|
||||||
|
{ "label": "Setup", "href": "/modules/setup/pi_control", "variant": "secondary" }
|
||||||
|
],
|
||||||
|
"tabs": [
|
||||||
|
{ "label": "Ueberblick", "href": "/module/pi_control", "match_prefixes": ["/module/pi_control"] },
|
||||||
|
{ "label": "Hosts", "href": "/module/pi_control/hosts", "match_prefixes": ["/module/pi_control/hosts"] },
|
||||||
|
{ "label": "Befehle", "href": "/module/pi_control/commands", "match_prefixes": ["/module/pi_control/commands"] },
|
||||||
|
{ "label": "Konsole", "href": "/module/pi_control/console", "match_prefixes": ["/module/pi_control/console"] }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -2,28 +2,6 @@
|
|||||||
"title": "Pi Control",
|
"title": "Pi Control",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Verwaltung und Steuerung von Raspberry Pis (SSH/Commands/Presets).",
|
"description": "Verwaltung und Steuerung von Raspberry Pis (SSH/Commands/Presets).",
|
||||||
"menu": [
|
|
||||||
{ "label": "Übersicht", "href": "/module/pi_control" },
|
|
||||||
{ "label": "Konsole", "href": "/module/pi_control/console" },
|
|
||||||
{
|
|
||||||
"label": "Settings",
|
|
||||||
"children": [
|
|
||||||
{ "label": "Hosts", "href": "/module/pi_control/hosts" },
|
|
||||||
{ "label": "Befehle", "href": "/module/pi_control/commands" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"sidebar": {
|
|
||||||
"enabled": true,
|
|
||||||
"collapsible": true,
|
|
||||||
"default": "collapsed",
|
|
||||||
"items": [
|
|
||||||
{ "label": "Übersicht", "href": "/module/pi_control" },
|
|
||||||
{ "label": "Konsole", "href": "/module/pi_control/console" },
|
|
||||||
{ "label": "Hosts", "href": "/module/pi_control/hosts" },
|
|
||||||
{ "label": "Befehle", "href": "/module/pi_control/commands" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"setup": {
|
"setup": {
|
||||||
"fields": [
|
"fields": [
|
||||||
{ "name": "use_separate_db", "label": "Eigene Modul-DB nutzen", "type": "checkbox", "required": false, "help": "Wenn aktiv, werden die DB-Daten unten verwendet. Sonst wird die Base-DB genutzt." },
|
{ "name": "use_separate_db", "label": "Eigene Modul-DB nutzen", "type": "checkbox", "required": false, "help": "Wenn aktiv, werden die DB-Daten unten verwendet. Sonst wird die Base-DB genutzt." },
|
||||||
|
|||||||
@@ -79,26 +79,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
|
|
||||||
$commands = $pdo->query('SELECT * FROM ' . $table('commands') . ' ORDER BY COALESCE(sort_order, id) ASC, id ASC')->fetchAll(PDO::FETCH_ASSOC);
|
$commands = $pdo->query('SELECT * FROM ' . $table('commands') . ' ORDER BY COALESCE(sort_order, id) ASC, id ASC')->fetchAll(PDO::FETCH_ASSOC);
|
||||||
?>
|
?>
|
||||||
<div class="card">
|
<?= module_shell_header('pi_control', [
|
||||||
<div class="pill">Pi Control</div>
|
'title' => 'Befehle',
|
||||||
<div style="display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-top:.75rem;">
|
]) ?>
|
||||||
<h1 style="margin:0;">Befehle</h1>
|
<div class="module-flow">
|
||||||
<button class="cta-button" type="button" data-command-new>+ Neuer Befehl</button>
|
<section class="module-box">
|
||||||
|
<div class="module-box-head">
|
||||||
|
<div>
|
||||||
|
<h2 class="module-box-title">Befehle</h2>
|
||||||
|
<p>Verwalte vordefinierte SSH-Befehle.</p>
|
||||||
|
</div>
|
||||||
|
<button class="module-button module-button--primary" type="button" data-command-new>+ Neuer Befehl</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="muted">Verwalte vordefinierte SSH-Befehle.</p>
|
|
||||||
|
|
||||||
<?php if ($error): ?>
|
<?php if ($error): ?>
|
||||||
<div class="card notice-card" style="margin-top:1rem; border-color:#ffb4a8; background:#fff5f3; color:#7a2114;">
|
<div class="setup-db-message setup-db-message--error" style="margin-top:16px;">
|
||||||
<?= e($error) ?>
|
<?= e($error) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($notice): ?>
|
<?php elseif ($notice): ?>
|
||||||
<div class="card notice-card" style="margin-top:1rem; border-color:var(--accent-2);">
|
<div class="setup-db-message setup-db-message--success" style="margin-top:16px;">
|
||||||
<?= e($notice) ?>
|
<?= e($notice) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="grid" style="margin-top:1rem;">
|
<div class="module-box" style="margin-top:16px;">
|
||||||
<div class="card" style="background:var(--panel-2);">
|
|
||||||
<strong>Vorhandene Befehle</strong>
|
<strong>Vorhandene Befehle</strong>
|
||||||
<?php if (!$commands): ?>
|
<?php if (!$commands): ?>
|
||||||
<div class="muted" style="margin-top:.75rem;">Keine Befehle vorhanden.</div>
|
<div class="muted" style="margin-top:.75rem;">Keine Befehle vorhanden.</div>
|
||||||
@@ -142,7 +146,7 @@ $commands = $pdo->query('SELECT * FROM ' . $table('commands') . ' ORDER BY COALE
|
|||||||
<p class="muted" style="margin-top:.5rem;">Reihenfolge per Drag & Drop ändern.</p>
|
<p class="muted" style="margin-top:.5rem;">Reihenfolge per Drag & Drop ändern.</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal" data-command-modal aria-hidden="true">
|
<div class="modal" data-command-modal aria-hidden="true">
|
||||||
@@ -174,3 +178,4 @@ $commands = $pdo->query('SELECT * FROM ' . $table('commands') . ' ORDER BY COALE
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?= module_shell_footer() ?>
|
||||||
|
|||||||
@@ -418,26 +418,32 @@ function sendToActiveConsole(array $host, string $command, bool $strictHostKey):
|
|||||||
return [false, $msg !== '' ? $msg : 'Befehl konnte nicht gesendet werden.'];
|
return [false, $msg !== '' ? $msg : 'Befehl konnte nicht gesendet werden.'];
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<div class="card">
|
<?= module_shell_header('pi_control', [
|
||||||
<div class="pill">Pi Control</div>
|
'title' => 'Konsole',
|
||||||
<h1 style="margin-top:.75rem;">Konsole</h1>
|
]) ?>
|
||||||
<p class="muted">Wähle einen Host und führe einen Befehl aus.</p>
|
<div class="module-flow">
|
||||||
|
<section class="module-box">
|
||||||
|
<div class="module-box-head">
|
||||||
|
<div>
|
||||||
|
<h2 class="module-box-title">Konsole</h2>
|
||||||
|
<p>Wähle einen Host und führe einen Befehl aus.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php if ($error): ?>
|
<?php if ($error): ?>
|
||||||
<div class="card notice-card" style="margin-top:1rem; border-color:#ffb4a8; background:#fff5f3; color:#7a2114;">
|
<div class="setup-db-message setup-db-message--error" style="margin-top:16px;">
|
||||||
<?= e($error) ?>
|
<?= e($error) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($notice): ?>
|
<?php elseif ($notice): ?>
|
||||||
<div class="card notice-card" style="margin-top:1rem; border-color:var(--accent-2);">
|
<div class="setup-db-message setup-db-message--success" style="margin-top:16px;">
|
||||||
<?= e($notice) ?>
|
<?= e($notice) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="grid" style="margin-top:1rem;">
|
<div class="module-box" style="margin-top:16px;">
|
||||||
<div class="card form-card" style="background:var(--panel-2);">
|
|
||||||
<strong>Live-Konsole</strong>
|
<strong>Live-Konsole</strong>
|
||||||
<div class="card" style="margin-top:1rem; border-color:#ffb4a8; background:#fff5f3; color:#7a2114; display:none;" data-console-error></div>
|
<div class="setup-db-message setup-db-message--error" style="margin-top:1rem; display:none;" data-console-error></div>
|
||||||
<div class="card" style="margin-top:1rem; border-color:var(--accent-2); display:none;" data-console-notice></div>
|
<div class="setup-db-message setup-db-message--success" style="margin-top:1rem; display:none;" data-console-notice></div>
|
||||||
<form method="post" class="form-grid" style="margin-top:.75rem;" data-console-form>
|
<form method="post" class="form-grid" style="margin-top:.75rem;" data-console-form>
|
||||||
<label class="form-field">
|
<label class="form-field">
|
||||||
<span class="muted">Host</span>
|
<span class="muted">Host</span>
|
||||||
@@ -516,5 +522,6 @@ function sendToActiveConsole(array $host, string $command, bool $strictHostKey):
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<?= module_shell_footer() ?>
|
||||||
|
|||||||
@@ -333,29 +333,34 @@ function hostAuthOk(array $host, bool $strictHostKey): bool
|
|||||||
return $exitCode === 0;
|
return $exitCode === 0;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<div class="card">
|
<?= module_shell_header('pi_control', [
|
||||||
<div class="pill">Pi Control</div>
|
'title' => 'Hosts',
|
||||||
<div style="display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-top:.75rem;">
|
]) ?>
|
||||||
<h1 style="margin:0;">Hosts</h1>
|
<div class="module-flow">
|
||||||
|
<section class="module-box">
|
||||||
|
<div class="module-box-head">
|
||||||
|
<div>
|
||||||
|
<h2 class="module-box-title">Hosts</h2>
|
||||||
|
<p>Verwalte die Raspberry Pis, die du steuern möchtest.</p>
|
||||||
|
</div>
|
||||||
<div style="display:flex; gap:10px; flex-wrap:wrap;">
|
<div style="display:flex; gap:10px; flex-wrap:wrap;">
|
||||||
<button class="nav-link" type="button" data-host-check-all>Alle Hosts prüfen</button>
|
<button class="module-button module-button--secondary module-button--small" type="button" data-host-check-all>Alle Hosts prüfen</button>
|
||||||
<button class="cta-button" type="button" data-host-new>+ Neuer Host</button>
|
<button class="module-button module-button--primary" type="button" data-host-new>+ Neuer Host</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="muted">Verwalte die Raspberry Pis, die du steuern möchtest.</p>
|
|
||||||
|
|
||||||
<?php if ($error): ?>
|
<?php if ($error): ?>
|
||||||
<div class="card notice-card" style="margin-top:1rem; border-color:#ffb4a8; background:#fff5f3; color:#7a2114;">
|
<div class="setup-db-message setup-db-message--error" style="margin-top:16px;">
|
||||||
<?= e($error) ?>
|
<?= e($error) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($notice): ?>
|
<?php elseif ($notice): ?>
|
||||||
<div class="card notice-card" style="margin-top:1rem; border-color:var(--accent-2);">
|
<div class="setup-db-message setup-db-message--success" style="margin-top:16px;">
|
||||||
<?= e($notice) ?>
|
<?= e($notice) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="grid" style="margin-top:1rem;">
|
<div class="module-box-grid module-box-grid--panels" style="margin-top:16px;">
|
||||||
<div class="card form-card" style="background:var(--panel-2);">
|
<div class="module-box form-card">
|
||||||
<strong>Registrierte Hosts</strong>
|
<strong>Registrierte Hosts</strong>
|
||||||
<?php if (!$hosts): ?>
|
<?php if (!$hosts): ?>
|
||||||
<div class="muted" style="margin-top:.75rem;">Keine Hosts vorhanden.</div>
|
<div class="muted" style="margin-top:.75rem;">Keine Hosts vorhanden.</div>
|
||||||
@@ -418,6 +423,8 @@ function hostAuthOk(array $host, bool $strictHostKey): bool
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal" data-host-modal aria-hidden="true">
|
<div class="modal" data-host-modal aria-hidden="true">
|
||||||
<div class="modal-card">
|
<div class="modal-card">
|
||||||
@@ -469,3 +476,4 @@ function hostAuthOk(array $host, bool $strictHostKey): bool
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?= module_shell_footer() ?>
|
||||||
|
|||||||
@@ -7,26 +7,35 @@ $hostCount = (int)$pdo->query('SELECT COUNT(*) FROM ' . $table('hosts'))->fetchC
|
|||||||
$cmdCount = (int)$pdo->query('SELECT COUNT(*) FROM ' . $table('commands'))->fetchColumn();
|
$cmdCount = (int)$pdo->query('SELECT COUNT(*) FROM ' . $table('commands'))->fetchColumn();
|
||||||
$runCount = (int)$pdo->query('SELECT COUNT(*) FROM ' . $table('runs'))->fetchColumn();
|
$runCount = (int)$pdo->query('SELECT COUNT(*) FROM ' . $table('runs'))->fetchColumn();
|
||||||
?>
|
?>
|
||||||
<div class="card">
|
<?= module_shell_header('pi_control', [
|
||||||
<div class="pill">Pi Control</div>
|
'title' => 'Raspberry Pi Steuerung',
|
||||||
<h1 style="margin-top:.75rem;">Raspberry Pi Steuerung</h1>
|
]) ?>
|
||||||
<p class="muted">SSH Hosts verwalten, Befehle definieren und Aktionen ausführen.</p>
|
<div class="module-flow">
|
||||||
|
<section class="module-box">
|
||||||
|
<div class="module-box-head">
|
||||||
|
<div>
|
||||||
|
<h2 class="module-box-title">Raspberry Pi Steuerung</h2>
|
||||||
|
<p>SSH Hosts verwalten, Befehle definieren und Aktionen ausführen.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div class="grid" style="margin-top:1rem;">
|
<div class="module-box-grid module-box-grid--stats">
|
||||||
<div class="card" style="background:var(--panel-2);">
|
<div class="module-box-soft">
|
||||||
<strong>Hosts</strong>
|
<strong>Hosts</strong>
|
||||||
<div class="muted" style="margin-top:.35rem;">Registriert: <?= e((string)$hostCount) ?></div>
|
<div class="muted" style="margin-top:.35rem;">Registriert: <?= e((string)$hostCount) ?></div>
|
||||||
<div style="margin-top:.75rem;"><a class="nav-link" href="/module/pi_control/hosts">Hosts verwalten</a></div>
|
<div style="margin-top:.75rem;"><a class="module-button module-button--secondary module-button--small" href="/module/pi_control/hosts">Hosts verwalten</a></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card" style="background:var(--panel-2);">
|
<div class="module-box-soft">
|
||||||
<strong>Befehle</strong>
|
<strong>Befehle</strong>
|
||||||
<div class="muted" style="margin-top:.35rem;">Presets: <?= e((string)$cmdCount) ?></div>
|
<div class="muted" style="margin-top:.35rem;">Presets: <?= e((string)$cmdCount) ?></div>
|
||||||
<div style="margin-top:.75rem;"><a class="nav-link" href="/module/pi_control/commands">Befehle verwalten</a></div>
|
<div style="margin-top:.75rem;"><a class="module-button module-button--secondary module-button--small" href="/module/pi_control/commands">Befehle verwalten</a></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card" style="background:var(--panel-2);">
|
<div class="module-box-soft">
|
||||||
<strong>Konsole</strong>
|
<strong>Konsole</strong>
|
||||||
<div class="muted" style="margin-top:.35rem;">Runs: <?= e((string)$runCount) ?></div>
|
<div class="muted" style="margin-top:.35rem;">Runs: <?= e((string)$runCount) ?></div>
|
||||||
<div style="margin-top:.75rem;"><a class="nav-link" href="/module/pi_control/console">Konsole öffnen</a></div>
|
<div style="margin-top:.75rem;"><a class="module-button module-button--secondary module-button--small" href="/module/pi_control/console">Konsole öffnen</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?= module_shell_footer() ?>
|
||||||
|
|||||||
@@ -2,18 +2,5 @@
|
|||||||
"title": "Pi-hole",
|
"title": "Pi-hole",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Pi-hole Monitoring, Listen und Steuerung fuer zwei Instanzen.",
|
"description": "Pi-hole Monitoring, Listen und Steuerung fuer zwei Instanzen.",
|
||||||
"menu": [
|
|
||||||
{ "label": "Dashboard", "href": "/module/pihole" },
|
|
||||||
{ "label": "Instanzen", "href": "/module/pihole/instances" }
|
|
||||||
],
|
|
||||||
"sidebar": {
|
|
||||||
"enabled": true,
|
|
||||||
"collapsible": true,
|
|
||||||
"default": "collapsed",
|
|
||||||
"items": [
|
|
||||||
{ "label": "Dashboard", "href": "/module/pihole" },
|
|
||||||
{ "label": "Instanzen", "href": "/module/pihole/instances" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"setup": { "fields": [] }
|
"setup": { "fields": [] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ $hasConfig = !empty($instances);
|
|||||||
'title' => 'Pi-hole Dashboard',
|
'title' => 'Pi-hole Dashboard',
|
||||||
'description' => 'Status, Blockings, Usage und Steuerung fuer beide Instanzen.',
|
'description' => 'Status, Blockings, Usage und Steuerung fuer beide Instanzen.',
|
||||||
]) ?>
|
]) ?>
|
||||||
<div class="card pihole-page" data-pihole-page="dashboard">
|
<div class="module-flow pihole-page" data-pihole-page="dashboard">
|
||||||
|
|
||||||
<div class="card" style="margin-top:1rem;">
|
<section class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Hosts</strong>
|
<strong>Hosts</strong>
|
||||||
<a class="nav-link" href="/module/pihole/instances">Instanzen verwalten</a>
|
<a class="module-button module-button--secondary module-button--small" href="/module/pihole/instances">Instanzen verwalten</a>
|
||||||
</div>
|
</div>
|
||||||
<?php if (!$instances): ?>
|
<?php if (!$instances): ?>
|
||||||
<div class="muted" style="margin-top:.75rem;">Keine Pi-hole Instanzen vorhanden. Bitte zuerst hinzufuegen.</div>
|
<div class="muted" style="margin-top:.75rem;">Keine Pi-hole Instanzen vorhanden. Bitte zuerst hinzufuegen.</div>
|
||||||
<div style="margin-top:.75rem;"><a class="cta-button" href="/module/pihole/instances">+ Neue Instanz</a></div>
|
<div style="margin-top:.75rem;"><a class="module-button module-button--primary" href="/module/pihole/instances">+ Neue Instanz</a></div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<div class="pihole-list" style="margin-top:1rem;">
|
<div class="pihole-list" style="margin-top:1rem;">
|
||||||
<?php foreach ($instances as $instance): ?>
|
<?php foreach ($instances as $instance): ?>
|
||||||
@@ -35,32 +35,32 @@ $hasConfig = !empty($instances);
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<?php if (!$hasConfig): ?>
|
<?php if (!$hasConfig): ?>
|
||||||
<?php return; ?>
|
<?php return; ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<div class="pihole-grid" style="margin-top:1rem;">
|
<div class="module-box-grid module-box-grid--stats pihole-grid">
|
||||||
<div class="card pihole-stat">
|
<div class="module-box-soft pihole-stat">
|
||||||
<div class="muted">DNS Queries (heute)</div>
|
<div class="muted">DNS Queries (heute)</div>
|
||||||
<div class="pihole-stat-value" data-summary-dns>–</div>
|
<div class="pihole-stat-value" data-summary-dns>–</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card pihole-stat">
|
<div class="module-box-soft pihole-stat">
|
||||||
<div class="muted">Ads geblockt</div>
|
<div class="muted">Ads geblockt</div>
|
||||||
<div class="pihole-stat-value" data-summary-blocked>–</div>
|
<div class="pihole-stat-value" data-summary-blocked>–</div>
|
||||||
<div class="pihole-stat-sub" data-summary-percent>–</div>
|
<div class="pihole-stat-sub" data-summary-percent>–</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card pihole-stat">
|
<div class="module-box-soft pihole-stat">
|
||||||
<div class="muted">Unique Clients</div>
|
<div class="muted">Unique Clients</div>
|
||||||
<div class="pihole-stat-value" data-summary-clients>–</div>
|
<div class="pihole-stat-value" data-summary-clients>–</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card pihole-stat">
|
<div class="module-box-soft pihole-stat">
|
||||||
<div class="muted">Status</div>
|
<div class="muted">Status</div>
|
||||||
<div class="pihole-stat-value" data-summary-status>–</div>
|
<div class="pihole-stat-value" data-summary-status>–</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card" style="margin-top:1.25rem;">
|
<section class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Blocker steuern (alle Instanzen)</strong>
|
<strong>Blocker steuern (alle Instanzen)</strong>
|
||||||
<span class="muted" data-summary-last-refresh>Letztes Update: –</span>
|
<span class="muted" data-summary-last-refresh>Letztes Update: –</span>
|
||||||
@@ -77,17 +77,17 @@ $hasConfig = !empty($instances);
|
|||||||
<button class="nav-link" data-action="disable-custom" data-instance="all">Custom</button>
|
<button class="nav-link" data-action="disable-custom" data-instance="all">Custom</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<div class="card" style="margin-top:1.25rem;">
|
<section class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Instanzen</strong>
|
<strong>Instanzen</strong>
|
||||||
<span class="muted">Einzeln steuerbar & getrennte Updates</span>
|
<span class="muted">Einzeln steuerbar & getrennte Updates</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pihole-instance-grid" data-instance-cards></div>
|
<div class="pihole-instance-grid" data-instance-cards></div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<div class="card" style="margin-top:1.25rem;">
|
<section class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Usage (Aggregiert)</strong>
|
<strong>Usage (Aggregiert)</strong>
|
||||||
<span class="muted">Query-Typen und Weiterleitungen</span>
|
<span class="muted">Query-Typen und Weiterleitungen</span>
|
||||||
@@ -102,12 +102,12 @@ $hasConfig = !empty($instances);
|
|||||||
<div class="pihole-list" data-forward-destinations></div>
|
<div class="pihole-list" data-forward-destinations></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template id="pihole-instance-template">
|
<template id="pihole-instance-template">
|
||||||
<div class="card pihole-instance" data-instance="">
|
<div class="module-box-soft pihole-instance" data-instance="">
|
||||||
<div class="pihole-instance-header">
|
<div class="pihole-instance-header">
|
||||||
<div>
|
<div>
|
||||||
<strong data-instance-name></strong>
|
<strong data-instance-name></strong>
|
||||||
|
|||||||
@@ -136,30 +136,34 @@ if ($primaryId === '') {
|
|||||||
'title' => 'Pi-hole Instanzen',
|
'title' => 'Pi-hole Instanzen',
|
||||||
'description' => 'Pi-hole Instanzen hinzufuegen, bearbeiten und loeschen.',
|
'description' => 'Pi-hole Instanzen hinzufuegen, bearbeiten und loeschen.',
|
||||||
]) ?>
|
]) ?>
|
||||||
<div class="card">
|
<div class="module-flow">
|
||||||
<div style="display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap;">
|
<section class="module-box">
|
||||||
<h1 style="margin:0;">Instanzen</h1>
|
<div class="module-box-head">
|
||||||
|
<div>
|
||||||
|
<h2 class="module-box-title">Instanzen</h2>
|
||||||
|
<p>Pi-hole Instanzen hinzufuegen, bearbeiten und loeschen.</p>
|
||||||
|
</div>
|
||||||
<div style="display:flex; gap:10px; flex-wrap:wrap;">
|
<div style="display:flex; gap:10px; flex-wrap:wrap;">
|
||||||
<button class="cta-button" type="button" data-instance-new>+ Neue Instanz</button>
|
<button class="module-button module-button--primary" type="button" data-instance-new>+ Neue Instanz</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($error): ?>
|
<?php if ($error): ?>
|
||||||
<div class="card notice-card" style="margin-top:1rem; border-color:#ffb4a8; background:#fff5f3; color:#7a2114;">
|
<div class="setup-db-message setup-db-message--error" style="margin-top:16px;">
|
||||||
<?= e($error) ?>
|
<?= e($error) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($notice): ?>
|
<?php elseif ($notice): ?>
|
||||||
<div class="card notice-card" style="margin-top:1rem; border-color:var(--accent-2);">
|
<div class="setup-db-message setup-db-message--success" style="margin-top:16px;">
|
||||||
<?= e($notice) ?>
|
<?= e($notice) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="pihole-instance-grid" style="margin-top:1rem;">
|
<div class="module-box-grid module-box-grid--panels" style="margin-top:16px;">
|
||||||
<?php if (!$instances): ?>
|
<?php if (!$instances): ?>
|
||||||
<div class="card" style="padding:16px;">Keine Instanzen vorhanden.</div>
|
<div class="module-box-soft">Keine Instanzen vorhanden.</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?php foreach ($instances as $instance): ?>
|
<?php foreach ($instances as $instance): ?>
|
||||||
<div class="card pihole-instance-card"
|
<div class="module-box-soft pihole-instance-card"
|
||||||
data-instance-id="<?= e((string)$instance['id']) ?>"
|
data-instance-id="<?= e((string)$instance['id']) ?>"
|
||||||
data-name="<?= e((string)($instance['name'] ?? '')) ?>"
|
data-name="<?= e((string)($instance['name'] ?? '')) ?>"
|
||||||
data-url="<?= e((string)($instance['url'] ?? '')) ?>"
|
data-url="<?= e((string)($instance['url'] ?? '')) ?>"
|
||||||
@@ -175,11 +179,11 @@ if ($primaryId === '') {
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="pihole-card-actions">
|
<div class="pihole-card-actions">
|
||||||
<button class="nav-link" type="button" data-instance-edit>Bearbeiten</button>
|
<button class="module-button module-button--secondary module-button--small" type="button" data-instance-edit>Bearbeiten</button>
|
||||||
<button class="nav-link" type="button" data-instance-test>Test Verbindung</button>
|
<button class="module-button module-button--secondary module-button--small" type="button" data-instance-test>Test Verbindung</button>
|
||||||
<form method="post" onsubmit="return confirm('Instanz wirklich loeschen?')">
|
<form method="post" onsubmit="return confirm('Instanz wirklich loeschen?')">
|
||||||
<input type="hidden" name="delete_id" value="<?= e((string)($instance['id'] ?? '')) ?>">
|
<input type="hidden" name="delete_id" value="<?= e((string)($instance['id'] ?? '')) ?>">
|
||||||
<button class="nav-link" type="submit">Loeschen</button>
|
<button class="module-button module-button--secondary module-button--small" type="submit">Loeschen</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="pihole-test-result" data-instance-result></div>
|
<div class="pihole-test-result" data-instance-result></div>
|
||||||
@@ -187,6 +191,7 @@ if ($primaryId === '') {
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal" data-instance-modal aria-hidden="true">
|
<div class="modal" data-instance-modal aria-hidden="true">
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ $hasConfig = !empty($instances);
|
|||||||
'title' => 'Listen & Domains',
|
'title' => 'Listen & Domains',
|
||||||
'description' => 'Top-Domains, Listen-Updates und neue Eintraege auf der Primaer-Instanz.',
|
'description' => 'Top-Domains, Listen-Updates und neue Eintraege auf der Primaer-Instanz.',
|
||||||
]) ?>
|
]) ?>
|
||||||
<div class="card pihole-page" data-pihole-page="lists">
|
<div class="module-flow pihole-page" data-pihole-page="lists">
|
||||||
<?php if (!$hasConfig): ?>
|
<?php if (!$hasConfig): ?>
|
||||||
<div class="card" style="margin-top:1rem; border-color:var(--accent);">
|
<div class="module-box">
|
||||||
<strong>Keine Instanzen konfiguriert</strong>
|
<strong>Keine Instanzen konfiguriert</strong>
|
||||||
<div class="muted" style="margin-top:.35rem;">Bitte zuerst eine Pi-hole Instanz hinzufuegen.</div>
|
<div class="muted" style="margin-top:.35rem;">Bitte zuerst eine Pi-hole Instanz hinzufuegen.</div>
|
||||||
<div style="margin-top:.75rem;"><a class="nav-link" href="/module/pihole/instances">Instanzen verwalten</a></div>
|
<div style="margin-top:.75rem;"><a class="module-button module-button--secondary module-button--small" href="/module/pihole/instances">Instanzen verwalten</a></div>
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<div class="card" style="margin-top:1rem;">
|
<section class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Listen-Updates</strong>
|
<strong>Listen-Updates</strong>
|
||||||
<span class="muted">Gravity / Blocklisten neu laden</span>
|
<span class="muted">Gravity / Blocklisten neu laden</span>
|
||||||
@@ -27,17 +27,17 @@ $hasConfig = !empty($instances);
|
|||||||
<button class="cta-button" data-action="gravity" data-instance="primary">Listen aktualisieren (Primaer)</button>
|
<button class="cta-button" data-action="gravity" data-instance="primary">Listen aktualisieren (Primaer)</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="pihole-update" data-list-update-status></div>
|
<div class="pihole-update" data-list-update-status></div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<div class="pihole-split" style="margin-top:1.25rem;">
|
<div class="module-box-grid module-box-grid--panels pihole-split">
|
||||||
<div class="card">
|
<div class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Top geblockte Domains (Aggregiert)</strong>
|
<strong>Top geblockte Domains (Aggregiert)</strong>
|
||||||
<span class="muted">Letzte Statistiken</span>
|
<span class="muted">Letzte Statistiken</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pihole-list" data-top-ads></div>
|
<div class="pihole-list" data-top-ads></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Top erlaubte Domains (Aggregiert)</strong>
|
<strong>Top erlaubte Domains (Aggregiert)</strong>
|
||||||
<span class="muted">Letzte Statistiken</span>
|
<span class="muted">Letzte Statistiken</span>
|
||||||
@@ -46,7 +46,7 @@ $hasConfig = !empty($instances);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card" style="margin-top:1.25rem;">
|
<section class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Domainlisten erweitern</strong>
|
<strong>Domainlisten erweitern</strong>
|
||||||
<span class="muted">Eintraege werden auf der Primaer-Instanz gesetzt</span>
|
<span class="muted">Eintraege werden auf der Primaer-Instanz gesetzt</span>
|
||||||
@@ -66,9 +66,9 @@ $hasConfig = !empty($instances);
|
|||||||
<button class="cta-button" type="submit">Hinzufuegen</button>
|
<button class="cta-button" type="submit">Hinzufuegen</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="pihole-update" data-domain-status></div>
|
<div class="pihole-update" data-domain-status></div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<div class="card" style="margin-top:1.25rem;">
|
<section class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Adlist-URL hinzufuegen</strong>
|
<strong>Adlist-URL hinzufuegen</strong>
|
||||||
<span class="muted">Optional: unterstuetzt nur wenn die API den Endpunkt anbietet.</span>
|
<span class="muted">Optional: unterstuetzt nur wenn die API den Endpunkt anbietet.</span>
|
||||||
@@ -81,7 +81,7 @@ $hasConfig = !empty($instances);
|
|||||||
<button class="nav-link" type="submit">Adlist hinzufuegen</button>
|
<button class="nav-link" type="submit">Adlist hinzufuegen</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="pihole-update" data-adlist-status></div>
|
<div class="pihole-update" data-adlist-status></div>
|
||||||
</div>
|
</section>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<?= module_shell_footer() ?>
|
<?= module_shell_footer() ?>
|
||||||
|
|||||||
@@ -10,23 +10,23 @@ $hasConfig = !empty($instances);
|
|||||||
'title' => 'Zugriffe & Blockings',
|
'title' => 'Zugriffe & Blockings',
|
||||||
'description' => 'Aktuelle Blockings, Top Clients und Status pro Instanz.',
|
'description' => 'Aktuelle Blockings, Top Clients und Status pro Instanz.',
|
||||||
]) ?>
|
]) ?>
|
||||||
<div class="card pihole-page" data-pihole-page="queries">
|
<div class="module-flow pihole-page" data-pihole-page="queries">
|
||||||
<?php if (!$hasConfig): ?>
|
<?php if (!$hasConfig): ?>
|
||||||
<div class="card" style="margin-top:1rem; border-color:var(--accent);">
|
<div class="module-box">
|
||||||
<strong>Keine Instanzen konfiguriert</strong>
|
<strong>Keine Instanzen konfiguriert</strong>
|
||||||
<div class="muted" style="margin-top:.35rem;">Bitte zuerst eine Pi-hole Instanz hinzufuegen.</div>
|
<div class="muted" style="margin-top:.35rem;">Bitte zuerst eine Pi-hole Instanz hinzufuegen.</div>
|
||||||
<div style="margin-top:.75rem;"><a class="nav-link" href="/module/pihole/instances">Instanzen verwalten</a></div>
|
<div style="margin-top:.75rem;"><a class="module-button module-button--secondary module-button--small" href="/module/pihole/instances">Instanzen verwalten</a></div>
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<div class="pihole-split" style="margin-top:1rem;">
|
<div class="module-box-grid module-box-grid--panels pihole-split">
|
||||||
<div class="card">
|
<div class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Aktuelle Blockings</strong>
|
<strong>Aktuelle Blockings</strong>
|
||||||
<span class="muted">Letzte geblockte Domains</span>
|
<span class="muted">Letzte geblockte Domains</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pihole-blocked" data-recent-blocked></div>
|
<div class="pihole-blocked" data-recent-blocked></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="module-box">
|
||||||
<div class="pihole-section-header">
|
<div class="pihole-section-header">
|
||||||
<strong>Top Clients (Aggregiert)</strong>
|
<strong>Top Clients (Aggregiert)</strong>
|
||||||
<span class="muted">Anfragen nach Client</span>
|
<span class="muted">Anfragen nach Client</span>
|
||||||
|
|||||||
@@ -364,7 +364,17 @@ function module_shell_header(string $module, array $options = []): string
|
|||||||
if ($label === '' || $href === '') {
|
if ($label === '' || $href === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
$matchPrefixes = is_array($tab['match_prefixes'] ?? null) ? $tab['match_prefixes'] : [];
|
||||||
$isActive = !empty($tab['active']) || $href === $requestPath;
|
$isActive = !empty($tab['active']) || $href === $requestPath;
|
||||||
|
if (!$isActive) {
|
||||||
|
foreach ($matchPrefixes as $prefix) {
|
||||||
|
$prefix = is_string($prefix) ? trim($prefix) : '';
|
||||||
|
if ($prefix !== '' && str_starts_with($requestPath, $prefix)) {
|
||||||
|
$isActive = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
$class = $isActive ? 'module-button module-button--tab-active' : 'module-button module-button--tab';
|
$class = $isActive ? 'module-button module-button--tab-active' : 'module-button module-button--tab';
|
||||||
$html .= '<a class="' . e($class) . '" href="' . e($href) . '">' . e($label) . '</a>';
|
$html .= '<a class="' . e($class) . '" href="' . e($href) . '">' . e($label) . '</a>';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user