Enhance ISO build process and documentation for Archipelago
- Updated BUILD-GUIDE.md to clarify instructions for building the Archipelago Auto-Installer ISO, emphasizing the recommended method of building directly on the target server. - Added auto-installation of missing dependencies (xorriso, podman) when running the build script with sudo. - Enhanced the build-auto-installer-iso.sh script to capture container images from the live server, ensuring the ISO includes the same set of applications as the dev server. - Revised deployment documentation to stress the importance of building the Rust backend on the Linux dev server and included new instructions for capturing system-level changes for ISO builds. - Improved UI components and added new bundled applications (BTCPay Server, Mempool Explorer, Nostr Relay, Strfry Relay, Tailscale) to enhance user experience.
This commit is contained in:
+270
-264
@@ -225,6 +225,13 @@
|
||||
.animate-ping {
|
||||
animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
|
||||
}
|
||||
|
||||
.modal-tab { transition: all 0.2s ease; }
|
||||
.modal-tab.active { background: rgba(255,255,255,0.2); color: white; }
|
||||
.modal-tab:not(.active) { color: rgba(255,255,255,0.6); }
|
||||
.modal-tab:not(.active):hover { color: rgba(255,255,255,0.9); }
|
||||
.tab-panel { display: none; }
|
||||
.tab-panel.active { display: block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -234,295 +241,260 @@
|
||||
<div class="overlay"></div>
|
||||
|
||||
<div class="container">
|
||||
<!-- Header - Glass card with logo top left -->
|
||||
<!-- Header - Glass card with logo and Settings button top-right -->
|
||||
<div class="glass-card p-6 mb-6">
|
||||
<div class="flex items-start gap-4">
|
||||
<!-- Logo - Top Left -->
|
||||
<div class="flex-shrink-0">
|
||||
<div class="logo-gradient-border">
|
||||
<img
|
||||
src="/assets/img/app-icons/lnd.svg"
|
||||
alt="LND"
|
||||
class="w-16 h-16"
|
||||
style="object-fit: contain; padding: 8px;"
|
||||
/>
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="flex items-start gap-4 flex-1 min-w-0">
|
||||
<div class="flex-shrink-0">
|
||||
<div class="logo-gradient-border">
|
||||
<img
|
||||
src="/assets/img/app-icons/lnd.svg"
|
||||
alt="LND"
|
||||
class="w-16 h-16"
|
||||
style="object-fit: contain; padding: 8px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<h1 class="text-3xl font-bold text-white mb-2">LND</h1>
|
||||
<p class="text-white/70">Lightning Network Daemon for instant Bitcoin payments</p>
|
||||
<p class="text-sm text-white/60 mt-2" id="headerNetwork">—</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Title and Description -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<h1 class="text-3xl font-bold text-white mb-2">LND</h1>
|
||||
<p class="text-white/70">Lightning Network Daemon for instant Bitcoin payments</p>
|
||||
<p class="text-sm text-white/60 mt-2">Regtest mode - Development environment</p>
|
||||
</div>
|
||||
<button
|
||||
onclick="openSettings()"
|
||||
class="flex-shrink-0 flex items-center gap-2 px-4 py-2.5 glass-button rounded-lg text-sm font-medium"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 2.31.903 2.31.903a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.903 2.31-.903 2.31a1.724 1.724 0 002.572 1.065c.426 1.756 2.924 1.756 3.35 0a1.724 1.724 0 002.573-1.066c1.543.94 2.31-.903 2.31-.903a1.724 1.724 0 001.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.903-2.31.903-2.31a1.724 1.724 0 00-2.572-1.065z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
Settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Summary strip -->
|
||||
<div class="glass-card p-6 mb-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div class="info-card flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="relative">
|
||||
<div class="w-3 h-3 rounded-full bg-green-400"></div>
|
||||
<div class="absolute inset-0 w-3 h-3 rounded-full bg-green-400 animate-ping opacity-75"></div>
|
||||
<div class="w-3 h-3 rounded-full bg-green-400" id="statusDot"></div>
|
||||
<div class="absolute inset-0 w-3 h-3 rounded-full bg-green-400 animate-ping opacity-75" id="statusPing" style="display:none"></div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-white">Node Status</p>
|
||||
<p class="text-xs text-white/60">Running</p>
|
||||
<p class="text-xs text-white/60" id="summaryNodeStatus">—</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="relative">
|
||||
<span class="text-2xl text-orange-500 font-bold">⚡</span>
|
||||
</div>
|
||||
<span class="text-2xl text-orange-500 font-bold">⚡</span>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-white">Channels</p>
|
||||
<p class="text-xs text-orange-500 font-medium" id="channelCount">0</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="relative">
|
||||
<div class="w-3 h-3 rounded-full bg-green-400"></div>
|
||||
<div class="absolute inset-0 w-3 h-3 rounded-full bg-green-400 animate-ping opacity-75"></div>
|
||||
<div class="w-3 h-3 rounded-full bg-green-400" id="restDot"></div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-white">REST API</p>
|
||||
<p class="text-xs text-white/60">Active</p>
|
||||
<p class="text-xs text-white/60" id="summaryRestStatus">—</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onclick="openSettings()"
|
||||
class="px-3 py-1.5 glass-button rounded text-xs font-medium"
|
||||
>
|
||||
Settings
|
||||
</button>
|
||||
<button onclick="openSettings(); setSettingsTab('rest');" class="px-3 py-1.5 glass-button rounded text-xs font-medium">Settings</button>
|
||||
</div>
|
||||
|
||||
<div class="info-card flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="relative">
|
||||
<div class="w-3 h-3 rounded-full bg-green-400"></div>
|
||||
<div class="absolute inset-0 w-3 h-3 rounded-full bg-green-400 animate-ping opacity-75"></div>
|
||||
<div class="w-3 h-3 rounded-full bg-green-400" id="grpcDot"></div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-white">gRPC</p>
|
||||
<p class="text-xs text-white/60">Connected</p>
|
||||
<p class="text-xs text-white/60" id="summaryGrpcStatus">—</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onclick="openLogs()"
|
||||
class="px-3 py-1.5 glass-button rounded text-xs font-medium"
|
||||
>
|
||||
Logs
|
||||
</button>
|
||||
<button onclick="openSettings(); setSettingsTab('logs');" class="px-3 py-1.5 glass-button rounded text-xs font-medium">Logs</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
|
||||
<div class="glass-card p-6">
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h2 class="text-xl font-semibold text-white mb-2">Node Status</h2>
|
||||
<p class="text-white/70 text-sm mb-4">Lightning node information</p>
|
||||
</div>
|
||||
<!-- Main content: placeholder for wallet (balance, Receive, Send, recent activity) -->
|
||||
<div class="glass-card p-6 mb-8">
|
||||
<h2 class="text-xl font-semibold text-white mb-4">Wallet</h2>
|
||||
<p class="text-white/60 text-sm mb-4">Balance, Receive, and Send will appear here when connected to your node.</p>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
||||
<div class="p-4 bg-white/5 rounded-lg">
|
||||
<p class="text-xs text-white/50 uppercase tracking-wide mb-1">Spendable</p>
|
||||
<p class="text-lg font-semibold text-white" id="balanceSpendable">—</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||
</svg>
|
||||
<span class="text-white/80 text-sm">Node Status</span>
|
||||
</div>
|
||||
<span class="text-green-400 text-sm font-medium">Running</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7" />
|
||||
</svg>
|
||||
<span class="text-white/80 text-sm">Network</span>
|
||||
</div>
|
||||
<span class="text-white/60 text-sm">Regtest</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
<span class="text-white/80 text-sm">Version</span>
|
||||
</div>
|
||||
<span class="text-white/60 text-sm">0.17.4-beta</span>
|
||||
</div>
|
||||
<div class="p-4 bg-white/5 rounded-lg">
|
||||
<p class="text-xs text-white/50 uppercase tracking-wide mb-1">Lightning</p>
|
||||
<p class="text-lg font-semibold text-white" id="balanceLightning">—</p>
|
||||
</div>
|
||||
<div class="p-4 bg-white/5 rounded-lg">
|
||||
<p class="text-xs text-white/50 uppercase tracking-wide mb-1">Total</p>
|
||||
<p class="text-lg font-semibold text-white" id="balanceTotal">—</p>
|
||||
</div>
|
||||
|
||||
<button class="mt-4 w-full info-card-button text-sm font-medium" onclick="openSettings()">
|
||||
Node Settings
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="glass-card p-6">
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h2 class="text-xl font-semibold text-white mb-2">REST API</h2>
|
||||
<p class="text-white/70 text-sm mb-4">HTTP REST API access</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
|
||||
</svg>
|
||||
<span class="text-white/80 text-sm">REST Endpoint</span>
|
||||
</div>
|
||||
<span class="text-white/60 text-sm font-mono">localhost:8080</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||
</svg>
|
||||
<span class="text-white/80 text-sm">API Status</span>
|
||||
</div>
|
||||
<span class="text-green-400 text-sm font-medium">Active</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span class="text-white/80 text-sm">API Version</span>
|
||||
</div>
|
||||
<span class="text-white/60 text-sm">v1</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="mt-4 w-full info-card-button text-sm font-medium" onclick="copyRESTInfo()">
|
||||
Copy REST Info
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="glass-card p-6">
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h2 class="text-xl font-semibold text-white mb-2">gRPC Connection</h2>
|
||||
<p class="text-white/70 text-sm mb-4">High-performance gRPC API</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
|
||||
</svg>
|
||||
<span class="text-white/80 text-sm">gRPC Host</span>
|
||||
</div>
|
||||
<span class="text-white/60 text-sm font-mono">localhost:10009</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||
</svg>
|
||||
<span class="text-white/80 text-sm">gRPC Status</span>
|
||||
</div>
|
||||
<span class="text-green-400 text-sm font-medium">Connected</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" />
|
||||
</svg>
|
||||
<span class="text-white/80 text-sm">P2P Port</span>
|
||||
</div>
|
||||
<span class="text-white/60 text-sm font-mono">9735</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="mt-4 w-full info-card-button text-sm font-medium" onclick="openLogs()">
|
||||
View Logs
|
||||
</button>
|
||||
<div class="flex gap-4">
|
||||
<button class="px-6 py-3 glass-button rounded-lg font-medium text-white/90 hover:text-white transition-colors" disabled>Receive</button>
|
||||
<button class="px-6 py-3 glass-button rounded-lg font-medium text-white/90 hover:text-white transition-colors" disabled>Send</button>
|
||||
</div>
|
||||
<p class="text-white/50 text-xs mt-4">Recent activity will be listed here.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabbed Settings Modal -->
|
||||
<div class="modal hidden fixed inset-0 bg-black/80 backdrop-blur-sm z-50 items-center justify-center p-4" id="settingsModal">
|
||||
<div class="glass-card p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-2xl font-bold text-white">Node Settings</h2>
|
||||
<div class="glass-card p-6 max-w-2xl w-full max-h-[85vh] overflow-hidden flex flex-col">
|
||||
<div class="flex justify-between items-center mb-4 flex-shrink-0">
|
||||
<h2 class="text-2xl font-bold text-white">Settings</h2>
|
||||
<button onclick="closeSettings()" class="glass-button px-3 py-2 rounded-lg text-xl font-medium">×</button>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="p-3 bg-white/5 rounded-lg">
|
||||
<div class="font-semibold text-white mb-1">Network Mode</div>
|
||||
<div class="text-white/70 text-sm">Regtest (Development)</div>
|
||||
</div>
|
||||
<div class="p-3 bg-white/5 rounded-lg">
|
||||
<div class="font-semibold text-white mb-1">Bitcoin Backend</div>
|
||||
<div class="text-white/70 text-sm">Connected to bitcoin:18443</div>
|
||||
</div>
|
||||
<div class="p-3 bg-white/5 rounded-lg">
|
||||
<div class="font-semibold text-white mb-1">ZMQ Subscriptions</div>
|
||||
<div class="text-white/70 text-sm">Blocks & Transactions monitored</div>
|
||||
</div>
|
||||
<div class="p-3 bg-white/5 rounded-lg">
|
||||
<div class="font-semibold text-white mb-1">Seed Backup</div>
|
||||
<div class="text-white/70 text-sm">Disabled (Development mode)</div>
|
||||
</div>
|
||||
<div class="flex gap-2 mb-4 flex-shrink-0 glass-card p-2 rounded-lg">
|
||||
<button class="modal-tab flex-1 px-4 py-2 rounded-lg text-sm font-medium active" data-tab="node">Node Status</button>
|
||||
<button class="modal-tab flex-1 px-4 py-2 rounded-lg text-sm font-medium" data-tab="rest">REST API</button>
|
||||
<button class="modal-tab flex-1 px-4 py-2 rounded-lg text-sm font-medium" data-tab="grpc">gRPC</button>
|
||||
<button class="modal-tab flex-1 px-4 py-2 rounded-lg text-sm font-medium" data-tab="logs">Logs</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal hidden fixed inset-0 bg-black/80 backdrop-blur-sm z-50 items-center justify-center p-4" id="logsModal">
|
||||
<div class="glass-card p-6 max-w-4xl w-full max-h-[80vh] overflow-y-auto">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-2xl font-bold text-white">Node Logs</h2>
|
||||
<button onclick="closeLogs()" class="glass-button px-3 py-2 rounded-lg text-xl font-medium">×</button>
|
||||
</div>
|
||||
<div class="bg-black/40 rounded-lg p-4 font-mono text-xs text-white/80 whitespace-pre-wrap break-all" id="logsContent">
|
||||
Loading logs...
|
||||
<div class="overflow-y-auto flex-1 min-h-0 space-y-4">
|
||||
<!-- Node Status tab -->
|
||||
<div id="panel-node" class="tab-panel active">
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-lg font-semibold text-white mb-1">Node Status</h3>
|
||||
<p class="text-white/70 text-sm">Lightning node information</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<span class="text-white/80 text-sm">Node Status</span>
|
||||
<span class="text-green-400 text-sm font-medium" id="modalNodeStatus">—</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<span class="text-white/80 text-sm">Network</span>
|
||||
<span class="text-white/60 text-sm" id="modalNetwork">—</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<span class="text-white/80 text-sm">Version</span>
|
||||
<span class="text-white/60 text-sm" id="modalVersion">—</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 space-y-3">
|
||||
<div class="p-3 bg-white/5 rounded-lg">
|
||||
<div class="font-semibold text-white mb-1">Network Mode</div>
|
||||
<div class="text-white/70 text-sm" id="modalNetworkMode">—</div>
|
||||
</div>
|
||||
<div class="p-3 bg-white/5 rounded-lg">
|
||||
<div class="font-semibold text-white mb-1">Bitcoin Backend</div>
|
||||
<div class="text-white/70 text-sm" id="modalBitcoinBackend">—</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- REST API tab -->
|
||||
<div id="panel-rest" class="tab-panel">
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01" /></svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-lg font-semibold text-white mb-1">REST API</h3>
|
||||
<p class="text-white/70 text-sm">HTTP REST API access</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<span class="text-white/80 text-sm">REST Endpoint</span>
|
||||
<span class="text-white/60 text-sm font-mono" id="modalRestEndpoint">—</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<span class="text-white/80 text-sm">API Status</span>
|
||||
<span class="text-green-400 text-sm font-medium" id="modalRestStatus">—</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<span class="text-white/80 text-sm">API Version</span>
|
||||
<span class="text-white/60 text-sm" id="modalRestVersion">v1</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="mt-4 w-full info-card-button text-sm font-medium py-3 rounded-lg" onclick="copyRESTInfo()">Copy REST Info</button>
|
||||
</div>
|
||||
<!-- gRPC tab -->
|
||||
<div id="panel-grpc" class="tab-panel">
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01" /></svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-lg font-semibold text-white mb-1">gRPC Connection</h3>
|
||||
<p class="text-white/70 text-sm">High-performance gRPC API</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<span class="text-white/80 text-sm">gRPC Host</span>
|
||||
<span class="text-white/60 text-sm font-mono" id="modalGrpcHost">—</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<span class="text-white/80 text-sm">gRPC Status</span>
|
||||
<span class="text-green-400 text-sm font-medium" id="modalGrpcStatus">—</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
||||
<span class="text-white/80 text-sm">P2P Port</span>
|
||||
<span class="text-white/60 text-sm font-mono">9735</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Logs tab -->
|
||||
<div id="panel-logs" class="tab-panel">
|
||||
<div class="flex justify-between items-center mb-3">
|
||||
<h3 class="text-lg font-semibold text-white">Node Logs</h3>
|
||||
<button onclick="loadLogs()" class="px-3 py-1.5 glass-button rounded text-xs font-medium">Refresh</button>
|
||||
</div>
|
||||
<div class="bg-black/40 rounded-lg p-4 font-mono text-xs text-white/80 whitespace-pre-wrap break-all min-h-[200px]" id="logsContent">Loading logs...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function copyRESTInfo() {
|
||||
const info = `REST API: http://localhost:8080\nAPI Version: v1`;
|
||||
navigator.clipboard.writeText(info).then(() => {
|
||||
alert('REST info copied to clipboard!');
|
||||
const REST_PORT = 8080;
|
||||
const GRPC_PORT = 10009;
|
||||
const P2P_PORT = 9735;
|
||||
const host = window.location.hostname;
|
||||
|
||||
function getBackendUrl() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
return params.get('backend') || '';
|
||||
}
|
||||
|
||||
function setSettingsTab(tabId) {
|
||||
document.querySelectorAll('.modal-tab').forEach(btn => {
|
||||
btn.classList.toggle('active', btn.getAttribute('data-tab') === tabId);
|
||||
});
|
||||
document.querySelectorAll('.tab-panel').forEach(panel => {
|
||||
panel.classList.toggle('active', panel.id === 'panel-' + tabId);
|
||||
});
|
||||
if (tabId === 'logs') loadLogs();
|
||||
}
|
||||
|
||||
document.querySelectorAll('.modal-tab').forEach(btn => {
|
||||
btn.addEventListener('click', () => setSettingsTab(btn.getAttribute('data-tab')));
|
||||
});
|
||||
|
||||
function copyRESTInfo() {
|
||||
const endpoint = host + ':' + REST_PORT;
|
||||
const info = 'REST API: http://' + endpoint + '\nAPI Version: v1';
|
||||
navigator.clipboard.writeText(info).then(() => alert('REST info copied to clipboard!'));
|
||||
}
|
||||
|
||||
function openSettings() {
|
||||
@@ -535,55 +507,89 @@
|
||||
document.getElementById('settingsModal').classList.remove('flex');
|
||||
}
|
||||
|
||||
function openLogs() {
|
||||
document.getElementById('logsModal').classList.remove('hidden');
|
||||
document.getElementById('logsModal').classList.add('flex');
|
||||
loadLogs();
|
||||
function applyLiveData(data) {
|
||||
if (data.getinfo) {
|
||||
const g = data.getinfo;
|
||||
const status = g.synced_to_chain ? 'Running' : 'Waiting for chain…';
|
||||
const network = (g.chains && g.chains[0]) ? g.chains[0].network || '—' : '—';
|
||||
const version = g.version || '—';
|
||||
setText('headerNetwork', 'Network: ' + network);
|
||||
setText('summaryNodeStatus', status);
|
||||
setText('modalNodeStatus', status);
|
||||
setText('modalNetwork', network);
|
||||
setText('modalVersion', version);
|
||||
setText('modalNetworkMode', network);
|
||||
setText('modalBitcoinBackend', '—');
|
||||
document.getElementById('statusPing').style.display = g.synced_to_chain ? 'block' : 'none';
|
||||
}
|
||||
if (data.channelCount !== undefined) {
|
||||
setText('channelCount', String(data.channelCount));
|
||||
}
|
||||
setText('modalRestEndpoint', host + ':' + REST_PORT);
|
||||
setText('modalRestStatus', data.restReachable ? 'Active' : '—');
|
||||
setText('summaryRestStatus', data.restReachable ? 'Active' : '—');
|
||||
setText('modalGrpcHost', host + ':' + GRPC_PORT);
|
||||
setText('modalGrpcStatus', data.grpcReachable ? 'Connected' : '—');
|
||||
setText('summaryGrpcStatus', data.grpcReachable ? 'Connected' : '—');
|
||||
}
|
||||
|
||||
function closeLogs() {
|
||||
document.getElementById('logsModal').classList.add('hidden');
|
||||
document.getElementById('logsModal').classList.remove('flex');
|
||||
function setText(id, text) {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.textContent = text;
|
||||
}
|
||||
|
||||
function loadLogs() {
|
||||
async function loadLogs() {
|
||||
const logsContent = document.getElementById('logsContent');
|
||||
logsContent.textContent = `LND version 0.17.4-beta commit=v0.17.4-beta
|
||||
|
||||
Attempting automatic RPC configuration to bitcoind
|
||||
Automatically obtained bitcoind's RPC credentials
|
||||
2024-01-15 12:00:00.000 [INF] LTND: Version: 0.17.4-beta commit=v0.17.4-beta
|
||||
2024-01-15 12:00:00.100 [INF] LTND: Active chain: Bitcoin (network=regtest)
|
||||
2024-01-15 12:00:00.200 [INF] CHDB: Checking for schema update
|
||||
2024-01-15 12:00:00.300 [INF] LTND: Primary chain is set to: bitcoin
|
||||
2024-01-15 12:00:01.000 [INF] RPCS: RPC server listening on 0.0.0.0:10009
|
||||
2024-01-15 12:00:01.100 [INF] RPCS: REST proxy started at 0.0.0.0:8080
|
||||
2024-01-15 12:00:01.200 [INF] LNWL: Opened wallet
|
||||
2024-01-15 12:00:02.000 [INF] LTND: Waiting for chain backend to finish sync`;
|
||||
const backendUrl = getBackendUrl();
|
||||
if (backendUrl) {
|
||||
logsContent.textContent = 'Loading logs...';
|
||||
try {
|
||||
const res = await fetch(backendUrl + '/api/container/logs?app_id=lnd&lines=200');
|
||||
if (!res.ok) throw new Error(res.statusText);
|
||||
const json = await res.json();
|
||||
const lines = json.result || json.logs || (Array.isArray(json) ? json : []);
|
||||
logsContent.textContent = Array.isArray(lines) ? lines.join('\n') : String(lines);
|
||||
} catch (e) {
|
||||
logsContent.textContent = 'Could not load logs: ' + e.message;
|
||||
}
|
||||
} else {
|
||||
logsContent.textContent = 'Open this app with ?backend=http://HOST:5678 to load logs from the server.';
|
||||
}
|
||||
}
|
||||
|
||||
let channelCount = 0;
|
||||
setInterval(() => {
|
||||
if (Math.random() > 0.9) {
|
||||
channelCount = Math.floor(Math.random() * 5);
|
||||
document.getElementById('channelCount').textContent = channelCount;
|
||||
async function fetchLiveData() {
|
||||
const backendUrl = getBackendUrl();
|
||||
const data = { channelCount: 0, restReachable: false, grpcReachable: false };
|
||||
if (backendUrl) {
|
||||
try {
|
||||
const getinfoRes = await fetch(backendUrl + '/proxy/lnd/v1/getinfo');
|
||||
if (getinfoRes.ok) {
|
||||
data.getinfo = await getinfoRes.json();
|
||||
data.restReachable = true;
|
||||
}
|
||||
} catch (_) {}
|
||||
try {
|
||||
const chRes = await fetch(backendUrl + '/proxy/lnd/v1/channels');
|
||||
if (chRes.ok) {
|
||||
const ch = await chRes.json();
|
||||
data.channelCount = (ch.channels && ch.channels.length) || 0;
|
||||
}
|
||||
} catch (_) {}
|
||||
data.grpcReachable = data.restReachable;
|
||||
}
|
||||
}, 10000);
|
||||
applyLiveData(data);
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
closeSettings();
|
||||
closeLogs();
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
fetchLiveData();
|
||||
});
|
||||
|
||||
document.querySelectorAll('.modal').forEach(modal => {
|
||||
modal.addEventListener('click', (e) => {
|
||||
if (e.target === modal) {
|
||||
closeSettings();
|
||||
closeLogs();
|
||||
}
|
||||
});
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') closeSettings();
|
||||
});
|
||||
|
||||
document.getElementById('settingsModal').addEventListener('click', (e) => {
|
||||
if (e.target.id === 'settingsModal') closeSettings();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user