Files
nexus/modules/pi_control/pages/commands.php
Lars Gebhardt-Kusche d6f09326f4
All checks were successful
Deploy / deploy-staging (push) Successful in 6s
Deploy / deploy-production (push) Has been skipped
dsfdsf
2026-04-24 23:54:04 +02:00

182 lines
7.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
$pdo = module_fn('pi_control', 'pdo');
module_fn('pi_control', 'ensure_schema');
$table = fn(string $name) => module_fn('pi_control', 'table', $name);
$assets = app()->assets();
if ($assets) {
$assets->addStyle('/module/pi_control/asset?file=pi_control.css');
$assets->addScript('/module/pi_control/asset?file=commands.js', 'footer', true);
}
$notice = null;
$error = null;
if (isset($_GET['reorder_json'])) {
require_admin();
$payload = json_decode(file_get_contents('php://input'), true);
$order = is_array($payload['order'] ?? null) ? $payload['order'] : [];
if ($order) {
$stmt = $pdo->prepare('UPDATE ' . $table('commands') . ' SET sort_order = :sort_order WHERE id = :id');
$pos = 1;
foreach ($order as $id) {
$stmt->execute([
'sort_order' => $pos++,
'id' => (int)$id,
]);
}
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['ok' => true]);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
require_admin();
$deleteId = (int)($_POST['delete_id'] ?? 0);
$editId = (int)($_POST['id'] ?? 0);
$label = trim((string)($_POST['label'] ?? ''));
$command = trim((string)($_POST['command'] ?? ''));
$adminOnly = !empty($_POST['admin_only']) ? 1 : 0;
$timeoutSec = (int)($_POST['timeout_sec'] ?? 0);
if ($deleteId > 0) {
$stmt = $pdo->prepare('DELETE FROM ' . $table('commands') . ' WHERE id = :id');
$stmt->execute(['id' => $deleteId]);
$notice = 'Befehl gelöscht.';
} else {
if ($label === '' || $command === '') {
$error = 'Bitte Label und Command angeben.';
} else {
if ($editId > 0) {
$stmt = $pdo->prepare(
'UPDATE ' . $table('commands') . ' SET label = :label, command = :command, admin_only = :admin_only, timeout_sec = :timeout_sec WHERE id = :id'
);
$stmt->execute([
'id' => $editId,
'label' => $label,
'command' => $command,
'admin_only' => $adminOnly,
'timeout_sec' => $timeoutSec > 0 ? $timeoutSec : null,
]);
$notice = 'Befehl aktualisiert.';
} else {
$nextSort = (int)$pdo->query('SELECT COALESCE(MAX(sort_order), 0) + 1 FROM ' . $table('commands'))->fetchColumn();
$stmt = $pdo->prepare(
'INSERT INTO ' . $table('commands') . ' (label, command, admin_only, timeout_sec, sort_order) VALUES (:label, :command, :admin_only, :timeout_sec, :sort_order)'
);
$stmt->execute([
'label' => $label,
'command' => $command,
'admin_only' => $adminOnly,
'timeout_sec' => $timeoutSec > 0 ? $timeoutSec : null,
'sort_order' => $nextSort,
]);
$notice = 'Befehl gespeichert.';
}
}
}
}
$commands = $pdo->query('SELECT * FROM ' . $table('commands') . ' ORDER BY COALESCE(sort_order, id) ASC, id ASC')->fetchAll(PDO::FETCH_ASSOC);
?>
<?= module_shell_header('pi_control', [
'title' => 'Befehle',
]) ?>
<div class="module-flow">
<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>
<?php if ($error): ?>
<div class="setup-db-message setup-db-message--error" style="margin-top:16px;">
<?= e($error) ?>
</div>
<?php elseif ($notice): ?>
<div class="setup-db-message setup-db-message--success" style="margin-top:16px;">
<?= e($notice) ?>
</div>
<?php endif; ?>
<div class="module-box" style="margin-top:16px;">
<strong>Vorhandene Befehle</strong>
<?php if (!$commands): ?>
<div class="muted" style="margin-top:.75rem;">Keine Befehle vorhanden.</div>
<?php else: ?>
<ul class="command-list" data-command-list style="margin-top:.75rem;">
<?php foreach ($commands as $c): ?>
<li class="command-item" draggable="true"
data-command-id="<?= e((string)$c['id']) ?>"
data-label="<?= e((string)($c['label'] ?? '')) ?>"
data-command="<?= e((string)($c['command'] ?? '')) ?>"
data-timeout="<?= e((string)($c['timeout_sec'] ?? '')) ?>"
data-admin="<?= !empty($c['admin_only']) ? '1' : '0' ?>">
<div class="command-drag">⋮⋮</div>
<div class="command-body">
<div class="command-title">
<strong><?= e($c['label'] ?? '') ?></strong>
<?php if (!empty($c['admin_only'])): ?>
<span class="pill">Admin</span>
<?php endif; ?>
</div>
<div class="muted" style="margin-top:4px;">
<code><?= e($c['command'] ?? '') ?></code>
</div>
<div class="muted" style="margin-top:4px;">
Timeout: <?= !empty($c['timeout_sec']) ? e((string)$c['timeout_sec']) . 's' : 'default' ?>
</div>
</div>
<details class="action-menu">
<summary>☰</summary>
<div class="action-menu-panel">
<button class="nav-link" type="button" data-command-edit>Bearbeiten</button>
<form method="post" onsubmit="return confirm('Befehl wirklich löschen?')">
<input type="hidden" name="delete_id" value="<?= e((string)$c['id']) ?>">
<button class="nav-link" type="submit">Löschen</button>
</form>
</div>
</details>
</li>
<?php endforeach; ?>
</ul>
<p class="muted" style="margin-top:.5rem;">Reihenfolge per Drag & Drop ändern.</p>
<?php endif; ?>
</div>
</section>
</div>
<div class="modal" data-command-modal aria-hidden="true">
<div class="modal-card">
<div class="modal-header">
<strong data-command-modal-title>Neuer Befehl</strong>
<button class="icon-button" type="button" data-command-close>×</button>
</div>
<form method="post" class="form-grid" style="margin-top:.75rem;" data-command-form>
<input type="hidden" name="id" value="">
<input type="text" name="label" placeholder="Label" required>
<textarea name="command" rows="4" placeholder="Command" required></textarea>
<input type="number" name="timeout_sec" placeholder="Timeout (Sek., optional)">
<label class="muted" style="display:flex; gap:8px; align-items:center;">
<input type="checkbox" name="admin_only" value="1">
Nur Admin
</label>
<div class="host-unsaved" data-command-unsaved style="display:none;">
<span class="muted">Änderungen nicht gespeichert.</span>
<div style="display:flex; gap:10px; flex-wrap:wrap;">
<button class="cta-button" type="submit" data-command-submit>Speichern</button>
<button class="nav-link" type="button" data-command-discard>Änderungen verwerfen</button>
</div>
</div>
<div style="display:flex; gap:10px; flex-wrap:wrap;">
<button class="cta-button" type="submit" data-command-submit>Speichern</button>
<button class="nav-link" type="button" data-command-cancel>Zurücksetzen</button>
</div>
</form>
</div>
</div>
<?= module_shell_footer() ?>