MeshDD-Bot/static/js/config.js
ppfeiffer 511ff20842 feat(ui): Sidebar-Gruppe Konfigurationen, /config-Seite, MeshDD-Dashboard (closes #4)
- app.js: Sidebar um Gruppen-Support erweitert; Konfigurationen-Gruppe
  mit Scheduler, NINA, Einstellungen (/config) als Untereinträge
- style.css: .sidebar-group-label + .sidebar-link-sub
- config.py: save()-Funktion für persistentes Schreiben in config.yaml
- webserver.py: GET/PUT /api/config + GET /config Route (Admin)
- static/config.html + static/js/config.js: neue Konfigurationsseite
  (Bot, Meshtastic, Web, Links editierbar)
- Alle HTML-Dateien: MeshDD-Bot → MeshDD-Dashboard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 22:33:18 +01:00

113 lines
4.3 KiB
JavaScript

let links = [];
initPage({ onAuth: (user) => {
if (!user || user.role !== 'admin') {
window.location.href = '/';
}
}});
// ── Links table ───────────────────────────────────────────────
function renderLinks() {
const tbody = document.getElementById('linksList');
if (links.length === 0) {
tbody.innerHTML = '<tr><td colspan="3" class="text-center text-body-secondary py-2"><small>Keine Links.</small></td></tr>';
return;
}
tbody.innerHTML = links.map((l, i) =>
`<tr>
<td><small>${escapeHtml(l.label)}</small></td>
<td><small class="text-body-secondary">${escapeHtml(l.url)}</small></td>
<td class="text-end">
<button type="button" class="btn btn-outline-danger btn-sm py-0 px-1"
onclick="removeLink(${i})" title="Entfernen">
<i class="bi bi-trash" style="font-size:.75rem"></i>
</button>
</td>
</tr>`
).join('');
}
function removeLink(idx) {
links.splice(idx, 1);
renderLinks();
}
document.getElementById('btnAddLink').addEventListener('click', () => {
const label = document.getElementById('newLinkLabel').value.trim();
const url = document.getElementById('newLinkUrl').value.trim();
if (!label || !url) return;
links.push({ label, url });
renderLinks();
document.getElementById('newLinkLabel').value = '';
document.getElementById('newLinkUrl').value = '';
});
// ── Load ─────────────────────────────────────────────────────
async function loadConfig() {
try {
const resp = await fetch('/api/config');
if (!resp.ok) return;
const cfg = await resp.json();
document.getElementById('botName').value = cfg.bot?.name ?? '';
document.getElementById('botPrefix').value = cfg.bot?.command_prefix ?? '';
document.getElementById('meshHost').value = cfg.meshtastic?.host ?? '';
document.getElementById('meshPort').value = cfg.meshtastic?.port ?? '';
document.getElementById('webPort').value = cfg.web?.port ?? '';
document.getElementById('onlineThreshold').value = cfg.web?.online_threshold ?? '';
links = Array.isArray(cfg.links) ? [...cfg.links] : [];
renderLinks();
} catch (e) {
console.error('Config load failed:', e);
}
}
// ── Save ──────────────────────────────────────────────────────
document.getElementById('btnSave').addEventListener('click', async () => {
const payload = {
bot: {
name: document.getElementById('botName').value.trim(),
command_prefix: document.getElementById('botPrefix').value.trim(),
},
meshtastic: {
host: document.getElementById('meshHost').value.trim(),
port: parseInt(document.getElementById('meshPort').value) || 4403,
},
web: {
port: parseInt(document.getElementById('webPort').value) || 8081,
online_threshold: parseInt(document.getElementById('onlineThreshold').value) || 900,
},
links: [...links],
};
const statusEl = document.getElementById('saveStatus');
try {
const resp = await fetch('/api/config', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (resp.ok) {
statusEl.textContent = 'Gespeichert ✓';
statusEl.className = 'small text-success';
statusEl.classList.remove('d-none');
setTimeout(() => statusEl.classList.add('d-none'), 3000);
} else {
statusEl.textContent = 'Fehler beim Speichern';
statusEl.className = 'small text-danger';
statusEl.classList.remove('d-none');
}
} catch (e) {
console.error('Save failed:', e);
statusEl.textContent = 'Netzwerkfehler';
statusEl.className = 'small text-danger';
statusEl.classList.remove('d-none');
}
});
loadConfig();