246 lines
8.9 KiB
HTML
246 lines
8.9 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}Admin – MK Control{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="container my-5">
|
||
<h1 class="mb-4">Admin-Bereich</h1>
|
||
|
||
<div class="row mb-4">
|
||
<div class="col">
|
||
<a href="{{ url_for('admin.admin_logs') }}" class="btn btn-outline-info">
|
||
<i class="bi bi-journal-text me-2"></i>Logs ansehen
|
||
</a>
|
||
</div>
|
||
<div class="col text-end d-flex gap-2 justify-content-end">
|
||
<a href="#" class="btn btn-outline-success" data-bs-toggle="modal" data-bs-target="#newConfigModal">
|
||
<i class="bi bi-plus-circle me-2"></i>Neue MK-Konfiguration
|
||
</a>
|
||
<a href="#" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#newThemeModal">
|
||
<i class="bi bi-music-note-list me-2"></i>Neues Soundboard-Theme
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 class="mt-5 mb-3">Vorhandene Konfigurationen</h3>
|
||
|
||
{% if configs %}
|
||
<div class="table-responsive">
|
||
<table class="table table-hover align-middle">
|
||
<thead class="table-dark">
|
||
<tr>
|
||
<th>Name</th>
|
||
<th>Hub-ID</th>
|
||
<th>Datei</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for cfg in configs %}
|
||
<tr>
|
||
<td>{{ cfg.name }}</td>
|
||
<td>{{ cfg.hub_id | default('–') }}</td>
|
||
<td><code>{{ cfg.filename }}</code></td>
|
||
<td>
|
||
<a href="{{ url_for('admin.admin_edit_config', filename=cfg.filename) }}"
|
||
class="btn btn-sm btn-primary">
|
||
<i class="bi bi-pencil"></i> Bearbeiten
|
||
</a>
|
||
<button class="btn btn-sm btn-danger delete-config-btn"
|
||
data-filename="{{ cfg.filename }}"
|
||
data-name="{{ cfg.name }}">
|
||
<i class="bi bi-trash"></i> Löschen
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{% else %}
|
||
<div class="alert alert-info">
|
||
Noch keine Konfigurationen vorhanden. Erstelle eine neue.
|
||
</div>
|
||
{% endif %}
|
||
|
||
<h3 class="mt-5 mb-3">Soundboard-Themes</h3>
|
||
{% if sb_configs %}
|
||
<div class="table-responsive">
|
||
<table class="table table-hover align-middle">
|
||
<thead class="table-dark">
|
||
<tr>
|
||
<th>Name</th>
|
||
<th>Datei</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for sb in sb_configs %}
|
||
<tr>
|
||
<td>{{ sb.name }}</td>
|
||
<td><code>{{ sb.filename }}</code></td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{% else %}
|
||
<div class="alert alert-info">Noch keine Themes vorhanden.</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<!-- Modal für neue MK-Konfiguration -->
|
||
<div class="modal fade" id="newConfigModal" tabindex="-1" aria-labelledby="newConfigModalLabel" aria-hidden="true">
|
||
<div class="modal-dialog modal-lg">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title" id="newConfigModalLabel">Neue Konfiguration anlegen</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="form-new-config">
|
||
<div class="row g-3">
|
||
<div class="col-md-6">
|
||
<label class="form-label">Name</label>
|
||
<input class="form-control" name="name" required placeholder="z.B. Dampflok BR 01">
|
||
</div>
|
||
<div class="col-md-3">
|
||
<label class="form-label">Hub-ID</label>
|
||
<input class="form-control" name="hub_id" type="number" min="0" max="2" value="0">
|
||
</div>
|
||
<div class="col-md-3">
|
||
<label class="form-label">Hub-Typ</label>
|
||
<select class="form-select" name="hub_type">
|
||
<option value="4channel">4channel</option>
|
||
<option value="6channel">6channel</option>
|
||
</select>
|
||
</div>
|
||
<div class="col-12">
|
||
<label class="form-label">Bilddatei (optional)</label>
|
||
<input class="form-control" name="image" placeholder="z.B. dampflok1.jpg">
|
||
<small class="text-muted">Datei im configs/-Ordner ablegen.</small>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
|
||
<button type="button" class="btn btn-primary" id="btn-save-config">Anlegen</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal für neues Soundboard-Theme -->
|
||
<div class="modal fade" id="newThemeModal" tabindex="-1" aria-labelledby="newThemeModalLabel" aria-hidden="true">
|
||
<div class="modal-dialog modal-lg">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title" id="newThemeModalLabel">Neues Soundboard-Theme anlegen</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="form-new-theme">
|
||
<div class="row g-3">
|
||
<div class="col-md-6">
|
||
<label class="form-label">Name</label>
|
||
<input class="form-control" name="name" required placeholder="z.B. Wilder Westen">
|
||
</div>
|
||
<div class="col-md-6">
|
||
<label class="form-label">Ordner (optional)</label>
|
||
<input class="form-control" name="folder" placeholder="wilder-westen">
|
||
<small class="text-muted">Unterordner in soundboards/. Standard: Slug des Namens.</small>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<label class="form-label">Dateiname</label>
|
||
<input class="form-control" name="filename" value="theme.json">
|
||
</div>
|
||
<div class="col-md-3">
|
||
<label class="form-label">Limit/h (Random)</label>
|
||
<input class="form-control" name="random_limit_per_hour" type="number" min="1" value="2">
|
||
</div>
|
||
<div class="col-md-3">
|
||
<label class="form-label">Fenster (Min)</label>
|
||
<input class="form-control" name="random_window_minutes" type="number" min="1" value="60">
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
|
||
<button type="button" class="btn btn-primary" id="btn-save-theme">Anlegen</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
document.querySelectorAll('.delete-config-btn').forEach(btn => {
|
||
btn.addEventListener('click', async () => {
|
||
const filename = btn.dataset.filename;
|
||
const name = btn.dataset.name;
|
||
|
||
if (!confirm(`Sicher löschen: ${name} (${filename}) ?`)) return;
|
||
|
||
try {
|
||
const res = await fetch(`/admin/delete/${filename}`, { method: 'POST' });
|
||
const data = await res.json();
|
||
if (data.success) {
|
||
alert('Gelöscht');
|
||
location.reload();
|
||
} else {
|
||
alert('Fehler: ' + data.message);
|
||
}
|
||
} catch (err) {
|
||
alert('Netzwerkfehler beim Löschen');
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
// Neue Config speichern
|
||
document.getElementById('btn-save-config')?.addEventListener('click', async () => {
|
||
const form = document.getElementById('form-new-config');
|
||
const data = Object.fromEntries(new FormData(form).entries());
|
||
data.hub_id = parseInt(data.hub_id || 0, 10);
|
||
try {
|
||
const res = await fetch('/admin/create_config', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(data)
|
||
});
|
||
const json = await res.json();
|
||
if (!json.success) throw new Error(json.message || 'Fehler');
|
||
alert('Konfiguration angelegt: ' + json.filename);
|
||
location.reload();
|
||
} catch (e) {
|
||
alert('Fehler: ' + e.message);
|
||
}
|
||
});
|
||
|
||
// Neues Theme speichern
|
||
document.getElementById('btn-save-theme')?.addEventListener('click', async () => {
|
||
const form = document.getElementById('form-new-theme');
|
||
const data = Object.fromEntries(new FormData(form).entries());
|
||
data.random_limit_per_hour = parseInt(data.random_limit_per_hour || 2, 10);
|
||
data.random_window_minutes = parseInt(data.random_window_minutes || 60, 10);
|
||
try {
|
||
const res = await fetch('/admin/create_theme', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(data)
|
||
});
|
||
const json = await res.json();
|
||
if (!json.success) throw new Error(json.message || 'Fehler');
|
||
alert('Theme angelegt: ' + json.path);
|
||
location.reload();
|
||
} catch (e) {
|
||
alert('Fehler: ' + e.message);
|
||
}
|
||
});
|
||
</script>
|
||
{% endblock %}
|