Files
catalog/ts_web/elements/upl-statuspage-statusmonth.demo.ts
2025-06-29 19:55:58 +00:00

876 lines
35 KiB
TypeScript

import { html } from '@design.estate/dees-element';
import type { IMonthlyUptime, IUptimeDay } from '../interfaces/index.js';
export const demoFunc = () => html`
<style>
.demo-container {
display: flex;
flex-direction: column;
gap: 20px;
}
.demo-section {
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
background: #f5f5f5;
}
.demo-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 16px;
color: #333;
}
.demo-controls {
display: flex;
gap: 10px;
margin-top: 16px;
flex-wrap: wrap;
}
.demo-button {
padding: 6px 12px;
border: 1px solid #ddd;
background: white;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
.demo-button:hover {
background: #f0f0f0;
}
.demo-button.active {
background: #2196F3;
color: white;
border-color: #2196F3;
}
.demo-info {
margin-top: 12px;
padding: 12px;
background: white;
border-radius: 4px;
font-size: 13px;
line-height: 1.6;
}
.stats-display {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 12px;
margin-top: 12px;
}
.stat-card {
background: white;
padding: 12px;
border-radius: 4px;
text-align: center;
}
.stat-value {
font-size: 18px;
font-weight: 600;
color: #2196F3;
}
.stat-label {
font-size: 11px;
color: #666;
margin-top: 4px;
}
.month-nav {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 12px;
}
</style>
<div class="demo-container">
<!-- Different Month Patterns -->
<div class="demo-section">
<div class="demo-title">Different Month Patterns</div>
<dees-demowrapper
.runAfterRender=${async (wrapperElement: any) => {
const statusMonth = wrapperElement.querySelector('upl-statuspage-statusmonth') as any;
// Pattern generators
const generateMonthPattern = (monthCount: number, pattern: 'perfect' | 'problematic' | 'improving' | 'degrading' | 'seasonal'): IMonthlyUptime[] => {
const months: IMonthlyUptime[] = [];
const now = new Date();
for (let monthOffset = monthCount - 1; monthOffset >= 0; monthOffset--) {
const monthDate = new Date(now.getFullYear(), now.getMonth() - monthOffset, 1);
const year = monthDate.getFullYear();
const month = monthDate.getMonth();
const monthKey = `${year}-${String(month + 1).padStart(2, '0')}`;
const daysInMonth = new Date(year, month + 1, 0).getDate();
const days: IUptimeDay[] = [];
let totalIncidents = 0;
let totalUptimeMinutes = 0;
for (let day = 1; day <= daysInMonth; day++) {
let uptime = 100;
let incidents = 0;
let downtime = 0;
let status: IUptimeDay['status'] = 'operational';
switch (pattern) {
case 'perfect':
// Near perfect uptime
if (Math.random() < 0.02) {
uptime = 99.9 + Math.random() * 0.099;
status = 'degraded';
}
break;
case 'problematic':
// Frequent issues
const problemRand = Math.random();
if (problemRand < 0.1) {
uptime = 70 + Math.random() * 20;
incidents = 2 + Math.floor(Math.random() * 3);
status = 'major_outage';
} else if (problemRand < 0.25) {
uptime = 90 + Math.random() * 8;
incidents = 1 + Math.floor(Math.random() * 2);
status = 'partial_outage';
} else if (problemRand < 0.4) {
uptime = 98 + Math.random() * 1.5;
incidents = 1;
status = 'degraded';
}
break;
case 'improving':
// Getting better over time
const improvementFactor = (monthCount - monthOffset) / monthCount;
const improveRand = Math.random();
if (improveRand < 0.3 * (1 - improvementFactor)) {
uptime = 85 + Math.random() * 10 + (improvementFactor * 10);
incidents = Math.max(0, 3 - Math.floor(improvementFactor * 3));
status = improvementFactor > 0.7 ? 'degraded' : 'partial_outage';
}
break;
case 'degrading':
// Getting worse over time
const degradationFactor = monthOffset / monthCount;
const degradeRand = Math.random();
if (degradeRand < 0.3 * (1 - degradationFactor)) {
uptime = 85 + Math.random() * 10 + (degradationFactor * 10);
incidents = Math.max(0, 3 - Math.floor(degradationFactor * 3));
status = degradationFactor > 0.7 ? 'degraded' : 'major_outage';
}
break;
case 'seasonal':
// Worse during certain months (simulating high traffic periods)
const monthNum = month;
if (monthNum === 11 || monthNum === 0) { // December, January
if (Math.random() < 0.3) {
uptime = 92 + Math.random() * 6;
incidents = 1 + Math.floor(Math.random() * 2);
status = 'degraded';
}
} else if (monthNum === 6 || monthNum === 7) { // July, August
if (Math.random() < 0.2) {
uptime = 94 + Math.random() * 5;
incidents = 1;
status = 'degraded';
}
}
break;
}
downtime = Math.floor((100 - uptime) * 14.4);
totalIncidents += incidents;
totalUptimeMinutes += uptime * 14.4;
days.push({
date: `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
uptime,
incidents,
totalDowntime: downtime,
status
});
}
const overallUptime = totalUptimeMinutes / (daysInMonth * 1440) * 100;
months.push({
month: monthKey,
days,
overallUptime,
totalIncidents
});
}
return months;
};
// Initial setup
statusMonth.serviceId = 'production-api';
statusMonth.serviceName = 'Production API';
statusMonth.monthlyData = generateMonthPattern(6, 'perfect');
// Create pattern controls
const controls = document.createElement('div');
controls.className = 'demo-controls';
const patterns = [
{ key: 'perfect', label: 'Perfect Uptime' },
{ key: 'problematic', label: 'Problematic' },
{ key: 'improving', label: 'Improving Trend' },
{ key: 'degrading', label: 'Degrading Trend' },
{ key: 'seasonal', label: 'Seasonal Pattern' }
];
patterns.forEach((pattern, index) => {
const button = document.createElement('button');
button.className = 'demo-button' + (index === 0 ? ' active' : '');
button.textContent = pattern.label;
button.onclick = () => {
controls.querySelectorAll('.demo-button').forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
statusMonth.loading = true;
setTimeout(() => {
statusMonth.monthlyData = generateMonthPattern(6, pattern.key as any);
statusMonth.loading = false;
updateStats();
}, 500);
};
controls.appendChild(button);
});
wrapperElement.appendChild(controls);
// Add statistics display
const statsDiv = document.createElement('div');
statsDiv.className = 'stats-display';
wrapperElement.appendChild(statsDiv);
const updateStats = () => {
const data = statusMonth.monthlyData || [];
const avgUptime = data.reduce((sum, month) => sum + month.overallUptime, 0) / data.length;
const totalIncidents = data.reduce((sum, month) => sum + month.totalIncidents, 0);
const worstMonth = data.reduce((worst, month) =>
month.overallUptime < worst.overallUptime ? month : worst, data[0]);
statsDiv.innerHTML = `
<div class="stat-card">
<div class="stat-value">${avgUptime.toFixed(3)}%</div>
<div class="stat-label">Avg Uptime</div>
</div>
<div class="stat-card">
<div class="stat-value">${totalIncidents}</div>
<div class="stat-label">Total Incidents</div>
</div>
<div class="stat-card">
<div class="stat-value">${data.length}</div>
<div class="stat-label">Months</div>
</div>
<div class="stat-card">
<div class="stat-value">${worstMonth ? worstMonth.overallUptime.toFixed(2) : '100'}%</div>
<div class="stat-label">Worst Month</div>
</div>
`;
};
updateStats();
// Handle day clicks
statusMonth.addEventListener('dayClick', (event: CustomEvent) => {
const { date, uptime, incidents, status, totalDowntime } = event.detail;
alert(`Day Details for ${date}:\n\nUptime: ${uptime.toFixed(3)}%\nIncidents: ${incidents}\nStatus: ${status}\nDowntime: ${totalDowntime} minutes`);
});
}}
>
<upl-statuspage-statusmonth></upl-statuspage-statusmonth>
</dees-demowrapper>
</div>
<!-- Different Time Spans -->
<div class="demo-section">
<div class="demo-title">Different Time Spans</div>
<dees-demowrapper
.runAfterRender=${async (wrapperElement: any) => {
const statusMonth = wrapperElement.querySelector('upl-statuspage-statusmonth') as any;
// Generate data for different time spans
const generateTimeSpanData = (months: number): IMonthlyUptime[] => {
const data: IMonthlyUptime[] = [];
const now = new Date();
for (let monthOffset = months - 1; monthOffset >= 0; monthOffset--) {
const monthDate = new Date(now.getFullYear(), now.getMonth() - monthOffset, 1);
const year = monthDate.getFullYear();
const month = monthDate.getMonth();
const monthKey = `${year}-${String(month + 1).padStart(2, '0')}`;
const daysInMonth = new Date(year, month + 1, 0).getDate();
const days: IUptimeDay[] = [];
let totalIncidents = 0;
let totalUptimeMinutes = 0;
for (let day = 1; day <= daysInMonth; day++) {
// Create realistic patterns
let uptime = 99.9 + Math.random() * 0.099;
let incidents = 0;
let status: IUptimeDay['status'] = 'operational';
if (Math.random() < 0.05) {
uptime = 95 + Math.random() * 4.9;
incidents = 1;
status = 'degraded';
} else if (Math.random() < 0.01) {
uptime = 85 + Math.random() * 10;
incidents = 2;
status = 'partial_outage';
}
const downtime = Math.floor((100 - uptime) * 14.4);
totalIncidents += incidents;
totalUptimeMinutes += uptime * 14.4;
days.push({
date: `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
uptime,
incidents,
totalDowntime: downtime,
status
});
}
const overallUptime = totalUptimeMinutes / (daysInMonth * 1440) * 100;
data.push({
month: monthKey,
days,
overallUptime,
totalIncidents
});
}
return data;
};
// Initial setup
statusMonth.serviceId = 'multi-region-lb';
statusMonth.serviceName = 'Multi-Region Load Balancer';
statusMonth.monthlyData = generateTimeSpanData(3);
// Create time span controls
const controls = document.createElement('div');
controls.className = 'demo-controls';
const timeSpans = [
{ months: 3, label: 'Last 3 Months' },
{ months: 6, label: 'Last 6 Months' },
{ months: 12, label: 'Last 12 Months' },
{ months: 24, label: 'Last 24 Months' }
];
timeSpans.forEach((span, index) => {
const button = document.createElement('button');
button.className = 'demo-button' + (index === 0 ? ' active' : '');
button.textContent = span.label;
button.onclick = () => {
controls.querySelectorAll('.demo-button').forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
statusMonth.loading = true;
setTimeout(() => {
statusMonth.monthlyData = generateTimeSpanData(span.months);
statusMonth.loading = false;
}, 500);
};
controls.appendChild(button);
});
wrapperElement.appendChild(controls);
// Add info display
const info = document.createElement('div');
info.className = 'demo-info';
info.innerHTML = 'Click on different time spans to see historical uptime data. The component automatically adjusts the display based on the number of months.';
wrapperElement.appendChild(info);
}}
>
<upl-statuspage-statusmonth></upl-statuspage-statusmonth>
</dees-demowrapper>
</div>
<!-- Current Month Real-time Updates -->
<div class="demo-section">
<div class="demo-title">Current Month with Real-time Updates</div>
<dees-demowrapper
.runAfterRender=${async (wrapperElement: any) => {
const statusMonth = wrapperElement.querySelector('upl-statuspage-statusmonth') as any;
// Generate current month data
const generateCurrentMonthData = (): IMonthlyUptime[] => {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth();
const today = now.getDate();
const monthKey = `${year}-${String(month + 1).padStart(2, '0')}`;
const daysInMonth = new Date(year, month + 1, 0).getDate();
const days: IUptimeDay[] = [];
let totalIncidents = 0;
let totalUptimeMinutes = 0;
// Generate data only up to today
for (let day = 1; day <= today; day++) {
let uptime = 99.9 + Math.random() * 0.099;
let incidents = 0;
let status: IUptimeDay['status'] = 'operational';
// Today might have ongoing issues
if (day === today) {
if (Math.random() < 0.3) {
uptime = 95 + Math.random() * 4;
incidents = 1;
status = 'degraded';
}
} else if (Math.random() < 0.05) {
uptime = 97 + Math.random() * 2.9;
incidents = 1;
status = 'degraded';
}
const downtime = Math.floor((100 - uptime) * 14.4);
totalIncidents += incidents;
totalUptimeMinutes += uptime * 14.4;
days.push({
date: `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
uptime,
incidents,
totalDowntime: downtime,
status
});
}
// Fill remaining days with placeholder
for (let day = today + 1; day <= daysInMonth; day++) {
days.push({
date: `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
uptime: 0,
incidents: 0,
totalDowntime: 0,
status: 'operational'
});
}
const overallUptime = today > 0 ? totalUptimeMinutes / (today * 1440) * 100 : 100;
return [{
month: monthKey,
days,
overallUptime,
totalIncidents
}];
};
// Initial setup
statusMonth.serviceId = 'realtime-monitor';
statusMonth.serviceName = 'Real-time Monitoring Service';
statusMonth.monthlyData = generateCurrentMonthData();
statusMonth.showCurrentDay = true;
// Update today's status periodically
const updateInterval = setInterval(() => {
const data = statusMonth.monthlyData;
if (data && data.length > 0) {
const currentMonth = data[0];
const today = new Date().getDate() - 1;
if (currentMonth.days[today]) {
// Simulate status changes
const rand = Math.random();
if (rand < 0.1) {
currentMonth.days[today].uptime = 95 + Math.random() * 4.9;
currentMonth.days[today].incidents = (currentMonth.days[today].incidents || 0) + 1;
currentMonth.days[today].status = 'degraded';
currentMonth.days[today].totalDowntime = Math.floor((100 - currentMonth.days[today].uptime) * 14.4);
// Recalculate overall uptime
let totalUptime = 0;
let validDays = 0;
currentMonth.days.forEach((day, index) => {
if (index <= today && day.uptime > 0) {
totalUptime += day.uptime;
validDays++;
}
});
currentMonth.overallUptime = validDays > 0 ? totalUptime / validDays : 100;
currentMonth.totalIncidents = currentMonth.days.reduce((sum, day) => sum + (day.incidents || 0), 0);
statusMonth.requestUpdate();
logUpdate('Status degraded - Uptime: ' + currentMonth.days[today].uptime.toFixed(2) + '%');
} else if (rand < 0.05 && currentMonth.days[today].status !== 'operational') {
// Recover from issues
currentMonth.days[today].uptime = 99.9 + Math.random() * 0.099;
currentMonth.days[today].status = 'operational';
currentMonth.days[today].totalDowntime = Math.floor((100 - currentMonth.days[today].uptime) * 14.4);
statusMonth.requestUpdate();
logUpdate('Service recovered to operational status');
}
}
}
}, 3000);
// Create controls
const controls = document.createElement('div');
controls.className = 'demo-controls';
controls.innerHTML = '<button class="demo-button" id="simulateOutage">Simulate Outage</button>' +
'<button class="demo-button" id="simulateRecovery">Simulate Recovery</button>' +
'<button class="demo-button" id="refreshData">Refresh Data</button>';
wrapperElement.appendChild(controls);
controls.querySelector('#simulateOutage')?.addEventListener('click', () => {
const data = statusMonth.monthlyData;
if (data && data.length > 0) {
const today = new Date().getDate() - 1;
data[0].days[today].uptime = 85 + Math.random() * 10;
data[0].days[today].incidents = (data[0].days[today].incidents || 0) + 1;
data[0].days[today].status = 'major_outage';
data[0].days[today].totalDowntime = Math.floor((100 - data[0].days[today].uptime) * 14.4);
statusMonth.requestUpdate();
logUpdate('Major outage simulated');
}
});
controls.querySelector('#simulateRecovery')?.addEventListener('click', () => {
const data = statusMonth.monthlyData;
if (data && data.length > 0) {
const today = new Date().getDate() - 1;
data[0].days[today].uptime = 99.95;
data[0].days[today].status = 'operational';
data[0].days[today].totalDowntime = Math.floor((100 - data[0].days[today].uptime) * 14.4);
statusMonth.requestUpdate();
logUpdate('Service recovered');
}
});
controls.querySelector('#refreshData')?.addEventListener('click', () => {
statusMonth.monthlyData = generateCurrentMonthData();
logUpdate('Data refreshed');
});
// Add update log
const logDiv = document.createElement('div');
logDiv.className = 'demo-info';
logDiv.style.maxHeight = '100px';
logDiv.style.overflowY = 'auto';
logDiv.innerHTML = '<strong>Update Log:</strong><br>';
wrapperElement.appendChild(logDiv);
const logUpdate = (message: string) => {
const time = new Date().toLocaleTimeString();
logDiv.innerHTML += '[' + time + '] ' + message + '<br>';
logDiv.scrollTop = logDiv.scrollHeight;
};
// Cleanup
wrapperElement.addEventListener('remove', () => {
clearInterval(updateInterval);
});
}}
>
<upl-statuspage-statusmonth></upl-statuspage-statusmonth>
</dees-demowrapper>
</div>
<!-- Edge Cases -->
<div class="demo-section">
<div class="demo-title">Edge Cases and Special Scenarios</div>
<dees-demowrapper
.runAfterRender=${async (wrapperElement: any) => {
const statusMonth = wrapperElement.querySelector('upl-statuspage-statusmonth') as any;
const scenarios = {
noData: {
name: 'No Data',
data: []
},
singleMonth: {
name: 'Single Month',
data: [{
month: '2024-01',
days: Array.from({ length: 31 }, (_, i) => ({
date: `2024-01-${String(i + 1).padStart(2, '0')}`,
uptime: 99.9 + Math.random() * 0.099,
incidents: 0,
totalDowntime: 0,
status: 'operational' as const
})),
overallUptime: 99.95,
totalIncidents: 0
}]
},
allDown: {
name: 'Complete Outage Month',
data: [{
month: '2024-01',
days: Array.from({ length: 31 }, (_, i) => ({
date: `2024-01-${String(i + 1).padStart(2, '0')}`,
uptime: 0,
incidents: 5,
totalDowntime: 1440,
status: 'major_outage' as const
})),
overallUptime: 0,
totalIncidents: 155
}]
},
maintenanceMonth: {
name: 'Maintenance Heavy Month',
data: [{
month: '2024-01',
days: Array.from({ length: 31 }, (_, i) => {
// Maintenance every weekend
const dayOfWeek = new Date(2024, 0, i + 1).getDay();
if (dayOfWeek === 0 || dayOfWeek === 6) {
return {
date: `2024-01-${String(i + 1).padStart(2, '0')}`,
uptime: 95,
incidents: 0,
totalDowntime: 72,
status: 'maintenance' as const
};
}
return {
date: `2024-01-${String(i + 1).padStart(2, '0')}`,
uptime: 99.95,
incidents: 0,
totalDowntime: 0.7,
status: 'operational' as const
};
}),
overallUptime: 98.2,
totalIncidents: 0
}]
},
mixedYear: {
name: 'Full Year Mixed',
data: Array.from({ length: 12 }, (_, monthIndex) => {
const year = 2023;
const month = monthIndex;
const daysInMonth = new Date(year, month + 1, 0).getDate();
// Different pattern each quarter
let monthPattern = 'operational';
if (monthIndex < 3) monthPattern = 'degraded';
else if (monthIndex < 6) monthPattern = 'improving';
else if (monthIndex < 9) monthPattern = 'stable';
else monthPattern = 'volatile';
const days = Array.from({ length: daysInMonth }, (_, dayIndex) => {
let uptime = 99.9;
let status: IUptimeDay['status'] = 'operational';
let incidents = 0;
if (monthPattern === 'degraded' && Math.random() < 0.3) {
uptime = 85 + Math.random() * 10;
status = 'degraded';
incidents = 1;
} else if (monthPattern === 'volatile' && Math.random() < 0.2) {
uptime = 90 + Math.random() * 9;
status = Math.random() < 0.5 ? 'partial_outage' : 'degraded';
incidents = Math.floor(Math.random() * 3) + 1;
}
return {
date: `${year}-${String(month + 1).padStart(2, '0')}-${String(dayIndex + 1).padStart(2, '0')}`,
uptime,
incidents,
totalDowntime: Math.floor((100 - uptime) * 14.4),
status
};
});
const totalIncidents = days.reduce((sum, day) => sum + day.incidents, 0);
const overallUptime = days.reduce((sum, day) => sum + day.uptime, 0) / days.length;
return {
month: `${year}-${String(month + 1).padStart(2, '0')}`,
days,
overallUptime,
totalIncidents
};
})
}
};
// Initial setup
let currentScenario = 'singleMonth';
statusMonth.serviceId = 'edge-case-service';
statusMonth.serviceName = 'Edge Case Service';
statusMonth.monthlyData = scenarios[currentScenario].data;
// Create scenario controls
const controls = document.createElement('div');
controls.className = 'demo-controls';
Object.entries(scenarios).forEach(([key, scenario]) => {
const button = document.createElement('button');
button.className = 'demo-button' + (key === currentScenario ? ' active' : '');
button.textContent = scenario.name;
button.onclick = () => {
controls.querySelectorAll('.demo-button').forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
currentScenario = key;
statusMonth.loading = true;
setTimeout(() => {
statusMonth.monthlyData = scenario.data;
statusMonth.loading = false;
}, 300);
};
controls.appendChild(button);
});
wrapperElement.appendChild(controls);
}}
>
<upl-statuspage-statusmonth></upl-statuspage-statusmonth>
</dees-demowrapper>
</div>
<!-- Loading and Navigation States -->
<div class="demo-section">
<div class="demo-title">Loading and Navigation Features</div>
<dees-demowrapper
.runAfterRender=${async (wrapperElement: any) => {
const statusMonth = wrapperElement.querySelector('upl-statuspage-statusmonth') as any;
// Start with loading
statusMonth.loading = true;
statusMonth.serviceId = 'navigation-demo';
statusMonth.serviceName = 'Navigation Demo Service';
const controls = document.createElement('div');
controls.className = 'demo-controls';
controls.innerHTML = '<button class="demo-button" id="toggleLoading">Toggle Loading</button>' +
'<button class="demo-button" id="loadSuccess">Load Successfully</button>' +
'<button class="demo-button" id="loadError">Simulate Error</button>' +
'<button class="demo-button" id="toggleTooltip">Toggle Tooltip</button>';
wrapperElement.appendChild(controls);
controls.querySelector('#toggleLoading')?.addEventListener('click', () => {
statusMonth.loading = !statusMonth.loading;
});
controls.querySelector('#loadSuccess')?.addEventListener('click', () => {
statusMonth.loading = true;
setTimeout(() => {
const months = 6;
const data: IMonthlyUptime[] = [];
const now = new Date();
for (let i = months - 1; i >= 0; i--) {
const monthDate = new Date(now.getFullYear(), now.getMonth() - i, 1);
const year = monthDate.getFullYear();
const month = monthDate.getMonth();
const daysInMonth = new Date(year, month + 1, 0).getDate();
data.push({
month: `${year}-${String(month + 1).padStart(2, '0')}`,
days: Array.from({ length: daysInMonth }, (_, d) => ({
date: `${year}-${String(month + 1).padStart(2, '0')}-${String(d + 1).padStart(2, '0')}`,
uptime: 99 + Math.random(),
incidents: Math.random() < 0.05 ? 1 : 0,
totalDowntime: Math.random() < 0.05 ? Math.floor(Math.random() * 60) : 0,
status: Math.random() < 0.05 ? 'degraded' : 'operational'
})),
overallUptime: 99.5 + Math.random() * 0.4,
totalIncidents: Math.floor(Math.random() * 5)
});
}
statusMonth.monthlyData = data;
statusMonth.loading = false;
}, 1000);
});
controls.querySelector('#loadError')?.addEventListener('click', () => {
statusMonth.loading = true;
setTimeout(() => {
statusMonth.loading = false;
statusMonth.monthlyData = [];
statusMonth.errorMessage = 'Failed to load monthly uptime data';
}, 1500);
});
controls.querySelector('#toggleTooltip')?.addEventListener('click', () => {
statusMonth.showTooltip = !statusMonth.showTooltip;
const btn = controls.querySelector('#toggleTooltip');
if (btn) btn.textContent = 'Toggle Tooltip (' + (statusMonth.showTooltip ? 'ON' : 'OFF') + ')';
});
// Month navigation
const navDiv = document.createElement('div');
navDiv.className = 'month-nav';
navDiv.innerHTML = '<button class="demo-button" id="prevMonth">← Previous</button>' +
'<span id="currentMonth">Loading...</span>' +
'<button class="demo-button" id="nextMonth">Next →</button>';
wrapperElement.appendChild(navDiv);
let currentMonthIndex = 0;
const updateNavigation = () => {
const data = statusMonth.monthlyData || [];
if (data.length > 0 && currentMonthIndex < data.length) {
const month = data[currentMonthIndex];
const currentMonthEl = navDiv.querySelector('#currentMonth');
if (currentMonthEl) currentMonthEl.textContent = month.month;
const prevBtn = navDiv.querySelector('#prevMonth') as HTMLButtonElement;
const nextBtn = navDiv.querySelector('#nextMonth') as HTMLButtonElement;
if (prevBtn) prevBtn.disabled = currentMonthIndex === 0;
if (nextBtn) nextBtn.disabled = currentMonthIndex === data.length - 1;
}
};
navDiv.querySelector('#prevMonth')?.addEventListener('click', () => {
if (currentMonthIndex > 0) {
currentMonthIndex--;
updateNavigation();
// Highlight the month somehow
statusMonth.highlightMonth = statusMonth.monthlyData[currentMonthIndex].month;
}
});
navDiv.querySelector('#nextMonth')?.addEventListener('click', () => {
if (currentMonthIndex < (statusMonth.monthlyData?.length || 0) - 1) {
currentMonthIndex++;
updateNavigation();
statusMonth.highlightMonth = statusMonth.monthlyData[currentMonthIndex].month;
}
});
// Initial load
setTimeout(() => {
const data = Array.from({ length: 3 }, (_, i) => ({
month: `2024-${String(i + 1).padStart(2, '0')}`,
days: Array.from({ length: 31 }, (_, d) => ({
date: `2024-${String(i + 1).padStart(2, '0')}-${String(d + 1).padStart(2, '0')}`,
uptime: 99.5 + Math.random() * 0.5,
incidents: 0,
totalDowntime: 0,
status: 'operational' as const
})),
overallUptime: 99.7 + Math.random() * 0.3,
totalIncidents: Math.floor(Math.random() * 3)
}));
statusMonth.monthlyData = data;
statusMonth.loading = false;
statusMonth.showTooltip = true;
updateNavigation();
}, 1000);
}}
>
<upl-statuspage-statusmonth></upl-statuspage-statusmonth>
</dees-demowrapper>
</div>
</div>
`;