feat(lnd-ui): on-chain + Lightning balance cards in the summary strip

Fetched from /proxy/lnd/v1/balance/{blockchain,channels}; the cards stay
hidden when the endpoints are unavailable so older deployments are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dorian 2026-07-14 03:39:56 +01:00
parent 890364331e
commit 5c2622f39a

View File

@ -196,6 +196,20 @@
<p class="text-sm font-medium text-orange" id="channelCount">0</p>
</div>
</div>
<div class="info-card flex items-center gap-3" id="onchainBalanceCard" style="display:none">
<span style="font-size:1.5rem;color:#f7931a;font-weight:700">&#8383;</span>
<div>
<p class="text-xs text-white-60 mb-1">On-chain</p>
<p class="text-sm font-medium text-white" id="onchainBalance">&mdash;</p>
</div>
</div>
<div class="info-card flex items-center gap-3" id="channelBalanceCard" style="display:none">
<span style="font-size:1.5rem;color:#4ade80;font-weight:700">&#9737;</span>
<div>
<p class="text-xs text-white-60 mb-1">Lightning Balance</p>
<p class="text-sm font-medium text-white" id="channelBalance">&mdash;</p>
</div>
</div>
<div class="info-card flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="status-dot-sm bg-green" id="restDot"></div>
@ -500,6 +514,12 @@
if (el) el.textContent = text;
}
function formatSats(sats) {
if (sats >= 1_000_000) return (sats / 1_000_000).toFixed(2).replace(/\.00$/, '') + 'M sats';
if (sats >= 1_000) return (sats / 1_000).toFixed(1).replace(/\.0$/, '') + 'k sats';
return sats.toLocaleString() + ' sats';
}
async function loadLogs() {
const logsContent = document.getElementById('logsContent');
const backendUrl = getBackendUrl();
@ -532,6 +552,29 @@
data.channelCount = (ch.channels && ch.channels.length) || 0;
}
} catch (_) {}
// Balances — cards stay hidden when the endpoints are unavailable.
try {
const wRes = await fetch(backendUrl + '/proxy/lnd/v1/balance/blockchain', { credentials: 'include' });
if (wRes.ok) {
const w = await wRes.json();
const sats = Number(w.confirmed_balance ?? w.total_balance ?? 0);
if (!isNaN(sats)) {
setText('onchainBalance', formatSats(sats));
document.getElementById('onchainBalanceCard').style.display = '';
}
}
} catch (_) {}
try {
const cRes = await fetch(backendUrl + '/proxy/lnd/v1/balance/channels', { credentials: 'include' });
if (cRes.ok) {
const c = await cRes.json();
const sats = Number((c.local_balance && c.local_balance.sat) ?? c.balance ?? 0);
if (!isNaN(sats)) {
setText('channelBalance', formatSats(sats));
document.getElementById('channelBalanceCard').style.display = '';
}
}
} catch (_) {}
data.grpcReachable = data.restReachable;
applyLiveData(data);
}