@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.
Files changed (96) hide show
  1. package/dist_bundle/bundle.js +4096 -504
  2. package/dist_bundle/bundle.js.map +4 -4
  3. package/dist_ts_web/00_commitinfo_data.js +2 -2
  4. package/dist_ts_web/elements/index.d.ts +3 -0
  5. package/dist_ts_web/elements/index.js +6 -1
  6. package/dist_ts_web/elements/internal/uplinternal-miniheading.d.ts +1 -0
  7. package/dist_ts_web/elements/internal/uplinternal-miniheading.js +78 -28
  8. package/dist_ts_web/elements/upl-statuspage-assetsselector.d.ts +14 -0
  9. package/dist_ts_web/elements/upl-statuspage-assetsselector.demo.d.ts +1 -0
  10. package/dist_ts_web/elements/upl-statuspage-assetsselector.demo.js +575 -0
  11. package/dist_ts_web/elements/upl-statuspage-assetsselector.js +605 -43
  12. package/dist_ts_web/elements/upl-statuspage-footer.d.ts +46 -2
  13. package/dist_ts_web/elements/upl-statuspage-footer.demo.d.ts +1 -0
  14. package/dist_ts_web/elements/upl-statuspage-footer.demo.js +679 -0
  15. package/dist_ts_web/elements/upl-statuspage-footer.js +792 -61
  16. package/dist_ts_web/elements/upl-statuspage-header.d.ts +5 -1
  17. package/dist_ts_web/elements/upl-statuspage-header.demo.d.ts +1 -0
  18. package/dist_ts_web/elements/upl-statuspage-header.demo.js +220 -0
  19. package/dist_ts_web/elements/upl-statuspage-header.js +313 -86
  20. package/dist_ts_web/elements/upl-statuspage-incidents.d.ts +22 -4
  21. package/dist_ts_web/elements/upl-statuspage-incidents.demo.d.ts +1 -0
  22. package/dist_ts_web/elements/upl-statuspage-incidents.demo.js +1147 -0
  23. package/dist_ts_web/elements/upl-statuspage-incidents.js +750 -74
  24. package/dist_ts_web/elements/upl-statuspage-pagetitle.d.ts +15 -0
  25. package/dist_ts_web/elements/upl-statuspage-pagetitle.demo.d.ts +1 -0
  26. package/dist_ts_web/elements/upl-statuspage-pagetitle.demo.js +25 -0
  27. package/dist_ts_web/elements/upl-statuspage-pagetitle.js +148 -0
  28. package/dist_ts_web/elements/upl-statuspage-statsgrid.d.ts +23 -0
  29. package/dist_ts_web/elements/upl-statuspage-statsgrid.demo.d.ts +1 -0
  30. package/dist_ts_web/elements/upl-statuspage-statsgrid.demo.js +295 -0
  31. package/dist_ts_web/elements/upl-statuspage-statsgrid.js +374 -0
  32. package/dist_ts_web/elements/upl-statuspage-statusbar.d.ts +4 -0
  33. package/dist_ts_web/elements/upl-statuspage-statusbar.demo.d.ts +1 -0
  34. package/dist_ts_web/elements/upl-statuspage-statusbar.demo.js +365 -0
  35. package/dist_ts_web/elements/upl-statuspage-statusbar.js +357 -44
  36. package/dist_ts_web/elements/upl-statuspage-statusdetails.d.ts +14 -0
  37. package/dist_ts_web/elements/upl-statuspage-statusdetails.demo.d.ts +1 -0
  38. package/dist_ts_web/elements/upl-statuspage-statusdetails.demo.js +706 -0
  39. package/dist_ts_web/elements/upl-statuspage-statusdetails.js +373 -63
  40. package/dist_ts_web/elements/upl-statuspage-statusmonth.d.ts +15 -0
  41. package/dist_ts_web/elements/upl-statuspage-statusmonth.demo.d.ts +1 -0
  42. package/dist_ts_web/elements/upl-statuspage-statusmonth.demo.js +798 -0
  43. package/dist_ts_web/elements/upl-statuspage-statusmonth.js +474 -100
  44. package/dist_ts_web/interfaces/index.d.ts +84 -0
  45. package/dist_ts_web/interfaces/index.js +4 -0
  46. package/dist_ts_web/pages/index.d.ts +4 -1
  47. package/dist_ts_web/pages/index.js +5 -2
  48. package/dist_ts_web/pages/statuspage-allgreen.d.ts +1 -0
  49. package/dist_ts_web/pages/statuspage-allgreen.js +386 -0
  50. package/dist_ts_web/pages/statuspage-demo.d.ts +1 -0
  51. package/dist_ts_web/pages/statuspage-demo.js +616 -0
  52. package/dist_ts_web/pages/statuspage-maintenance.d.ts +1 -0
  53. package/dist_ts_web/pages/statuspage-maintenance.js +544 -0
  54. package/dist_ts_web/pages/statuspage-outage.d.ts +1 -0
  55. package/dist_ts_web/pages/statuspage-outage.js +543 -0
  56. package/dist_ts_web/styles/shared.styles.d.ts +80 -0
  57. package/dist_ts_web/styles/shared.styles.js +351 -0
  58. package/dist_watch/bundle.js +54534 -26433
  59. package/dist_watch/bundle.js.map +4 -4
  60. package/dist_watch/index.html +3 -10
  61. package/npmextra.json +9 -3
  62. package/package.json +19 -19
  63. package/readme.hints.md +292 -0
  64. package/readme.md +326 -149
  65. package/readme.plan.md +261 -0
  66. package/ts_web/00_commitinfo_data.ts +1 -1
  67. package/ts_web/elements/index.ts +6 -0
  68. package/ts_web/elements/internal/uplinternal-miniheading.ts +24 -17
  69. package/ts_web/elements/upl-statuspage-assetsselector.demo.ts +607 -0
  70. package/ts_web/elements/upl-statuspage-assetsselector.ts +526 -18
  71. package/ts_web/elements/upl-statuspage-footer.demo.ts +744 -0
  72. package/ts_web/elements/upl-statuspage-footer.ts +608 -30
  73. package/ts_web/elements/upl-statuspage-header.demo.ts +241 -0
  74. package/ts_web/elements/upl-statuspage-header.ts +220 -52
  75. package/ts_web/elements/upl-statuspage-incidents.demo.ts +1216 -0
  76. package/ts_web/elements/upl-statuspage-incidents.ts +649 -26
  77. package/ts_web/elements/upl-statuspage-pagetitle.demo.ts +25 -0
  78. package/ts_web/elements/upl-statuspage-pagetitle.ts +89 -0
  79. package/ts_web/elements/upl-statuspage-statsgrid.demo.ts +315 -0
  80. package/ts_web/elements/upl-statuspage-statsgrid.ts +306 -0
  81. package/ts_web/elements/upl-statuspage-statusbar.demo.ts +393 -0
  82. package/ts_web/elements/upl-statuspage-statusbar.ts +281 -20
  83. package/ts_web/elements/upl-statuspage-statusdetails.demo.ts +754 -0
  84. package/ts_web/elements/upl-statuspage-statusdetails.ts +297 -38
  85. package/ts_web/elements/upl-statuspage-statusmonth.demo.ts +876 -0
  86. package/ts_web/elements/upl-statuspage-statusmonth.ts +397 -76
  87. package/ts_web/interfaces/index.ts +95 -0
  88. package/ts_web/pages/index.ts +4 -1
  89. package/ts_web/pages/statuspage-allgreen.ts +412 -0
  90. package/ts_web/pages/statuspage-demo.ts +653 -0
  91. package/ts_web/pages/statuspage-maintenance.ts +570 -0
  92. package/ts_web/pages/statuspage-outage.ts +568 -0
  93. package/ts_web/styles/shared.styles.ts +367 -0
  94. package/dist_ts_web/pages/page1.d.ts +0 -1
  95. package/dist_ts_web/pages/page1.js +0 -11
  96. 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
+ `;