@uptime.link/statuspage 1.0.74 → 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 (95) 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 +51691 -32432
  59. package/dist_watch/bundle.js.map +4 -4
  60. package/npmextra.json +9 -3
  61. package/package.json +19 -19
  62. package/readme.hints.md +292 -0
  63. package/readme.md +326 -149
  64. package/readme.plan.md +261 -0
  65. package/ts_web/00_commitinfo_data.ts +1 -1
  66. package/ts_web/elements/index.ts +6 -0
  67. package/ts_web/elements/internal/uplinternal-miniheading.ts +24 -17
  68. package/ts_web/elements/upl-statuspage-assetsselector.demo.ts +607 -0
  69. package/ts_web/elements/upl-statuspage-assetsselector.ts +526 -18
  70. package/ts_web/elements/upl-statuspage-footer.demo.ts +744 -0
  71. package/ts_web/elements/upl-statuspage-footer.ts +608 -30
  72. package/ts_web/elements/upl-statuspage-header.demo.ts +241 -0
  73. package/ts_web/elements/upl-statuspage-header.ts +220 -52
  74. package/ts_web/elements/upl-statuspage-incidents.demo.ts +1216 -0
  75. package/ts_web/elements/upl-statuspage-incidents.ts +649 -26
  76. package/ts_web/elements/upl-statuspage-pagetitle.demo.ts +25 -0
  77. package/ts_web/elements/upl-statuspage-pagetitle.ts +89 -0
  78. package/ts_web/elements/upl-statuspage-statsgrid.demo.ts +315 -0
  79. package/ts_web/elements/upl-statuspage-statsgrid.ts +306 -0
  80. package/ts_web/elements/upl-statuspage-statusbar.demo.ts +393 -0
  81. package/ts_web/elements/upl-statuspage-statusbar.ts +281 -20
  82. package/ts_web/elements/upl-statuspage-statusdetails.demo.ts +754 -0
  83. package/ts_web/elements/upl-statuspage-statusdetails.ts +297 -38
  84. package/ts_web/elements/upl-statuspage-statusmonth.demo.ts +876 -0
  85. package/ts_web/elements/upl-statuspage-statusmonth.ts +397 -76
  86. package/ts_web/interfaces/index.ts +95 -0
  87. package/ts_web/pages/index.ts +4 -1
  88. package/ts_web/pages/statuspage-allgreen.ts +412 -0
  89. package/ts_web/pages/statuspage-demo.ts +653 -0
  90. package/ts_web/pages/statuspage-maintenance.ts +570 -0
  91. package/ts_web/pages/statuspage-outage.ts +568 -0
  92. package/ts_web/styles/shared.styles.ts +367 -0
  93. package/dist_ts_web/pages/page1.d.ts +0 -1
  94. package/dist_ts_web/pages/page1.js +0 -11
  95. package/ts_web/pages/page1.ts +0 -11
@@ -5,11 +5,15 @@ import {
5
5
  customElement,
6
6
  type TemplateResult,
7
7
  css,
8
- cssManager
8
+ cssManager,
9
+ unsafeCSS
9
10
  } from '@design.estate/dees-element';
10
11
  import * as domtools from '@design.estate/dees-domtools';
12
+ import type { IMonthlyUptime } from '../interfaces/index.js';
13
+ import * as sharedStyles from '../styles/shared.styles.js';
11
14
 
12
15
  import './internal/uplinternal-miniheading.js';
16
+ import { demoFunc } from './upl-statuspage-statusmonth.demo.js';
13
17
 
14
18
  declare global {
15
19
  interface HTMLElementTagNameMap {
@@ -19,7 +23,25 @@ declare global {
19
23
 
20
24
  @customElement('upl-statuspage-statusmonth')
21
25
  export class UplStatuspageStatusmonth extends DeesElement {
22
- public static demo = () => html` <upl-statuspage-statusmonth></upl-statuspage-statusmonth> `;
26
+ public static demo = demoFunc;
27
+
28
+ @property({ type: Array })
29
+ accessor monthlyData: IMonthlyUptime[] = [];
30
+
31
+ @property({ type: String })
32
+ accessor serviceId: string = '';
33
+
34
+ @property({ type: String })
35
+ accessor serviceName: string = 'Service';
36
+
37
+ @property({ type: Boolean })
38
+ accessor loading: boolean = false;
39
+
40
+ @property({ type: Boolean })
41
+ accessor showTooltip: boolean = true;
42
+
43
+ @property({ type: Number })
44
+ accessor monthsToShow: number = 5;
23
45
 
24
46
  constructor() {
25
47
  super();
@@ -27,104 +49,403 @@ export class UplStatuspageStatusmonth extends DeesElement {
27
49
 
28
50
  public static styles = [
29
51
  domtools.elementBasic.staticStyles,
52
+ sharedStyles.commonStyles,
30
53
  css`
31
54
  :host {
32
55
  position: relative;
33
- padding: 0px 0px 15px 0px;
34
56
  display: block;
35
- background: ${cssManager.bdTheme('#eeeeeb', '#222222')};;
36
- font-family: Inter;
37
- color: #fff;
57
+ background: transparent;
58
+ font-family: ${unsafeCSS(sharedStyles.fonts.base)};
59
+ color: ${sharedStyles.colors.text.primary};
60
+ }
61
+
62
+ .container {
63
+ max-width: 1200px;
64
+ margin: 0 auto;
65
+ padding: 0 ${unsafeCSS(sharedStyles.spacing.lg)} ${unsafeCSS(sharedStyles.spacing.lg)} ${unsafeCSS(sharedStyles.spacing.lg)};
38
66
  }
39
67
 
40
68
  .mainbox {
41
- margin: auto;
42
- max-width: 900px;
43
69
  display: grid;
44
- grid-template-columns: repeat(5, calc(100% / 5 - 80px / 5));
45
- grid-column-gap: 20px;
70
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
71
+ gap: ${unsafeCSS(sharedStyles.spacing.lg)};
46
72
  }
47
73
 
48
74
  .statusMonth {
49
- background: ${cssManager.bdTheme('#ffffff', '#333333')};;
50
- min-height: 20px;
75
+ background: ${cssManager.bdTheme('#ffffff', '#0a0a0a')};
76
+ padding: ${unsafeCSS(sharedStyles.spacing.lg)};
77
+ border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)};
78
+ border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
79
+ position: relative;
80
+ transition: all 0.2s ease;
81
+ display: flex;
82
+ flex-direction: column;
83
+ min-height: 280px;
84
+ box-shadow: ${cssManager.bdTheme('0 1px 2px 0 rgba(0, 0, 0, 0.05)', 'none')};
85
+ }
86
+
87
+ .statusMonth:hover {
88
+ border-color: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
89
+ box-shadow: ${cssManager.bdTheme('0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)', '0 0 0 1px rgba(255, 255, 255, 0.1)')};
90
+ }
91
+
92
+ .month-header {
93
+ font-size: 13px;
94
+ font-weight: 600;
95
+ margin-bottom: ${unsafeCSS(sharedStyles.spacing.md)};
96
+ color: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
97
+ letter-spacing: 0.02em;
98
+ text-transform: uppercase;
99
+ }
100
+
101
+ .days-container {
102
+ flex: 1;
103
+ display: flex;
104
+ flex-direction: column;
105
+ margin-bottom: ${unsafeCSS(sharedStyles.spacing.lg)};
106
+ }
107
+
108
+ .days-grid {
109
+ display: grid;
110
+ grid-template-columns: repeat(7, 1fr);
111
+ gap: 3px;
112
+ width: 100%;
113
+ }
114
+
115
+ .weekday-label {
116
+ font-size: 10px;
117
+ text-align: center;
118
+ color: ${cssManager.bdTheme('#9ca3af', '#71717a')};
119
+ font-weight: 500;
120
+ height: 20px;
121
+ line-height: 20px;
122
+ margin-bottom: ${unsafeCSS(sharedStyles.spacing.sm)};
123
+ text-transform: uppercase;
124
+ }
125
+
126
+ .statusDay {
127
+ aspect-ratio: 1;
128
+ border-radius: 4px;
129
+ cursor: pointer;
130
+ transition: all 0.15s ease;
131
+ position: relative;
132
+ }
133
+
134
+ .statusDay:hover:not(.empty) {
135
+ transform: scale(1.15);
136
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
137
+ z-index: 1;
138
+ }
139
+
140
+ .statusDay.operational {
141
+ background: #22c55e;
142
+ }
143
+
144
+ .statusDay.degraded {
145
+ background: #fbbf24;
146
+ }
147
+
148
+ .statusDay.partial_outage {
149
+ background: #f87171;
150
+ }
151
+
152
+ .statusDay.major_outage {
153
+ background: #ef4444;
154
+ }
155
+
156
+ .statusDay.maintenance {
157
+ background: #60a5fa;
158
+ }
159
+
160
+ .statusDay.no-data {
161
+ background: ${cssManager.bdTheme('#e5e7eb', '#27272a')};
162
+ opacity: 0.6;
163
+ }
164
+
165
+ .statusDay.empty {
166
+ background: transparent;
167
+ cursor: default;
168
+ pointer-events: none;
169
+ }
170
+
171
+ .overall-uptime {
172
+ font-size: 12px;
173
+ margin-top: auto;
174
+ padding-top: ${unsafeCSS(sharedStyles.spacing.md)};
175
+ color: ${cssManager.bdTheme('#6b7280', '#a1a1aa')};
176
+ display: flex;
177
+ flex-direction: column;
178
+ gap: 6px;
179
+ border-top: 1px solid ${cssManager.bdTheme('#f3f4f6', '#1f1f1f')};
180
+ }
181
+
182
+ .uptime-stat {
183
+ display: flex;
184
+ justify-content: space-between;
185
+ align-items: center;
186
+ }
187
+
188
+ .uptime-value {
189
+ font-weight: 600;
190
+ color: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
191
+ font-variant-numeric: tabular-nums;
192
+ font-size: 13px;
193
+ }
194
+
195
+ .loading-skeleton {
196
+ display: flex;
197
+ flex-direction: column;
198
+ gap: ${unsafeCSS(sharedStyles.spacing.sm)};
199
+ height: 100%;
200
+ }
201
+
202
+ .skeleton-header {
203
+ height: 20px;
204
+ width: 80px;
205
+ background: ${cssManager.bdTheme('#f3f4f6', '#27272a')};
206
+ border-radius: 4px;
207
+ animation: pulse 2s infinite;
208
+ }
209
+
210
+ .skeleton-grid {
211
+ flex: 1;
51
212
  display: grid;
52
- padding: 10px;
53
- grid-template-columns: repeat(6, auto);
54
- grid-gap: 9px;
55
- border-radius: 3px;
213
+ grid-template-columns: repeat(7, 1fr);
214
+ gap: 2px;
215
+ }
216
+
217
+ .skeleton-day {
218
+ background: ${cssManager.bdTheme('#f3f4f6', '#27272a')};
219
+ border-radius: 2px;
220
+ animation: pulse 2s infinite;
221
+ animation-delay: calc(var(--index) * 0.05s);
222
+ }
223
+
224
+ @keyframes pulse {
225
+ 0%, 100% { opacity: 1; }
226
+ 50% { opacity: 0.5; }
227
+ }
228
+
229
+ @keyframes loading {
230
+ 0% { transform: translateX(-100%); }
231
+ 100% { transform: translateX(200%); }
232
+ }
233
+
234
+ .tooltip {
235
+ position: absolute;
236
+ background: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
237
+ color: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
238
+ padding: 8px 12px;
239
+ border-radius: 4px;
240
+ font-size: 12px;
241
+ pointer-events: none;
242
+ opacity: 0;
243
+ transition: opacity 0.15s;
244
+ z-index: 50;
245
+ white-space: nowrap;
246
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
247
+ line-height: 1.5;
248
+ }
249
+
250
+ .tooltip.visible {
251
+ opacity: 1;
252
+ }
253
+
254
+ .tooltip-date {
255
+ font-weight: 500;
256
+ margin-bottom: 4px;
257
+ }
258
+
259
+ .tooltip-stat {
260
+ font-size: 11px;
261
+ opacity: 0.9;
56
262
  }
57
263
 
58
- .statusMonth .statusDay {
59
- width: 16px;
60
- height: 16px;
61
- background: #2deb51;
62
- border-radius: 3px;
264
+ .no-data-message {
265
+ grid-column: 1 / -1;
266
+ text-align: center;
267
+ padding: ${unsafeCSS(sharedStyles.spacing['2xl'])};
268
+ color: ${sharedStyles.colors.text.secondary};
269
+ }
270
+
271
+ @media (max-width: 640px) {
272
+ .container {
273
+ padding: 0 ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)};
274
+ }
275
+
276
+ .mainbox {
277
+ grid-template-columns: 1fr;
278
+ gap: ${unsafeCSS(sharedStyles.spacing.md)};
279
+ }
280
+
281
+ .statusMonth {
282
+ padding: ${unsafeCSS(sharedStyles.spacing.md)};
283
+ min-height: 260px;
284
+ }
285
+
286
+ .loading-skeleton {
287
+ height: 180px;
288
+ padding: ${unsafeCSS(sharedStyles.spacing.md)};
289
+ }
63
290
  }
64
291
  `
65
292
  ]
66
293
 
67
294
  public render(): TemplateResult {
295
+ const totalDays = this.monthlyData.reduce((sum, month) => sum + month.days.length, 0);
296
+
68
297
  return html`
69
- <style></style>
70
- <uplinternal-miniheading>Last 150 days</uplinternal-miniheading>
71
- <div class="mainbox">
72
- <div class="statusMonth">
73
- ${(() => {
74
- let counter = 0;
75
- const returnArray: TemplateResult[] = [];
76
- while (counter < 30) {
77
- counter++;
78
- returnArray.push(html` <div class="statusDay"></div> `);
79
- }
80
- return returnArray;
81
- })()}
82
- </div>
83
- <div class="statusMonth">
84
- ${(() => {
85
- let counter = 0;
86
- const returnArray: TemplateResult[] = [];
87
- while (counter < 30) {
88
- counter++;
89
- returnArray.push(html` <div class="statusDay"></div> `);
90
- }
91
- return returnArray;
92
- })()}
298
+ <div class="container">
299
+ <uplinternal-miniheading>${this.serviceName} - Last ${totalDays} Days</uplinternal-miniheading>
300
+ <div class="mainbox">
301
+ ${this.loading ? html`
302
+ ${Array(this.monthsToShow).fill(0).map((_, index) => html`
303
+ <div class="statusMonth">
304
+ <div class="loading-skeleton">
305
+ <div class="skeleton-header"></div>
306
+ <div class="days-container">
307
+ <div class="skeleton-grid">
308
+ ${Array(42).fill(0).map((_, i) => html`
309
+ <div class="skeleton-day" style="--index: ${i}"></div>
310
+ `)}
311
+ </div>
312
+ </div>
313
+ <div style="height: 48px; border-top: 1px solid ${cssManager.bdTheme('#f3f4f6', '#1f1f1f')}; margin-top: auto; padding-top: 16px;"></div>
314
+ </div>
315
+ </div>
316
+ `)}
317
+ ` : this.monthlyData.length === 0 ? html`
318
+ <div class="no-data-message">No uptime data available</div>
319
+ ` : this.monthlyData.map(month => this.renderMonth(month))}
93
320
  </div>
94
- <div class="statusMonth">
95
- ${(() => {
96
- let counter = 0;
97
- const returnArray: TemplateResult[] = [];
98
- while (counter < 30) {
99
- counter++;
100
- returnArray.push(html` <div class="statusDay"></div> `);
101
- }
102
- return returnArray;
103
- })()}
104
- </div>
105
- <div class="statusMonth">
106
- ${(() => {
107
- let counter = 0;
108
- const returnArray: TemplateResult[] = [];
109
- while (counter < 30) {
110
- counter++;
111
- returnArray.push(html` <div class="statusDay"></div> `);
112
- }
113
- return returnArray;
114
- })()}
321
+ ${this.showTooltip ? html`<div class="tooltip" id="tooltip"></div>` : ''}
322
+ </div>
323
+ `;
324
+ }
325
+
326
+ private renderMonth(monthData: IMonthlyUptime): TemplateResult {
327
+ const monthDate = new Date(monthData.month + '-01');
328
+ const monthName = monthDate.toLocaleDateString('en-US', { month: 'short', year: 'numeric' });
329
+ const firstDayOfWeek = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1).getDay();
330
+
331
+ return html`
332
+ <div class="statusMonth" @mouseleave=${this.hideTooltip}>
333
+ <div class="month-header">${monthName}</div>
334
+ <div class="days-container">
335
+ <div class="days-grid">
336
+ ${this.renderWeekdayLabels()}
337
+ ${this.renderEmptyDays(firstDayOfWeek)}
338
+ ${monthData.days.map(day => this.renderDay(day))}
339
+ ${this.renderTrailingEmptyDays(firstDayOfWeek + monthData.days.length)}
340
+ </div>
115
341
  </div>
116
- <div class="statusMonth">
117
- ${(() => {
118
- let counter = 0;
119
- const returnArray: TemplateResult[] = [];
120
- while (counter < 30) {
121
- counter++;
122
- returnArray.push(html` <div class="statusDay"></div> `);
123
- }
124
- return returnArray;
125
- })()}
342
+ <div class="overall-uptime">
343
+ <div class="uptime-stat">
344
+ <span>Uptime</span>
345
+ <span class="uptime-value">${monthData.overallUptime.toFixed(2)}%</span>
346
+ </div>
347
+ ${monthData.totalIncidents > 0 ? html`
348
+ <div class="uptime-stat">
349
+ <span>Incidents</span>
350
+ <span class="uptime-value">${monthData.totalIncidents}</span>
351
+ </div>
352
+ ` : ''}
126
353
  </div>
127
354
  </div>
128
355
  `;
129
356
  }
357
+
358
+ private renderWeekdayLabels(): TemplateResult[] {
359
+ const weekdays = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
360
+ return weekdays.map(day => html`<div class="weekday-label">${day}</div>`);
361
+ }
362
+
363
+ private renderEmptyDays(count: number): TemplateResult[] {
364
+ return Array(count).fill(0).map(() => html`<div class="statusDay empty"></div>`);
365
+ }
366
+
367
+ private renderTrailingEmptyDays(totalCells: number): TemplateResult[] {
368
+ const remainder = totalCells % 7;
369
+ const trailingCount = remainder === 0 ? 0 : 7 - remainder;
370
+ return Array(trailingCount).fill(0).map(() => html`<div class="statusDay empty"></div>`);
371
+ }
372
+
373
+ private renderDay(day: any): TemplateResult {
374
+ const status = day.status || 'no-data';
375
+ const date = new Date(day.date);
376
+ const dayNumber = date.getDate();
377
+
378
+ return html`
379
+ <div
380
+ class="statusDay ${status}"
381
+ @mouseenter=${(e: MouseEvent) => this.showTooltip && this.showDayTooltip(e, day)}
382
+ @click=${() => this.handleDayClick(day)}
383
+ >
384
+ ${status === 'major_outage' || status === 'partial_outage' ? html`
385
+ <div style="
386
+ position: absolute;
387
+ top: 50%;
388
+ left: 50%;
389
+ transform: translate(-50%, -50%);
390
+ font-size: 8px;
391
+ font-weight: bold;
392
+ color: white;
393
+ ">${day.incidents}</div>
394
+ ` : ''}
395
+ </div>
396
+ `;
397
+ }
398
+
399
+ private showDayTooltip(event: MouseEvent, day: any) {
400
+ const tooltip = this.shadowRoot?.getElementById('tooltip') as HTMLElement;
401
+ if (!tooltip) return;
402
+
403
+ const date = new Date(day.date);
404
+ const dateStr = date.toLocaleDateString('en-US', {
405
+ weekday: 'long',
406
+ year: 'numeric',
407
+ month: 'long',
408
+ day: 'numeric'
409
+ });
410
+
411
+ let statusText = day.status.replace(/_/g, ' ');
412
+ statusText = statusText.charAt(0).toUpperCase() + statusText.slice(1);
413
+
414
+ tooltip.innerHTML = `
415
+ <div class="tooltip-date">${dateStr}</div>
416
+ <div class="tooltip-stat">Status: ${statusText}</div>
417
+ <div class="tooltip-stat">Uptime: ${day.uptime.toFixed(2)}%</div>
418
+ ${day.incidents > 0 ? `<div class="tooltip-stat">Incidents: ${day.incidents}</div>` : ''}
419
+ ${day.totalDowntime > 0 ? `<div class="tooltip-stat">Downtime: ${day.totalDowntime} min</div>` : ''}
420
+ `;
421
+
422
+ const rect = (event.target as HTMLElement).getBoundingClientRect();
423
+ const containerRect = this.getBoundingClientRect();
424
+
425
+ tooltip.style.left = `${rect.left - containerRect.left + rect.width / 2}px`;
426
+ tooltip.style.top = `${rect.top - containerRect.top - 80}px`;
427
+ tooltip.style.transform = 'translateX(-50%)';
428
+ tooltip.classList.add('visible');
429
+ }
430
+
431
+ private hideTooltip() {
432
+ const tooltip = this.shadowRoot?.getElementById('tooltip') as HTMLElement;
433
+ if (tooltip) {
434
+ tooltip.classList.remove('visible');
435
+ }
436
+ }
437
+
438
+ private handleDayClick(day: any) {
439
+ this.dispatchEvent(new CustomEvent('dayClick', {
440
+ detail: {
441
+ date: day.date,
442
+ uptime: day.uptime,
443
+ incidents: day.incidents,
444
+ status: day.status,
445
+ serviceId: this.serviceId
446
+ },
447
+ bubbles: true,
448
+ composed: true
449
+ }));
450
+ }
130
451
  }
@@ -0,0 +1,95 @@
1
+ export interface IServiceStatus {
2
+ id: string;
3
+ name: string;
4
+ displayName: string;
5
+ description?: string;
6
+ currentStatus: 'operational' | 'degraded' | 'partial_outage' | 'major_outage' | 'maintenance';
7
+ lastChecked: number; // timestamp
8
+ uptime30d: number; // percentage
9
+ uptime90d: number; // percentage
10
+ responseTime: number; // milliseconds
11
+ category?: string;
12
+ dependencies?: string[];
13
+ selected?: boolean;
14
+ }
15
+
16
+ export interface IStatusHistoryPoint {
17
+ timestamp: number;
18
+ status: 'operational' | 'degraded' | 'partial_outage' | 'major_outage' | 'maintenance';
19
+ responseTime?: number;
20
+ errorRate?: number;
21
+ }
22
+
23
+ export interface IIncidentUpdate {
24
+ id: string;
25
+ timestamp: number;
26
+ status: 'investigating' | 'identified' | 'monitoring' | 'resolved' | 'postmortem';
27
+ message: string;
28
+ author?: string;
29
+ }
30
+
31
+ export interface IIncidentDetails {
32
+ id: string;
33
+ title: string;
34
+ status: 'investigating' | 'identified' | 'monitoring' | 'resolved' | 'postmortem';
35
+ severity: 'critical' | 'major' | 'minor' | 'maintenance';
36
+ affectedServices: string[];
37
+ startTime: number;
38
+ endTime?: number;
39
+ updates: IIncidentUpdate[];
40
+ impact: string;
41
+ rootCause?: string;
42
+ resolution?: string;
43
+ }
44
+
45
+ export interface IUptimeDay {
46
+ date: string; // YYYY-MM-DD
47
+ uptime: number; // percentage
48
+ incidents: number;
49
+ totalDowntime: number; // minutes
50
+ status: 'operational' | 'degraded' | 'partial_outage' | 'major_outage';
51
+ }
52
+
53
+ export interface IMonthlyUptime {
54
+ month: string; // YYYY-MM
55
+ days: IUptimeDay[];
56
+ overallUptime: number; // percentage
57
+ totalIncidents: number;
58
+ }
59
+
60
+ export interface IOverallStatus {
61
+ status: 'operational' | 'degraded' | 'partial_outage' | 'major_outage' | 'maintenance';
62
+ message: string;
63
+ lastUpdated: number;
64
+ affectedServices: number;
65
+ totalServices: number;
66
+ }
67
+
68
+ export interface IStatusPageConfig {
69
+ apiEndpoint?: string;
70
+ refreshInterval?: number; // milliseconds
71
+ timeZone?: string;
72
+ dateFormat?: string;
73
+ enableWebSocket?: boolean;
74
+ enableNotifications?: boolean;
75
+ theme?: 'light' | 'dark' | 'auto';
76
+ language?: string;
77
+ showHistoricalDays?: number;
78
+ whitelabel?: boolean;
79
+ companyName?: string;
80
+ companyLogo?: string;
81
+ supportEmail?: string;
82
+ statusPageUrl?: string;
83
+ legalUrl?: string;
84
+ }
85
+
86
+ export interface ISubscription {
87
+ email?: string;
88
+ phone?: string;
89
+ webhook?: string;
90
+ services: string[];
91
+ severityFilter: ('critical' | 'major' | 'minor' | 'maintenance')[];
92
+ }
93
+
94
+ // Re-export the incident interface from @uptime.link/interfaces if needed
95
+ // Note: The IIncident interface is imported in the incidents component directly from plugins
@@ -1 +1,4 @@
1
- export * from './page1.js';
1
+ export * from './statuspage-demo.js';
2
+ export * from './statuspage-allgreen.js';
3
+ export * from './statuspage-outage.js';
4
+ export * from './statuspage-maintenance.js';