Add node peers, blue banners, glowing diff ranges, fix back navigation
- Show Bitcoin Core peer count on block height card (hover for in/out) - BestSharePage disclaimers now use solid blue styling - Difficulty distribution ranges glow from warm peach to deep red - Back-to-dashboard buttons always navigate to dashboard instead of using browser history
This commit is contained in:
@@ -343,6 +343,20 @@ func (c *RPC) GetRawMempoolVerbose(ctx context.Context) (map[string]RawMempoolEn
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type NetworkInfo struct {
|
||||
Connections int `json:"connections"`
|
||||
ConnectionsIn int `json:"connections_in"`
|
||||
ConnectionsOut int `json:"connections_out"`
|
||||
}
|
||||
|
||||
func (c *RPC) GetNetworkInfo(ctx context.Context) (*NetworkInfo, error) {
|
||||
var out NetworkInfo
|
||||
if err := c.Call(ctx, "getnetworkinfo", nil, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
// IsRPCError checks if err is an rpcError with a specific code.
|
||||
func IsRPCError(err error, code int) bool {
|
||||
var rerr *rpcError
|
||||
|
||||
@@ -98,6 +98,11 @@ type Snapshot struct {
|
||||
HasLastZMQEvent bool `json:"has_last_zmq_event"`
|
||||
TipChangedAge float64 `json:"tip_changed_age"` // seconds since tip height last changed
|
||||
|
||||
// Bitcoin Core peer connections.
|
||||
PeerCount int `json:"peer_count"`
|
||||
PeersIn int `json:"peers_in"`
|
||||
PeersOut int `json:"peers_out"`
|
||||
|
||||
// Share counters: raw counts (1 submission = 1 share regardless of diff).
|
||||
// Session = since ckpool started; AllTime = persisted across restarts.
|
||||
SessionAccepted int64 `json:"session_accepted"`
|
||||
@@ -460,6 +465,13 @@ func (a *Aggregator) refresh(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- bitcoind: peer connections ---
|
||||
if ni, err := a.RPC.GetNetworkInfo(ctx); err == nil {
|
||||
next.PeerCount = ni.Connections
|
||||
next.PeersIn = ni.ConnectionsIn
|
||||
next.PeersOut = ni.ConnectionsOut
|
||||
}
|
||||
|
||||
// --- predicted difficulty adjustment ---
|
||||
// Fetch the timestamp of the first block in the current retarget
|
||||
// epoch (height - height%2016) once per epoch and cache it, then
|
||||
|
||||
@@ -399,15 +399,15 @@
|
||||
}
|
||||
.disclaimer {
|
||||
font-size: 0.82rem;
|
||||
color: var(--fg-dim);
|
||||
background: rgba(245, 196, 71, 0.08);
|
||||
border: 1px solid rgba(245, 196, 71, 0.25);
|
||||
color: rgb(160, 195, 240);
|
||||
background: rgb(20, 35, 60);
|
||||
border: 1px solid rgb(60, 100, 170);
|
||||
border-radius: 6px;
|
||||
padding: 0.5em 0.85em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.disclaimer strong {
|
||||
color: var(--fg);
|
||||
color: rgb(200, 220, 250);
|
||||
}
|
||||
.head {
|
||||
display: flex;
|
||||
|
||||
@@ -208,7 +208,12 @@
|
||||
<div class="card height-card" class:new-block={heightFlash}>
|
||||
<div class="stat-label">Block height</div>
|
||||
<div class="stat-value">{height ? height.toLocaleString() : "—"}</div>
|
||||
<div class="stat-sub">{data.chain?.chain === "main" ? "mainnet" : data.chain?.chain ?? "—"}</div>
|
||||
<div class="stat-sub">
|
||||
{data.chain?.chain === "main" ? "mainnet" : data.chain?.chain ?? "—"}
|
||||
{#if data.peer_count > 0}
|
||||
<span class="peers" title="{data.peers_in} inbound · {data.peers_out} outbound"> · {data.peer_count} peers</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
|
||||
// --- Difficulty distribution ---
|
||||
const bucketLabels = ["< 1M", "1M\u2013100M", "100M\u20131G", "1G\u2013100G", "100G\u20131T", "\u2265 1T"];
|
||||
// Fire intensity classes: none for <1M, then progressively more intense.
|
||||
const fireClasses = ["", "fire-1", "fire-2", "fire-3", "fire-4", "fire-5"];
|
||||
|
||||
type BucketRow = {
|
||||
label: string;
|
||||
@@ -180,7 +182,7 @@
|
||||
|
||||
<!-- Difficulty Distribution Table -->
|
||||
<section class="card">
|
||||
<h3>Difficulty Distribution</h3>
|
||||
<h3>Difficulty Distribution - Amount of shares in different difficulty ranges</h3>
|
||||
{#if !hasDistData}
|
||||
<div class="empty">No accepted shares yet</div>
|
||||
{:else}
|
||||
@@ -196,9 +198,16 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each bucketRows as row}
|
||||
<tr class:dim-row={row.session === 0 && row.alltime === 0}>
|
||||
<td>{row.label}</td>
|
||||
{#each bucketRows as row, i}
|
||||
{@const hasShares = row.session > 0 || row.alltime > 0}
|
||||
<tr class:dim-row={!hasShares && !fireClasses[i]}>
|
||||
<td>
|
||||
{#if fireClasses[i]}
|
||||
<span class="fire-label {fireClasses[i]}" class:fire-active={hasShares} class:fire-dimmed={!hasShares}>{row.label}</span>
|
||||
{:else}
|
||||
{row.label}
|
||||
{/if}
|
||||
</td>
|
||||
<td class="num">{row.session.toLocaleString()}</td>
|
||||
<td class="num">{row.sessionPct.toFixed(1)}%</td>
|
||||
<td class="num">{row.alltime.toLocaleString()}</td>
|
||||
@@ -310,4 +319,24 @@
|
||||
tr[title]:hover td { color: var(--accent); }
|
||||
.dim-row td { opacity: 0.35; }
|
||||
|
||||
/* --- Glowing range labels --- */
|
||||
.fire-label {
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
}
|
||||
.fire-dimmed { opacity: 0.2; }
|
||||
.fire-active { animation: glow-pulse 2s ease-in-out infinite alternate; }
|
||||
|
||||
.fire-1.fire-active { color: #ffcc80; --glow: 255, 180, 100; }
|
||||
.fire-2.fire-active { color: #ff9a5c; --glow: 255, 140, 60; }
|
||||
.fire-3.fire-active { color: #ff6e40; --glow: 255, 90, 30; }
|
||||
.fire-4.fire-active { color: #f44336; --glow: 230, 40, 20; }
|
||||
.fire-5.fire-active { color: #c62828; --glow: 180, 20, 10; }
|
||||
|
||||
@keyframes glow-pulse {
|
||||
0% { text-shadow: 0 0 8px rgba(var(--glow), 0.4); }
|
||||
100% { text-shadow: 0 0 8px rgba(var(--glow), 0.85),
|
||||
0 0 16px rgba(var(--glow), 0.3); }
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -74,16 +74,5 @@ export function selectBestShare(): void {
|
||||
}
|
||||
|
||||
export function clearSelection(): void {
|
||||
if (
|
||||
window.history.length > 1 &&
|
||||
(window.location.hash.startsWith(USER_PREFIX) ||
|
||||
window.location.hash.startsWith(WORKER_PREFIX) ||
|
||||
window.location.hash === ACCELERATOR_HASH ||
|
||||
window.location.hash === STATS_HASH ||
|
||||
window.location.hash === BESTSHARE_HASH)
|
||||
) {
|
||||
window.history.back();
|
||||
} else {
|
||||
window.location.hash = "";
|
||||
}
|
||||
window.location.hash = "";
|
||||
}
|
||||
|
||||
@@ -147,6 +147,9 @@ export type Snapshot = {
|
||||
has_last_zmq_event: boolean;
|
||||
last_zmq_event_age?: number; // seconds
|
||||
tip_changed_age: number; // seconds since tip height last changed
|
||||
peer_count: number;
|
||||
peers_in: number;
|
||||
peers_out: number;
|
||||
// Share counters (raw, 1 submission = 1 share).
|
||||
session_accepted: number;
|
||||
session_rejected: number;
|
||||
|
||||
Reference in New Issue
Block a user