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
+229 -32
View File
@@ -2,59 +2,256 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<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>
<body>
<main>
<h1>Munin Bitcoin</h1>
<p class="subtitle">Bitcoin watch-only wallet monitoring and label management</p>
<h2>Service</h2>
<p id="service">Loading...</p>
<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>Bitcoin Node</h2>
<p id="bitcoinNode">Loading...</p>
<div class="row">
<span class="label">Fulcrum (Electrum server)</span>
<span id="fulcrum-status" class="status">
<span class="dot"></span>
<span>Checking...</span>
</span>
</div>
<h2>Wallet</h2>
<p id="wallet">Loading...</p>
<div class="row">
<span class="label">Fulcrum endpoint</span>
<span id="fulcrum-url" class="value muted">Checking...</span>
</div>
</section>
<h2>Statistics</h2>
<p>Labels: <span id="labels">0</span></p>
<p>Transactions: <span id="transactions">0</span></p>
<section class="card">
<div class="row">
<span class="label">Wallet</span>
<span id="wallet" class="value muted">Not configured</span>
</div>
<h2>Last scan</h2>
<p id="lastScan">Loading...</p>
<div class="row">
<span class="label">Labels</span>
<span id="labels" class="value">0</span>
</div>
<div class="row">
<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>
<button type="button" onclick="loadStatus()">Refresh status</button>
<p id="error" class="error"></p>
</section>
</main>
<script>
fetch('/api/status')
.then(response => response.json())
.then(status => {
document.getElementById('service').textContent =
'🟢 ' + status.service;
function setStatus(element, text, state) {
element.className = `status ${state}`;
element.querySelector('span:last-child').textContent = text;
}
document.getElementById('bitcoinNode').textContent =
status.bitcoinNode;
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 =
status.wallet;
status.wallet || 'Not configured';
document.getElementById('labels').textContent =
status.labels;
status.labels ?? 0;
document.getElementById('transactions').textContent =
status.transactions;
status.transactions ?? 0;
document.getElementById('lastScan').textContent =
status.lastScan;
})
.catch(error => {
document.getElementById('service').textContent =
'🔴 Error loading status';
document.getElementById('last-scan').textContent =
status.lastScan || 'Never';
} catch (error) {
setStatus(
document.getElementById('service-status'),
'Unavailable',
'disconnected',
);
console.error(error);
});
setStatus(
document.getElementById('fulcrum-status'),
'Unavailable',
'disconnected',
);
document.getElementById('fulcrum-url').textContent = 'Unavailable';
errorElement.textContent = 'Unable to retrieve service status.';
}
}
loadStatus();
setInterval(loadStatus, 10000);
</script>
</body>
</html>