← Commit history

v2.0.721 (insiders): The dashboard stops blinking: each live update now patches only what changed, so window and taskbar icons are no longer recreated and reloaded every 2 seconds (measured on ConfRoomROG: 0 of 30 icons recreated across 10 updates, was all 30 every update). Includes 2.0.720. Gates on arav-rog and ConfRoomROG: smoke all pass, parity 55/56, jump list 11/14 (baseline); foreground pass on arav-rog, and on ConfRoomROG 1 of 27 samples caught a blank window on top during the cold open, then two reruns passed (an intermittent cold-start flash, not this change).

John Lauer ·ff1c4b38a6 ·27d ago ·parent f47fdd8
3 files changed +37−18
rust/Cargo.lock+12−12
@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"  [[package]] name = "adom-pup-bridge"-version = "2.0.720"+version = "2.0.721" dependencies = [  "pup-browser",  "pup-cdp",@@ -781,7 +781,7 @@ dependencies = [  [[package]] name = "pup-browser"-version = "2.0.720"+version = "2.0.721" dependencies = [  "pup-core",  "pup-host",@@ -793,7 +793,7 @@ dependencies = [  [[package]] name = "pup-cdp"-version = "2.0.720"+version = "2.0.721" dependencies = [  "serde_json",  "thiserror",@@ -803,7 +803,7 @@ dependencies = [  [[package]] name = "pup-core"-version = "2.0.720"+version = "2.0.721" dependencies = [  "serde",  "serde_json",@@ -813,7 +813,7 @@ dependencies = [  [[package]] name = "pup-dashboard"-version = "2.0.720"+version = "2.0.721" dependencies = [  "pup-cdp",  "pup-core",@@ -826,7 +826,7 @@ dependencies = [  [[package]] name = "pup-host"-version = "2.0.720"+version = "2.0.721" dependencies = [  "serde",  "serde_json",@@ -835,7 +835,7 @@ dependencies = [  [[package]] name = "pup-host-mac"-version = "2.0.720"+version = "2.0.721" dependencies = [  "core-foundation",  "core-graphics",@@ -851,7 +851,7 @@ dependencies = [  [[package]] name = "pup-host-win"-version = "2.0.720"+version = "2.0.721" dependencies = [  "pup-core",  "pup-host",@@ -861,7 +861,7 @@ dependencies = [  [[package]] name = "pup-identity"-version = "2.0.720"+version = "2.0.721" dependencies = [  "fontdue",  "image",@@ -871,7 +871,7 @@ dependencies = [  [[package]] name = "pup-session"-version = "2.0.720"+version = "2.0.721" dependencies = [  "pup-core",  "serde",@@ -881,7 +881,7 @@ dependencies = [  [[package]] name = "pup-vault"-version = "2.0.720"+version = "2.0.721" dependencies = [  "pup-core",  "pup-host",@@ -892,7 +892,7 @@ dependencies = [  [[package]] name = "pup-verbs"-version = "2.0.720"+version = "2.0.721" dependencies = [  "base64",  "png 0.17.16",
rust/Cargo.toml+1−1
@@ -4,7 +4,7 @@ members = ["core", "host", "host-win", "host-mac", "cdp", "browser", "session",  # One version for the whole bridge, in lockstep with src/BRIDGE_VERSION (tools/ship.sh bumps both). [workspace.package]-version = "2.0.720"+version = "2.0.721" edition = "2021" license = "MIT" 
rust/dashboard/assets/dashboard.html+24−5
@@ -371,6 +371,25 @@ function favTags(f){   return '<span class="fttray" title="'+esc(tip)+'">'+bits.join('')+'</span>'; } +// 2.0.721 (John on CRR: "i keep seeing it blink like every second"): every snapshot used to replace these lists+// with innerHTML, so every icon <img> was recreated and reloaded every 2 s. morph() patches the live DOM against+// the new markup instead: unchanged nodes and images stay as they are, only changed text and attributes move.+function morph(el,html){const t=document.createElement(el.tagName);t.innerHTML=html;morphKids(el,t);}+function morphKids(a,b){+  const bk=Array.from(b.childNodes);+  bk.forEach((bn,i)=>{const an=a.childNodes[i];+    if(!an){a.appendChild(bn);return;}+    if(an.nodeType!==bn.nodeType||an.nodeName!==bn.nodeName){a.replaceChild(bn,an);return;}+    if(an.nodeType!==1){if(an.nodeValue!==bn.nodeValue)an.nodeValue=bn.nodeValue;return;}+    const img=an.tagName==='IMG', srcChanged=img&&an.getAttribute('src')!==bn.getAttribute('src');+    // a broken icon hidden by the error handler keeps its style until its src changes+    for(const at of Array.from(an.attributes)) if(!bn.hasAttribute(at.name)&&!(img&&at.name==='style'&&!srcChanged)) an.removeAttribute(at.name);+    for(const at of Array.from(bn.attributes)) if(an.getAttribute(at.name)!==at.value) an.setAttribute(at.name,at.value);+    morphKids(an,bn);+  });+  while(a.childNodes.length>bk.length) a.removeChild(a.lastChild);+}+ function render(){   if(!SNAP)return; const d=SNAP;   if(d.bridge&&d.bridge.version&&d.bridge.version!==PAGE_VERSION){location.reload();return;}@@ -401,7 +420,7 @@ function render(){   // from his actual taskbar), and NO overlay at all when pup has not painted one (a bare Chrome   // button must render bare here too, otherwise the mimic lies).   const ghosts=(d.untrackedWindows||[]).map(h=>'<div class="tbi ghost" title="a window of the pup-managed Chrome is on the real taskbar but pup has NO window record for it (hwnd '+h+'). The mimic cannot know its icon - this is why the header LED is red.">?<span class="led red"></span></div>').join('');-  _q('#taskbar').innerHTML='<span class="lbl" title="mimics ONLY the taskbar buttons of pup-managed Chrome windows. Other Adom apps (Adom Hydrogen, Adom Bridge) have their own teal-tile buttons that are out of pup scope.">TASKBAR (pup)</span>'+groups.map((g,i)=>{+  morph(_q('#taskbar'),'<span class="lbl" title="mimics ONLY the taskbar buttons of pup-managed Chrome windows. Other Adom apps (Adom Hydrogen, Adom Bridge) have their own teal-tile buttons that are out of pup scope.">TASKBAR (pup)</span>'+groups.map((g,i)=>{     const fg=g.wins.some(w=>w.foreground);     return '<div class="tbi'+(fg?' fg':'')+'" data-jump="g'+i+'" title="'+esc(g.label)+': '+esc(g.ledWhy||'')+'">'       +'<img class="base" src="'+esc(g.baseIcon||'')+'" data-fallback="hide">'@@ -409,10 +428,10 @@ function render(){       +'<span class="led '+esc(g.led||'red')+'" title="'+esc(g.ledWhy||'')+'"></span>'       +(g.wins.length>1?'<span class="n">'+g.wins.length+'</span>':'')       +(fg?'<span class="u"></span>':'')+'</div>';-  }).join('')+ghosts;+  }).join('')+ghosts);    // tree: taskbar icon -> windows -> tabs-  _q('#m').innerHTML=groups.length?groups.map((g,gi)=>{+  morph(_q('#m'),groups.length?groups.map((g,gi)=>{     const gid='g'+gi, gcoll=COLL.has(gid);     return '<div class="tbnode" id="'+gid+'">'       +'<div class="row"><span class="tog" data-toggle="'+gid+'">'+(gcoll?'▸':'▾')+'</span>'@@ -461,7 +480,7 @@ function render(){             +'<button class="btn xs danger" data-act="close-tab" data-sid="'+esc(w.sessionId)+'" data-tid="'+esc(t.tabId)+'">close</button></span></div>'           ).join('')+'</div></div></div>';       }).join('')+'</div></div>';-  }).join(''):'<div class="empty">no pup windows open'+(th||q?' matching this filter':'')+'</div>';+  }).join(''):'<div class="empty">no pup windows open'+(th||q?' matching this filter':'')+'</div>');   _q('#ft').textContent='bridge up '+ago(d.bridge.uptimeMs)+' \u00b7 '+d.bridge.platform+' \u00b7 deps '+(d.bridge.depsOk?'ok':'MISSING')+' \u00b7 win32 '+(d.bridge.win32InProcess?'in-process':'powershell fallback');   // v2.0.315 LOOP RADAR (John): the periodic loops and in-process Win32 calls no longer show in ab's   // activity log, so they are shown HERE, per minute, with the declared cadence next to each so a@@ -470,7 +489,7 @@ function render(){     const lp=d.bridge.loops||{}; const w=d.bridge.win32Calls||{};     const rows=Object.entries(lp).map(([n,v])=>{const exp=Math.max(1,Math.ceil(60000/v.cadenceMs));const hot=v.lastMin>exp*1.5;return '<span class="lp'+(hot?' hot':'')+'" title="declared cadence '+v.cadenceMs+'ms = '+exp+'/min; avg '+v.avgMs+'ms, max '+v.maxMs+'ms, '+v.ticks+' ticks total, '+v.slowTicks+' slow">'+n+' <b>'+v.lastMin+'</b>/'+exp+'</span>';}).join('');     const wc=Object.entries(w).map(([n,v])=>n+'='+v).join(' ');-    _q('#loops').innerHTML='<div class="lpt">loops, ticks in the last minute (actual/declared)</div>'+rows+'<div class="lpt">in-process win32 calls since boot: '+(wc||'none')+' \u00b7 ab enum_windows last minute: '+(d.bridge.abEnumLastMin||0)+'</div>';+    morph(_q('#loops'),'<div class="lpt">loops, ticks in the last minute (actual/declared)</div>'+rows+'<div class="lpt">in-process win32 calls since boot: '+(wc||'none')+' \u00b7 ab enum_windows last minute: '+(d.bridge.abEnumLastMin||0)+'</div>');   }catch(e){} } function toast(msg,type){