MeshDD-Bot/static/js/settings.js
ppfeiffer f2c6ba8e62 feat: v0.6.7 - Dashboard-Upgrade: Tabler-Theme, Charts, Kanalfilter, Node-Suche
- Tabler 1.4.0 als Admin-Theme: Bootstrap CSS/JS in allen 6 HTML-Seiten ersetzt
- style.css komplett ueberarbeitet: Inter-Font, Tabler CSS-Variablen, Schatten,
  verfeinerte Sidebar (Rounded Active-Links), Hover-Animation auf Info-Boxen,
  pulsierender Status-Dot
- app.js als shared Modul: Duplikation in allen JS-Dateien eliminiert (initPage,
  applyTheme, escapeHtml, Sidebar-Injektion)
- WebSocket Auth-Fix: Nachrichten nur noch an eingeloggte Clients (auth_clients)
- Bot-Uptime + Meshtastic-Verbindungsstatus in Dashboard und Stats-API
- Dark Mode Kartentiles: CartoDB Dark Matter fuer Karte + Node-Modal
- 3 Charts: Kanal-Anfragen (Doughnut), Hop-Verteilung (Bar), Hardware Top 5
- Nodes-Tabelle: Suchfeld, Online-Filter, sortierbare Spalten
- Nachrichten Kanalfilter: Filter-Buttons im Nachrichten-Card-Header

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 22:43:35 +01:00

104 lines
4 KiB
JavaScript

let currentUser = null;
initPage({ onAuth: (user) => { currentUser = user; } });
// Labels for display
const deviceLabels = {
long_name: "Name",
short_name: "Kurzname",
node_num: "Node-Nummer",
hw_model: "Hardware",
firmware_version: "Firmware",
role: "Role",
max_channels: "Max Channels",
};
const loraLabels = {
region: "Region",
modem_preset: "Modem-Preset",
hop_limit: "Hop-Limit",
tx_power: "TX-Power",
bandwidth: "Bandwidth",
frequency_offset: "Freq-Offset",
tx_enabled: "TX aktiviert",
use_preset: "Preset nutzen",
};
const positionLabels = {
gps_mode: "GPS-Modus",
position_broadcast_secs: "Broadcast-Interval (s)",
fixed_position: "Feste Position",
};
const powerLabels = {
mesh_sds_timeout_secs: "Mesh-SDS-Timeout (s)",
ls_secs: "LS-Secs",
min_wake_secs: "Min-Wake-Secs",
is_power_saving: "Energiesparmodus",
};
function renderKeyValue(tableId, data, labels) {
const tbody = document.getElementById(tableId);
const rows = [];
for (const [key, label] of Object.entries(labels)) {
const val = data[key];
if (val === "" || val === undefined || val === null) continue;
const display = typeof val === "boolean" ? (val ? "Ja" : "Nein") : String(val);
rows.push(`<tr><td class="text-body-secondary" style="width:45%">${escapeHtml(label)}</td><td>${escapeHtml(display)}</td></tr>`);
}
tbody.innerHTML = rows.length > 0 ? rows.join("") : '<tr><td colspan="2" class="text-center text-body-secondary py-2">Keine Daten</td></tr>';
}
function renderChannels(channels) {
const tbody = document.getElementById("channelsTable");
if (!channels || channels.length === 0) {
tbody.innerHTML = '<tr><td colspan="4" class="text-center text-body-secondary py-2">Keine Channels</td></tr>';
return;
}
tbody.innerHTML = channels.map(ch =>
`<tr><td>${ch.index}</td><td>${escapeHtml(ch.name)}</td><td>${escapeHtml(ch.role)}</td><td>${escapeHtml(ch.psk)}</td></tr>`
).join("");
}
function renderBtNet(bluetooth, network) {
const tbody = document.getElementById("btNetTable");
const rows = [];
const btLabels = { enabled: "BT aktiviert", mode: "BT-Modus" };
const netLabels = { wifi_enabled: "WiFi aktiviert", ntp_server: "NTP-Server" };
for (const [key, label] of Object.entries(btLabels)) {
const val = bluetooth[key];
if (val === "" || val === undefined || val === null) continue;
const display = typeof val === "boolean" ? (val ? "Ja" : "Nein") : String(val);
rows.push(`<tr><td class="text-body-secondary" style="width:45%">${escapeHtml(label)}</td><td>${escapeHtml(display)}</td></tr>`);
}
for (const [key, label] of Object.entries(netLabels)) {
const val = network[key];
if (val === "" || val === undefined || val === null) continue;
const display = typeof val === "boolean" ? (val ? "Ja" : "Nein") : String(val);
rows.push(`<tr><td class="text-body-secondary" style="width:45%">${escapeHtml(label)}</td><td>${escapeHtml(display)}</td></tr>`);
}
tbody.innerHTML = rows.length > 0 ? rows.join("") : '<tr><td colspan="2" class="text-center text-body-secondary py-2">Keine Daten</td></tr>';
}
async function loadConfig() {
try {
const resp = await fetch("/api/node/config");
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();
renderKeyValue("deviceTable", data.device || {}, deviceLabels);
renderKeyValue("loraTable", data.lora || {}, loraLabels);
renderChannels(data.channels || []);
renderKeyValue("positionTable", data.position || {}, positionLabels);
renderKeyValue("powerTable", data.power || {}, powerLabels);
renderBtNet(data.bluetooth || {}, data.network || {});
} catch (e) {
console.error("Failed to load config:", e);
document.getElementById("deviceTable").innerHTML =
'<tr><td colspan="2" class="text-center text-danger py-2">Fehler beim Laden</td></tr>';
}
}
loadConfig();