Update web/index.html

Add Fulcrum status dashboard
This commit is contained in:
2026-08-08 14:37:32 +00:00
parent 5b37cefcc8
commit a79b2ea1f6
+232 -35
View File
@@ -1,60 +1,257 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Munin Bitcoin</title> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Munin Bitcoin</title>
<style>
:root {
color-scheme: dark;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: #111827;
color: #f9fafb;
}
body {
margin: 0;
min-height: 100vh;
background: #111827;
}
main {
max-width: 760px;
margin: 0 auto;
padding: 48px 24px;
}
h1 {
margin: 0 0 8px;
font-size: 32px;
}
.subtitle {
margin: 0 0 32px;
color: #9ca3af;
}
.card {
background: #1f2937;
border: 1px solid #374151;
border-radius: 12px;
padding: 24px;
margin-bottom: 16px;
}
.row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 14px 0;
border-bottom: 1px solid #374151;
}
.row:last-child {
border-bottom: 0;
padding-bottom: 0;
}
.row:first-child {
padding-top: 0;
}
.label {
color: #d1d5db;
}
.value {
text-align: right;
word-break: break-word;
}
.status {
display: inline-flex;
align-items: center;
gap: 8px;
font-weight: 600;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #6b7280;
}
.status.connected .dot,
.status.running .dot {
background: #22c55e;
}
.status.disconnected .dot {
background: #ef4444;
}
.muted {
color: #9ca3af;
}
.error {
color: #fca5a5;
}
button {
margin-top: 16px;
padding: 10px 16px;
border: 0;
border-radius: 8px;
background: #374151;
color: #f9fafb;
cursor: pointer;
font: inherit;
}
button:hover {
background: #4b5563;
}
</style>
</head> </head>
<body> <body>
<main>
<h1>Munin Bitcoin</h1>
<p class="subtitle">Bitcoin watch-only wallet monitoring and label management</p>
<h1>Munin Bitcoin</h1> <section class="card">
<div class="row">
<span class="label">Munin service</span>
<span id="service-status" class="status">
<span class="dot"></span>
<span>Checking...</span>
</span>
</div>
<h2>Service</h2> <div class="row">
<p id="service">Loading...</p> <span class="label">Fulcrum (Electrum server)</span>
<span id="fulcrum-status" class="status">
<span class="dot"></span>
<span>Checking...</span>
</span>
</div>
<h2>Bitcoin Node</h2> <div class="row">
<p id="bitcoinNode">Loading...</p> <span class="label">Fulcrum endpoint</span>
<span id="fulcrum-url" class="value muted">Checking...</span>
</div>
</section>
<h2>Wallet</h2> <section class="card">
<p id="wallet">Loading...</p> <div class="row">
<span class="label">Wallet</span>
<span id="wallet" class="value muted">Not configured</span>
</div>
<h2>Statistics</h2> <div class="row">
<p>Labels: <span id="labels">0</span></p> <span class="label">Labels</span>
<p>Transactions: <span id="transactions">0</span></p> <span id="labels" class="value">0</span>
</div>
<h2>Last scan</h2> <div class="row">
<p id="lastScan">Loading...</p> <span class="label">Transactions</span>
<span id="transactions" class="value">0</span>
</div>
<div class="row">
<span class="label">Last scan</span>
<span id="last-scan" class="value muted">Never</span>
</div>
<script> <button type="button" onclick="loadStatus()">Refresh status</button>
fetch('/api/status')
.then(response => response.json())
.then(status => {
document.getElementById('service').textContent =
'🟢 ' + status.service;
document.getElementById('bitcoinNode').textContent = <p id="error" class="error"></p>
status.bitcoinNode; </section>
</main>
<script>
function setStatus(element, text, state) {
element.className = `status ${state}`;
element.querySelector('span:last-child').textContent = text;
}
async function loadStatus() {
const errorElement = document.getElementById('error');
errorElement.textContent = '';
try {
const response = await fetch('/api/status');
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const status = await response.json();
setStatus(
document.getElementById('service-status'),
status.service === 'running' ? 'Running' : 'Not running',
status.service === 'running' ? 'running' : 'disconnected',
);
const fulcrum = status.fulcrum || {};
if (fulcrum.connected) {
setStatus(
document.getElementById('fulcrum-status'),
'Connected',
'connected',
);
} else if (fulcrum.configured) {
setStatus(
document.getElementById('fulcrum-status'),
'Not connected',
'disconnected',
);
} else {
setStatus(
document.getElementById('fulcrum-status'),
'Not configured',
'disconnected',
);
}
document.getElementById('fulcrum-url').textContent =
fulcrum.url || 'Not configured';
document.getElementById('wallet').textContent = document.getElementById('wallet').textContent =
status.wallet; status.wallet || 'Not configured';
document.getElementById('labels').textContent = document.getElementById('labels').textContent =
status.labels; status.labels ?? 0;
document.getElementById('transactions').textContent = document.getElementById('transactions').textContent =
status.transactions; status.transactions ?? 0;
document.getElementById('lastScan').textContent = document.getElementById('last-scan').textContent =
status.lastScan; status.lastScan || 'Never';
}) } catch (error) {
.catch(error => { setStatus(
document.getElementById('service').textContent = document.getElementById('service-status'),
'🔴 Error loading status'; 'Unavailable',
'disconnected',
);
console.error(error); setStatus(
}); document.getElementById('fulcrum-status'),
</script> 'Unavailable',
'disconnected',
);
document.getElementById('fulcrum-url').textContent = 'Unavailable';
errorElement.textContent = 'Unable to retrieve service status.';
}
}
loadStatus();
setInterval(loadStatus, 10000);
</script>
</body> </body>
</html> </html>