From cfc0f68d23e07064d339afd3648c9982f9e40d6c Mon Sep 17 00:00:00 2001 From: Jordan SkyLF Date: Tue, 12 May 2026 22:45:45 -0700 Subject: [PATCH] fix: show update whats-new links for webui and agent --- api/routes.py | 4 + api/updates.py | 12 ++ docs/images/update-banner-whats-new-after.png | Bin 0 -> 32865 bytes .../images/update-banner-whats-new-before.png | Bin 0 -> 32321 bytes static/index.html | 2 +- static/panels.js | 1 + static/ui.js | 97 ++++++++++---- tests/test_issue1579_whats_new_link_404.py | 44 +++---- tests/test_update_banner_fixes.py | 122 ++++++++++++++++++ 9 files changed, 235 insertions(+), 47 deletions(-) create mode 100644 docs/images/update-banner-whats-new-after.png create mode 100644 docs/images/update-banner-whats-new-before.png diff --git a/api/routes.py b/api/routes.py index 765857ca..70a25fcc 100644 --- a/api/routes.py +++ b/api/routes.py @@ -3718,6 +3718,8 @@ def handle_get(handler, parsed) -> bool: "current_sha": "abc1234", "latest_sha": "def5678", "branch": "master", + "repo_url": "https://github.com/nesquena/hermes-webui", + "compare_url": "https://github.com/nesquena/hermes-webui/compare/abc1234...def5678", }, "agent": { "name": "agent", @@ -3725,6 +3727,8 @@ def handle_get(handler, parsed) -> bool: "current_sha": "aaa0001", "latest_sha": "bbb0002", "branch": "master", + "repo_url": "https://github.com/NousResearch/hermes-agent", + "compare_url": "https://github.com/NousResearch/hermes-agent/compare/aaa0001...bbb0002", }, "checked_at": 0, }, diff --git a/api/updates.py b/api/updates.py index e3e025c2..c6b619cb 100644 --- a/api/updates.py +++ b/api/updates.py @@ -12,6 +12,7 @@ import subprocess import threading import time from pathlib import Path +from urllib.parse import urlparse from api.config import REPO_ROOT, STREAMS, STREAMS_LOCK @@ -169,6 +170,16 @@ def _normalize_remote_url(remote_url): return remote_url.rstrip('/') +def _build_compare_url(repo_url, current_sha, latest_sha): + """Return a safe browser compare URL, or None when any piece is missing.""" + if not (repo_url and current_sha and latest_sha): + return None + parsed = urlparse(repo_url) + if parsed.scheme not in ('http', 'https') or not parsed.netloc: + return None + return f"{repo_url}/compare/{current_sha}...{latest_sha}" + + def _split_remote_ref(ref): """Split 'origin/branch-name' into ('origin', 'branch-name'). @@ -262,6 +273,7 @@ def _check_repo(path, name): 'latest_sha': latest, 'branch': compare_ref, 'repo_url': remote_url, + 'compare_url': _build_compare_url(remote_url, current, latest), } diff --git a/docs/images/update-banner-whats-new-after.png b/docs/images/update-banner-whats-new-after.png new file mode 100644 index 0000000000000000000000000000000000000000..7b0469f9129bd0c19f926512cab851abf3826ad4 GIT binary patch literal 32865 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 Q01zT8sr0E*{Bz*{19(VSj{pDw literal 0 HcmV?d00001 diff --git a/docs/images/update-banner-whats-new-before.png b/docs/images/update-banner-whats-new-before.png new file mode 100644 index 0000000000000000000000000000000000000000..1940cfce9ac420ea82d87e75608200c5854ed899 GIT binary patch literal 32321 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 literal 0 HcmV?d00001 diff --git a/static/index.html b/static/index.html index 8a530d16..6f8b22a6 100644 --- a/static/index.html +++ b/static/index.html @@ -342,7 +342,7 @@

diff --git a/static/panels.js b/static/panels.js index d942fac0..62b91aab 100644 --- a/static/panels.js +++ b/static/panels.js @@ -5996,6 +5996,7 @@ async function checkUpdatesNow(){ if(typeof _showUpdateBanner==='function') _showUpdateBanner(data); } else { if(status){status.textContent=t('settings_up_to_date');status.style.color='var(--success)';} + if(typeof _showUpdateBanner==='function') _showUpdateBanner(data); } } } catch(e){ diff --git a/static/ui.js b/static/ui.js index d0f27aa8..076ec07b 100644 --- a/static/ui.js +++ b/static/ui.js @@ -3878,38 +3878,91 @@ function _formatUpdateTargetStatus(label,info){ const branch=info.branch?` (${info.branch})`:''; return `${label}${branch}: ${info.behind} update${info.behind>1?'s':''}`; } +function _isSafeUpdateCompareUrl(url){ + if(!url||!/^https?:\/\//i.test(url)) return false; + try{ + const parsed=new URL(url); + return parsed.protocol==='https:'||parsed.protocol==='http:'; + }catch(e){ + return false; + } +} +function _updateCompareUrl(info){ + if(!info) return null; + const compareUrl=info.compare_url||null; + if(compareUrl) return _isSafeUpdateCompareUrl(compareUrl)?compareUrl:null; + const repo_url=info.repo_url; + const currentSha=info.current_sha; + const latestSha=info.latest_sha; + if(!(repo_url&¤tSha&&latestSha)) return null; + const fallbackUrl=repo_url+'/compare/'+currentSha+'...'+latestSha; + return _isSafeUpdateCompareUrl(fallbackUrl)?fallbackUrl:null; +} +function _updateWhatsNewTargets(data){ + const targets=[ + {key:'webui',label:'WebUI',info:data&&data.webui}, + {key:'agent',label:'Agent',info:data&&data.agent}, + ]; + return targets.map((target)=>({ + key:target.key, + label:target.label, + info:target.info, + url:_updateCompareUrl(target.info), + })).filter((target)=>target.info&&target.info.behind>0&&target.url); +} +function _renderUpdateWhatsNewLinks(data){ + const container=$('updateWhatsNewLinks'); + if(!container) return; + container.replaceChildren(); + const targets=_updateWhatsNewTargets(data); + if(!targets.length){ + container.style.display='none'; + return; + } + container.style.display='block'; + if(targets.length===1){ + const target=targets[0]; + const link=document.createElement('a'); + link.href=target.url; + link.target='_blank'; + link.rel='noopener'; + link.style.color='var(--accent)'; + link.style.textDecoration='underline'; + link.textContent="What's new in "+target.label+'?'; + container.appendChild(link); + return; + } + container.appendChild(document.createTextNode("What's new: ")); + targets.forEach((target,idx)=>{ + if(idx>0) container.appendChild(document.createTextNode(' \u00b7 ')); + const link=document.createElement('a'); + link.href=target.url; + link.target='_blank'; + link.rel='noopener'; + link.style.color='var(--accent)'; + link.style.textDecoration='underline'; + link.textContent=target.label; + container.appendChild(link); + }); +} function _showUpdateBanner(data){ const parts=[]; const webuiPart=_formatUpdateTargetStatus('WebUI',data.webui); const agentPart=_formatUpdateTargetStatus('Agent',data.agent); if(webuiPart) parts.push(webuiPart); if(agentPart) parts.push(agentPart); - if(!parts.length)return; + window._updateData=data; + if(!parts.length){ + _renderUpdateWhatsNewLinks(data); + const staleBanner=$('updateBanner'); + if(staleBanner) staleBanner.classList.remove('visible'); + return; + } const msg=$('updateMsg'); if(msg) msg.textContent='\u2B06 '+parts.join(', ')+' available'; const banner=$('updateBanner'); if(banner) banner.classList.add('visible'); - window._updateData=data; - // Wire up "What's new?" link. - // - // Reset display:none + clear the href on every render — otherwise a stale - // link from a prior update banner can stay visible after we've moved past - // a state where the new payload no longer carries usable SHAs (#1579 case - // when the local HEAD diverges from upstream and the compare URL would 404). - const link=$('updateWhatsNew'); - if(link){ - link.style.display='none'; - link.removeAttribute('href'); - if(data.webui){ - const repoUrl=data.webui.repo_url; - const curSha=data.webui.current_sha; - const newSha=data.webui.latest_sha; - if(repoUrl && curSha && newSha){ - link.href=repoUrl+'/compare/'+curSha+'...'+newSha; - link.style.display='inline'; - } - } - } + _renderUpdateWhatsNewLinks(data); } function dismissUpdate(){ const b=$('updateBanner');if(b)b.classList.remove('visible'); diff --git a/tests/test_issue1579_whats_new_link_404.py b/tests/test_issue1579_whats_new_link_404.py index 6f8bb7db..9b851ac2 100644 --- a/tests/test_issue1579_whats_new_link_404.py +++ b/tests/test_issue1579_whats_new_link_404.py @@ -187,39 +187,35 @@ def _read_ui_js(): return (REPO_ROOT / 'static' / 'ui.js').read_text(encoding='utf-8') -def test_whats_new_link_resets_display_and_href_on_every_render(): +def test_whats_new_link_resets_display_and_contents_on_every_render(): """Without reset, a stale link from a prior banner can stay visible after a re-render where the new payload has current_sha=None. """ src = _read_ui_js() - # Find the "What's new" wiring block (~50-line window) - idx = src.find("Wire up \"What's new?\" link") - assert idx != -1, "What's-new link wiring block not found" - block = src[idx:idx + 800] + idx = src.find("function _renderUpdateWhatsNewLinks(data)") + assert idx != -1, "What's-new link renderer not found" + block = src[idx:idx + 1200] - # Reset must happen BEFORE the conditional href set - reset_idx = block.find("style.display='none'") - set_idx = block.find("style.display='inline'") - href_clear_idx = block.find("removeAttribute('href')") - href_set_idx = block.find("link.href=repoUrl") + clear_idx = block.find("container.replaceChildren()") + hide_idx = block.find("container.style.display='none'") + show_idx = block.find("container.style.display='block'") - assert reset_idx != -1, "Missing display='none' reset on every render" - assert href_clear_idx != -1, "Missing removeAttribute('href') reset on every render" - assert reset_idx < set_idx, "display reset must precede inline set" - assert href_clear_idx < href_set_idx, "href clear must precede href assignment" + assert clear_idx != -1, "Missing container contents reset on every render" + assert hide_idx != -1, "Missing display='none' reset when no safe links exist" + assert clear_idx < show_idx, "contents reset must precede link rendering" + assert hide_idx < show_idx, "hidden state must be handled before visible rendering" -def test_whats_new_link_suppressed_when_curSha_falsy(): - """The conditional must guard on all three of repoUrl/curSha/newSha.""" +def test_whats_new_link_suppressed_when_current_sha_falsy(): + """The legacy fallback must guard on all three of repo_url/current_sha/latest_sha.""" src = _read_ui_js() - idx = src.find("Wire up \"What's new?\" link") - block = src[idx:idx + 800] - # Match "if(repoUrl && curSha && newSha)" with arbitrary whitespace - pattern = re.compile(r'if\s*\(\s*repoUrl\s*&&\s*curSha\s*&&\s*newSha\s*\)') - assert pattern.search(block), ( - "Link must require all three of repoUrl, curSha, newSha to be truthy. " - "If any is null/empty, link stays display:none." - ) + idx = src.find("function _updateCompareUrl(info)") + assert idx != -1, "Compare URL helper not found" + block = src[idx:idx + 500] + compact = re.sub(r"\s+", "", block) + assert "if(!(repo_url&¤tSha&&latestSha))returnnull;" in compact + assert "constfallbackUrl=repo_url+'/compare/'+currentSha+'...'+latestSha;" in compact + assert "return_isSafeUpdateCompareUrl(fallbackUrl)?fallbackUrl:null;" in compact # ── 3. End-to-end: simulate the exact reporter URL shape ── diff --git a/tests/test_update_banner_fixes.py b/tests/test_update_banner_fixes.py index 5eaee61e..274b7af4 100644 --- a/tests/test_update_banner_fixes.py +++ b/tests/test_update_banner_fixes.py @@ -29,6 +29,81 @@ def read(rel): # ── api/updates.py ──────────────────────────────────────────────────────────── class TestUpdateChecker: + def test_build_compare_url_requires_all_pieces(self): + import api.updates as upd + + assert upd._build_compare_url( + 'https://github.com/nesquena/hermes-webui', 'abc1234', 'def5678' + ) == 'https://github.com/nesquena/hermes-webui/compare/abc1234...def5678' + assert upd._build_compare_url(None, 'abc1234', 'def5678') is None + assert upd._build_compare_url('https://github.com/nesquena/hermes-webui', None, 'def5678') is None + assert upd._build_compare_url('https://github.com/nesquena/hermes-webui', 'abc1234', None) is None + + def test_build_compare_url_rejects_unsafe_remote_urls(self): + import api.updates as upd + + assert upd._build_compare_url('javascript:alert(1)', 'abc1234', 'def5678') is None + assert upd._build_compare_url('file:///tmp/hermes-webui', 'abc1234', 'def5678') is None + assert upd._build_compare_url('https:github.com/nesquena/hermes-webui', 'abc1234', 'def5678') is None + assert upd._build_compare_url('https://github.com/nesquena/hermes-webui', 'abc1234', 'def5678') + + def test_check_repo_includes_compare_url_from_normalized_remote_and_merge_base(self, tmp_path, monkeypatch): + import api.updates as upd + + (tmp_path / '.git').mkdir() + + def fake_run(args, cwd, timeout=10): + if args[0] == 'fetch': + return '', True + if args[:2] == ['rev-parse', '--abbrev-ref']: + return 'origin/master', True + if args[:2] == ['rev-list', '--count']: + return '2', True + if args[0] == 'merge-base': + return 'abcdef1234567890', True + if args[:3] == ['rev-parse', '--short', 'abcdef1234567890']: + return 'abcdef1', True + if args[:3] == ['rev-parse', '--short', 'origin/master']: + return 'def5678', True + if args[:2] == ['remote', 'get-url']: + return 'git@github.com:NousResearch/hermes-agent.git', True + return '', True + + monkeypatch.setattr(upd, '_run_git', fake_run) + result = upd._check_repo(tmp_path, 'agent') + + assert result['repo_url'] == 'https://github.com/NousResearch/hermes-agent' + assert result['current_sha'] == 'abcdef1' + assert result['latest_sha'] == 'def5678' + assert result['compare_url'] == 'https://github.com/NousResearch/hermes-agent/compare/abcdef1...def5678' + + def test_check_repo_omits_compare_url_when_merge_base_missing(self, tmp_path, monkeypatch): + import api.updates as upd + + (tmp_path / '.git').mkdir() + + def fake_run(args, cwd, timeout=10): + if args[0] == 'fetch': + return '', True + if args[:2] == ['rev-parse', '--abbrev-ref']: + return 'origin/master', True + if args[:2] == ['rev-list', '--count']: + return '2', True + if args[0] == 'merge-base': + return 'fatal: no merge base', False + if args[:3] == ['rev-parse', '--short', 'origin/master']: + return 'def5678', True + if args[:2] == ['remote', 'get-url']: + return 'https://github.com/nesquena/hermes-webui.git', True + return '', True + + monkeypatch.setattr(upd, '_run_git', fake_run) + result = upd._check_repo(tmp_path, 'webui') + + assert result['current_sha'] is None + assert result['latest_sha'] == 'def5678' + assert result['compare_url'] is None + def test_repo_url_strips_only_dot_git_suffix(self, tmp_path, monkeypatch): import api.updates as upd @@ -603,6 +678,53 @@ class TestSequentialUpdateRestartCoordination: ) + +class TestUpdateCompareSource: + def test_simulated_update_check_payload_includes_both_safe_compare_urls(self): + src = read('api/routes.py') + assert '"repo_url": "https://github.com/nesquena/hermes-webui"' in src + assert '"compare_url": "https://github.com/nesquena/hermes-webui/compare/abc1234...def5678"' in src + assert '"repo_url": "https://github.com/NousResearch/hermes-agent"' in src + assert '"compare_url": "https://github.com/NousResearch/hermes-agent/compare/aaa0001...bbb0002"' in src + + def test_update_banner_html_uses_multi_target_links_container(self): + src = read('static/index.html') + assert 'id="updateWhatsNewLinks"' in src + assert 'id="updateWhatsNew"' not in src + + def test_update_banner_frontend_uses_data_driven_compare_helpers(self): + src = read('static/ui.js') + assert 'function _isSafeUpdateCompareUrl(url)' in src + assert 'function _updateCompareUrl(info)' in src + assert 'function _updateWhatsNewTargets(data)' in src + assert 'function _renderUpdateWhatsNewLinks(data)' in src + assert "$('updateWhatsNewLinks')" in src + assert "compare_url" in src + assert "repo_url+'/compare/'+currentSha+'...'+latestSha" in src + assert "_isSafeUpdateCompareUrl(compareUrl)?compareUrl:null" in src + assert "_renderUpdateWhatsNewLinks(data);" in src + assert "data.webui.repo_url" not in src + assert "$('updateWhatsNew')" not in src + + def test_update_banner_clears_stale_links_when_no_updates_remain(self): + src = read('static/ui.js') + start = src.find('function _showUpdateBanner(data)') + assert start != -1, "_showUpdateBanner not found" + fn = src[start:src.find('function dismissUpdate()', start)] + empty_idx = fn.find('if(!parts.length)') + assert empty_idx != -1, "_showUpdateBanner must handle empty update payloads" + empty_block = fn[empty_idx:fn.find('return;', empty_idx) + len('return;')] + assert '_renderUpdateWhatsNewLinks(data);' in empty_block + assert "classList.remove('visible')" in empty_block + + def test_manual_up_to_date_check_clears_update_banner(self): + src = read('static/panels.js') + up_to_date_idx = src.find("settings_up_to_date") + assert up_to_date_idx != -1, "manual update up-to-date branch not found" + block = src[up_to_date_idx:up_to_date_idx + 300] + assert "_showUpdateBanner(data)" in block + + # ── Regression: force button reset on retry ────────────────────────────────── class TestForceButtonResetOnRetry: