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 = 'Keine Links.'; return; } tbody.innerHTML = links.map((l, i) => ` ${escapeHtml(l.label)} ${escapeHtml(l.url)} ` ).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();