feat: v0.8 Iteration C UI — mesh/temp slot display, N4 reach badge

Diagnostics follow the new topology: network summary shows mesh count against
the cap plus temp referral count (Preferred/Local/Wide tiles are gone), the
connections list labels slots mesh vs temp referral, and peers can show an N4
reach badge. Verified against the Rust DTOs (mesh_count/mesh_cap/temp_count/
n4_distinct, MeshSlot Display -> "mesh"/"temp") and the style.css classes.

Cargo.lock picks up the 0.8.0-alpha version bump.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGiPD2cF75mnvneSCjdDC5
This commit is contained in:
Scott Reimers 2026-07-30 13:05:20 -04:00
parent 6e22e60c7b
commit fa02ace4cc
3 changed files with 16 additions and 16 deletions

6
Cargo.lock generated
View file

@ -2732,7 +2732,7 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "itsgoin-cli"
version = "0.7.3"
version = "0.8.0-alpha"
dependencies = [
"anyhow",
"hex",
@ -2744,7 +2744,7 @@ dependencies = [
[[package]]
name = "itsgoin-core"
version = "0.7.3"
version = "0.8.0-alpha"
dependencies = [
"anyhow",
"base64 0.22.1",
@ -2769,7 +2769,7 @@ dependencies = [
[[package]]
name = "itsgoin-desktop"
version = "0.7.3"
version = "0.8.0-alpha"
dependencies = [
"anyhow",
"base64 0.22.1",

View file

@ -1550,6 +1550,7 @@ async function loadPeers() {
else if (p.reach === 'n1') reachBadge = '<span class="reach-badge reach-n1">N1</span>';
else if (p.reach === 'n2') reachBadge = '<span class="reach-badge reach-n2">N2</span>';
else if (p.reach === 'n3') reachBadge = '<span class="reach-badge reach-n3">N3</span>';
else if (p.reach === 'n4') reachBadge = '<span class="reach-badge reach-n4">N4</span>';
let actions = '';
if (p.nodeId === myNodeId) {
@ -2078,11 +2079,11 @@ async function loadNetworkSummary() {
const s = await invoke('get_network_summary');
networkSummaryEl.innerHTML = `<div class="diag-grid">
<div class="diag-item"><span class="diag-value">${s.totalConnections}</span><span class="diag-label">Connections</span></div>
<div class="diag-item"><span class="diag-value">${s.preferredCount}</span><span class="diag-label">Preferred</span></div>
<div class="diag-item"><span class="diag-value">${s.localCount}</span><span class="diag-label">Mesh</span></div>
<div class="diag-item"><span class="diag-value">${s.wideCount}</span><span class="diag-label">Non-mesh N1</span></div>
<div class="diag-item"><span class="diag-value">${s.meshCount}/${s.meshCap}</span><span class="diag-label">Mesh</span></div>
<div class="diag-item"><span class="diag-value">${s.tempCount}</span><span class="diag-label">Temp referral</span></div>
<div class="diag-item"><span class="diag-value">${s.n2Distinct}</span><span class="diag-label">N2 Reach</span></div>
<div class="diag-item"><span class="diag-value">${s.n3Distinct}</span><span class="diag-label">N3 Reach</span></div>
<div class="diag-item"><span class="diag-value">${s.n4Distinct}</span><span class="diag-label">N4 Reach</span></div>
</div>`;
} catch (e) {
networkSummaryEl.innerHTML = `<p class="empty-hint">Could not load network summary</p>`;
@ -2099,10 +2100,9 @@ async function loadConnections() {
connectionsList.innerHTML = conns.map(c => {
const label = escapeHtml(peerLabel(c.nodeId, c.displayName));
const icon = generateIdenticon(c.nodeId, 18);
const slotClass = c.slotKind === 'Preferred' ? 'slot-preferred'
: c.slotKind === 'Wide' ? 'slot-wide' : 'slot-local';
const slotLabel = c.slotKind === 'Local' ? 'Mesh'
: c.slotKind === 'Wide' ? 'Non-mesh N1' : c.slotKind;
const slotClass = c.slotKind === 'temp' ? 'slot-temp' : 'slot-mesh';
const slotLabel = c.slotKind === 'mesh' ? 'Mesh'
: c.slotKind === 'temp' ? 'Temp referral' : c.slotKind;
const duration = c.connectedAt ? relativeTime(c.connectedAt) : '';
return `<div class="peer-card">
<div class="peer-card-row">${icon} ${label} <span class="slot-badge ${slotClass}">${slotLabel}</span></div>
@ -3680,7 +3680,7 @@ function openDiagnostics() {
</div>
<div style="display:flex;gap:0.5rem;margin-top:0.5rem;flex-wrap:wrap;justify-content:center">
<button id="rebalance-btn" class="btn btn-ghost btn-sm">Rebalance Now</button>
<button id="request-referrals-btn" class="btn btn-ghost btn-sm">Request Referrals</button>
<button id="request-referrals-btn" class="btn btn-ghost btn-sm">Find Peers (Convection)</button>
</div>
<div style="display:flex;gap:0.5rem;margin-top:0.5rem;flex-wrap:wrap;justify-content:center">
<button id="show-ourinfo-btn" class="btn btn-ghost btn-sm">Our Info</button>
@ -3816,11 +3816,11 @@ function openDiagnostics() {
try {
const r = await invoke('request_referrals');
btn.textContent = r;
setTimeout(() => { btn.textContent = 'Request Referrals'; btn.disabled = false; }, 3000);
setTimeout(() => { btn.textContent = 'Find Peers (Convection)'; btn.disabled = false; }, 3000);
loadAllDiagnostics();
} catch (e) {
btn.textContent = 'Failed';
setTimeout(() => { btn.textContent = 'Request Referrals'; btn.disabled = false; }, 3000);
setTimeout(() => { btn.textContent = 'Find Peers (Convection)'; btn.disabled = false; }, 3000);
}
});
loadAllDiagnostics();

View file

@ -359,9 +359,8 @@ header h1 { font-size: clamp(1.4rem, 2.5vw, 2rem); color: #7fdbca; margin: 0; }
/* Slot kind badges */
.slot-badge { font-size: 0.65rem; padding: 0.1rem 0.4rem; border-radius: 3px; font-family: system-ui, sans-serif; }
.slot-preferred { background: #1a3a2e; color: #7fdbca; }
.slot-local { background: #1e2040; color: #aab; }
.slot-wide { background: #2a2a1e; color: #e2b93d; }
.slot-mesh { background: #1e2040; color: #aab; }
.slot-temp { background: #2a2a1e; color: #e2b93d; }
/* Reach level badges */
.reach-badge { font-size: 0.65rem; padding: 0.1rem 0.4rem; border-radius: 3px; font-family: system-ui, sans-serif; }
@ -369,6 +368,7 @@ header h1 { font-size: clamp(1.4rem, 2.5vw, 2rem); color: #7fdbca; margin: 0; }
.reach-n1 { background: #1a2e3a; color: #7fc4db; }
.reach-n2 { background: #1e2040; color: #aab; }
.reach-n3 { background: #1e2040; color: #667; }
.reach-n4 { background: #1a1a2e; color: #556; }
/* Diagnostics summary grid */
.diag-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.4rem; margin-bottom: 0.75rem; }