← back to Ticket System
board: toggle FLEET TICKETS stat pills on/off (persisted); fixes shown-count always 0
79770148f83fe0a2998a77e7a7c982e6f24fe250 · 2026-08-10 15:50:50 -0700 · steve@designerwallcoverings.com
Files touched
Diff
commit 79770148f83fe0a2998a77e7a7c982e6f24fe250
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date: Mon Aug 10 15:50:50 2026 -0700
board: toggle FLEET TICKETS stat pills on/off (persisted); fixes shown-count always 0
---
board.html | 37 +++++++++++++++++++++++++++----------
1 file changed, 27 insertions(+), 10 deletions(-)
diff --git a/board.html b/board.html
index 1d02ea96..2a07b772 100644
--- a/board.html
+++ b/board.html
@@ -35,9 +35,10 @@
.thread .c{font-size:12px;margin:4px 0;color:#c6ccd8} .thread .c i{color:var(--mut);font-style:normal;font-size:10px;margin:0 4px}
.c.k-note{color:#e8d48b}.c.k-action{color:#8fd49a}.c.k-win{color:#34d399}.c.k-challenge{color:#e06c75}.c.k-cody{color:#f59e0b}.c.none{color:var(--faint)}
.cts{color:var(--faint);font-size:10px;margin-left:6px}
- #colmenu{position:absolute;top:44px;right:14px;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:8px;display:none;z-index:10;max-height:70vh;overflow:auto;min-width:180px}
- #colmenu.show{display:block} #colmenu label{display:flex;gap:7px;align-items:center;font-size:12px;padding:3px 6px;cursor:pointer;border-radius:6px} #colmenu label:hover{background:#1c2130}
- #colmenu .gh{font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--faint);margin:6px 6px 2px}
+ #colmenu,#pillmenu,#detmenu{position:absolute;top:44px;right:14px;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:8px;display:none;z-index:10;max-height:70vh;overflow:auto;min-width:180px}
+ #colmenu.show,#pillmenu.show,#detmenu.show{display:block} #colmenu label,#pillmenu label,#detmenu label{display:flex;gap:7px;align-items:center;font-size:12px;padding:3px 6px;cursor:pointer;border-radius:6px} #colmenu label:hover,#pillmenu label:hover,#detmenu label:hover{background:#1c2130}
+ #colmenu .gh,#pillmenu .gh,#detmenu .gh{font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--faint);margin:6px 6px 2px}
+ .btn.off{opacity:.5}
.dms{margin:12px 14px;background:#141821;border:1px solid var(--line);border-radius:8px}
.dms>summary{cursor:pointer;padding:9px 13px;font-size:12px;text-transform:uppercase;letter-spacing:.1em;color:#c9a4f2}
.convos{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:10px;padding:4px 13px 13px}
@@ -52,10 +53,12 @@
<span class="grow"></span>
<input type="range" id="dens" min="4" max="14" step="1" title="row density">
<button class="btn" id="colsBtn">▦ Columns</button>
- <button class="btn" id="resetBtn" title="Reset columns/sort/density">↺ Reset</button>
+ <button class="btn" id="pillsBtn" title="Toggle stat pills">◍ Pills</button>
+ <button class="btn" id="resetBtn" title="Reset columns/sort/density/pills">↺ Reset</button>
<a class="btn" href="/kanban">Kanban</a><a class="btn" href="/office">Office</a>
</header>
<div id="colmenu"></div>
+<div id="pillmenu"></div>
<div class="tblwrap"><table class="g"><thead><tr id="thead"></tr></thead><tbody id="tbody"></tbody></table></div>
<div id="dmwrap"></div>
<script>
@@ -84,6 +87,9 @@ let DATA=[], q='', sortKey='age', sortDir=-1;
let VIS=LS('tkCols',null)||Object.fromEntries(COLS.map(c=>[c.k,!!c.def]));
let ORDER=(Array.isArray(LS('tkOrder',null))?LS('tkOrder',null):[]).filter(k=>CK.includes(k)); for(const k of CK)if(!ORDER.includes(k))ORDER.push(k);
let WID=LS('tkWid',{}), DENS=LS('tkDens',7);
+// toggleable stat pills — mirrors the column-visibility pattern (persists to localStorage)
+const PILLS=[{k:'open',l:'open'},{k:'doing',l:'doing'},{k:'blocked',l:'blocked'},{k:'done',l:'done'},{k:'stale',l:'stale'},{k:'totals',l:'total / shown'}];
+let PILL_VIS=LS('tkPills',null)||Object.fromEntries(PILLS.map(p=>[p.k,1]));
document.documentElement.style.setProperty('--rowpad',DENS+'px'); $('#dens').value=DENS;
const ordered=()=>ORDER.map(k=>COLS.find(c=>c.k===k)).filter(c=>c&&VIS[c.k]);
@@ -134,20 +140,31 @@ function render(){
function renderPills(){
const by={open:0,doing:0,blocked:0,done:0};for(const t of DATA)by[t.status]=(by[t.status]||0)+1;
const stale=DATA.filter(t=>t.status==='doing'&&agoH(lastTs(t))>24).length;
- $('#pills').innerHTML=Object.entries(by).map(([s,n])=>`<span class="pill" onclick="setQ('${s}')"><span class="dot s-${s}" style="background:currentColor"></span>${s} <b>${n}</b></span>`).join('')
- +`<span class="pill" title="doing >24h">⚠ stale <b>${stale}</b></span><span class="pill">total <b>${DATA.length}</b> · shown <b id="count">0</b></span>`;
+ const statPill=s=>`<span class="pill" onclick="setQ('${s}')"><span class="dot s-${s}" style="background:currentColor"></span>${s} <b>${by[s]}</b></span>`;
+ const html={
+ open:statPill('open'), doing:statPill('doing'), blocked:statPill('blocked'), done:statPill('done'),
+ stale:`<span class="pill" title="doing >24h">⚠ stale <b>${stale}</b></span>`,
+ totals:`<span class="pill">total <b>${DATA.length}</b> · shown <b id="count">${DATA.filter(match).length}</b></span>`,
+ };
+ $('#pills').innerHTML=PILLS.filter(p=>PILL_VIS[p.k]).map(p=>html[p.k]).join('');
}
function renderColMenu(){
const m=$('#colmenu');const groups=[...new Set(COLS.map(c=>c.g))];
m.innerHTML=groups.map(g=>`<div class="gh">${g}</div>`+COLS.filter(c=>c.g===g).map(c=>`<label><input type="checkbox" data-k="${c.k}" ${VIS[c.k]?'checked':''}>${esc(c.l)}</label>`).join('')).join('');
m.querySelectorAll('input').forEach(cb=>cb.onchange=()=>{VIS[cb.dataset.k]=cb.checked;save('tkCols',VIS);render();});
}
+function renderPillMenu(){
+ const m=$('#pillmenu');
+ m.innerHTML=`<div class="gh">Stat pills</div>`+PILLS.map(p=>`<label><input type="checkbox" data-k="${p.k}" ${PILL_VIS[p.k]?'checked':''}>${esc(p.l)}</label>`).join('');
+ m.querySelectorAll('input').forEach(cb=>cb.onchange=()=>{PILL_VIS[cb.dataset.k]=cb.checked?1:0;save('tkPills',PILL_VIS);renderPills();});
+}
window.setQ=v=>{$('#q').value=v;q=v;render();};
$('#q').oninput=e=>{q=e.target.value;render();};
$('#dens').oninput=e=>{DENS=+e.target.value;document.documentElement.style.setProperty('--rowpad',DENS+'px');save('tkDens',DENS);};
-$('#colsBtn').onclick=()=>{$('#colmenu').classList.toggle('show');};
-$('#resetBtn').onclick=()=>{['tkCols','tkOrder','tkWid','tkDens'].forEach(k=>localStorage.removeItem(k));location.reload();};
-document.addEventListener('click',e=>{if(!e.target.closest('#colmenu,#colsBtn'))$('#colmenu').classList.remove('show');});
+$('#colsBtn').onclick=()=>{$('#pillmenu').classList.remove('show');$('#colmenu').classList.toggle('show');};
+$('#pillsBtn').onclick=()=>{$('#colmenu').classList.remove('show');$('#pillmenu').classList.toggle('show');};
+$('#resetBtn').onclick=()=>{['tkCols','tkOrder','tkWid','tkDens','tkPills'].forEach(k=>localStorage.removeItem(k));location.reload();};
+document.addEventListener('click',e=>{if(!e.target.closest('#colmenu,#colsBtn'))$('#colmenu').classList.remove('show');if(!e.target.closest('#pillmenu,#pillsBtn'))$('#pillmenu').classList.remove('show');});
function dmPanel(mm){
const map=new Map(mm.map(m=>[m.mid,m]));const rootOf=mid=>{let id=mid,c=map.get(mid),seen=new Set([id]);while(c&&c.re&&map.get(c.re)){if(seen.has(c.re))break;seen.add(c.re);id=c.re;c=map.get(id);}return id;};
const th=new Map();for(const m of mm){const r=rootOf(m.mid);(th.get(r)||th.set(r,[]).get(r)).push(m);}
@@ -163,5 +180,5 @@ async function load(){
DATA=t; render(); dmPanel(m);
}catch(e){$('#tbody').innerHTML=`<tr><td>load failed: ${esc(e.message)}</td></tr>`;}
}
-renderColMenu(); load(); setInterval(load,30000);
+renderColMenu(); renderPillMenu(); load(); setInterval(load,30000);
</script></body></html>
← 8ee20d87 board: adjustable-columns TABLE view at / (resize/reorder/to
·
back to Ticket System
·
board: on/off toggles for all four field groups — columns (▦ c65f1c1b →