Sunstead trust scoring project
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 3.9 kB View raw
1<!doctype html> 2<meta charset="utf-8"> 3<title>Tangled backfill — live</title> 4<style> 5 :root { color-scheme: dark; } 6 body { margin: 0; background: #0d1117; color: #e6edf3; 7 font: 14px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; } 8 header { padding: 18px 24px; border-bottom: 1px solid #21262d; display: flex; 9 align-items: baseline; gap: 16px; flex-wrap: wrap; } 10 h1 { font-size: 16px; margin: 0; font-weight: 600; } 11 .dot { width: 9px; height: 9px; border-radius: 50%; background: #3fb950; 12 display: inline-block; box-shadow: 0 0 8px #3fb950; animation: pulse 1.5s infinite; } 13 @keyframes pulse { 50% { opacity: .35; } } 14 .total { font-size: 28px; font-weight: 700; color: #58a6ff; } 15 .rate { color: #8b949e; } 16 main { padding: 16px 24px; max-width: 920px; } 17 .row { display: grid; grid-template-columns: 230px 1fr 90px; align-items: center; 18 gap: 12px; margin: 6px 0; } 19 .name { color: #c9d1d9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } 20 .name.active { color: #3fb950; } 21 .bar { background: #161b22; border-radius: 4px; height: 20px; overflow: hidden; } 22 .fill { height: 100%; background: linear-gradient(90deg, #1f6feb, #58a6ff); 23 width: 0; transition: width .4s ease; } 24 .fill.active { background: linear-gradient(90deg, #238636, #3fb950); } 25 .num { text-align: right; color: #e6edf3; } 26 .zero .name { color: #6e7681; } .zero .num { color: #6e7681; } 27 footer { padding: 12px 24px; color: #8b949e; border-top: 1px solid #21262d; } 28 .derived span { margin-right: 18px; } .derived b { color: #e6edf3; } 29 .err { color: #f85149; } 30</style> 31<header> 32 <a href="/" style="display:block;width:100%;margin-bottom:8px"><img src="/static/logo.svg" alt="CyberCred" height="24"></a> 33 <span class="dot" id="dot"></span> 34 <h1>Tangled backfill</h1> 35 <span class="total" id="total"></span> 36 <span class="rate" id="rate"></span> 37 <span class="rate" id="stamp"></span> 38</header> 39<main id="rows"></main> 40<footer class="derived" id="derived"></footer> 41<script> 42let prevTotal = null, prevT = null, peak = 1; 43const fmt = n => n.toLocaleString(); 44 45async function tick() { 46 let d; 47 try { 48 d = await (await fetch('/backfill/status', {cache: 'no-store'})).json(); 49 } catch (e) { 50 document.getElementById('stamp').innerHTML = '<span class="err">offline — is the API up?</span>'; 51 return; 52 } 53 const now = Date.now(); 54 document.getElementById('total').textContent = fmt(d.total); 55 if (prevTotal !== null && now > prevT) { 56 const rps = (d.total - prevTotal) / ((now - prevT) / 1000); 57 document.getElementById('rate').textContent = rps >= 0.5 ? `+${rps.toFixed(0)}/s` : ''; 58 document.getElementById('dot').style.opacity = rps >= 0.5 ? 1 : 0.3; 59 } 60 document.getElementById('stamp').textContent = new Date().toLocaleTimeString(); 61 62 const entries = Object.entries(d.collections); 63 peak = Math.max(peak, ...entries.map(([, n]) => n), 1); 64 const rows = document.getElementById('rows'); 65 rows.innerHTML = entries.map(([name, n]) => { 66 const active = window._prev && window._prev[name] !== undefined && n > window._prev[name]; 67 const w = (n / peak * 100).toFixed(1); 68 return `<div class="row ${n === 0 ? 'zero' : ''}"> 69 <div class="name ${active ? 'active' : ''}">${active ? '▸ ' : ''}${name}</div> 70 <div class="bar"><div class="fill ${active ? 'active' : ''}" style="width:${w}%"></div></div> 71 <div class="num">${fmt(n)}</div></div>`; 72 }).join(''); 73 window._prev = d.collections; 74 75 const x = d.derived; 76 document.getElementById('derived').innerHTML = 77 `derived &rarr; <span>contributors <b>${fmt(x.contributors)}</b></span>` + 78 `<span>vouches <b>${fmt(x.vouches)}</b></span>` + 79 `<span>pull_requests <b>${fmt(x.pull_requests)}</b></span>`; 80 81 prevTotal = d.total; prevT = now; 82} 83tick(); 84setInterval(tick, 1500); 85</script>