From 69b84153b4036f7c5c046ed035110a7aafe9fef8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 19:46:40 +0000 Subject: [PATCH] Address code review: tighten bip110 key matching, fix redundant condition, extract shared badge config, add CSS classes --- app/sovran_systemsos_web/server.py | 10 +++-- app/sovran_systemsos_web/static/css/tiles.css | 12 ++++++ app/sovran_systemsos_web/static/js/helpers.js | 14 +++++++ .../static/js/service-detail.js | 39 ++----------------- app/sovran_systemsos_web/static/js/tiles.js | 35 +---------------- 5 files changed, 38 insertions(+), 72 deletions(-) diff --git a/app/sovran_systemsos_web/server.py b/app/sovran_systemsos_web/server.py index 0a436a5..2eea02f 100644 --- a/app/sovran_systemsos_web/server.py +++ b/app/sovran_systemsos_web/server.py @@ -2436,8 +2436,10 @@ def _get_bip110_status() -> dict: deployments = deploy_info.get("deployments", {}) if isinstance(deployments, dict): for key, entry in deployments.items(): - # Generic scan: match key containing "bip110" or "110" - if not ("bip110" in key.lower() or "110" in key.lower()): + # Generic scan: match key that contains "bip110" (case-insensitive). + # Deliberately not matching bare "110" to avoid false positives on + # unrelated deployments whose names happen to include that digit sequence. + if "bip110" not in key.lower(): continue if not isinstance(entry, dict): continue @@ -2460,7 +2462,7 @@ def _get_bip110_status() -> dict: if status in ("started", "defined"): # Check whether the node is currently signaling this period stats = bip9.get("statistics") or bip8.get("statistics") or {} - signaling = bool(stats.get("signaling", False)) if stats else False + signaling = bool(stats.get("signaling", False)) if signaling: return {"supported": True, "signaling": True, "state": "signaling", "source": "getdeploymentinfo"} return {"supported": True, "signaling": False, "state": "not_signaling", "source": "getdeploymentinfo"} @@ -2474,7 +2476,7 @@ def _get_bip110_status() -> dict: if net_info is not None: subversion = net_info.get("subversion", "") or "" sv_lower = subversion.lower() - if "bip110" in sv_lower or "uasf-bip110" in sv_lower or "uasf" in sv_lower: + if "bip110" in sv_lower or "uasf-bip110" in sv_lower: return {"supported": True, "signaling": True, "state": "signaling", "source": "subversion"} # Node is reachable via RPC but no BIP-110 marker found anywhere return {"supported": False, "signaling": False, "state": "unsupported", "source": "subversion"} diff --git a/app/sovran_systemsos_web/static/css/tiles.css b/app/sovran_systemsos_web/static/css/tiles.css index e8aba2c..94e9f7f 100644 --- a/app/sovran_systemsos_web/static/css/tiles.css +++ b/app/sovran_systemsos_web/static/css/tiles.css @@ -206,6 +206,18 @@ border: 1px solid var(--border-color); } +.bip110-status-row { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} + +.bip110-source-label { + color: var(--text-dim); + font-size: 0.75rem; +} + /* ── Service detail modal sections ───────────────────────────────── */ .svc-detail-section { diff --git a/app/sovran_systemsos_web/static/js/helpers.js b/app/sovran_systemsos_web/static/js/helpers.js index 470e711..d452fca 100644 --- a/app/sovran_systemsos_web/static/js/helpers.js +++ b/app/sovran_systemsos_web/static/js/helpers.js @@ -60,3 +60,17 @@ async function apiFetch(path, options) { } return res.json(); } + + +// ── BIP-110 badge state config ──────────────────────────────────── +// Shared lookup used by tiles.js and service-detail.js. +// Keys match the "state" values returned by /api/bitcoin/bip110. + +var BIP110_BADGE_CONFIG = { + active: { cls: 'tile-bip110-badge--active', label: 'BIP\u2011110: Active \u2713', title: 'BIP-110 is active on this node' }, + locked_in: { cls: 'tile-bip110-badge--locked_in', label: 'BIP\u2011110: Locked In', title: 'BIP-110 is locked in and will activate shortly' }, + signaling: { cls: 'tile-bip110-badge--signaling', label: 'BIP\u2011110: Signaling', title: 'Node is signaling readiness for BIP-110' }, + not_signaling: { cls: 'tile-bip110-badge--not_signaling',label: 'BIP\u2011110: Not Signaling', title: 'Node supports BIP-110 but is not signaling this period' }, + unsupported: { cls: 'tile-bip110-badge--unsupported', label: 'BIP\u2011110: Not Supported', title: 'This node build does not include BIP-110' }, + unknown: { cls: 'tile-bip110-badge--unknown', label: 'BIP\u2011110: \u2014', title: 'Status unavailable (node syncing or RPC not ready)' } +}; diff --git a/app/sovran_systemsos_web/static/js/service-detail.js b/app/sovran_systemsos_web/static/js/service-detail.js index 87918bf..a86a6c6 100644 --- a/app/sovran_systemsos_web/static/js/service-detail.js +++ b/app/sovran_systemsos_web/static/js/service-detail.js @@ -111,43 +111,12 @@ async function openServiceDetailModal(unit, name, icon) { if (icon === 'bip110' && data.bip110) { var bip110 = data.bip110; var bip110State = bip110.state || 'unknown'; - var bip110BadgeCls, bip110Label, bip110Tooltip; - switch (bip110State) { - case 'active': - bip110BadgeCls = 'tile-bip110-badge--active'; - bip110Label = 'BIP\u2011110: Active \u2713'; - bip110Tooltip = 'BIP-110 is active on this node'; - break; - case 'locked_in': - bip110BadgeCls = 'tile-bip110-badge--locked_in'; - bip110Label = 'BIP\u2011110: Locked In'; - bip110Tooltip = 'BIP-110 is locked in and will activate shortly'; - break; - case 'signaling': - bip110BadgeCls = 'tile-bip110-badge--signaling'; - bip110Label = 'BIP\u2011110: Signaling'; - bip110Tooltip = 'Node is signaling readiness for BIP-110'; - break; - case 'not_signaling': - bip110BadgeCls = 'tile-bip110-badge--not_signaling'; - bip110Label = 'BIP\u2011110: Not Signaling'; - bip110Tooltip = 'Node supports BIP-110 but is not signaling this period'; - break; - case 'unsupported': - bip110BadgeCls = 'tile-bip110-badge--unsupported'; - bip110Label = 'BIP\u2011110: Not Supported'; - bip110Tooltip = 'This node build does not include BIP-110'; - break; - default: - bip110BadgeCls = 'tile-bip110-badge--unknown'; - bip110Label = 'BIP\u2011110: \u2014'; - bip110Tooltip = 'Status unavailable (node syncing or RPC not ready)'; - } - var bip110Source = bip110.source ? ' (source: ' + escHtml(bip110.source) + ')' : ''; + var bip110Cfg = BIP110_BADGE_CONFIG[bip110State] || BIP110_BADGE_CONFIG.unknown; + var bip110Source = bip110.source ? ' (source: ' + escHtml(bip110.source) + ')' : ''; html += '
' + '
BIP-110 Deployment Status
' + - '
' + - '' + escHtml(bip110Label) + '' + + '
' + + '' + escHtml(bip110Cfg.label) + '' + bip110Source + '
' + '
'; diff --git a/app/sovran_systemsos_web/static/js/tiles.js b/app/sovran_systemsos_web/static/js/tiles.js index 7d8b974..045ccd2 100644 --- a/app/sovran_systemsos_web/static/js/tiles.js +++ b/app/sovran_systemsos_web/static/js/tiles.js @@ -9,39 +9,8 @@ var _btcSyncPrev = {}; function _renderBip110Badge(bip110) { if (!bip110) return ''; var state = bip110.state || 'unknown'; - var label, cls, title; - switch (state) { - case 'active': - label = 'BIP\u2011110: Active \u2713'; - cls = 'tile-bip110-badge--active'; - title = 'BIP-110 is active on this node'; - break; - case 'locked_in': - label = 'BIP\u2011110: Locked In'; - cls = 'tile-bip110-badge--locked_in'; - title = 'BIP-110 is locked in and will activate shortly'; - break; - case 'signaling': - label = 'BIP\u2011110: Signaling'; - cls = 'tile-bip110-badge--signaling'; - title = 'Node is signaling readiness for BIP-110'; - break; - case 'not_signaling': - label = 'BIP\u2011110: Not Signaling'; - cls = 'tile-bip110-badge--not_signaling'; - title = 'Node supports BIP-110 but is not signaling this period'; - break; - case 'unsupported': - label = 'BIP\u2011110: Not Supported'; - cls = 'tile-bip110-badge--unsupported'; - title = 'This node build does not include BIP-110'; - break; - default: - label = 'BIP\u2011110: \u2014'; - cls = 'tile-bip110-badge--unknown'; - title = 'Status unavailable (node syncing or RPC not ready)'; - } - return '
' + escHtml(label) + '
'; + var cfg = BIP110_BADGE_CONFIG[state] || BIP110_BADGE_CONFIG.unknown; + return '
' + escHtml(cfg.label) + '
'; } // ── Render: initial build ─────────────────────────────────────────