@uptime.link/statuspage 1.0.74 → 1.2.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 +5019 -519
  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 +679 -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 +846 -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 +373 -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 +937 -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 +549 -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 +408 -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 +397 -62
  40. package/dist_ts_web/elements/upl-statuspage-statusmonth.d.ts +17 -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 +662 -103
  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 +102 -0
  57. package/dist_ts_web/styles/shared.styles.js +494 -0
  58. package/dist_watch/bundle.js +52265 -32033
  59. package/dist_watch/bundle.js.map +4 -4
  60. package/dist_watch/index.html +1 -0
  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 +600 -18
  71. package/ts_web/elements/upl-statuspage-footer.demo.ts +744 -0
  72. package/ts_web/elements/upl-statuspage-footer.ts +662 -30
  73. package/ts_web/elements/upl-statuspage-header.demo.ts +241 -0
  74. package/ts_web/elements/upl-statuspage-header.ts +289 -52
  75. package/ts_web/elements/upl-statuspage-incidents.demo.ts +1216 -0
  76. package/ts_web/elements/upl-statuspage-incidents.ts +840 -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 +478 -0
  81. package/ts_web/elements/upl-statuspage-statusbar.demo.ts +393 -0
  82. package/ts_web/elements/upl-statuspage-statusbar.ts +332 -20
  83. package/ts_web/elements/upl-statuspage-statusdetails.demo.ts +754 -0
  84. package/ts_web/elements/upl-statuspage-statusdetails.ts +321 -37
  85. package/ts_web/elements/upl-statuspage-statusmonth.demo.ts +876 -0
  86. package/ts_web/elements/upl-statuspage-statusmonth.ts +584 -79
  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 +531 -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
@@ -7,9 +7,13 @@ import {
7
7
  type TemplateResult,
8
8
  css,
9
9
  cssManager,
10
+ unsafeCSS,
10
11
  } from '@design.estate/dees-element';
12
+ import type { IStatusHistoryPoint } 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-statusdetails.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-statusdetails')
21
25
  export class UplStatuspageStatusdetails extends DeesElement {
22
- public static demo = () => html` <upl-statuspage-statusdetails></upl-statuspage-statusdetails> `;
26
+ public static demo = demoFunc;
27
+
28
+ @property({ type: Array })
29
+ accessor historyData: IStatusHistoryPoint[] = [];
30
+
31
+ @property({ type: Array })
32
+ accessor dataPoints: IStatusHistoryPoint[] = [];
33
+
34
+ @property({ type: String })
35
+ accessor serviceId: string = '';
36
+
37
+ @property({ type: String })
38
+ accessor serviceName: string = 'Service';
39
+
40
+ @property({ type: Boolean })
41
+ accessor loading: boolean = false;
42
+
43
+ @property({ type: Number })
44
+ accessor hoursToShow: number = 48;
23
45
 
24
46
  constructor() {
25
47
  super();
@@ -27,69 +49,331 @@ export class UplStatuspageStatusdetails extends DeesElement {
27
49
 
28
50
  public static styles = [
29
51
  plugins.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)};
66
+ }
67
+
68
+ .graph-wrapper {
69
+ display: flex;
70
+ flex-direction: column;
71
+ gap: 4px;
72
+ }
73
+
74
+ .graph-container {
75
+ position: relative;
76
+ animation: fadeIn 0.3s ${unsafeCSS(sharedStyles.easings.default)};
77
+ }
78
+
79
+ @keyframes fadeIn {
80
+ from { opacity: 0; }
81
+ to { opacity: 1; }
38
82
  }
39
83
 
40
84
  .mainbox {
41
- margin: auto;
42
- max-width: 900px;
43
- text-align: right;
44
- background: ${cssManager.bdTheme('#ffffff', '#333333')};;
45
- line-height: 50px;
46
- border-radius: 3px;
85
+ background: transparent;
86
+ border: none;
87
+ border-radius: 0;
88
+ padding: 0;
47
89
  }
48
90
 
49
91
  .mainbox .barContainer {
50
92
  position: relative;
51
93
  display: flex;
52
- padding: 6px;
94
+ gap: 2px;
95
+ padding: ${unsafeCSS(sharedStyles.spacing.sm)};
96
+ background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
97
+ border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
98
+ border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)};
53
99
  overflow: hidden;
100
+ height: 40px;
54
101
  }
55
102
 
56
103
  .mainbox .barContainer .bar {
57
- margin: 4px;
58
- width: 11px;
104
+ flex: 1;
105
+ height: 100%;
106
+ cursor: pointer;
107
+ transition: all ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)};
108
+ position: relative;
59
109
  border-radius: 3px;
60
- height: 40px;
61
- background: #2deb51;
110
+ animation: barGrow 0.4s ${unsafeCSS(sharedStyles.easings.default)} both;
111
+ animation-delay: calc(var(--bar-index, 0) * 8ms);
112
+ transform-origin: bottom;
113
+ }
114
+
115
+ @keyframes barGrow {
116
+ from {
117
+ transform: scaleY(0);
118
+ opacity: 0;
119
+ }
120
+ to {
121
+ transform: scaleY(1);
122
+ opacity: 1;
123
+ }
62
124
  }
63
- .timeIndicator {
125
+
126
+ .mainbox .barContainer .bar:hover {
127
+ transform: scaleY(1.15);
128
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
129
+ z-index: 1;
130
+ }
131
+
132
+ .mainbox .barContainer .bar.operational {
133
+ background: ${cssManager.bdTheme('#22c55e', '#22c55e')};
134
+ }
135
+
136
+ .mainbox .barContainer .bar.degraded {
137
+ background: ${cssManager.bdTheme('#fbbf24', '#fbbf24')};
138
+ }
139
+
140
+ .mainbox .barContainer .bar.partial_outage {
141
+ background: ${cssManager.bdTheme('#f87171', '#f87171')};
142
+ }
143
+
144
+ .mainbox .barContainer .bar.major_outage {
145
+ background: ${cssManager.bdTheme('#ef4444', '#ef4444')};
146
+ }
147
+
148
+ .mainbox .barContainer .bar.maintenance {
149
+ background: ${cssManager.bdTheme('#60a5fa', '#60a5fa')};
150
+ }
151
+
152
+ .mainbox .barContainer .bar.no-data {
153
+ background: ${cssManager.bdTheme('#e5e7eb', '#27272a')};
154
+ opacity: 0.6;
155
+ }
156
+
157
+
158
+ .time-labels {
159
+ display: flex;
160
+ justify-content: space-between;
161
+ padding: 0;
162
+ margin-top: ${unsafeCSS(sharedStyles.spacing.xs)};
163
+ font-size: 10px;
164
+ color: ${cssManager.bdTheme('#9ca3af', '#71717a')};
165
+ font-family: ${unsafeCSS(sharedStyles.fonts.base)};
166
+ opacity: 0.8;
167
+ }
168
+
169
+ .tooltip {
64
170
  position: absolute;
65
- width: 11px;
66
- height: 11px;
67
- background: #FF9800;
68
- top: 56px;
69
- left: 400px;
70
- transform: rotate(45deg);
171
+ background: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
172
+ color: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
173
+ padding: 8px 12px;
174
+ border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)};
175
+ font-size: 11px;
176
+ pointer-events: none;
177
+ opacity: 0;
178
+ transition: opacity ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)},
179
+ transform ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)};
180
+ z-index: 50;
181
+ white-space: nowrap;
182
+ box-shadow: ${unsafeCSS(sharedStyles.shadows.lg)};
183
+ line-height: 1.5;
184
+ transform: translateY(4px);
185
+ }
186
+
187
+ .tooltip.visible {
188
+ opacity: 1;
189
+ transform: translateY(0);
190
+ }
191
+
192
+ .tooltip-time {
193
+ font-weight: 600;
194
+ display: block;
195
+ margin-bottom: 2px;
196
+ }
197
+
198
+ .tooltip-stat {
199
+ font-size: 10px;
200
+ opacity: 0.9;
201
+ }
202
+
203
+ .loading-skeleton {
204
+ display: flex;
205
+ gap: 1px;
206
+ height: 24px;
207
+ }
208
+
209
+ .loading-skeleton .skeleton-bar {
210
+ flex: 1;
211
+ height: 100%;
212
+ background: ${cssManager.bdTheme('#f3f4f6', '#27272a')};
213
+ animation: pulse 2s infinite;
214
+ }
215
+
216
+ @keyframes pulse {
217
+ 0%, 100% { opacity: 1; }
218
+ 50% { opacity: 0.5; }
219
+ }
220
+
221
+ @keyframes loading {
222
+ 0% { background-position: 200% 0; }
223
+ 100% { background-position: -200% 0; }
224
+ }
225
+
226
+
227
+ @media (max-width: 640px) {
228
+ .container {
229
+ padding: 0 ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)};
230
+ }
231
+
232
+ .graph-container {
233
+ padding: ${unsafeCSS(sharedStyles.spacing.sm)};
234
+ }
235
+
236
+ .mainbox .barContainer {
237
+ height: 32px;
238
+ padding: ${unsafeCSS(sharedStyles.spacing.xs)};
239
+ }
240
+
241
+ .time-labels {
242
+ font-size: 9px;
243
+ }
244
+
245
+ .stats-row {
246
+ font-size: 11px;
247
+ flex-direction: column;
248
+ gap: ${unsafeCSS(sharedStyles.spacing.sm)};
249
+ align-items: flex-start;
250
+ }
71
251
  }
72
252
  `,
73
253
  ];
74
254
 
75
255
  public render(): TemplateResult {
76
256
  return html`
77
- <style></style>
78
- <uplinternal-miniheading>Yesterday & Today</uplinternal-miniheading>
79
- <div class="mainbox">
80
- <div class="barContainer">
81
- ${(() => {
82
- let counter = 0;
83
- const returnArray: TemplateResult[] = [];
84
- while (counter < 48) {
85
- counter++;
86
- returnArray.push(html` <div class="bar"></div> `);
87
- }
88
- return returnArray;
89
- })()}
90
- <div class="timeIndicator"></div>
257
+ <div class="container">
258
+ <uplinternal-miniheading>${this.serviceName} - Last ${this.hoursToShow} Hours</uplinternal-miniheading>
259
+ <div class="mainbox">
260
+ ${this.loading ? html`
261
+ <div class="graph-container">
262
+ <div class="barContainer" style="background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')}; border: 1px solid ${cssManager.bdTheme('#f3f4f6', '#1f1f1f')}; border-radius: ${sharedStyles.borderRadius.base}; padding: ${sharedStyles.spacing.sm}; height: 40px;">
263
+ <div class="loading-skeleton">
264
+ ${Array(this.hoursToShow).fill(0).map(() => html`<div class="skeleton-bar"></div>`)}
265
+ </div>
266
+ </div>
267
+ </div>
268
+ ` : html`
269
+ <div class="graph-container">
270
+ <div class="barContainer" @mouseleave=${this.hideTooltip}>
271
+ ${this.renderBars()}
272
+ </div>
273
+ </div>
274
+ <div class="time-labels">
275
+ <span>${this.getTimeLabel(this.hoursToShow - 1)}</span>
276
+ <span>${this.getTimeLabel(Math.floor(this.hoursToShow * 3 / 4))}</span>
277
+ <span>${this.getTimeLabel(Math.floor(this.hoursToShow / 2))}</span>
278
+ <span>${this.getTimeLabel(Math.floor(this.hoursToShow / 4))}</span>
279
+ <span>now</span>
280
+ </div>
281
+ `}
91
282
  </div>
283
+ <div class="tooltip" id="tooltip"></div>
92
284
  </div>
93
285
  `;
94
286
  }
287
+
288
+ private renderBars(): TemplateResult[] {
289
+ const bars: TemplateResult[] = [];
290
+ const now = Date.now();
291
+
292
+ for (let i = 0; i < this.hoursToShow; i++) {
293
+ const hourIndex = this.hoursToShow - 1 - i;
294
+ const timestamp = now - (hourIndex * 60 * 60 * 1000);
295
+ const dataPoint = this.findDataPointForTime(timestamp);
296
+
297
+ const status = dataPoint?.status || 'no-data';
298
+ const responseTime = dataPoint?.responseTime || 0;
299
+
300
+ bars.push(html`
301
+ <div
302
+ class="bar ${status}"
303
+ style="--bar-index: ${i}"
304
+ @mouseenter=${(e: MouseEvent) => this.showTooltip(e, timestamp, status, responseTime)}
305
+ @click=${() => this.handleBarClick(timestamp, status, responseTime)}
306
+ ></div>
307
+ `);
308
+ }
309
+
310
+ return bars;
311
+ }
312
+
313
+ private getData(): IStatusHistoryPoint[] {
314
+ return this.dataPoints?.length > 0 ? this.dataPoints : this.historyData || [];
315
+ }
316
+
317
+ private findDataPointForTime(timestamp: number): IStatusHistoryPoint | undefined {
318
+ const data = this.getData();
319
+ if (!data || data.length === 0) return undefined;
320
+
321
+ // Find the closest data point within the same hour
322
+ const targetHour = new Date(timestamp).getHours();
323
+ const targetDate = new Date(timestamp).toDateString();
324
+
325
+ return data.find(point => {
326
+ const pointDate = new Date(point.timestamp);
327
+ return pointDate.toDateString() === targetDate &&
328
+ pointDate.getHours() === targetHour;
329
+ });
330
+ }
331
+
332
+
333
+ private getTimeLabel(hoursAgo: number): string {
334
+ const date = new Date(Date.now() - (hoursAgo * 60 * 60 * 1000));
335
+ if (hoursAgo >= 24) {
336
+ return `${date.getMonth() + 1}/${date.getDate()}`;
337
+ }
338
+ return `${date.getHours()}h`;
339
+ }
340
+
341
+ private showTooltip(event: MouseEvent, timestamp: number, status: string, responseTime: number) {
342
+ const tooltip = this.shadowRoot?.getElementById('tooltip') as HTMLElement;
343
+ if (!tooltip) return;
344
+
345
+ const date = new Date(timestamp);
346
+ const timeStr = date.toLocaleString();
347
+ const statusStr = status.replace(/_/g, ' ').replace('no-data', 'No Data');
348
+
349
+ tooltip.innerHTML = `
350
+ <div class="tooltip-time">${timeStr}</div>
351
+ <div class="tooltip-stat">Status: ${statusStr}</div>
352
+ ${responseTime > 0 ? `<div class="tooltip-stat">Response Time: ${responseTime.toFixed(0)}ms</div>` : ''}
353
+ `;
354
+
355
+ const rect = (event.target as HTMLElement).getBoundingClientRect();
356
+ const containerRect = this.getBoundingClientRect();
357
+
358
+ tooltip.style.left = `${rect.left - containerRect.left + rect.width / 2}px`;
359
+ tooltip.style.top = `${rect.top - containerRect.top - 10}px`;
360
+ tooltip.style.transform = 'translate(-50%, -100%)';
361
+ tooltip.classList.add('visible');
362
+ }
363
+
364
+ private hideTooltip() {
365
+ const tooltip = this.shadowRoot?.getElementById('tooltip') as HTMLElement;
366
+ if (tooltip) {
367
+ tooltip.classList.remove('visible');
368
+ }
369
+ }
370
+
371
+ private handleBarClick(timestamp: number, status: string, responseTime: number) {
372
+ this.dispatchEvent(new CustomEvent('barClick', {
373
+ detail: { timestamp, status, responseTime, serviceId: this.serviceId },
374
+ bubbles: true,
375
+ composed: true
376
+ }));
377
+ }
378
+
95
379
  }