Post-Incident Review Action Item Tracker

Post-Incident Review Action Item Tracker

Action Item Dashboard

Add New Action Item

Configuration

Manage Owners

    Manage Statuses

      No action items match the current filters. Add one from the 'Add Action Item' tab.

      `; pdfDownloadBtn.style.display = 'none'; return; } const statusColors = { 'Completed': 'var(--pir-status-completed)', 'In Progress': 'var(--pir-status-progress)', 'Not Started': 'var(--pir-status-notstarted)' }; let tableHTML = ``; filteredItems.forEach((item, index) => { const originalIndex = actionItems.findIndex(ai => ai.id === item.id); tableHTML += ``; }); tableHTML += '
      IncidentAction ItemOwnerDue DatePriorityStatusActions
      ${escapeHTML(item.incident)} ${escapeHTML(item.desc)} ${escapeHTML(item.owner)} ${item.dueDate} ${item.priority} ${item.status}
      '; dashboardContent.innerHTML = tableHTML; pdfDownloadBtn.style.display = 'block'; } function populateDropdowns() { const populate = (select, options, includeAll = false) => { select.innerHTML = includeAll ? '' : ''; options.forEach(opt => select.innerHTML += ``); }; populate(ownerSelect, owners); populate(statusSelect, statuses); populate(prioritySelect, priorities); populate(filterStatus, statuses, true); populate(filterPriority, priorities, true); populate(filterOwner, owners, true); } function renderConfigLists() { const renderList = (listEl, data, deleteClass) => { listEl.innerHTML = data.map((item, i) => `
    • ${escapeHTML(item)}
    • `).join(''); }; renderList(ownersList, owners, 'pir-delete-owner'); renderList(statusesList, statuses, 'pir-delete-status'); } function loadSampleData() { owners = ['Infra Team (USA)', 'Dev Team (USA)', 'Security Team']; statuses = ['Not Started', 'In Progress', 'Completed', 'Blocked']; actionItems = [{ id: Date.now(), incident: 'Q3 US-East-1 Outage', desc: 'Implement redundant power supply for core routers.', owner: 'Infra Team (USA)', dueDate: '2025-11-15', priority: 'High', status: 'In Progress' }, { id: Date.now() + 1, incident: 'Q3 US-East-1 Outage', desc: 'Update monitoring alerts for latency spikes.', owner: 'Dev Team (USA)', dueDate: '2025-11-01', priority: 'Medium', status: 'Completed' }]; renderAll(); } function renderAll() { renderConfigLists(); populateDropdowns(); renderDashboard(); } async function downloadPdf() { const { jsPDF } = jspdf; const content = container.querySelector('#pir-pdf-target'); container.classList.add('pir-pdf-view'); try { const canvas = await html2canvas(content, { scale: 2, useCORS: true, logging: false }); const pdf = new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'a4' }); const imgData = canvas.toDataURL('image/png'); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = (canvas.height * pdfWidth) / canvas.width; pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight); pdf.save('PIR_Action_Items.pdf'); } catch (error) { console.error("PDF Error:", error); alert("Error generating PDF."); } finally { container.classList.remove('pir-pdf-view'); } } function escapeHTML(str) { return str.replace(/[&<>"']/g, m => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[m])); } // --- 4. EVENT BINDING --- tabButtons.forEach((btn, i) => btn.addEventListener('click', () => showPirTab(i))); navNext.addEventListener('click', () => showPirTab(currentPirTab + 1)); navPrev.addEventListener('click', () => showPirTab(currentPirTab - 1)); pdfDownloadBtn.addEventListener('click', downloadPdf); [filterStatus, filterPriority, filterOwner].forEach(el => el.addEventListener('change', renderDashboard)); addItemForm.addEventListener('submit', (e) => { e.preventDefault(); actionItems.push({ id: Date.now(), incident: incidentNameInput.value, desc: actionDescInput.value, owner: ownerSelect.value, dueDate: dueDateInput.value, priority: prioritySelect.value, status: statusSelect.value, }); addItemForm.reset(); renderDashboard(); showPirTab(0); }); addOwnerBtn.addEventListener('click', () => { const newOwner = newOwnerInput.value.trim(); if (newOwner && !owners.includes(newOwner)) { owners.push(newOwner); newOwnerInput.value = ''; renderAll(); } }); addStatusBtn.addEventListener('click', () => { const newStatus = newStatusInput.value.trim(); if (newStatus && !statuses.includes(newStatus)) { statuses.push(newStatus); newStatusInput.value = ''; renderAll(); } }); container.addEventListener('click', (e) => { const target = e.target; const deleteAction = (list, renderFn) => { if (confirm('Are you sure you want to delete this item?')) { list.splice(parseInt(target.dataset.index, 10), 1); renderFn(); } }; if (target.classList.contains('pir-delete-item')) deleteAction(actionItems, renderDashboard); if (target.classList.contains('pir-delete-owner')) deleteAction(owners, renderAll); if (target.classList.contains('pir-delete-status')) deleteAction(statuses, renderAll); }); // --- 5. INITIALIZATION --- loadSampleData(); showPirTab(0); });
      Scroll to Top