diff --git a/projects/msp-tools/bug-tracker/dashboard.html b/projects/msp-tools/bug-tracker/dashboard.html index 99c3d88f..33e3eeba 100644 --- a/projects/msp-tools/bug-tracker/dashboard.html +++ b/projects/msp-tools/bug-tracker/dashboard.html @@ -200,7 +200,20 @@ const SECTIONS = [ { id: 'gc-all', label: 'GuruConnect', repos: ['guru-connect'], filter: () => true }, { id: 'ct-bugs', label: 'Harness / Skill Bugs', repos: ['claudetools'], filter: i => getType(i)==='bug' || getType(i)==='security' }, { id: 'ct-skills', label: 'Skill Work', repos: ['claudetools'], filter: i => getType(i)==='skill' }, - { id: 'ct-projects', label: 'Projects', repos: ['claudetools'], filter: i => getType(i)==='project' || getType(i)==='feature' }, + { id: 'ct-projects', label: 'Projects', repos: ['claudetools'], filter: i => (getType(i)==='project' || getType(i)==='feature') && !isClientProject(i) }, +]; +// Client project sections — built dynamically from labels +const CLIENT_SECTIONS = [ + { id: 'cp-all', label: 'All Client Projects', client: null }, + { id: 'cp-cascades', label: 'Cascades', client: 'client:cascades' }, + { id: 'cp-glaztech', label: 'GlazTech', client: 'client:glaztech' }, + { id: 'cp-sif', label: 'SIF / Oidak', client: 'client:sif-oidak' }, + { id: 'cp-goldstein', label: 'Goldstein', client: 'client:goldstein' }, + { id: 'cp-prairie', label: 'Prairie Schooner', client: 'client:prairie-schooner' }, + { id: 'cp-cryoweave', label: 'CryoWeave', client: 'client:cryoweave' }, + { id: 'cp-tedards', label: 'Tedards Law', client: 'client:tedards' }, + { id: 'cp-vwp', label: 'Valley Water Pumps', client: 'client:vwp' }, + { id: 'cp-acg', label: 'ACG Internal', client: 'client:acg' }, ]; const ALL_REPOS = ['gururmm','guru-rmm','guru-connect','claudetools']; const REPO_NAMES = { 'gururmm':'GuruRMM', 'guru-rmm':'GuruRMM', 'guru-connect':'GuruConnect', 'claudetools':'ClaudeTools' }; @@ -288,6 +301,15 @@ function getType(i) { for(const t of ['bug','feature','skill','project','security']) if(i.labels.some(l=>l.name===t)) return t; return null; } +function isClientProject(i) { return i.labels.some(l => l.name === 'client-project'); } +function getAssignee(i) { + const a = i.labels.find(l => l.name.startsWith('assigned:')); + return a ? a.name.split(':')[1] : null; +} +function getClient(i) { + const c = i.labels.find(l => l.name.startsWith('client:')); + return c ? c.name : null; +} function getDiscovered(i) { // Parse "**Discovered:** YYYY-MM-DD" from issue body if (!i.body) return null; @@ -306,9 +328,19 @@ function tagStyle(l) { return `background:#${l.color}20;color:#${l.color};`; } function getFiltered() { let items = allIssues; - if (currentSection !== 'all' && currentSection !== 'activity') { + if (currentSection.startsWith('cp-')) { + // Client project section + const cs = CLIENT_SECTIONS.find(s=>s.id===currentSection); + if (cs) { + items = items.filter(i => isClientProject(i)); + if (cs.client) items = items.filter(i => i.labels.some(l => l.name === cs.client)); + } + } else if (currentSection === 'all') { + // Exclude client projects from "all issues" + items = items.filter(i => !isClientProject(i)); + } else if (currentSection !== 'activity') { const sec = SECTIONS.find(s=>s.id===currentSection); - if (sec) items = items.filter(i => sec.repos.includes(i._repo) && sec.filter(i)); + if (sec) items = items.filter(i => sec.repos.includes(i._repo) && sec.filter(i) && !isClientProject(i)); } if (searchText) { const q = searchText.toLowerCase(); @@ -355,6 +387,27 @@ function renderSidebar() { ${sec.label} ${countFor(sec)} `; } + + // Client projects section + const cpCount = (cs) => { + let items = allIssues.filter(i => i.state !== 'closed' && isClientProject(i)); + if (cs && cs.client) items = items.filter(i => i.labels.some(l => l.name === cs.client)); + return items.length; + }; + const totalCp = cpCount(null); + html += ``; + html += ``; + for (const cs of CLIENT_SECTIONS.filter(s=>s.client)) { + const cnt = cpCount(cs); + if (cnt > 0) { + html += ``; + } + } + sb.innerHTML = html; } @@ -407,11 +460,14 @@ function renderStats(items) { function makeCard(i) { const p=getPriority(i); const st=getStatus(i); - const tags=i.labels.filter(l=>!l.name.match(/^P\d/)&&!['in-progress','blocked','dropped','fixed','verified','wontfix'].includes(l.name)); + const tags=i.labels.filter(l=>!l.name.match(/^P\d/)&&!['in-progress','blocked','dropped','fixed','verified','wontfix','client-project'].includes(l.name)&&!l.name.startsWith('assigned:')&&!l.name.startsWith('client:')); + const assignee=getAssignee(i); + const isCp=isClientProject(i); + const clientLabel=getClient(i); return `
-
${i._rname}#${i.number}
+
${isCp && clientLabel ? clientLabel.split(':')[1] : i._rname}#${i.number}
${esc(i.title)}
-
${tags.map(l=>`${esc(l.name)}`).join('')}
+
${tags.map(l=>`${esc(l.name)}`).join('')}${assignee?`${assignee}`:''}
${p?`${p}`:''} ${timeAgo(getDiscovered(i)||i.created_at)} old · upd ${timeAgo(i.updated_at)} @@ -591,6 +647,7 @@ function showNewIssue() { +
@@ -609,6 +666,30 @@ function showNewIssue() {
+
@@ -619,6 +700,18 @@ function showNewIssue() {
`; document.getElementById('new-overlay').classList.add('open'); + // Show/hide client fields based on type + const typeEl = document.getElementById('ni-type'); + const clientRow = document.getElementById('ni-client-row'); + const toggleClient = () => { clientRow.style.display = typeEl.value === 'client-project' ? 'flex' : 'none'; }; + typeEl.onchange = toggleClient; + // Pre-select client-project if we're in a client section + if (currentSection.startsWith('cp-')) { + typeEl.value = 'client-project'; + toggleClient(); + const cs = CLIENT_SECTIONS.find(s=>s.id===currentSection); + if (cs && cs.client) document.getElementById('ni-client').value = cs.client; + } setTimeout(()=>document.getElementById('ni-title').focus(), 100); } function closeNew() { document.getElementById('new-overlay').classList.remove('open'); } @@ -630,11 +723,16 @@ async function submitNew() { const type=document.getElementById('ni-type').value; const prio=document.getElementById('ni-prio').value; const comp=document.getElementById('ni-comp').value; + const client=document.getElementById('ni-client').value; + const assign=document.getElementById('ni-assign').value; const err=document.getElementById('ni-err'); if(!title) { err.textContent='Title required'; err.style.display='block'; return; } + if(type==='client-project'&&!client) { err.textContent='Select a client'; err.style.display='block'; return; } const lc=labelCache[repo]||{}; const ids=[lc[type],lc[prio]].filter(Boolean); if(comp&&lc[comp]) ids.push(lc[comp]); + if(client&&lc[client]) ids.push(lc[client]); + if(assign&&lc[assign]) ids.push(lc[assign]); try { const r=await fetch(`${API}/repos/${OWNER}/${repo}/issues`, {method:'POST', headers:{...headers(),'Content-Type':'application/json'}, body:JSON.stringify({title,body,labels:ids})}); if(!r.ok) { const e=await r.json(); err.textContent=e.message||'Failed'; err.style.display='block'; return; } diff --git a/session-logs/2026-07/2026-07-17-howard-bug-tracker-deployment.md b/session-logs/2026-07/2026-07-17-howard-bug-tracker-deployment.md index bd767e7a..2d35925d 100644 --- a/session-logs/2026-07/2026-07-17-howard-bug-tracker-deployment.md +++ b/session-logs/2026-07/2026-07-17-howard-bug-tracker-deployment.md @@ -109,6 +109,12 @@ docker run -d --name acg-tracker --restart unless-stopped \ - Consider adding assignee support to the dashboard (Gitea supports assignees) - RMM Thoughts backlog (RMM_THOUGHTS.md) now has corresponding Gitea issues — future feature requests should go directly to Gitea via the tracker +## Update: 20:15 PT — Client project tracking added + +Added client project tracking to the tracker dashboard. Created `client-project` label + 14 client-specific labels (client:cascades, client:glaztech, etc.) + `assigned:mike` / `assigned:howard` labels on the claudetools repo. Filed 10 Cascades project items from the wiki REMAINING-WORK-PLAN (domain join, M365 relicensing, break-glass accounts, PAA removal, Juan offboard, ASSISTNURSE-PC kiosk, ALIS records, Zeke MFA, KPI dashboard, voice QoS). Each tagged with client, priority, and assignee. + +Updated the dashboard with a "Client Projects" sidebar section separate from All Issues. Client projects are excluded from the code bug/feature views. The sidebar shows per-client counts and only displays clients that have active projects. Cards show assignee tags. The new issue form adds Client and Assigned To dropdowns when "Client Project" type is selected, auto-selecting the current client when filing from a client section. Filed GuruRMM feature request (gururmm #74) for built-in client/site project tracking in the RMM dashboard as the long-term solution. + ## Reference Information - Dashboard source: `projects/msp-tools/bug-tracker/dashboard.html`