fix(meshcore): BLE scan feedback and cancel-during-connecting

- Scan button shows 'Scanning...' and disables during fetch; shows
  'No devices found' or 'Scan failed' on empty/error result; auto-
  selects device if only one is returned
- Disconnect button now enabled during 'connecting' state so users
  can cancel a stuck connection and retry with a different device

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
James Smith
2026-05-13 20:42:25 +01:00
parent 4658be799a
commit 1f573ee6ed
+20 -6
View File
@@ -57,7 +57,7 @@ const MeshCore = (function () {
_connected = state === 'connected'; _connected = state === 'connected';
if (connectBtn) connectBtn.disabled = state === 'connecting' || _connected; if (connectBtn) connectBtn.disabled = state === 'connecting' || _connected;
if (disconnectBtn) disconnectBtn.disabled = !_connected; if (disconnectBtn) disconnectBtn.disabled = state !== 'connecting' && !_connected;
if (_connected && !_eventSource) _startSSE(); if (_connected && !_eventSource) _startSSE();
if (!_connected && _eventSource) { _eventSource.close(); _eventSource = null; } if (!_connected && _eventSource) { _eventSource.close(); _eventSource = null; }
@@ -133,19 +133,33 @@ const MeshCore = (function () {
} }
async function scanBle() { async function scanBle() {
const btn = document.querySelector('[onclick="MeshCore.scanBle()"]');
const sel = document.getElementById('meshcoreBleSelect');
if (btn) { btn.textContent = 'Scanning…'; btn.disabled = true; }
if (sel) sel.innerHTML = '<option value="">Scanning…</option>';
try { try {
const r = await fetch('/meshcore/ble/scan'); const r = await fetch('/meshcore/ble/scan');
const d = await r.json(); const d = await r.json();
const sel = document.getElementById('meshcoreBleSelect');
if (!sel) return; if (!sel) return;
sel.innerHTML = '<option value="">Select device</option>'; const devices = d.devices || [];
(d.devices || []).forEach(dev => { if (!devices.length) {
sel.innerHTML = '<option value="">No devices found</option>';
return;
}
sel.innerHTML = '<option value="">Select device…</option>';
devices.forEach(dev => {
const o = document.createElement('option'); const o = document.createElement('option');
o.value = dev.address; o.value = dev.address;
o.textContent = `${dev.name || 'Unknown'} (${dev.address}) RSSI ${dev.rssi}`; o.textContent = `${dev.name || 'Unknown'} (${dev.address})${dev.rssi ? ' · ' + dev.rssi + ' dBm' : ''}`;
sel.appendChild(o); sel.appendChild(o);
}); });
} catch (e) { console.error('BLE scan failed:', e); } if (devices.length === 1) sel.value = devices[0].address;
} catch (e) {
if (sel) sel.innerHTML = '<option value="">Scan failed — retry</option>';
console.error('BLE scan failed:', e);
} finally {
if (btn) { btn.textContent = 'Scan'; btn.disabled = false; }
}
} }
// ── SSE Stream ───────────────────────────────────────────────────────── // ── SSE Stream ─────────────────────────────────────────────────────────