mrfakename commited on
Commit
0383b17
·
1 Parent(s): 89f16da

wake all sleeping spaces

Browse files
Files changed (2) hide show
  1. app.py +47 -0
  2. templates/dashboard.html +140 -0
app.py CHANGED
@@ -383,6 +383,53 @@ def logout():
383
  return redirect(url_for("index"))
384
 
385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  # Initialize database on startup
387
  init_db()
388
 
 
383
  return redirect(url_for("index"))
384
 
385
 
386
+ @app.route("/api/wake-all", methods=["POST"])
387
+ def wake_all_spaces():
388
+ if "user" not in session:
389
+ return {"error": "Not authenticated"}, 401
390
+
391
+ username = session["user"]["username"]
392
+ token = session.get("access_token")
393
+
394
+ if not token:
395
+ return {"error": "No access token"}, 401
396
+
397
+ spaces = fetch_user_spaces(username, token)
398
+ sleeping_spaces = [
399
+ s for s in spaces
400
+ if s.get("runtime", {}).get("stage", "").upper() == "SLEEPING"
401
+ ]
402
+
403
+ results = []
404
+ for space in sleeping_spaces:
405
+ space_id = space.get("id", "")
406
+ try:
407
+ resp = requests.post(
408
+ f"https://huggingface.co/api/spaces/{space_id}/restart",
409
+ headers={"Authorization": f"Bearer {token}"},
410
+ timeout=10,
411
+ )
412
+ results.append({
413
+ "id": space_id,
414
+ "success": resp.status_code == 200,
415
+ "status": resp.status_code,
416
+ })
417
+ except Exception as e:
418
+ results.append({
419
+ "id": space_id,
420
+ "success": False,
421
+ "error": str(e),
422
+ })
423
+
424
+ # Clear cache so next load shows updated status
425
+ cache_key = f"spaces:{username}"
426
+ db = get_db()
427
+ db.execute("DELETE FROM cache WHERE key = ?", (cache_key,))
428
+ db.commit()
429
+
430
+ return {"results": results, "total": len(sleeping_spaces)}
431
+
432
+
433
  # Initialize database on startup
434
  init_db()
435
 
templates/dashboard.html CHANGED
@@ -360,6 +360,146 @@
360
  color: #444;
361
  font-size: 0.875rem;
362
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  </style>
364
  </head>
365
  <body>
 
360
  color: #444;
361
  font-size: 0.875rem;
362
  }
363
+ .utils-btn {
364
+ font-size: 0.75rem;
365
+ padding: 0.25rem 0.5rem;
366
+ background: transparent;
367
+ border: 1px solid #333;
368
+ border-radius: 4px;
369
+ color: #888;
370
+ cursor: pointer;
371
+ transition: all 0.15s;
372
+ margin-right: 1rem;
373
+ }
374
+ .utils-btn:hover {
375
+ border-color: #555;
376
+ color: #e5e5e5;
377
+ }
378
+ .modal-overlay {
379
+ display: none;
380
+ position: fixed;
381
+ top: 0;
382
+ left: 0;
383
+ right: 0;
384
+ bottom: 0;
385
+ background: rgba(0, 0, 0, 0.8);
386
+ z-index: 200;
387
+ align-items: center;
388
+ justify-content: center;
389
+ }
390
+ .modal-overlay.open {
391
+ display: flex;
392
+ }
393
+ .modal {
394
+ background: #141414;
395
+ border: 1px solid #222;
396
+ border-radius: 8px;
397
+ padding: 1.5rem;
398
+ max-width: 400px;
399
+ width: 90%;
400
+ }
401
+ .modal-header {
402
+ display: flex;
403
+ justify-content: space-between;
404
+ align-items: center;
405
+ margin-bottom: 1.5rem;
406
+ }
407
+ .modal-title {
408
+ font-size: 1rem;
409
+ font-weight: 500;
410
+ color: #e5e5e5;
411
+ }
412
+ .modal-close {
413
+ background: none;
414
+ border: none;
415
+ color: #666;
416
+ font-size: 1.25rem;
417
+ cursor: pointer;
418
+ padding: 0;
419
+ line-height: 1;
420
+ }
421
+ .modal-close:hover {
422
+ color: #e5e5e5;
423
+ }
424
+ .util-item {
425
+ padding: 0.75rem;
426
+ background: #1a1a1a;
427
+ border: 1px solid #222;
428
+ border-radius: 6px;
429
+ margin-bottom: 0.5rem;
430
+ }
431
+ .util-item-header {
432
+ display: flex;
433
+ justify-content: space-between;
434
+ align-items: center;
435
+ }
436
+ .util-name {
437
+ font-size: 0.875rem;
438
+ color: #e5e5e5;
439
+ }
440
+ .util-desc {
441
+ font-size: 0.75rem;
442
+ color: #666;
443
+ margin-top: 0.25rem;
444
+ }
445
+ .util-btn {
446
+ font-size: 0.75rem;
447
+ padding: 0.375rem 0.75rem;
448
+ background: #22c55e;
449
+ border: none;
450
+ border-radius: 4px;
451
+ color: #000;
452
+ cursor: pointer;
453
+ transition: opacity 0.15s;
454
+ }
455
+ .util-btn:hover {
456
+ opacity: 0.9;
457
+ }
458
+ .util-btn:disabled {
459
+ opacity: 0.5;
460
+ cursor: not-allowed;
461
+ }
462
+ .progress-container {
463
+ margin-top: 1rem;
464
+ display: none;
465
+ }
466
+ .progress-container.active {
467
+ display: block;
468
+ }
469
+ .progress-bar {
470
+ height: 4px;
471
+ background: #222;
472
+ border-radius: 2px;
473
+ overflow: hidden;
474
+ margin-bottom: 0.5rem;
475
+ }
476
+ .progress-fill {
477
+ height: 100%;
478
+ background: #22c55e;
479
+ width: 0%;
480
+ transition: width 0.3s;
481
+ }
482
+ .progress-text {
483
+ font-size: 0.75rem;
484
+ color: #666;
485
+ }
486
+ .progress-results {
487
+ margin-top: 0.75rem;
488
+ max-height: 150px;
489
+ overflow-y: auto;
490
+ }
491
+ .progress-result {
492
+ font-size: 0.75rem;
493
+ padding: 0.25rem 0;
494
+ display: flex;
495
+ justify-content: space-between;
496
+ }
497
+ .progress-result.success {
498
+ color: #22c55e;
499
+ }
500
+ .progress-result.error {
501
+ color: #ef4444;
502
+ }
503
  </style>
504
  </head>
505
  <body>