← back to Ticket System
Show ticket runtime beside ticket number
7992a04f9d3dae02980690e71178c39a3ce940ad · 2026-08-31 01:42:24 -0700 · Steve Abrams
Files touched
Diff
commit 7992a04f9d3dae02980690e71178c39a3ce940ad
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 31 01:42:24 2026 -0700
Show ticket runtime beside ticket number
---
board.html | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/board.html b/board.html
index 5f3e1124..5608d2e9 100644
--- a/board.html
+++ b/board.html
@@ -39,6 +39,9 @@
tr.grp input{accent-color:var(--acc);margin-right:8px;cursor:pointer;vertical-align:-1px}
.mono{font-family:ui-monospace,Menlo,monospace}
a.cell{color:var(--acc);text-decoration:none} a.cell:hover{text-decoration:underline}
+ .ticket-top{display:flex;flex-direction:column;gap:2px;line-height:1.15}
+ .ticket-runtime{font:10px -apple-system,BlinkMacSystemFont,sans-serif;color:var(--mut);white-space:nowrap}
+ .ticket-runtime.running{color:#8fd49a}
.stpill{display:inline-flex;align-items:center;gap:5px;font-size:11px;padding:1px 8px;border-radius:20px;border:1px solid var(--line)}
.s-open{color:var(--open)} .s-doing{color:var(--doing)} .s-blocked{color:var(--blocked)} .s-done{color:var(--done);opacity:.8} .s-stopped{color:var(--stopped);text-decoration:line-through}
.vb{display:inline-flex;align-items:center;gap:4px;font-size:11px;padding:1px 7px;border-radius:20px;border:1px solid var(--line)}
@@ -116,6 +119,8 @@
const $=s=>document.querySelector(s), esc=s=>String(s==null?'':s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
const dt=s=>{if(!s)return '—';const d=new Date(s);if(isNaN(d))return '—';return '<span title="'+esc(new Date(s).toISOString())+'">'+esc(d.toLocaleString(undefined,{year:'numeric',month:'short',day:'numeric',hour:'numeric',minute:'2-digit'}))+'</span>';};
const agoH=s=>s?((Date.now()-new Date(s).getTime())/3600000):null;
+const elapsed=s=>{const ms=Math.max(0,Date.now()-new Date(s||Date.now()).getTime()),m=Math.floor(ms/60000),h=Math.floor(m/60),d=Math.floor(h/24);return d?`${d}d ${h%24}h`:h?`${h}h ${m%60}m`:`${m}m`;};
+const ticketCell=t=>{const short=esc(t.id.replace(/^(TK-\d+).*/,'$1')),age=elapsed(t.created_at),running=t.status==='doing';return `<span class="ticket-top"><a class="cell mono" href="#" onclick="setQ('${esc(t.id)}');return false" title="${esc(t.id)}">${short}</a><span class="ticket-runtime${running?' running':''}" title="since ${esc(t.created_at||'unknown')}">${running?'running':'age'} ${age}</span></span>`;};
// ── DTD run-now verdicts (fetched from /api/dtd): { TK-id: {verdict,yes,no,confidence} } ──
let DTD={running:false,verdicts:null};
const verdictOf=t=>{const v=DTD.verdicts&&DTD.verdicts.tickets&&DTD.verdicts.tickets[t.id];return v||null;};
@@ -139,7 +144,7 @@ const COLS=[
{k:'tier', l:'Tier', g:'Priority', w:86, def:1, cell:t=>tierCell(t), raw:t=>({high:3,med:2,low:1}[t.tier]||0)},
{k:'priority',l:'Prio', g:'Priority', w:64, def:1, cell:t=>`<span class="prio">${t.priority!=null?t.priority.toFixed(1):'—'}</span>`, raw:t=>t.priority||0},
{k:'ratings',l:'Ratings',g:'Priority',w:150, def:1, cell:t=>barsCell(t), raw:t=>t.priority||0},
- {k:'id', l:'Ticket', g:'Core', w:150, def:1, cell:t=>`<a class="cell mono" href="#" onclick="setQ('${esc(t.id)}');return false" title="${esc(t.id)}">${esc(t.id.replace(/^(TK-\d+).*/,'$1'))}</a>`, raw:t=>t.id},
+ {k:'id', l:'Ticket', g:'Core', w:150, def:1, cell:t=>ticketCell(t), raw:t=>t.id},
{k:'status',l:'Status', g:'Core', w:96, def:1, cell:t=>`<span class="stpill s-${t.status}"><span class="dot" style="background:currentColor"></span>${t.status==='stopped'?'TicketStopped':t.status}</span>`, raw:t=>t.status},
{k:'runnow',l:'Run now?',g:'Core',w:118, def:1, cell:t=>verdictCell(t), raw:t=>verdictRank(t)},
{k:'title', l:'Title', g:'Core', w:400, def:1, cell:t=>esc(t.title), raw:t=>t.title},
← 36de9af9 Verify YOLO recovery before ticket updates
·
back to Ticket System
·
Measure ticket runtime from latest status change 7445e60c →