Total Downtime
${formatMinutes(totalDowntime)}
MTTR
${formatMinutes(Math.round(mttr))}
Uptime (30d)
${uptimePercentage.toFixed(3)}%
`;
};
const renderDataTable = () => {
dataTableBody.innerHTML = '';
// Sort by most recent date
const sortedIncidents = [...state.incidents].sort((a, b) => new Date(b.date) - new Date(a.date));
sortedIncidents.forEach(inc => {
const row = `
| ${inc.date} |
${inc.cause} |
${inc.duration} |
`;
dataTableBody.innerHTML += row;
});
};
const renderCharts = () => {
const aggregatedData = getAggregatedData();
const labels = aggregatedData.map(d => d.cause);
const durationData = aggregatedData.map(d => d.totalDuration);
const frequencyData = aggregatedData.map(d => d.count);
const chartColors = ['#2563eb', '#f97316', '#16a34a', '#dc2626', '#9333ea'];
// Duration Bar Chart
if (durationChart) durationChart.destroy();
durationChart = new Chart(durationCanvas.getContext('2d'), {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Total Downtime (Minutes)',
data: durationData,
backgroundColor: 'rgba(37, 99, 235, 0.7)',
borderColor: 'rgba(37, 99, 235, 1)',
borderWidth: 1
}]
},
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } } }
});
// Frequency Pie Chart
if (frequencyChart) frequencyChart.destroy();
frequencyChart = new Chart(frequencyCanvas.getContext('2d'), {
type: 'pie',
data: {
labels: labels,
datasets: [{
data: frequencyData,
backgroundColor: chartColors,
}]
},
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' } } }
});
};
const renderConfigRows = () => {
configRowsContainer.innerHTML = '';
state.incidents.forEach(inc => {
const row = `
`;
configRowsContainer.innerHTML += row;
});
addConfigEventListeners();
};
// --- EVENT HANDLERS ---
const handleConfigChange = (e) => {
const id = parseInt(e.target.dataset.id);
const field = e.target.dataset.field;
const value = field === 'duration' ? parseInt(e.target.value, 10) || 0 : e.target.value;
const incident = state.incidents.find(inc => inc.id === id);
if (incident) {
incident[field] = value;
}
renderAll();
};
const handleAddIncident = () => {
const newId = state.incidents.length > 0 ? Math.max(...state.incidents.map(inc => inc.id)) + 1 : 1;
const today = new Date().toISOString().split('T')[0];
state.incidents.push({ id: newId, date: today, cause: "New Incident", duration: 0 });
renderAll();
};
const handleRemoveIncident = (e) => {
const id = parseInt(e.target.dataset.id);
state.incidents = state.incidents.filter(inc => inc.id !== id);
renderAll();
};
const addConfigEventListeners = () => {
document.querySelectorAll('.config-input').forEach(input => input.addEventListener('change', handleConfigChange));
document.querySelectorAll('.remove-incident-btn').forEach(button => button.addEventListener('click', handleRemoveIncident));
};
const handleDownloadPdf = () => {
const { jsPDF } = window.jspdf;
const pdfContent = document.getElementById('pdf-content');
document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'hidden');
Chart.defaults.animation = false;
html2canvas(pdfContent, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => {
document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'visible');
Chart.defaults.animation = true;
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const imgWidth = pdfWidth - 20;
const imgHeight = canvas.height * imgWidth / canvas.width;
pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight);
pdf.save('Network-Downtime-Analysis.pdf');
});
};
// --- TABBING LOGIC ---
let currentTabIndex = 0;
const updateTabButtons = () => {
prevTabBtn.disabled = currentTabIndex === 0;
nextTabBtn.disabled = currentTabIndex === tabContents.length - 1;
};
const switchTab = (index) => {
tabButtons.forEach(btn => btn.classList.remove('active'));
tabContents.forEach(content => content.classList.remove('active'));
tabButtons[index].classList.add('active');
tabContents[index].classList.add('active');
currentTabIndex = index;
updateTabButtons();
};
tabButtons.forEach((button, index) => button.addEventListener('click', () => switchTab(index)));
prevTabBtn.addEventListener('click', () => { if (currentTabIndex > 0) switchTab(currentTabIndex - 1); });
nextTabBtn.addEventListener('click', () => { if (currentTabIndex < tabContents.length - 1) switchTab(currentTabIndex + 1); });
// --- INITIALIZATION ---
if (kpiCardsContainer && addIncidentBtn && downloadPdfBtn) {
addIncidentBtn.addEventListener('click', handleAddIncident);
downloadPdfBtn.addEventListener('click', handleDownloadPdf);
renderAll();
updateTabButtons();
} else {
console.error("Essential dashboard elements could not be found.");
}
});