Service Level Agreement (SLA) Dashboard
Overall SLA Compliance
0%
System Uptime
0%
Target: > 99.9%Avg. First Response Time
0m
Target: < 15mAvg. Resolution Time
0h 0m
Target: < 4hSLA Success Rate by Tier
SLA Adherence by Priority
Recent Ticket Performance
| Ticket ID | Priority | Tier | Response Time | Resolution Time | SLA Met? |
|---|
Add/Edit Ticket Data
All Ticket Records
| ID | Priority | Tier | Resolution Time | Action |
|---|
Error: A required library is missing.
'; return; } // --- DATA MANAGEMENT & SLA DEFINITIONS --- let ticketData = JSON.parse(localStorage.getItem('sla_tickets')) || []; const SLA_TARGETS = { uptime: 99.9, frt: 15, art: 4, // Global targets for display priority: { Critical: { frt: 15, art: 4 * 60 }, // in minutes High: { frt: 60, art: 8 * 60 }, Normal: { frt: 4 * 60, art: 24 * 60 } } }; const getSampleData = () => { const tickets = []; const priorities = ['Critical', 'High', 'Normal']; const tiers = ['Enterprise', 'Business', 'Standard']; for (let i = 0; i < 50; i++) { const priority = priorities[Math.floor(Math.random() * 3)]; const sla = SLA_TARGETS.priority[priority]; const metSla = Math.random() > 0.1; // 90% success rate const frt = metSla ? Math.floor(Math.random() * sla.frt * 0.9) + 1 : Math.floor(Math.random() * sla.frt * 0.5) + sla.frt; const art = metSla ? Math.floor(Math.random() * sla.art * 0.9) + frt : Math.floor(Math.random() * sla.art * 0.5) + sla.art; tickets.push({ id: `T${7500 + i}`, priority: priority, tier: tiers[Math.floor(Math.random() * 3)], responseTime: frt, resolutionTime: art, }); } return tickets; }; if (ticketData.length === 0) ticketData = getSampleData(); const saveState = () => localStorage.setItem('sla_tickets', JSON.stringify(ticketData)); // --- CHART INSTANCES & UTILITIES --- let tierChart, priorityChart; const tabButtons = document.querySelectorAll('.sla-tab-button'); const tabContents = document.querySelectorAll('.sla-tab-content'); const nextBtn = document.getElementById('sla-next-btn'); const prevBtn = document.getElementById('sla-prev-btn'); const formatMinutes = (minutes) => { if (minutes < 60) return `${Math.round(minutes)}m`; const hours = Math.floor(minutes / 60); const mins = Math.round(minutes % 60); return `${hours}h ${mins}m`; }; // --- RENDER FUNCTIONS --- const renderAll = () => { try { const processedTickets = ticketData.map(t => { const sla = SLA_TARGETS.priority[t.priority]; const slaMet = t.responseTime <= sla.frt && t.resolutionTime <= sla.art; return { ...t, slaMet }; }); renderKPIs(processedTickets); renderTierChart(processedTickets); renderPriorityChart(processedTickets); renderTicketLog(processedTickets); renderManageTable(processedTickets); updateNavButtons(); } catch(error) { console.error("Dashboard rendering failed:", error); } }; const renderKPIs = (data) => { const slaMetCount = data.filter(t => t.slaMet).length; const overallCompliance = data.length > 0 ? (slaMetCount / data.length) * 100 : 100; const avgFrt = data.length > 0 ? data.reduce((sum, t) => sum + t.responseTime, 0) / data.length : 0; const avgArt = data.length > 0 ? data.reduce((sum, t) => sum + t.resolutionTime, 0) / data.length : 0; const uptimeEl = document.getElementById('sla-uptime-kpi'); uptimeEl.textContent = '99.98%'; // Static sample uptimeEl.style.color = 99.98 >= SLA_TARGETS.uptime ? 'var(--sla-success-color)' : 'var(--sla-danger-color)'; const frtEl = document.getElementById('sla-frt-kpi'); frtEl.textContent = formatMinutes(avgFrt); frtEl.style.color = avgFrt <= SLA_TARGETS.frt ? 'var(--sla-success-color)' : 'var(--sla-danger-color)'; const artEl = document.getElementById('sla-art-kpi'); artEl.textContent = formatMinutes(avgArt); artEl.style.color = avgArt / 60 <= SLA_TARGETS.art ? 'var(--sla-success-color)' : 'var(--sla-danger-color)'; const complianceEl = document.getElementById('sla-overall-compliance-kpi'); complianceEl.textContent = `${overallCompliance.toFixed(1)}%`; complianceEl.style.color = overallCompliance >= 95 ? 'var(--sla-success-color)' : 'var(--sla-danger-color)'; }; const renderTierChart = (data) => { const tiers = ['Enterprise', 'Business', 'Standard']; const successRates = tiers.map(tier => { const tierTickets = data.filter(t => t.tier === tier); if (tierTickets.length === 0) return 0; const metCount = tierTickets.filter(t => t.slaMet).length; return (metCount / tierTickets.length) * 100; }); const options = { chart: { type: 'bar', height: 350, toolbar: { show: false } }, series: [{ name: 'Success Rate', data: successRates.map(r => r.toFixed(1)) }], xaxis: { categories: tiers }, yaxis: { min: 0, max: 100, labels: { formatter: (val) => `${val}%` } }, plotOptions: { bar: { distributed: true, horizontal: false } }, colors: successRates.map(r => r >= 90 ? 'var(--sla-success-color)' : r >= 80 ? 'var(--sla-warning-color)' : 'var(--sla-danger-color)'), legend: { show: false }, dataLabels: { enabled: true, formatter: (val) => `${val}%`, style: { colors: ['#333'] } } }; if(tierChart) tierChart.destroy(); document.querySelector("#sla-tier-chart").innerHTML = ''; tierChart = new ApexCharts(document.querySelector("#sla-tier-chart"), options); tierChart.render(); }; const renderPriorityChart = (data) => { const priorities = ['Critical', 'High', 'Normal']; const responseMet = priorities.map(p => { const pTickets = data.filter(t => t.priority === p); if (pTickets.length === 0) return 100; return (pTickets.filter(t => t.responseTime <= SLA_TARGETS.priority[p].frt).length / pTickets.length) * 100; }); const resolutionMet = priorities.map(p => { const pTickets = data.filter(t => t.priority === p); if (pTickets.length === 0) return 100; return (pTickets.filter(t => t.resolutionTime <= SLA_TARGETS.priority[p].art).length / pTickets.length) * 100; }); const options = { chart: { type: 'bar', height: 350, toolbar: { show: false } }, series: [ { name: 'Response SLA Met', data: responseMet.map(r => r.toFixed(1)) }, { name: 'Resolution SLA Met', data: resolutionMet.map(r => r.toFixed(1)) } ], xaxis: { categories: priorities }, yaxis: { min: 0, max: 100, labels: { formatter: (val) => `${val}%` } }, plotOptions: { bar: { horizontal: false } }, colors: ['var(--sla-secondary-color)', 'var(--sla-success-color)'], legend: { position: 'top' }, dataLabels: { enabled: false } }; if(priorityChart) priorityChart.destroy(); document.querySelector("#sla-priority-chart").innerHTML = ''; priorityChart = new ApexCharts(document.querySelector("#sla-priority-chart"), options); priorityChart.render(); }; const renderTicketLog = (data) => { const tbody = document.getElementById('sla-tickets-tbody'); tbody.innerHTML = ''; data.slice(0,10).forEach(t => { const statusClass = t.slaMet ? 'sla-status-met' : 'sla-status-breached'; tbody.innerHTML += `