/**
* hamlib_ui.js — VIRTUAL RADIO panel (Hamlib NET rigctl emulation, SETTINGS)
*
* Visible to everyone (so the user knows which ports to connect their
* program to), but enabling/disabling TCP ports and saving the config —
* ADMIN ONLY. Toggling these servers affects all users at once (shared
* port), so not everyone with access to the panel can do it — for other
* roles it's a plain status view.
*/
(function () {
'use strict';
async function load() {
const box = document.getElementById('hamlib-slots');
if (!box) return;
box.innerHTML = `
${I18n.t('settings_loading')}
`;
try {
const r = await fetch('/api/hamlib/status');
const d = await r.json();
_render(d.servers || []);
} catch (e) {
box.innerHTML = `${I18n.t('hamlib_load_error')}
`;
}
}
function _render(servers) {
const box = document.getElementById('hamlib-slots');
if (!box) return;
const isAdmin = window.AppState?.role === 'admin';
const saveBtn = document.getElementById('hamlib-save-btn');
if (saveBtn) saveBtn.style.display = isAdmin ? '' : 'none';
if (!servers.length) {
box.innerHTML = `${I18n.t('hamlib_no_ports')}
`;
return;
}
box.innerHTML = servers.map((s, i) => {
const clientWord = s.clients === 1 ? I18n.t('hamlib_client_singular') : I18n.t('hamlib_client_plural');
const running = s.running
? `● ${I18n.t('hamlib_active')} · ${s.clients || 0} ${clientWord}`
: `${I18n.t('hamlib_disabled')} `;
if (isAdmin) {
return `
${running}
`;
}
return `
${s.port} — ${_esc(s.label || '')}
${running}
`;
}).join('');
}
function _esc(s) {
return String(s).replace(/[&<>"']/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
}
async function save() {
// The panel hides this button for non-admins, but the backend enforces
// it anyway (role != admin -> 403) — this is just a local guard against
// an accidental call before the DOM has re-rendered.
if (window.AppState?.role !== 'admin') return;
const msg = document.getElementById('hamlib-msg');
const rows = document.querySelectorAll('#hamlib-slots [data-slot]');
const bySlot = {};
rows.forEach(el => {
const i = el.dataset.slot;
bySlot[i] = bySlot[i] || {};
if (el.classList.contains('hamlib-enabled')) bySlot[i].enabled = el.checked;
if (el.classList.contains('hamlib-port')) bySlot[i].port = parseInt(el.value) || 0;
if (el.classList.contains('hamlib-label')) bySlot[i].label = el.value;
});
const servers = Object.keys(bySlot).sort((a, b) => a - b).map(k => bySlot[k]);
if (msg) msg.textContent = I18n.t('hamlib_saving');
try {
const r = await fetch('/api/hamlib/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ servers }),
});
const d = await r.json();
if (msg) msg.textContent = d.message || (d.ok ? I18n.t('settings_saved_short') : (d.error || I18n.t('status_error_generic')));
await load();
} catch (e) {
if (msg) msg.textContent = I18n.t('settings_save_error_plain');
}
}
window.HamlibUI = { load, save };
})();