mio dashboard docs.kosmonum.space/mio/
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

v23

+98 -104
+98 -104
dashboard.html
··· 3 3 <head> 4 4 <meta charset="UTF-8"> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 - <title>MIO Dashboard</title> 6 + <title>MIO Instances</title> 7 + 7 8 <style> 8 9 * { 9 10 margin: 0; ··· 12 13 } 13 14 14 15 body { 15 - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; 16 - background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); 16 + font-family: system-ui,sans-serif; 17 + background: linear-gradient(135deg, #4c566a 0%, #2e3440 100%); 17 18 min-height: 100vh; 18 19 padding: 20px; 19 20 } 20 21 21 22 /* Header Styles */ 22 23 .header { 23 - background: white; 24 + background: #3b4252; 24 25 padding: 16px 24px; 25 26 border-radius: 8px; 26 27 display: flex; 27 28 align-items: center; 28 29 justify-content: space-between; 29 30 margin-bottom: 24px; 30 - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); 31 + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); 32 + border-left: 8px solid #88c0d0; 31 33 } 32 34 33 35 .header-left { ··· 39 41 .header-title { 40 42 font-size: 18px; 41 43 font-weight: 600; 42 - color: #333; 44 + color: #eceff4; 45 + text-transform: uppercase; 43 46 } 44 47 45 48 .butterfly-icon { 46 - font-size: 24px; 49 + font-size: 36px; 47 50 } 48 51 49 52 .header-right { ··· 55 58 .btn { 56 59 padding: 8px 12px; 57 60 border: none; 58 - background: #f0f2f5; 59 - color: #333; 61 + background: #4c566a; 62 + color: #eceff4; 60 63 border-radius: 6px; 61 64 cursor: pointer; 62 65 font-size: 16px; ··· 68 71 } 69 72 70 73 .btn:hover { 71 - background: #e4e6eb; 74 + background: #5e81ac; 72 75 transform: translateY(-1px); 73 76 } 74 77 75 78 .btn-primary { 76 - background: #f0f2f5; 79 + background: #4c566a; 77 80 font-weight: 500; 78 81 } 79 82 ··· 89 92 90 93 .avatar-btn { 91 94 border-radius: 50%; 92 - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 93 - color: white; 95 + background: linear-gradient(135deg, #81a1c1 0%, #5e81ac 100%); 96 + color: #eceff4; 94 97 font-weight: 600; 95 98 position: relative; 96 99 cursor: pointer; ··· 106 109 position: absolute; 107 110 top: 100%; 108 111 right: 0; 109 - background: white; 112 + background: #3b4252; 110 113 border-radius: 6px; 111 - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); 114 + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); 112 115 min-width: 160px; 113 116 z-index: 1000; 114 117 display: none; 115 118 margin-top: 4px; 116 119 overflow: hidden; 120 + border: 1px solid #4c566a; 117 121 } 118 122 119 123 .dropdown-menu.active { ··· 125 129 display: flex; 126 130 align-items: center; 127 131 gap: 8px; 128 - color: #333; 132 + color: #eceff4; 129 133 cursor: pointer; 130 134 transition: background 0.2s ease; 131 135 border: none; ··· 136 140 } 137 141 138 142 .dropdown-item:hover { 139 - background: #f0f2f5; 143 + background: #4c566a; 140 144 } 141 145 142 146 .dropdown-item.danger { 143 - color: #dc3545; 147 + color: #bf616a; 144 148 } 145 149 146 150 .dropdown-item.danger:hover { 147 - background: #ffe5e5; 151 + background: #4c566a; 148 152 } 149 153 150 154 /* Instances Container */ ··· 155 159 156 160 /* Instance Card */ 157 161 .instance { 158 - background: white; 159 - padding: 16px 20px; 162 + background: #3b4252; 163 + padding: 16px 12px 16px 20px; 160 164 border-radius: 8px; 161 165 margin-bottom: 12px; 162 - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); 166 + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); 163 167 transition: all 0.2s ease; 164 168 display: grid; 165 169 grid-template-columns: auto 1fr auto auto; 166 170 grid-template-rows: auto auto; 167 171 gap: 12px 12px; 168 172 align-items: start; 173 + border-left: 8px solid #b48ead; 169 174 } 170 175 171 176 .instance:hover { 172 - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); 177 + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); 178 + background: #434c5e; 173 179 } 174 180 175 - /* Heartbeat on its own row */ 176 - .heartbeat { 177 - font-size: 20px; 178 - animation: pulse 1.5s ease-in-out infinite; 179 - width: 24px; 180 - height: 24px; 181 - display: flex; 182 - align-items: center; 183 - justify-content: center; 184 - flex-shrink: 0; 185 - grid-column: 1; 186 - grid-row: 1; 187 - } 188 - 189 - .heartbeat.healthy { 190 - color: #28a745; 181 + .instance.healthy { 182 + border-left-color: #a3be8c; 191 183 } 192 184 193 - .heartbeat.warning { 194 - color: #ffc107; 185 + .instance.warning { 186 + border-left-color: #ebcb8b; 195 187 } 196 188 197 - .heartbeat.critical { 198 - color: #dc3545; 189 + .instance.critical { 190 + border-left-color: #bf616a; 199 191 } 200 192 201 193 @keyframes pulse { ··· 206 198 /* First line: name + tags + menu */ 207 199 .instance-name { 208 200 font-weight: 500; 209 - color: #333; 201 + color: #eceff4; 210 202 display: flex; 211 203 align-items: center; 212 - grid-column: 2; 204 + grid-column: 1; 213 205 grid-row: 1; 214 - text-transform: uppercase; 215 - font-size: 13px; 206 + font-size: 14px; 216 207 letter-spacing: 0.5px; 217 208 height: 24px; 218 209 } ··· 222 213 display: flex; 223 214 gap: 8px; 224 215 align-items: center; 225 - grid-column: 3; 216 + grid-column: 2; 226 217 grid-row: 1; 227 218 justify-self: end; 228 219 height: 24px; ··· 232 223 display: inline-flex; 233 224 align-items: center; 234 225 padding: 4px 8px; 235 - background: #f0f2f5; 236 - color: #333; 226 + background: #4c566a; 227 + color: #88c0d0; 237 228 border-radius: 4px; 238 229 font-size: 11px; 239 230 font-weight: 500; ··· 241 232 transition: all 0.2s ease; 242 233 position: relative; 243 234 text-transform: uppercase; 235 + border: 1px solid #5e81ac; 244 236 } 245 237 246 238 .tag:hover { 247 - background: #e4e6eb; 239 + background: #5e81ac; 240 + color: #eceff4; 248 241 } 249 242 250 243 /* Tag tooltip */ ··· 254 247 bottom: -24px; 255 248 left: 50%; 256 249 transform: translateX(-50%); 257 - background: #333; 258 - color: white; 250 + background: #2e3440; 251 + color: #88c0d0; 259 252 padding: 4px 8px; 260 253 border-radius: 4px; 261 254 font-size: 10px; ··· 265 258 pointer-events: none; 266 259 transition: opacity 0.2s ease; 267 260 z-index: 100; 261 + border: 1px solid #4c566a; 268 262 } 269 263 270 264 .tag:hover::before { ··· 275 269 .metrics { 276 270 display: flex; 277 271 gap: 24px; 278 - grid-column: 2 / 4; 272 + grid-column: 1 / 3; 279 273 grid-row: 2; 280 274 } 281 275 ··· 289 283 290 284 .metric-bar { 291 285 height: 8px; 292 - background: #e9ecef; 286 + background: #2e3440; 293 287 border-radius: 4px; 294 288 overflow: hidden; 295 289 cursor: pointer; ··· 303 297 } 304 298 305 299 .metric-utilization .metric-fill { 306 - background: linear-gradient(90deg, #4a90e2 0%, #357abd 100%); 300 + background: linear-gradient(90deg, #81a1c1 0%, #5e81ac 100%); 307 301 } 308 302 309 303 .metric-saturation .metric-fill { 310 - background: linear-gradient(90deg, #f5a623 0%, #d68910 100%); 304 + background: linear-gradient(90deg, #d08770 0%, #bf616a 100%); 311 305 } 312 306 313 307 .metric-error .metric-fill { 314 - background: linear-gradient(90deg, #e74c3c 0%, #c0392b 100%); 308 + background: linear-gradient(90deg, #bf616a 0%, #a3414a 100%); 315 309 } 316 310 317 311 .metric-latency .metric-fill { 318 - background: linear-gradient(90deg, #9b59b6 0%, #8e44ad 100%); 312 + background: linear-gradient(90deg, #b48ead 0%, #a3429e 100%); 319 313 } 320 314 321 315 .metric-uptime .metric-fill { 322 - background: linear-gradient(90deg, #28a745 0%, #20c997 100%); 316 + background: linear-gradient(90deg, #a3be8c 0%, #8fb78a 100%); 323 317 } 324 318 325 319 /* Metric value tooltip */ ··· 328 322 bottom: -24px; 329 323 left: 50%; 330 324 transform: translateX(-50%); 331 - background: #333; 332 - color: white; 325 + background: #2e3440; 326 + color: #88c0d0; 333 327 padding: 4px 8px; 334 328 border-radius: 4px; 335 329 font-size: 11px; ··· 339 333 pointer-events: none; 340 334 transition: opacity 0.2s ease; 341 335 z-index: 100; 336 + border: 1px solid #4c566a; 342 337 } 343 338 344 339 .metric-bar:hover + .metric-tooltip, ··· 350 345 .instance-menu { 351 346 flex-shrink: 0; 352 347 position: relative; 353 - grid-column: 4; 348 + grid-column: 3; 354 349 grid-row: 1; 355 350 justify-self: end; 356 351 display: flex; ··· 360 355 361 356 .menu-btn { 362 357 background: none; 363 - border: none; 358 + border: 1px solid #4c566a; 364 359 font-size: 18px; 365 - color: #666; 360 + color: #81a1c1; 366 361 cursor: pointer; 367 362 padding: 4px 8px; 368 363 border-radius: 4px; ··· 374 369 } 375 370 376 371 .menu-btn:hover { 377 - background: #f0f2f5; 378 - color: #333; 372 + background: #4c566a; 373 + color: #88c0d0; 379 374 } 380 375 381 376 /* Responsive Design */ 382 377 @media (max-width: 768px) { 383 378 .instance { 384 379 grid-template-columns: auto 1fr auto; 380 + } 381 + 382 + .instance-name { 383 + font-size: 13px; 385 384 } 386 385 387 386 .instance-tags { ··· 398 397 399 398 @media (max-width: 480px) { 400 399 .header { 401 - flex-direction: column; 402 - gap: 12px; 403 - align-items: flex-start; 400 + padding-left: 16px; 401 + padding-right: 16px; 404 402 } 405 403 406 404 .header-right { 407 - width: 100%; 408 - justify-content: flex-end; 409 405 } 410 406 411 407 .instance { 412 408 grid-template-columns: auto 1fr auto; 413 409 gap: 8px; 410 + padding-left: 16px; 411 + padding-right: 16px; 414 412 } 415 413 416 414 .instance-tags { ··· 422 420 } 423 421 424 422 .tag { 425 - font-size: 10px; 426 - padding: 3px 6px; 423 + font-size: 8px; 424 + padding: 2px 4px; 427 425 } 428 426 } 429 427 </style> ··· 433 431 <div class="header"> 434 432 <div class="header-left"> 435 433 <span class="butterfly-icon">🦋</span> 436 - <h1 class="header-title">MIO Dashboard</h1> 434 + <h1 class="header-title">MIO Instances</h1> 437 435 </div> 438 436 <div class="header-right"> 439 437 <button class="btn btn-primary btn-icon" onclick="showAddInstanceModal()" title="Add Instance"> ··· 452 450 453 451 <!-- Instances List --> 454 452 <div class="instances-container" id="instancesList"> 455 - <!-- Instance 1: Healthy --> 456 - <div class="instance"> 457 - <div class="heartbeat healthy">♥</div> 458 - <div class="instance-name">prod-server-01</div> 453 + <!-- Instance 1 --> 454 + <div class="instance critical"> 455 + <div class="instance-name">netti</div> 459 456 <div class="instance-tags"> 460 - <span class="tag" data-label="Type">compute</span> 457 + <span class="tag" data-label="App">netbox</span> 461 458 <span class="tag" data-label="Location">us-east-1</span> 462 459 </div> 463 460 <div class="instance-menu dropdown"> ··· 473 470 <div class="metrics"> 474 471 <div class="metric metric-utilization"> 475 472 <div class="metric-bar"> 476 - <div class="metric-fill" style="width: 65%"></div> 473 + <div class="metric-fill" style="width: 15%"></div> 477 474 </div> 478 - <div class="metric-tooltip">Utilization: 65%</div> 475 + <div class="metric-tooltip">Utilization: 15%</div> 479 476 </div> 480 477 <div class="metric metric-saturation"> 481 478 <div class="metric-bar"> ··· 485 482 </div> 486 483 <div class="metric metric-error"> 487 484 <div class="metric-bar"> 488 - <div class="metric-fill" style="width: 2%"></div> 485 + <div class="metric-fill" style="width: 62%"></div> 489 486 </div> 490 - <div class="metric-tooltip">Error Rate: 0.2%</div> 487 + <div class="metric-tooltip">Error Rate: 62%</div> 491 488 </div> 492 489 <div class="metric metric-latency"> 493 490 <div class="metric-bar"> ··· 497 494 </div> 498 495 <div class="metric metric-uptime"> 499 496 <div class="metric-bar"> 500 - <div class="metric-fill" style="width: 99.9%"></div> 497 + <div class="metric-fill" style="width: 20.9%"></div> 501 498 </div> 502 - <div class="metric-tooltip">Uptime: 99.9%</div> 499 + <div class="metric-tooltip">Uptime: 20.9%</div> 503 500 </div> 504 501 </div> 505 502 </div> 506 503 507 - <!-- Instance 2: Warning --> 508 - <div class="instance"> 509 - <div class="heartbeat warning">♥</div> 510 - <div class="instance-name">staging-api-02</div> 504 + <!-- Instance 2 --> 505 + <div class="instance warning"> 506 + <div class="instance-name">papi</div> 511 507 <div class="instance-tags"> 512 - <span class="tag" data-label="Type">api</span> 508 + <span class="tag" data-label="App">paperless</span> 513 509 <span class="tag" data-label="Location">eu-west-1</span> 514 510 </div> 515 511 <div class="instance-menu dropdown"> 516 512 <button class="menu-btn" onclick="toggleInstanceMenu(this)">☰</button> 517 513 <div class="dropdown-menu"> 518 - <button class="dropdown-item">�� Terminal</button> 514 + <button class="dropdown-item">💻 Terminal</button> 519 515 <button class="dropdown-item">💾 Backup</button> 520 516 <button class="dropdown-item">⬆️ Upgrade</button> 521 517 <button class="dropdown-item">🔄 Reboot</button> ··· 556 552 </div> 557 553 </div> 558 554 559 - <!-- Instance 3: Critical --> 555 + <!-- Instance 3 --> 560 556 <div class="instance"> 561 - <div class="heartbeat critical">♥</div> 562 - <div class="instance-name">worker-queue-03</div> 557 + <div class="instance-name">ci</div> 563 558 <div class="instance-tags"> 564 - <span class="tag" data-label="Type">worker</span> 559 + <span class="tag" data-label="App">buildbot</span> 565 560 <span class="tag" data-label="Location">ap-south-1</span> 566 561 </div> 567 562 <div class="instance-menu dropdown"> ··· 608 603 </div> 609 604 </div> 610 605 611 - <!-- Instance 4: Healthy --> 612 - <div class="instance"> 613 - <div class="heartbeat healthy">♥</div> 614 - <div class="instance-name">db-primary-01</div> 606 + <!-- Instance 4 --> 607 + <div class="instance healthy"> 608 + <div class="instance-name">chat</div> 615 609 <div class="instance-tags"> 616 - <span class="tag" data-label="Type">database</span> 610 + <span class="tag" data-label="App">irc</span> 617 611 <span class="tag" data-label="Location">us-west-2</span> 618 612 </div> 619 613 <div class="instance-menu dropdown"> ··· 680 674 // Toggle instance menu 681 675 function toggleInstanceMenu(button) { 682 676 const menu = button.nextElementSibling; 683 - 677 + 684 678 // Close all other menus 685 679 document.querySelectorAll('.instance-menu .dropdown-menu').forEach(m => { 686 680 if (m !== menu) m.classList.remove('active'); 687 681 }); 688 - 682 + 689 683 menu.classList.toggle('active'); 690 684 } 691 685 ··· 711 705 }); 712 706 </script> 713 707 </body> 714 - </html> 708 + </html>