Audit Findings Dashboard

Current Status

Findings by Status

Open Findings by Department

Actionable Findings Queue

Add New Finding

Master Findings List

Total Findings

${all.length}

Open Findings

${open.length}

Overdue

${overdueCount}

Critical/High Risk Open

${(byRisk['Critical'] || 0) + (byRisk['High'] || 0)}

`; } function renderCharts(all, open) { const byStatus = all.reduce((acc, f) => { acc[f.status] = (acc[f.status] || 0) + 1; return acc; }, {}); renderChart('audit-status-chart', 'doughnut', { labels: Object.keys(byStatus), datasets: [{ data: Object.values(byStatus), backgroundColor: ['#fde68a', '#c4b5fd', '#dcfce7', '#e5e7eb'] }] }, { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom' } } } ); const byDept = open.reduce((acc, f) => { acc[f.dept] = (acc[f.dept] || 0) + 1; return acc; }, {}); renderChart('audit-dept-chart', 'bar', { labels: Object.keys(byDept), datasets: [{ label: 'Open Findings', data: Object.values(byDept), backgroundColor: 'rgba(7, 89, 133, 0.7)' }] }, { responsive: true, maintainAspectRatio: false, indexAxis: 'y', plugins: { legend: { display: false } } } ); } const renderTable = (tbodyId, theadId, data, isMaster = false) => { document.getElementById(theadId).innerHTML = `RiskDescriptionDepartmentOwnerDue DateStatusActions`; const tbody = document.getElementById(tbodyId); tbody.innerHTML = data.map(f => { const isOverdue = new Date(f.due) < new Date() && (f.status === 'Open' || f.status === 'In Progress'); const actionButtons = { "Open": ``, "In Progress": ``, }; return ` ${f.risk} ${f.desc}${f.dept}${f.owner} ${f.due}${isOverdue ? ' \u26A0' : ''} ${f.status} ${!isMaster ? (actionButtons[f.status] || '') : ``} `; }).join(''); } const renderFindingsTable = (data) => renderTable('audit-findings-table-body', 'audit-findings-table-head', data); const renderMasterTable = (data) => renderTable('audit-master-table-body', 'audit-master-table-head', data, true); // --- Data Management & Actions --- window.auditAddFinding = function() { findings.push({ id: Date.now(), desc: document.getElementById('add-desc').value, dept: document.getElementById('add-dept').value, owner: document.getElementById('add-owner').value, risk: document.getElementById('add-risk').value, status: 'Open', due: document.getElementById('add-due').value, }); renderAll(); } function handleActionClick(e) { if (!e.target.matches('.action-btn')) return; const id = parseInt(e.target.dataset.id); const action = e.target.dataset.action; if (action === 'delete') { findings = findings.filter(f => f.id !== id); } else { const finding = findings.find(f => f.id === id); if (finding) { if(action === 'progress') finding.status = 'In Progress'; else if(action === 'remediate') finding.status = 'Remediated'; } } renderAll(); } // --- Global & Utility --- window.auditShowTab = id => { document.querySelectorAll('.audit-main-tab-content, .audit-main-tab-button').forEach(el => el.classList.remove('active')); document.getElementById(`audit-tab-${id}`).classList.add('active'); document.querySelector(`.audit-main-tab-button[onclick="auditShowTab('${id}')"]`).classList.add('active'); }; window.auditDownloadPDF = () => { html2canvas(document.getElementById('audit-pdf-content'), { scale: 2 }).then(canvas => { const pdf = new jspdf.jsPDF({ orientation: 'landscape', unit: 'pt', format: 'a4' }); pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 40, 40, pdf.internal.pageSize.getWidth() - 80, 0); pdf.save('Audit_Findings_Dashboard.pdf'); }); }; initialize(); });
Scroll to Top