@uptime.link/statuspage 1.0.73 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_bundle/bundle.js +4096 -504
- package/dist_bundle/bundle.js.map +4 -4
- package/dist_ts_web/00_commitinfo_data.js +2 -2
- package/dist_ts_web/elements/index.d.ts +3 -0
- package/dist_ts_web/elements/index.js +6 -1
- package/dist_ts_web/elements/internal/uplinternal-miniheading.d.ts +1 -0
- package/dist_ts_web/elements/internal/uplinternal-miniheading.js +78 -28
- package/dist_ts_web/elements/upl-statuspage-assetsselector.d.ts +14 -0
- package/dist_ts_web/elements/upl-statuspage-assetsselector.demo.d.ts +1 -0
- package/dist_ts_web/elements/upl-statuspage-assetsselector.demo.js +575 -0
- package/dist_ts_web/elements/upl-statuspage-assetsselector.js +605 -43
- package/dist_ts_web/elements/upl-statuspage-footer.d.ts +46 -2
- package/dist_ts_web/elements/upl-statuspage-footer.demo.d.ts +1 -0
- package/dist_ts_web/elements/upl-statuspage-footer.demo.js +679 -0
- package/dist_ts_web/elements/upl-statuspage-footer.js +792 -61
- package/dist_ts_web/elements/upl-statuspage-header.d.ts +5 -1
- package/dist_ts_web/elements/upl-statuspage-header.demo.d.ts +1 -0
- package/dist_ts_web/elements/upl-statuspage-header.demo.js +220 -0
- package/dist_ts_web/elements/upl-statuspage-header.js +313 -86
- package/dist_ts_web/elements/upl-statuspage-incidents.d.ts +22 -4
- package/dist_ts_web/elements/upl-statuspage-incidents.demo.d.ts +1 -0
- package/dist_ts_web/elements/upl-statuspage-incidents.demo.js +1147 -0
- package/dist_ts_web/elements/upl-statuspage-incidents.js +750 -74
- package/dist_ts_web/elements/upl-statuspage-pagetitle.d.ts +15 -0
- package/dist_ts_web/elements/upl-statuspage-pagetitle.demo.d.ts +1 -0
- package/dist_ts_web/elements/upl-statuspage-pagetitle.demo.js +25 -0
- package/dist_ts_web/elements/upl-statuspage-pagetitle.js +148 -0
- package/dist_ts_web/elements/upl-statuspage-statsgrid.d.ts +23 -0
- package/dist_ts_web/elements/upl-statuspage-statsgrid.demo.d.ts +1 -0
- package/dist_ts_web/elements/upl-statuspage-statsgrid.demo.js +295 -0
- package/dist_ts_web/elements/upl-statuspage-statsgrid.js +374 -0
- package/dist_ts_web/elements/upl-statuspage-statusbar.d.ts +4 -0
- package/dist_ts_web/elements/upl-statuspage-statusbar.demo.d.ts +1 -0
- package/dist_ts_web/elements/upl-statuspage-statusbar.demo.js +365 -0
- package/dist_ts_web/elements/upl-statuspage-statusbar.js +357 -44
- package/dist_ts_web/elements/upl-statuspage-statusdetails.d.ts +14 -0
- package/dist_ts_web/elements/upl-statuspage-statusdetails.demo.d.ts +1 -0
- package/dist_ts_web/elements/upl-statuspage-statusdetails.demo.js +706 -0
- package/dist_ts_web/elements/upl-statuspage-statusdetails.js +373 -63
- package/dist_ts_web/elements/upl-statuspage-statusmonth.d.ts +15 -0
- package/dist_ts_web/elements/upl-statuspage-statusmonth.demo.d.ts +1 -0
- package/dist_ts_web/elements/upl-statuspage-statusmonth.demo.js +798 -0
- package/dist_ts_web/elements/upl-statuspage-statusmonth.js +474 -100
- package/dist_ts_web/interfaces/index.d.ts +84 -0
- package/dist_ts_web/interfaces/index.js +4 -0
- package/dist_ts_web/pages/index.d.ts +4 -1
- package/dist_ts_web/pages/index.js +5 -2
- package/dist_ts_web/pages/statuspage-allgreen.d.ts +1 -0
- package/dist_ts_web/pages/statuspage-allgreen.js +386 -0
- package/dist_ts_web/pages/statuspage-demo.d.ts +1 -0
- package/dist_ts_web/pages/statuspage-demo.js +616 -0
- package/dist_ts_web/pages/statuspage-maintenance.d.ts +1 -0
- package/dist_ts_web/pages/statuspage-maintenance.js +544 -0
- package/dist_ts_web/pages/statuspage-outage.d.ts +1 -0
- package/dist_ts_web/pages/statuspage-outage.js +543 -0
- package/dist_ts_web/styles/shared.styles.d.ts +80 -0
- package/dist_ts_web/styles/shared.styles.js +351 -0
- package/dist_watch/bundle.js +54534 -26433
- package/dist_watch/bundle.js.map +4 -4
- package/dist_watch/index.html +3 -10
- package/npmextra.json +9 -3
- package/package.json +19 -19
- package/readme.hints.md +292 -0
- package/readme.md +326 -149
- package/readme.plan.md +261 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/index.ts +6 -0
- package/ts_web/elements/internal/uplinternal-miniheading.ts +24 -17
- package/ts_web/elements/upl-statuspage-assetsselector.demo.ts +607 -0
- package/ts_web/elements/upl-statuspage-assetsselector.ts +526 -18
- package/ts_web/elements/upl-statuspage-footer.demo.ts +744 -0
- package/ts_web/elements/upl-statuspage-footer.ts +608 -30
- package/ts_web/elements/upl-statuspage-header.demo.ts +241 -0
- package/ts_web/elements/upl-statuspage-header.ts +220 -52
- package/ts_web/elements/upl-statuspage-incidents.demo.ts +1216 -0
- package/ts_web/elements/upl-statuspage-incidents.ts +649 -26
- package/ts_web/elements/upl-statuspage-pagetitle.demo.ts +25 -0
- package/ts_web/elements/upl-statuspage-pagetitle.ts +89 -0
- package/ts_web/elements/upl-statuspage-statsgrid.demo.ts +315 -0
- package/ts_web/elements/upl-statuspage-statsgrid.ts +306 -0
- package/ts_web/elements/upl-statuspage-statusbar.demo.ts +393 -0
- package/ts_web/elements/upl-statuspage-statusbar.ts +281 -20
- package/ts_web/elements/upl-statuspage-statusdetails.demo.ts +754 -0
- package/ts_web/elements/upl-statuspage-statusdetails.ts +297 -38
- package/ts_web/elements/upl-statuspage-statusmonth.demo.ts +876 -0
- package/ts_web/elements/upl-statuspage-statusmonth.ts +397 -76
- package/ts_web/interfaces/index.ts +95 -0
- package/ts_web/pages/index.ts +4 -1
- package/ts_web/pages/statuspage-allgreen.ts +412 -0
- package/ts_web/pages/statuspage-demo.ts +653 -0
- package/ts_web/pages/statuspage-maintenance.ts +570 -0
- package/ts_web/pages/statuspage-outage.ts +568 -0
- package/ts_web/styles/shared.styles.ts +367 -0
- package/dist_ts_web/pages/page1.d.ts +0 -1
- package/dist_ts_web/pages/page1.js +0 -11
- package/ts_web/pages/page1.ts +0 -11
|
@@ -0,0 +1,754 @@
|
|
|
1
|
+
import { html } from '@design.estate/dees-element';
|
|
2
|
+
import type { IStatusHistoryPoint } from '../interfaces/index.js';
|
|
3
|
+
|
|
4
|
+
export const demoFunc = () => html`
|
|
5
|
+
<style>
|
|
6
|
+
.demo-container {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: 20px;
|
|
10
|
+
}
|
|
11
|
+
.demo-section {
|
|
12
|
+
border: 1px solid #ddd;
|
|
13
|
+
border-radius: 8px;
|
|
14
|
+
padding: 20px;
|
|
15
|
+
background: #f5f5f5;
|
|
16
|
+
}
|
|
17
|
+
.demo-title {
|
|
18
|
+
font-size: 14px;
|
|
19
|
+
font-weight: 600;
|
|
20
|
+
margin-bottom: 16px;
|
|
21
|
+
color: #333;
|
|
22
|
+
}
|
|
23
|
+
.demo-controls {
|
|
24
|
+
display: flex;
|
|
25
|
+
gap: 10px;
|
|
26
|
+
margin-top: 16px;
|
|
27
|
+
flex-wrap: wrap;
|
|
28
|
+
}
|
|
29
|
+
.demo-button {
|
|
30
|
+
padding: 6px 12px;
|
|
31
|
+
border: 1px solid #ddd;
|
|
32
|
+
background: white;
|
|
33
|
+
border-radius: 4px;
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
font-size: 13px;
|
|
36
|
+
}
|
|
37
|
+
.demo-button:hover {
|
|
38
|
+
background: #f0f0f0;
|
|
39
|
+
}
|
|
40
|
+
.demo-button.active {
|
|
41
|
+
background: #2196F3;
|
|
42
|
+
color: white;
|
|
43
|
+
border-color: #2196F3;
|
|
44
|
+
}
|
|
45
|
+
.demo-info {
|
|
46
|
+
margin-top: 12px;
|
|
47
|
+
padding: 12px;
|
|
48
|
+
background: white;
|
|
49
|
+
border-radius: 4px;
|
|
50
|
+
font-size: 13px;
|
|
51
|
+
}
|
|
52
|
+
.stats-grid {
|
|
53
|
+
display: grid;
|
|
54
|
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
55
|
+
gap: 12px;
|
|
56
|
+
margin-top: 12px;
|
|
57
|
+
}
|
|
58
|
+
.stat-box {
|
|
59
|
+
background: white;
|
|
60
|
+
padding: 12px;
|
|
61
|
+
border-radius: 4px;
|
|
62
|
+
text-align: center;
|
|
63
|
+
}
|
|
64
|
+
.stat-value {
|
|
65
|
+
font-size: 20px;
|
|
66
|
+
font-weight: 600;
|
|
67
|
+
color: #2196F3;
|
|
68
|
+
}
|
|
69
|
+
.stat-label {
|
|
70
|
+
font-size: 12px;
|
|
71
|
+
color: #666;
|
|
72
|
+
margin-top: 4px;
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
75
|
+
|
|
76
|
+
<div class="demo-container">
|
|
77
|
+
<!-- Time Range Demo -->
|
|
78
|
+
<div class="demo-section">
|
|
79
|
+
<div class="demo-title">Different Time Ranges</div>
|
|
80
|
+
<dees-demowrapper
|
|
81
|
+
.runAfterRender=${async (wrapperElement: any) => {
|
|
82
|
+
const statusDetails = wrapperElement.querySelector('upl-statuspage-statusdetails') as any;
|
|
83
|
+
|
|
84
|
+
// Generate data for different time ranges
|
|
85
|
+
const generateDataForRange = (hours: number, pattern: 'stable' | 'degrading' | 'improving' | 'volatile' = 'stable'): IStatusHistoryPoint[] => {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
const data: IStatusHistoryPoint[] = [];
|
|
88
|
+
|
|
89
|
+
// For proper display, we need hourly data points that align with actual hours
|
|
90
|
+
for (let i = hours - 1; i >= 0; i--) {
|
|
91
|
+
// Create timestamp at the start of each hour
|
|
92
|
+
const date = new Date();
|
|
93
|
+
date.setMinutes(0, 0, 0);
|
|
94
|
+
date.setHours(date.getHours() - i);
|
|
95
|
+
const timestamp = date.getTime();
|
|
96
|
+
let status: IStatusHistoryPoint['status'] = 'operational';
|
|
97
|
+
let responseTime = 50 + Math.random() * 50;
|
|
98
|
+
let errorRate = 0;
|
|
99
|
+
|
|
100
|
+
switch (pattern) {
|
|
101
|
+
case 'degrading':
|
|
102
|
+
// Getting worse over time
|
|
103
|
+
const degradation = (hours - i) / hours;
|
|
104
|
+
if (degradation > 0.7) {
|
|
105
|
+
status = 'major_outage';
|
|
106
|
+
responseTime = 800 + Math.random() * 200;
|
|
107
|
+
errorRate = 0.3 + Math.random() * 0.2;
|
|
108
|
+
} else if (degradation > 0.5) {
|
|
109
|
+
status = 'partial_outage';
|
|
110
|
+
responseTime = 500 + Math.random() * 200;
|
|
111
|
+
errorRate = 0.1 + Math.random() * 0.1;
|
|
112
|
+
} else if (degradation > 0.3) {
|
|
113
|
+
status = 'degraded';
|
|
114
|
+
responseTime = 200 + Math.random() * 100;
|
|
115
|
+
errorRate = 0.02 + Math.random() * 0.03;
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
|
|
119
|
+
case 'improving':
|
|
120
|
+
// Getting better over time
|
|
121
|
+
const improvement = i / hours;
|
|
122
|
+
if (improvement < 0.3) {
|
|
123
|
+
status = 'major_outage';
|
|
124
|
+
responseTime = 800 + Math.random() * 200;
|
|
125
|
+
errorRate = 0.3 + Math.random() * 0.2;
|
|
126
|
+
} else if (improvement < 0.5) {
|
|
127
|
+
status = 'partial_outage';
|
|
128
|
+
responseTime = 500 + Math.random() * 200;
|
|
129
|
+
errorRate = 0.1 + Math.random() * 0.1;
|
|
130
|
+
} else if (improvement < 0.7) {
|
|
131
|
+
status = 'degraded';
|
|
132
|
+
responseTime = 200 + Math.random() * 100;
|
|
133
|
+
errorRate = 0.02 + Math.random() * 0.03;
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
|
|
137
|
+
case 'volatile':
|
|
138
|
+
// Random ups and downs
|
|
139
|
+
const rand = Math.random();
|
|
140
|
+
if (rand < 0.05) {
|
|
141
|
+
status = 'major_outage';
|
|
142
|
+
responseTime = 800 + Math.random() * 200;
|
|
143
|
+
errorRate = 0.3 + Math.random() * 0.2;
|
|
144
|
+
} else if (rand < 0.1) {
|
|
145
|
+
status = 'partial_outage';
|
|
146
|
+
responseTime = 500 + Math.random() * 200;
|
|
147
|
+
errorRate = 0.1 + Math.random() * 0.1;
|
|
148
|
+
} else if (rand < 0.2) {
|
|
149
|
+
status = 'degraded';
|
|
150
|
+
responseTime = 200 + Math.random() * 100;
|
|
151
|
+
errorRate = 0.02 + Math.random() * 0.03;
|
|
152
|
+
} else if (rand < 0.25) {
|
|
153
|
+
status = 'maintenance';
|
|
154
|
+
responseTime = 100 + Math.random() * 50;
|
|
155
|
+
errorRate = 0;
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
|
|
159
|
+
default:
|
|
160
|
+
// Stable with occasional hiccups
|
|
161
|
+
if (Math.random() < 0.02) {
|
|
162
|
+
status = 'degraded';
|
|
163
|
+
responseTime = 200 + Math.random() * 100;
|
|
164
|
+
errorRate = 0.01 + Math.random() * 0.02;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
data.push({
|
|
169
|
+
timestamp,
|
|
170
|
+
status,
|
|
171
|
+
responseTime,
|
|
172
|
+
errorRate
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return data;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Initial setup
|
|
180
|
+
statusDetails.serviceId = 'api-gateway';
|
|
181
|
+
statusDetails.serviceName = 'API Gateway';
|
|
182
|
+
statusDetails.historyData = generateDataForRange(24);
|
|
183
|
+
|
|
184
|
+
// Create controls
|
|
185
|
+
const controls = document.createElement('div');
|
|
186
|
+
controls.className = 'demo-controls';
|
|
187
|
+
|
|
188
|
+
const timeRanges = [
|
|
189
|
+
{ hours: 24, label: '24 Hours' },
|
|
190
|
+
{ hours: 168, label: '7 Days' },
|
|
191
|
+
{ hours: 720, label: '30 Days' },
|
|
192
|
+
{ hours: 2160, label: '90 Days' }
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
timeRanges.forEach((range, index) => {
|
|
196
|
+
const button = document.createElement('button');
|
|
197
|
+
button.className = 'demo-button' + (index === 0 ? ' active' : '');
|
|
198
|
+
button.textContent = range.label;
|
|
199
|
+
button.onclick = () => {
|
|
200
|
+
// Update active button
|
|
201
|
+
controls.querySelectorAll('.demo-button').forEach(btn => btn.classList.remove('active'));
|
|
202
|
+
button.classList.add('active');
|
|
203
|
+
|
|
204
|
+
// Load new data with loading state
|
|
205
|
+
statusDetails.loading = true;
|
|
206
|
+
setTimeout(() => {
|
|
207
|
+
statusDetails.historyData = generateDataForRange(range.hours, 'volatile');
|
|
208
|
+
statusDetails.loading = false;
|
|
209
|
+
updateStats();
|
|
210
|
+
}, 500);
|
|
211
|
+
};
|
|
212
|
+
controls.appendChild(button);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
wrapperElement.appendChild(controls);
|
|
216
|
+
|
|
217
|
+
// Add statistics display
|
|
218
|
+
const statsDiv = document.createElement('div');
|
|
219
|
+
statsDiv.className = 'stats-grid';
|
|
220
|
+
wrapperElement.appendChild(statsDiv);
|
|
221
|
+
|
|
222
|
+
const updateStats = () => {
|
|
223
|
+
const data = statusDetails.historyData || [];
|
|
224
|
+
const operational = data.filter(d => d.status === 'operational').length;
|
|
225
|
+
const avgResponseTime = data.reduce((sum, d) => sum + (d.responseTime || 0), 0) / data.length;
|
|
226
|
+
const uptime = (operational / data.length) * 100;
|
|
227
|
+
const incidents = data.filter(d => d.status !== 'operational' && d.status !== 'maintenance').length;
|
|
228
|
+
|
|
229
|
+
statsDiv.innerHTML = `
|
|
230
|
+
<div class="stat-box">
|
|
231
|
+
<div class="stat-value">${uptime.toFixed(2)}%</div>
|
|
232
|
+
<div class="stat-label">Uptime</div>
|
|
233
|
+
</div>
|
|
234
|
+
<div class="stat-box">
|
|
235
|
+
<div class="stat-value">${avgResponseTime.toFixed(0)}ms</div>
|
|
236
|
+
<div class="stat-label">Avg Response Time</div>
|
|
237
|
+
</div>
|
|
238
|
+
<div class="stat-box">
|
|
239
|
+
<div class="stat-value">${incidents}</div>
|
|
240
|
+
<div class="stat-label">Incidents</div>
|
|
241
|
+
</div>
|
|
242
|
+
<div class="stat-box">
|
|
243
|
+
<div class="stat-value">${data.length}</div>
|
|
244
|
+
<div class="stat-label">Data Points</div>
|
|
245
|
+
</div>
|
|
246
|
+
`;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
updateStats();
|
|
250
|
+
|
|
251
|
+
// Handle bar clicks
|
|
252
|
+
statusDetails.addEventListener('barClick', (event: CustomEvent) => {
|
|
253
|
+
const { timestamp, status, responseTime, errorRate } = event.detail;
|
|
254
|
+
const date = new Date(timestamp);
|
|
255
|
+
alert(`Details for ${date.toLocaleString()}:\n\nStatus: ${status}\nResponse Time: ${responseTime.toFixed(0)}ms\nError Rate: ${(errorRate * 100).toFixed(2)}%`);
|
|
256
|
+
});
|
|
257
|
+
}}
|
|
258
|
+
>
|
|
259
|
+
<upl-statuspage-statusdetails></upl-statuspage-statusdetails>
|
|
260
|
+
</dees-demowrapper>
|
|
261
|
+
</div>
|
|
262
|
+
|
|
263
|
+
<!-- Data Pattern Scenarios -->
|
|
264
|
+
<div class="demo-section">
|
|
265
|
+
<div class="demo-title">Different Data Patterns</div>
|
|
266
|
+
<dees-demowrapper
|
|
267
|
+
.runAfterRender=${async (wrapperElement: any) => {
|
|
268
|
+
const statusDetails = wrapperElement.querySelector('upl-statuspage-statusdetails') as any;
|
|
269
|
+
|
|
270
|
+
// Pattern generators
|
|
271
|
+
const patterns = {
|
|
272
|
+
stable: () => {
|
|
273
|
+
const data: IStatusHistoryPoint[] = [];
|
|
274
|
+
for (let i = 47; i >= 0; i--) {
|
|
275
|
+
const date = new Date();
|
|
276
|
+
date.setMinutes(0, 0, 0);
|
|
277
|
+
date.setHours(date.getHours() - i);
|
|
278
|
+
data.push({
|
|
279
|
+
timestamp: date.getTime(),
|
|
280
|
+
status: 'operational',
|
|
281
|
+
responseTime: 40 + Math.random() * 20,
|
|
282
|
+
errorRate: 0
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
return data;
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
degrading: () => {
|
|
289
|
+
const now = Date.now();
|
|
290
|
+
const data: IStatusHistoryPoint[] = [];
|
|
291
|
+
for (let i = 47; i >= 0; i--) {
|
|
292
|
+
const degradation = (47 - i) / 47;
|
|
293
|
+
let status: IStatusHistoryPoint['status'] = 'operational';
|
|
294
|
+
let responseTime = 50;
|
|
295
|
+
let errorRate = 0;
|
|
296
|
+
|
|
297
|
+
if (degradation > 0.8) {
|
|
298
|
+
status = 'major_outage';
|
|
299
|
+
responseTime = 800 + Math.random() * 200;
|
|
300
|
+
errorRate = 0.4;
|
|
301
|
+
} else if (degradation > 0.6) {
|
|
302
|
+
status = 'partial_outage';
|
|
303
|
+
responseTime = 500 + Math.random() * 100;
|
|
304
|
+
errorRate = 0.2;
|
|
305
|
+
} else if (degradation > 0.4) {
|
|
306
|
+
status = 'degraded';
|
|
307
|
+
responseTime = 200 + Math.random() * 100;
|
|
308
|
+
errorRate = 0.05;
|
|
309
|
+
} else {
|
|
310
|
+
responseTime = 50 + degradation * 100;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
data.push({
|
|
314
|
+
timestamp: now - (i * 60 * 60 * 1000),
|
|
315
|
+
status,
|
|
316
|
+
responseTime,
|
|
317
|
+
errorRate
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return data;
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
recovering: () => {
|
|
324
|
+
const now = Date.now();
|
|
325
|
+
const data: IStatusHistoryPoint[] = [];
|
|
326
|
+
for (let i = 47; i >= 0; i--) {
|
|
327
|
+
const recovery = i / 47;
|
|
328
|
+
let status: IStatusHistoryPoint['status'] = 'operational';
|
|
329
|
+
let responseTime = 50;
|
|
330
|
+
let errorRate = 0;
|
|
331
|
+
|
|
332
|
+
if (recovery < 0.2) {
|
|
333
|
+
status = 'operational';
|
|
334
|
+
responseTime = 50 + Math.random() * 20;
|
|
335
|
+
} else if (recovery < 0.4) {
|
|
336
|
+
status = 'degraded';
|
|
337
|
+
responseTime = 150 + Math.random() * 50;
|
|
338
|
+
errorRate = 0.02;
|
|
339
|
+
} else if (recovery < 0.7) {
|
|
340
|
+
status = 'partial_outage';
|
|
341
|
+
responseTime = 400 + Math.random() * 100;
|
|
342
|
+
errorRate = 0.15;
|
|
343
|
+
} else {
|
|
344
|
+
status = 'major_outage';
|
|
345
|
+
responseTime = 800 + Math.random() * 200;
|
|
346
|
+
errorRate = 0.35;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
data.push({
|
|
350
|
+
timestamp: now - (i * 60 * 60 * 1000),
|
|
351
|
+
status,
|
|
352
|
+
responseTime,
|
|
353
|
+
errorRate
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return data;
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
periodic: () => {
|
|
360
|
+
const now = Date.now();
|
|
361
|
+
const data: IStatusHistoryPoint[] = [];
|
|
362
|
+
for (let i = 47; i >= 0; i--) {
|
|
363
|
+
// Issues every 12 hours
|
|
364
|
+
const hourOfDay = i % 24;
|
|
365
|
+
let status: IStatusHistoryPoint['status'] = 'operational';
|
|
366
|
+
let responseTime = 50 + Math.random() * 30;
|
|
367
|
+
let errorRate = 0;
|
|
368
|
+
|
|
369
|
+
if (hourOfDay >= 9 && hourOfDay <= 11) {
|
|
370
|
+
// Morning peak
|
|
371
|
+
status = 'degraded';
|
|
372
|
+
responseTime = 200 + Math.random() * 100;
|
|
373
|
+
errorRate = 0.05;
|
|
374
|
+
} else if (hourOfDay >= 18 && hourOfDay <= 20) {
|
|
375
|
+
// Evening peak
|
|
376
|
+
status = 'degraded';
|
|
377
|
+
responseTime = 250 + Math.random() * 150;
|
|
378
|
+
errorRate = 0.08;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
data.push({
|
|
382
|
+
timestamp: now - (i * 60 * 60 * 1000),
|
|
383
|
+
status,
|
|
384
|
+
responseTime,
|
|
385
|
+
errorRate
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
return data;
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
maintenance: () => {
|
|
392
|
+
const now = Date.now();
|
|
393
|
+
const data: IStatusHistoryPoint[] = [];
|
|
394
|
+
for (let i = 47; i >= 0; i--) {
|
|
395
|
+
let status: IStatusHistoryPoint['status'] = 'operational';
|
|
396
|
+
let responseTime = 50 + Math.random() * 30;
|
|
397
|
+
let errorRate = 0;
|
|
398
|
+
|
|
399
|
+
// Maintenance window from hour 20-24
|
|
400
|
+
if (i >= 20 && i <= 24) {
|
|
401
|
+
status = 'maintenance';
|
|
402
|
+
responseTime = 0;
|
|
403
|
+
errorRate = 0;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
data.push({
|
|
407
|
+
timestamp: now - (i * 60 * 60 * 1000),
|
|
408
|
+
status,
|
|
409
|
+
responseTime,
|
|
410
|
+
errorRate
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
return data;
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// Initial setup
|
|
418
|
+
statusDetails.serviceId = 'web-server';
|
|
419
|
+
statusDetails.serviceName = 'Web Server';
|
|
420
|
+
statusDetails.historyData = patterns.stable();
|
|
421
|
+
|
|
422
|
+
// Create controls
|
|
423
|
+
const controls = document.createElement('div');
|
|
424
|
+
controls.className = 'demo-controls';
|
|
425
|
+
|
|
426
|
+
Object.entries(patterns).forEach(([name, generator]) => {
|
|
427
|
+
const button = document.createElement('button');
|
|
428
|
+
button.className = 'demo-button' + (name === 'stable' ? ' active' : '');
|
|
429
|
+
button.textContent = name.charAt(0).toUpperCase() + name.slice(1);
|
|
430
|
+
button.onclick = () => {
|
|
431
|
+
controls.querySelectorAll('.demo-button').forEach(btn => btn.classList.remove('active'));
|
|
432
|
+
button.classList.add('active');
|
|
433
|
+
|
|
434
|
+
statusDetails.loading = true;
|
|
435
|
+
setTimeout(() => {
|
|
436
|
+
statusDetails.historyData = generator();
|
|
437
|
+
statusDetails.loading = false;
|
|
438
|
+
updateInfo(name);
|
|
439
|
+
}, 300);
|
|
440
|
+
};
|
|
441
|
+
controls.appendChild(button);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
wrapperElement.appendChild(controls);
|
|
445
|
+
|
|
446
|
+
// Add info display
|
|
447
|
+
const info = document.createElement('div');
|
|
448
|
+
info.className = 'demo-info';
|
|
449
|
+
wrapperElement.appendChild(info);
|
|
450
|
+
|
|
451
|
+
const updateInfo = (pattern: string) => {
|
|
452
|
+
const descriptions = {
|
|
453
|
+
stable: 'Service running smoothly with consistent performance',
|
|
454
|
+
degrading: 'Service health deteriorating over time',
|
|
455
|
+
recovering: 'Service recovering from a major outage',
|
|
456
|
+
periodic: 'Regular performance issues during peak hours (9-11 AM and 6-8 PM)',
|
|
457
|
+
maintenance: 'Scheduled maintenance window (hours 20-24)'
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
info.innerHTML = `<strong>Pattern:</strong> ${descriptions[pattern as keyof typeof descriptions] || pattern}`;
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
updateInfo('stable');
|
|
464
|
+
}}
|
|
465
|
+
>
|
|
466
|
+
<upl-statuspage-statusdetails></upl-statuspage-statusdetails>
|
|
467
|
+
</dees-demowrapper>
|
|
468
|
+
</div>
|
|
469
|
+
|
|
470
|
+
<!-- Interactive Real-time Updates -->
|
|
471
|
+
<div class="demo-section">
|
|
472
|
+
<div class="demo-title">Real-time Updates with Manual Control</div>
|
|
473
|
+
<dees-demowrapper
|
|
474
|
+
.runAfterRender=${async (wrapperElement: any) => {
|
|
475
|
+
const statusDetails = wrapperElement.querySelector('upl-statuspage-statusdetails') as any;
|
|
476
|
+
|
|
477
|
+
// Initialize with recent data
|
|
478
|
+
const now = Date.now();
|
|
479
|
+
const initialData: IStatusHistoryPoint[] = [];
|
|
480
|
+
for (let i = 23; i >= 0; i--) {
|
|
481
|
+
initialData.push({
|
|
482
|
+
timestamp: now - (i * 60 * 60 * 1000),
|
|
483
|
+
status: 'operational',
|
|
484
|
+
responseTime: 50 + Math.random() * 30,
|
|
485
|
+
errorRate: 0
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
statusDetails.serviceId = 'real-time-api';
|
|
490
|
+
statusDetails.serviceName = 'Real-time API';
|
|
491
|
+
statusDetails.historyData = initialData;
|
|
492
|
+
statusDetails.timeRange = '24h';
|
|
493
|
+
|
|
494
|
+
// Create controls
|
|
495
|
+
const controls = document.createElement('div');
|
|
496
|
+
controls.className = 'demo-controls';
|
|
497
|
+
controls.innerHTML = `
|
|
498
|
+
<button class="demo-button" id="addHealthy">Add Healthy Point</button>
|
|
499
|
+
<button class="demo-button" id="addDegraded">Add Degraded Point</button>
|
|
500
|
+
<button class="demo-button" id="addOutage">Add Outage Point</button>
|
|
501
|
+
<button class="demo-button" id="simulateSpike">Simulate Traffic Spike</button>
|
|
502
|
+
<button class="demo-button" id="clearData">Clear All Data</button>
|
|
503
|
+
`;
|
|
504
|
+
wrapperElement.appendChild(controls);
|
|
505
|
+
|
|
506
|
+
const addDataPoint = (status: IStatusHistoryPoint['status'], responseTime: number, errorRate: number = 0) => {
|
|
507
|
+
const data = [...(statusDetails.historyData || [])];
|
|
508
|
+
if (data.length >= 24) {
|
|
509
|
+
data.shift(); // Keep only 24 points
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
data.push({
|
|
513
|
+
timestamp: Date.now(),
|
|
514
|
+
status,
|
|
515
|
+
responseTime,
|
|
516
|
+
errorRate
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
statusDetails.historyData = data;
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
controls.querySelector('#addHealthy')?.addEventListener('click', () => {
|
|
523
|
+
addDataPoint('operational', 50 + Math.random() * 30);
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
controls.querySelector('#addDegraded')?.addEventListener('click', () => {
|
|
527
|
+
addDataPoint('degraded', 200 + Math.random() * 100, 0.05);
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
controls.querySelector('#addOutage')?.addEventListener('click', () => {
|
|
531
|
+
addDataPoint('major_outage', 800 + Math.random() * 200, 0.5);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
controls.querySelector('#simulateSpike')?.addEventListener('click', () => {
|
|
535
|
+
// Add several degraded points
|
|
536
|
+
for (let i = 0; i < 3; i++) {
|
|
537
|
+
setTimeout(() => {
|
|
538
|
+
addDataPoint('degraded', 300 + Math.random() * 200, 0.1 + Math.random() * 0.1);
|
|
539
|
+
}, i * 1000);
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
controls.querySelector('#clearData')?.addEventListener('click', () => {
|
|
544
|
+
statusDetails.historyData = [];
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
// Auto-update every 5 seconds
|
|
548
|
+
let autoUpdate = setInterval(() => {
|
|
549
|
+
const rand = Math.random();
|
|
550
|
+
if (rand < 0.8) {
|
|
551
|
+
addDataPoint('operational', 40 + Math.random() * 40);
|
|
552
|
+
} else if (rand < 0.95) {
|
|
553
|
+
addDataPoint('degraded', 150 + Math.random() * 100, 0.02);
|
|
554
|
+
} else {
|
|
555
|
+
addDataPoint('partial_outage', 400 + Math.random() * 200, 0.15);
|
|
556
|
+
}
|
|
557
|
+
}, 5000);
|
|
558
|
+
|
|
559
|
+
// Add toggle for auto-updates
|
|
560
|
+
const autoToggle = document.createElement('button');
|
|
561
|
+
autoToggle.className = 'demo-button active';
|
|
562
|
+
autoToggle.textContent = 'Auto-update: ON';
|
|
563
|
+
autoToggle.style.marginLeft = '10px';
|
|
564
|
+
autoToggle.onclick = () => {
|
|
565
|
+
if (autoUpdate) {
|
|
566
|
+
clearInterval(autoUpdate);
|
|
567
|
+
autoUpdate = null;
|
|
568
|
+
autoToggle.textContent = 'Auto-update: OFF';
|
|
569
|
+
autoToggle.classList.remove('active');
|
|
570
|
+
} else {
|
|
571
|
+
autoUpdate = setInterval(() => {
|
|
572
|
+
const rand = Math.random();
|
|
573
|
+
if (rand < 0.8) {
|
|
574
|
+
addDataPoint('operational', 40 + Math.random() * 40);
|
|
575
|
+
} else if (rand < 0.95) {
|
|
576
|
+
addDataPoint('degraded', 150 + Math.random() * 100, 0.02);
|
|
577
|
+
} else {
|
|
578
|
+
addDataPoint('partial_outage', 400 + Math.random() * 200, 0.15);
|
|
579
|
+
}
|
|
580
|
+
}, 5000);
|
|
581
|
+
autoToggle.textContent = 'Auto-update: ON';
|
|
582
|
+
autoToggle.classList.add('active');
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
controls.appendChild(autoToggle);
|
|
586
|
+
|
|
587
|
+
// Cleanup on unmount
|
|
588
|
+
wrapperElement.addEventListener('remove', () => {
|
|
589
|
+
if (autoUpdate) clearInterval(autoUpdate);
|
|
590
|
+
});
|
|
591
|
+
}}
|
|
592
|
+
>
|
|
593
|
+
<upl-statuspage-statusdetails></upl-statuspage-statusdetails>
|
|
594
|
+
</dees-demowrapper>
|
|
595
|
+
</div>
|
|
596
|
+
|
|
597
|
+
<!-- Edge Cases -->
|
|
598
|
+
<div class="demo-section">
|
|
599
|
+
<div class="demo-title">Edge Cases and Special Scenarios</div>
|
|
600
|
+
<dees-demowrapper
|
|
601
|
+
.runAfterRender=${async (wrapperElement: any) => {
|
|
602
|
+
const statusDetails = wrapperElement.querySelector('upl-statuspage-statusdetails') as any;
|
|
603
|
+
|
|
604
|
+
const scenarios = {
|
|
605
|
+
noData: {
|
|
606
|
+
name: 'No Data Available',
|
|
607
|
+
data: []
|
|
608
|
+
},
|
|
609
|
+
singlePoint: {
|
|
610
|
+
name: 'Single Data Point',
|
|
611
|
+
data: [{
|
|
612
|
+
timestamp: Date.now(),
|
|
613
|
+
status: 'operational' as const,
|
|
614
|
+
responseTime: 75,
|
|
615
|
+
errorRate: 0
|
|
616
|
+
}]
|
|
617
|
+
},
|
|
618
|
+
allDown: {
|
|
619
|
+
name: 'Complete Outage',
|
|
620
|
+
data: Array.from({ length: 48 }, (_, i) => ({
|
|
621
|
+
timestamp: Date.now() - (i * 60 * 60 * 1000),
|
|
622
|
+
status: 'major_outage' as const,
|
|
623
|
+
responseTime: 0,
|
|
624
|
+
errorRate: 1
|
|
625
|
+
}))
|
|
626
|
+
},
|
|
627
|
+
highLatency: {
|
|
628
|
+
name: 'High Latency Issues',
|
|
629
|
+
data: Array.from({ length: 48 }, (_, i) => ({
|
|
630
|
+
timestamp: Date.now() - (i * 60 * 60 * 1000),
|
|
631
|
+
status: 'operational' as const,
|
|
632
|
+
responseTime: 2000 + Math.random() * 1000,
|
|
633
|
+
errorRate: 0
|
|
634
|
+
}))
|
|
635
|
+
},
|
|
636
|
+
mixedStatuses: {
|
|
637
|
+
name: 'All Status Types',
|
|
638
|
+
data: Array.from({ length: 50 }, (_, i) => {
|
|
639
|
+
const statuses: IStatusHistoryPoint['status'][] = ['operational', 'degraded', 'partial_outage', 'major_outage', 'maintenance'];
|
|
640
|
+
const status = statuses[i % statuses.length];
|
|
641
|
+
return {
|
|
642
|
+
timestamp: Date.now() - (i * 60 * 60 * 1000),
|
|
643
|
+
status,
|
|
644
|
+
responseTime: status === 'operational' ? 50 : status === 'maintenance' ? 0 : 200 + Math.random() * 600,
|
|
645
|
+
errorRate: status === 'operational' || status === 'maintenance' ? 0 : 0.1 + Math.random() * 0.4
|
|
646
|
+
};
|
|
647
|
+
})
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
// Initial scenario
|
|
652
|
+
let currentScenario = 'noData';
|
|
653
|
+
statusDetails.serviceId = 'edge-case-service';
|
|
654
|
+
statusDetails.serviceName = 'Edge Case Service';
|
|
655
|
+
statusDetails.historyData = scenarios[currentScenario].data;
|
|
656
|
+
|
|
657
|
+
// Create scenario buttons
|
|
658
|
+
const controls = document.createElement('div');
|
|
659
|
+
controls.className = 'demo-controls';
|
|
660
|
+
|
|
661
|
+
Object.entries(scenarios).forEach(([key, scenario]) => {
|
|
662
|
+
const button = document.createElement('button');
|
|
663
|
+
button.className = 'demo-button' + (key === currentScenario ? ' active' : '');
|
|
664
|
+
button.textContent = scenario.name;
|
|
665
|
+
button.onclick = () => {
|
|
666
|
+
controls.querySelectorAll('.demo-button').forEach(btn => btn.classList.remove('active'));
|
|
667
|
+
button.classList.add('active');
|
|
668
|
+
|
|
669
|
+
currentScenario = key;
|
|
670
|
+
statusDetails.loading = true;
|
|
671
|
+
setTimeout(() => {
|
|
672
|
+
statusDetails.historyData = scenario.data;
|
|
673
|
+
statusDetails.loading = false;
|
|
674
|
+
}, 300);
|
|
675
|
+
};
|
|
676
|
+
controls.appendChild(button);
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
wrapperElement.appendChild(controls);
|
|
680
|
+
}}
|
|
681
|
+
>
|
|
682
|
+
<upl-statuspage-statusdetails></upl-statuspage-statusdetails>
|
|
683
|
+
</dees-demowrapper>
|
|
684
|
+
</div>
|
|
685
|
+
|
|
686
|
+
<!-- Loading and Error States -->
|
|
687
|
+
<div class="demo-section">
|
|
688
|
+
<div class="demo-title">Loading and Error Handling</div>
|
|
689
|
+
<dees-demowrapper
|
|
690
|
+
.runAfterRender=${async (wrapperElement: any) => {
|
|
691
|
+
const statusDetails = wrapperElement.querySelector('upl-statuspage-statusdetails') as any;
|
|
692
|
+
|
|
693
|
+
// Start with loading
|
|
694
|
+
statusDetails.loading = true;
|
|
695
|
+
statusDetails.serviceId = 'loading-demo';
|
|
696
|
+
statusDetails.serviceName = 'Loading Demo Service';
|
|
697
|
+
|
|
698
|
+
const controls = document.createElement('div');
|
|
699
|
+
controls.className = 'demo-controls';
|
|
700
|
+
controls.innerHTML = `
|
|
701
|
+
<button class="demo-button" id="toggleLoading">Toggle Loading</button>
|
|
702
|
+
<button class="demo-button" id="loadSuccess">Load Successfully</button>
|
|
703
|
+
<button class="demo-button" id="loadError">Simulate Error</button>
|
|
704
|
+
<button class="demo-button" id="loadSlowly">Load Slowly (3s)</button>
|
|
705
|
+
`;
|
|
706
|
+
wrapperElement.appendChild(controls);
|
|
707
|
+
|
|
708
|
+
controls.querySelector('#toggleLoading')?.addEventListener('click', () => {
|
|
709
|
+
statusDetails.loading = !statusDetails.loading;
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
controls.querySelector('#loadSuccess')?.addEventListener('click', () => {
|
|
713
|
+
statusDetails.loading = true;
|
|
714
|
+
setTimeout(() => {
|
|
715
|
+
const now = Date.now();
|
|
716
|
+
statusDetails.historyData = Array.from({ length: 24 }, (_, i) => ({
|
|
717
|
+
timestamp: now - (i * 60 * 60 * 1000),
|
|
718
|
+
status: Math.random() > 0.9 ? 'degraded' : 'operational',
|
|
719
|
+
responseTime: 50 + Math.random() * 50,
|
|
720
|
+
errorRate: 0
|
|
721
|
+
}));
|
|
722
|
+
statusDetails.loading = false;
|
|
723
|
+
}, 500);
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
controls.querySelector('#loadError')?.addEventListener('click', () => {
|
|
727
|
+
statusDetails.loading = true;
|
|
728
|
+
setTimeout(() => {
|
|
729
|
+
statusDetails.loading = false;
|
|
730
|
+
statusDetails.historyData = [];
|
|
731
|
+
statusDetails.errorMessage = 'Failed to load status data: Connection timeout';
|
|
732
|
+
}, 1500);
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
controls.querySelector('#loadSlowly')?.addEventListener('click', () => {
|
|
736
|
+
statusDetails.loading = true;
|
|
737
|
+
setTimeout(() => {
|
|
738
|
+
const now = Date.now();
|
|
739
|
+
statusDetails.historyData = Array.from({ length: 48 }, (_, i) => ({
|
|
740
|
+
timestamp: now - (i * 60 * 60 * 1000),
|
|
741
|
+
status: 'operational',
|
|
742
|
+
responseTime: 45 + Math.random() * 30,
|
|
743
|
+
errorRate: 0
|
|
744
|
+
}));
|
|
745
|
+
statusDetails.loading = false;
|
|
746
|
+
}, 3000);
|
|
747
|
+
});
|
|
748
|
+
}}
|
|
749
|
+
>
|
|
750
|
+
<upl-statuspage-statusdetails></upl-statuspage-statusdetails>
|
|
751
|
+
</dees-demowrapper>
|
|
752
|
+
</div>
|
|
753
|
+
</div>
|
|
754
|
+
`;
|