@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
@@ -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,306 @@ 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;
38
76
  }
39
77
 
40
78
  .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;
79
+ background: transparent;
80
+ border: none;
81
+ border-radius: 0;
82
+ padding: 0;
47
83
  }
48
84
 
49
85
  .mainbox .barContainer {
50
86
  position: relative;
51
87
  display: flex;
52
- padding: 6px;
88
+ gap: 2px;
89
+ padding: ${unsafeCSS(sharedStyles.spacing.sm)};
90
+ background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
91
+ border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
92
+ border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)};
53
93
  overflow: hidden;
94
+ height: 40px;
54
95
  }
55
96
 
56
97
  .mainbox .barContainer .bar {
57
- margin: 4px;
58
- width: 11px;
59
- border-radius: 3px;
60
- height: 40px;
61
- background: #2deb51;
98
+ flex: 1;
99
+ height: 100%;
100
+ cursor: pointer;
101
+ transition: all 0.15s ease;
102
+ position: relative;
103
+ border-radius: 2px;
104
+ }
105
+
106
+ .mainbox .barContainer .bar:hover {
107
+ transform: scaleY(1.1);
108
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
109
+ }
110
+
111
+ .mainbox .barContainer .bar.operational {
112
+ background: ${cssManager.bdTheme('#22c55e', '#22c55e')};
113
+ }
114
+
115
+ .mainbox .barContainer .bar.degraded {
116
+ background: ${cssManager.bdTheme('#fbbf24', '#fbbf24')};
117
+ }
118
+
119
+ .mainbox .barContainer .bar.partial_outage {
120
+ background: ${cssManager.bdTheme('#f87171', '#f87171')};
121
+ }
122
+
123
+ .mainbox .barContainer .bar.major_outage {
124
+ background: ${cssManager.bdTheme('#ef4444', '#ef4444')};
125
+ }
126
+
127
+ .mainbox .barContainer .bar.maintenance {
128
+ background: ${cssManager.bdTheme('#60a5fa', '#60a5fa')};
62
129
  }
63
- .timeIndicator {
130
+
131
+ .mainbox .barContainer .bar.no-data {
132
+ background: ${cssManager.bdTheme('#e5e7eb', '#27272a')};
133
+ opacity: 0.6;
134
+ }
135
+
136
+
137
+ .time-labels {
138
+ display: flex;
139
+ justify-content: space-between;
140
+ padding: 0;
141
+ margin-top: ${unsafeCSS(sharedStyles.spacing.xs)};
142
+ font-size: 10px;
143
+ color: ${cssManager.bdTheme('#9ca3af', '#71717a')};
144
+ font-family: ${unsafeCSS(sharedStyles.fonts.base)};
145
+ opacity: 0.8;
146
+ }
147
+
148
+ .tooltip {
64
149
  position: absolute;
65
- width: 11px;
66
- height: 11px;
67
- background: #FF9800;
68
- top: 56px;
69
- left: 400px;
70
- transform: rotate(45deg);
150
+ background: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
151
+ color: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
152
+ padding: 6px 10px;
153
+ border-radius: 4px;
154
+ font-size: 11px;
155
+ pointer-events: none;
156
+ opacity: 0;
157
+ transition: opacity 0.15s;
158
+ z-index: 50;
159
+ white-space: nowrap;
160
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
161
+ line-height: 1.4;
162
+ }
163
+
164
+ .tooltip.visible {
165
+ opacity: 1;
166
+ }
167
+
168
+ .tooltip-time {
169
+ font-weight: 600;
170
+ display: block;
171
+ margin-bottom: 2px;
172
+ }
173
+
174
+ .tooltip-stat {
175
+ font-size: 10px;
176
+ opacity: 0.9;
177
+ }
178
+
179
+ .loading-skeleton {
180
+ display: flex;
181
+ gap: 1px;
182
+ height: 24px;
183
+ }
184
+
185
+ .loading-skeleton .skeleton-bar {
186
+ flex: 1;
187
+ height: 100%;
188
+ background: ${cssManager.bdTheme('#f3f4f6', '#27272a')};
189
+ animation: pulse 2s infinite;
190
+ }
191
+
192
+ @keyframes pulse {
193
+ 0%, 100% { opacity: 1; }
194
+ 50% { opacity: 0.5; }
195
+ }
196
+
197
+ @keyframes loading {
198
+ 0% { background-position: 200% 0; }
199
+ 100% { background-position: -200% 0; }
200
+ }
201
+
202
+
203
+ @media (max-width: 640px) {
204
+ .container {
205
+ padding: 0 ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)};
206
+ }
207
+
208
+ .graph-container {
209
+ padding: ${unsafeCSS(sharedStyles.spacing.sm)};
210
+ }
211
+
212
+ .mainbox .barContainer {
213
+ height: 32px;
214
+ padding: ${unsafeCSS(sharedStyles.spacing.xs)};
215
+ }
216
+
217
+ .time-labels {
218
+ font-size: 9px;
219
+ }
220
+
221
+ .stats-row {
222
+ font-size: 11px;
223
+ flex-direction: column;
224
+ gap: ${unsafeCSS(sharedStyles.spacing.sm)};
225
+ align-items: flex-start;
226
+ }
71
227
  }
72
228
  `,
73
229
  ];
74
230
 
75
231
  public render(): TemplateResult {
76
232
  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>
233
+ <div class="container">
234
+ <uplinternal-miniheading>${this.serviceName} - Last ${this.hoursToShow} Hours</uplinternal-miniheading>
235
+ <div class="mainbox">
236
+ ${this.loading ? html`
237
+ <div class="graph-container">
238
+ <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;">
239
+ <div class="loading-skeleton">
240
+ ${Array(this.hoursToShow).fill(0).map(() => html`<div class="skeleton-bar"></div>`)}
241
+ </div>
242
+ </div>
243
+ </div>
244
+ ` : html`
245
+ <div class="graph-container">
246
+ <div class="barContainer" @mouseleave=${this.hideTooltip}>
247
+ ${this.renderBars()}
248
+ </div>
249
+ </div>
250
+ <div class="time-labels">
251
+ <span>${this.getTimeLabel(this.hoursToShow - 1)}</span>
252
+ <span>${this.getTimeLabel(Math.floor(this.hoursToShow * 3 / 4))}</span>
253
+ <span>${this.getTimeLabel(Math.floor(this.hoursToShow / 2))}</span>
254
+ <span>${this.getTimeLabel(Math.floor(this.hoursToShow / 4))}</span>
255
+ <span>now</span>
256
+ </div>
257
+ `}
91
258
  </div>
259
+ <div class="tooltip" id="tooltip"></div>
92
260
  </div>
93
261
  `;
94
262
  }
263
+
264
+ private renderBars(): TemplateResult[] {
265
+ const bars: TemplateResult[] = [];
266
+ const now = Date.now();
267
+
268
+ for (let i = 0; i < this.hoursToShow; i++) {
269
+ const hourIndex = this.hoursToShow - 1 - i;
270
+ const timestamp = now - (hourIndex * 60 * 60 * 1000);
271
+ const dataPoint = this.findDataPointForTime(timestamp);
272
+
273
+ const status = dataPoint?.status || 'no-data';
274
+ const responseTime = dataPoint?.responseTime || 0;
275
+
276
+ bars.push(html`
277
+ <div
278
+ class="bar ${status}"
279
+ @mouseenter=${(e: MouseEvent) => this.showTooltip(e, timestamp, status, responseTime)}
280
+ @click=${() => this.handleBarClick(timestamp, status, responseTime)}
281
+ ></div>
282
+ `);
283
+ }
284
+
285
+ return bars;
286
+ }
287
+
288
+ private getData(): IStatusHistoryPoint[] {
289
+ return this.dataPoints?.length > 0 ? this.dataPoints : this.historyData || [];
290
+ }
291
+
292
+ private findDataPointForTime(timestamp: number): IStatusHistoryPoint | undefined {
293
+ const data = this.getData();
294
+ if (!data || data.length === 0) return undefined;
295
+
296
+ // Find the closest data point within the same hour
297
+ const targetHour = new Date(timestamp).getHours();
298
+ const targetDate = new Date(timestamp).toDateString();
299
+
300
+ return data.find(point => {
301
+ const pointDate = new Date(point.timestamp);
302
+ return pointDate.toDateString() === targetDate &&
303
+ pointDate.getHours() === targetHour;
304
+ });
305
+ }
306
+
307
+
308
+ private getTimeLabel(hoursAgo: number): string {
309
+ const date = new Date(Date.now() - (hoursAgo * 60 * 60 * 1000));
310
+ if (hoursAgo >= 24) {
311
+ return `${date.getMonth() + 1}/${date.getDate()}`;
312
+ }
313
+ return `${date.getHours()}h`;
314
+ }
315
+
316
+ private showTooltip(event: MouseEvent, timestamp: number, status: string, responseTime: number) {
317
+ const tooltip = this.shadowRoot?.getElementById('tooltip') as HTMLElement;
318
+ if (!tooltip) return;
319
+
320
+ const date = new Date(timestamp);
321
+ const timeStr = date.toLocaleString();
322
+ const statusStr = status.replace(/_/g, ' ').replace('no-data', 'No Data');
323
+
324
+ tooltip.innerHTML = `
325
+ <div class="tooltip-time">${timeStr}</div>
326
+ <div class="tooltip-stat">Status: ${statusStr}</div>
327
+ ${responseTime > 0 ? `<div class="tooltip-stat">Response Time: ${responseTime.toFixed(0)}ms</div>` : ''}
328
+ `;
329
+
330
+ const rect = (event.target as HTMLElement).getBoundingClientRect();
331
+ const containerRect = this.getBoundingClientRect();
332
+
333
+ tooltip.style.left = `${rect.left - containerRect.left + rect.width / 2}px`;
334
+ tooltip.style.top = `${rect.top - containerRect.top - 10}px`;
335
+ tooltip.style.transform = 'translate(-50%, -100%)';
336
+ tooltip.classList.add('visible');
337
+ }
338
+
339
+ private hideTooltip() {
340
+ const tooltip = this.shadowRoot?.getElementById('tooltip') as HTMLElement;
341
+ if (tooltip) {
342
+ tooltip.classList.remove('visible');
343
+ }
344
+ }
345
+
346
+ private handleBarClick(timestamp: number, status: string, responseTime: number) {
347
+ this.dispatchEvent(new CustomEvent('barClick', {
348
+ detail: { timestamp, status, responseTime, serviceId: this.serviceId },
349
+ bubbles: true,
350
+ composed: true
351
+ }));
352
+ }
353
+
95
354
  }