jerdev38282 commited on
Commit
68aa291
·
verified ·
1 Parent(s): 09f0702

Update public/index.html

Browse files
Files changed (1) hide show
  1. public/index.html +276 -58
public/index.html CHANGED
@@ -1,73 +1,291 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
- <meta charset="UTF-8">
5
- <title>Uptime Performance Monitor</title>
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
8
- <style>
9
- body {
10
- background: linear-gradient(135deg, #0f2027, #203a43, #2c5364);
11
- color: #fff;
12
- min-height: 100vh;
13
- font-family: "Segoe UI", sans-serif;
14
- }
15
- .glass {
16
- background: rgba(255,255,255,0.08);
17
- backdrop-filter: blur(12px);
18
- border-radius: 16px;
19
- padding: 20px;
20
- box-shadow: 0 8px 32px rgba(0,0,0,0.4);
21
- }
22
- .badge-online { background: #00ff9d; color: #000; }
23
- .badge-offline { background: #ff4d4d; }
24
- h1 span { color: #00ff9d; }
25
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  </head>
27
  <body>
28
 
29
- <div class="container py-5">
30
- <h1 class="text-center mb-4">⚡ <span>Uptime Performance</span> Monitor</h1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
- <div id="uptime" class="text-center mb-3"></div>
 
 
 
 
 
 
 
 
 
 
 
33
 
34
- <div class="row" id="cards"></div>
 
 
 
 
35
  </div>
36
 
37
  <script>
38
- async function loadStatus() {
39
- const res = await fetch("/status");
40
- const data = await res.json();
41
-
42
- document.getElementById("uptime").innerHTML =
43
- ` Server Uptime: <b>${data.uptimeSeconds}s</b> | 🕒 ${data.serverTime}`;
44
-
45
- const cards = document.getElementById("cards");
46
- cards.innerHTML = "";
47
-
48
- Object.values(data.targets).forEach(t => {
49
- const badge = t.lastStatus === "online"
50
- ? "badge-online"
51
- : "badge-offline";
52
-
53
- cards.innerHTML += `
54
- <div class="col-md-4 mb-4">
55
- <div class="glass">
56
- <h5>${t.url}</h5>
57
- <span class="badge ${badge}">${t.lastStatus}</span>
58
- <hr>
59
- <p>✅ Success: ${t.success}</p>
60
- <p>❌ Fail: ${t.fail}</p>
61
- <small>Last Ping: ${t.lastPing || "N/A"}</small>
62
- </div>
63
- </div>
64
- `;
65
- });
66
- }
67
 
68
- loadStatus();
69
- setInterval(loadStatus, 5000);
70
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  </body>
73
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <title>System Status | Live Monitor</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
11
+
12
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
13
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
14
+
15
+ <style>
16
+ :root {
17
+ --bg-color: #0b0f19;
18
+ --card-bg: rgba(23, 32, 51, 0.7);
19
+ --border-color: rgba(255, 255, 255, 0.1);
20
+ --accent-green: #10b981;
21
+ --accent-red: #ef4444;
22
+ --text-muted: #94a3b8;
23
+ }
24
+
25
+ body {
26
+ background-color: var(--bg-color);
27
+ background-image:
28
+ radial-gradient(at 0% 0%, rgba(16, 185, 129, 0.1) 0px, transparent 50%),
29
+ radial-gradient(at 100% 100%, rgba(59, 130, 246, 0.1) 0px, transparent 50%);
30
+ color: #fff;
31
+ font-family: 'Inter', sans-serif;
32
+ min-height: 100vh;
33
+ -webkit-font-smoothing: antialiased;
34
+ }
35
+
36
+ /* --- Header Stats --- */
37
+ .stats-bar {
38
+ background: rgba(255,255,255,0.03);
39
+ border-bottom: 1px solid var(--border-color);
40
+ padding: 15px 0;
41
+ margin-bottom: 40px;
42
+ backdrop-filter: blur(10px);
43
+ }
44
+
45
+ .stat-item {
46
+ border-right: 1px solid var(--border-color);
47
+ }
48
+ .stat-item:last-child { border-right: none; }
49
+ .stat-label { font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px; }
50
+ .stat-value { font-family: 'JetBrains Mono', monospace; font-size: 1.2rem; font-weight: 700; }
51
+
52
+ /* --- Cards --- */
53
+ .monitor-card {
54
+ background: var(--card-bg);
55
+ border: 1px solid var(--border-color);
56
+ border-radius: 12px;
57
+ padding: 24px;
58
+ transition: all 0.3s ease;
59
+ position: relative;
60
+ overflow: hidden;
61
+ backdrop-filter: blur(12px);
62
+ }
63
+
64
+ .monitor-card:hover {
65
+ transform: translateY(-5px);
66
+ border-color: rgba(255, 255, 255, 0.2);
67
+ box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.5);
68
+ }
69
+
70
+ /* --- Typography & Elements --- */
71
+ h5 { font-weight: 600; font-size: 1.1rem; margin: 0; }
72
+ .mono-text { font-family: 'JetBrains Mono', monospace; font-size: 0.85rem; color: var(--text-muted); }
73
+
74
+ /* --- Status Indicators --- */
75
+ .status-dot {
76
+ height: 10px;
77
+ width: 10px;
78
+ border-radius: 50%;
79
+ display: inline-block;
80
+ margin-right: 8px;
81
+ }
82
+
83
+ .status-online {
84
+ background-color: var(--accent-green);
85
+ box-shadow: 0 0 10px var(--accent-green);
86
+ animation: pulse-green 2s infinite;
87
+ }
88
+
89
+ .status-offline {
90
+ background-color: var(--accent-red);
91
+ box-shadow: 0 0 10px var(--accent-red);
92
+ animation: pulse-red 2s infinite;
93
+ }
94
+
95
+ @keyframes pulse-green {
96
+ 0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); }
97
+ 70% { box-shadow: 0 0 0 10px rgba(16, 185, 129, 0); }
98
+ 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
99
+ }
100
+ @keyframes pulse-red {
101
+ 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
102
+ 70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); }
103
+ 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
104
+ }
105
+
106
+ /* --- Progress Bar --- */
107
+ .reliability-track {
108
+ height: 6px;
109
+ background: rgba(255,255,255,0.1);
110
+ border-radius: 3px;
111
+ margin-top: 15px;
112
+ margin-bottom: 8px;
113
+ overflow: hidden;
114
+ }
115
+ .reliability-bar {
116
+ height: 100%;
117
+ border-radius: 3px;
118
+ transition: width 0.5s ease;
119
+ }
120
+
121
+ /* --- Loading Skeleton --- */
122
+ .skeleton {
123
+ background: linear-gradient(90deg, #1f2937 25%, #374151 50%, #1f2937 75%);
124
+ background-size: 200% 100%;
125
+ animation: loading 1.5s infinite;
126
+ border-radius: 4px;
127
+ color: transparent !important;
128
+ }
129
+ @keyframes loading {
130
+ 0% { background-position: 200% 0; }
131
+ 100% { background-position: -200% 0; }
132
+ }
133
+ </style>
134
  </head>
135
  <body>
136
 
137
+ <div class="stats-bar sticky-top">
138
+ <div class="container">
139
+ <div class="row align-items-center">
140
+ <div class="col-md-4 mb-2 mb-md-0">
141
+ <div class="d-flex align-items-center gap-2">
142
+ <i class="bi bi-activity text-primary fs-4"></i>
143
+ <h4 class="m-0 fw-bold">Uptime<span class="text-primary">Monitor</span></h4>
144
+ </div>
145
+ </div>
146
+ <div class="col-md-8">
147
+ <div class="row text-center text-md-end">
148
+ <div class="col-4 stat-item">
149
+ <div class="stat-label">System Uptime</div>
150
+ <div class="stat-value text-white" id="server-uptime">--:--:--</div>
151
+ </div>
152
+ <div class="col-4 stat-item">
153
+ <div class="stat-label">Active Monitors</div>
154
+ <div class="stat-value text-info" id="monitor-count">-</div>
155
+ </div>
156
+ <div class="col-4 stat-item">
157
+ <div class="stat-label">Server Time</div>
158
+ <div class="stat-value text-warning" id="server-time">--:--</div>
159
+ </div>
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </div>
165
 
166
+ <div class="container pb-5">
167
+ <div class="d-flex justify-content-between align-items-end mb-4">
168
+ <div>
169
+ <h2 class="fw-bold mb-1">Service Status</h2>
170
+ <p class="text-muted m-0">Real-time performance metrics</p>
171
+ </div>
172
+ <div class="text-end">
173
+ <span class="badge bg-dark border border-secondary text-secondary" id="last-updated">
174
+ <i class="bi bi-arrow-repeat spin"></i> Connecting...
175
+ </span>
176
+ </div>
177
+ </div>
178
 
179
+ <div class="row g-4" id="cards-container">
180
+ <div class="col-md-6 col-lg-4"><div class="monitor-card skeleton" style="height: 200px"></div></div>
181
+ <div class="col-md-6 col-lg-4"><div class="monitor-card skeleton" style="height: 200px"></div></div>
182
+ <div class="col-md-6 col-lg-4"><div class="monitor-card skeleton" style="height: 200px"></div></div>
183
+ </div>
184
  </div>
185
 
186
  <script>
187
+ // Helper to format seconds into H:M:S
188
+ function formatDuration(seconds) {
189
+ const h = Math.floor(seconds / 3600);
190
+ const m = Math.floor((seconds % 3600) / 60);
191
+ const s = Math.floor(seconds % 60);
192
+ return `${h}h ${m}m ${s}s`;
193
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
+ // Helper to calculate percentage
196
+ function calcPercentage(success, fail) {
197
+ const total = success + fail;
198
+ if (total === 0) return 100;
199
+ return ((success / total) * 100).toFixed(1);
200
+ }
201
+
202
+ async function loadStatus() {
203
+ try {
204
+ const res = await fetch("/status");
205
+ const data = await res.json();
206
+
207
+ // 1. Update Header Stats
208
+ document.getElementById("server-uptime").innerText = formatDuration(data.uptimeSeconds);
209
+ document.getElementById("server-time").innerText = data.serverTime;
210
+ document.getElementById("monitor-count").innerText = Object.keys(data.targets).length;
211
+
212
+ const now = new Date();
213
+ document.getElementById("last-updated").innerHTML =
214
+ `<i class="bi bi-check-circle-fill text-success"></i> Updated: ${now.toLocaleTimeString()}`;
215
+
216
+ // 2. Build Cards
217
+ const container = document.getElementById("cards-container");
218
+ let html = "";
219
+
220
+ Object.values(data.targets).forEach(t => {
221
+ const isOnline = t.lastStatus === "online";
222
+ const statusClass = isOnline ? "status-online" : "status-offline";
223
+ const statusText = isOnline ? "Operational" : "Downtime Detected";
224
+ const badgeColor = isOnline ? "text-success" : "text-danger";
225
+
226
+ // Calculate reliability
227
+ const percent = calcPercentage(t.success, t.fail);
228
+ const barColor = percent > 90 ? 'bg-success' : (percent > 50 ? 'bg-warning' : 'bg-danger');
229
 
230
+ html += `
231
+ <div class="col-md-6 col-lg-4">
232
+ <div class="monitor-card">
233
+ <div class="d-flex justify-content-between align-items-start mb-3">
234
+ <div class="d-flex align-items-center">
235
+ <span class="status-dot ${statusClass}"></span>
236
+ <div>
237
+ <h5 class="text-truncate" style="max-width: 200px;" title="${t.url}">${t.url}</h5>
238
+ <small class="${badgeColor} fw-bold" style="font-size: 0.75rem;">${statusText}</small>
239
+ </div>
240
+ </div>
241
+ <span class="badge bg-dark border border-secondary text-muted font-monospace">
242
+ HTTP/2
243
+ </span>
244
+ </div>
245
+
246
+ <div class="d-flex justify-content-between align-items-end">
247
+ <span class="text-muted" style="font-size: 0.8rem">Reliability</span>
248
+ <span class="fw-bold ${badgeColor}">${percent}%</span>
249
+ </div>
250
+ <div class="reliability-track">
251
+ <div class="reliability-bar ${barColor}" style="width: ${percent}%"></div>
252
+ </div>
253
+
254
+ <hr class="border-secondary opacity-25 my-3">
255
+
256
+ <div class="row text-center">
257
+ <div class="col-4 border-end border-secondary border-opacity-25">
258
+ <div class="d-block text-muted" style="font-size: 0.7rem">SUCCESS</div>
259
+ <div class="fw-bold text-white">${t.success}</div>
260
+ </div>
261
+ <div class="col-4 border-end border-secondary border-opacity-25">
262
+ <div class="d-block text-muted" style="font-size: 0.7rem">FAILED</div>
263
+ <div class="fw-bold text-danger">${t.fail}</div>
264
+ </div>
265
+ <div class="col-4">
266
+ <div class="d-block text-muted" style="font-size: 0.7rem">LAST PING</div>
267
+ <div class="mono-text text-white">${t.lastPing ? t.lastPing.split(' ')[1] : 'N/A'}</div>
268
+ </div>
269
+ </div>
270
+ </div>
271
+ </div>
272
+ `;
273
+ });
274
+
275
+ container.innerHTML = html;
276
+
277
+ } catch (error) {
278
+ console.error("Fetch error:", error);
279
+ document.getElementById("last-updated").innerHTML =
280
+ `<i class="bi bi-exclamation-triangle-fill text-danger"></i> Connection Lost`;
281
+ }
282
+ }
283
+
284
+ // Initial load
285
+ loadStatus();
286
+ // Poll every 5 seconds
287
+ setInterval(loadStatus, 5000);
288
+
289
+ </script>
290
  </body>
291
  </html>