Spaces:
Sleeping
Sleeping
Commit
·
3e016a0
1
Parent(s):
42cce6f
update
Browse files- README.md +1 -0
- app.py +25 -0
- templates/dashboard.html +87 -0
README.md
CHANGED
|
@@ -12,6 +12,7 @@ hf_oauth: true
|
|
| 12 |
hf_oauth_expiration_minutes: 480
|
| 13 |
hf_oauth_scopes:
|
| 14 |
- read-repos
|
|
|
|
| 15 |
- manage-repos
|
| 16 |
---
|
| 17 |
|
|
|
|
| 12 |
hf_oauth_expiration_minutes: 480
|
| 13 |
hf_oauth_scopes:
|
| 14 |
- read-repos
|
| 15 |
+
- write-repos
|
| 16 |
- manage-repos
|
| 17 |
---
|
| 18 |
|
app.py
CHANGED
|
@@ -365,6 +365,31 @@ def logout():
|
|
| 365 |
return redirect(url_for("index"))
|
| 366 |
|
| 367 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 368 |
@app.route("/api/wake-all", methods=["POST"])
|
| 369 |
def wake_all_spaces():
|
| 370 |
if "user" not in session:
|
|
|
|
| 365 |
return redirect(url_for("index"))
|
| 366 |
|
| 367 |
|
| 368 |
+
@app.route("/api/refresh", methods=["POST"])
|
| 369 |
+
def force_refresh():
|
| 370 |
+
if "user" not in session:
|
| 371 |
+
return jsonify({"error": "Not authenticated"}), 401
|
| 372 |
+
|
| 373 |
+
username = session["user"]["username"]
|
| 374 |
+
token = session.get("access_token")
|
| 375 |
+
|
| 376 |
+
if not token:
|
| 377 |
+
return jsonify({"error": "No access token"}), 401
|
| 378 |
+
|
| 379 |
+
# Clear all user cache
|
| 380 |
+
db = get_db()
|
| 381 |
+
db.execute("DELETE FROM cache WHERE key LIKE ?", (f"spaces:{username}%",))
|
| 382 |
+
db.execute("DELETE FROM cache WHERE key LIKE ?", (f"discussions:%",))
|
| 383 |
+
db.execute("DELETE FROM cache WHERE key LIKE ?", (f"space_detail:%",))
|
| 384 |
+
db.commit()
|
| 385 |
+
|
| 386 |
+
# Start background job to reload
|
| 387 |
+
job_id = create_job("initial_load", username)
|
| 388 |
+
start_job_thread(run_initial_load_job, job_id, username, token)
|
| 389 |
+
|
| 390 |
+
return jsonify({"job_id": job_id})
|
| 391 |
+
|
| 392 |
+
|
| 393 |
@app.route("/api/wake-all", methods=["POST"])
|
| 394 |
def wake_all_spaces():
|
| 395 |
if "user" not in session:
|
templates/dashboard.html
CHANGED
|
@@ -652,6 +652,19 @@
|
|
| 652 |
<h3 class="modal-title">Utils</h3>
|
| 653 |
<button class="modal-close" id="modal-close">×</button>
|
| 654 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 655 |
<div class="util-item">
|
| 656 |
<div class="util-item-header">
|
| 657 |
<span class="util-name">Wake All Sleeping Spaces</span>
|
|
@@ -696,6 +709,80 @@
|
|
| 696 |
}
|
| 697 |
});
|
| 698 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 699 |
const wakeAllBtn = document.getElementById('wake-all-btn');
|
| 700 |
const wakeProgress = document.getElementById('wake-progress');
|
| 701 |
const wakeProgressFill = document.getElementById('wake-progress-fill');
|
|
|
|
| 652 |
<h3 class="modal-title">Utils</h3>
|
| 653 |
<button class="modal-close" id="modal-close">×</button>
|
| 654 |
</div>
|
| 655 |
+
<div class="util-item">
|
| 656 |
+
<div class="util-item-header">
|
| 657 |
+
<span class="util-name">Force Refresh</span>
|
| 658 |
+
<button class="util-btn" id="refresh-btn" style="background:#6366f1;">Refresh</button>
|
| 659 |
+
</div>
|
| 660 |
+
<div class="util-desc">Clear cache and refetch all spaces and discussions</div>
|
| 661 |
+
<div class="progress-container" id="refresh-progress">
|
| 662 |
+
<div class="progress-bar">
|
| 663 |
+
<div class="progress-fill" id="refresh-progress-fill"></div>
|
| 664 |
+
</div>
|
| 665 |
+
<div class="progress-text" id="refresh-progress-text">Starting...</div>
|
| 666 |
+
</div>
|
| 667 |
+
</div>
|
| 668 |
<div class="util-item">
|
| 669 |
<div class="util-item-header">
|
| 670 |
<span class="util-name">Wake All Sleeping Spaces</span>
|
|
|
|
| 709 |
}
|
| 710 |
});
|
| 711 |
|
| 712 |
+
// Refresh functionality
|
| 713 |
+
const refreshBtn = document.getElementById('refresh-btn');
|
| 714 |
+
const refreshProgress = document.getElementById('refresh-progress');
|
| 715 |
+
const refreshProgressFill = document.getElementById('refresh-progress-fill');
|
| 716 |
+
const refreshProgressText = document.getElementById('refresh-progress-text');
|
| 717 |
+
|
| 718 |
+
const stageNames = {
|
| 719 |
+
'spaces': 'Fetching spaces',
|
| 720 |
+
'discussions': 'Loading discussions',
|
| 721 |
+
'pending': 'Starting',
|
| 722 |
+
'': 'Starting'
|
| 723 |
+
};
|
| 724 |
+
|
| 725 |
+
refreshBtn.addEventListener('click', async () => {
|
| 726 |
+
refreshBtn.disabled = true;
|
| 727 |
+
refreshProgress.classList.add('active');
|
| 728 |
+
refreshProgressFill.style.width = '0%';
|
| 729 |
+
refreshProgressFill.style.background = '#6366f1';
|
| 730 |
+
refreshProgressText.textContent = 'Clearing cache...';
|
| 731 |
+
|
| 732 |
+
try {
|
| 733 |
+
const resp = await fetch('/api/refresh', { method: 'POST' });
|
| 734 |
+
const data = await resp.json();
|
| 735 |
+
|
| 736 |
+
if (data.error) {
|
| 737 |
+
refreshProgressText.textContent = 'Error: ' + data.error;
|
| 738 |
+
refreshProgressFill.style.background = '#ef4444';
|
| 739 |
+
refreshProgressFill.style.width = '100%';
|
| 740 |
+
refreshBtn.disabled = false;
|
| 741 |
+
return;
|
| 742 |
+
}
|
| 743 |
+
|
| 744 |
+
const jobId = data.job_id;
|
| 745 |
+
const pollJob = async () => {
|
| 746 |
+
const jobResp = await fetch('/api/job/' + jobId);
|
| 747 |
+
const job = await jobResp.json();
|
| 748 |
+
|
| 749 |
+
if (job.status === 'completed') {
|
| 750 |
+
refreshProgressFill.style.width = '100%';
|
| 751 |
+
refreshProgressText.textContent = 'Done! Reloading...';
|
| 752 |
+
setTimeout(() => window.location.reload(), 500);
|
| 753 |
+
return;
|
| 754 |
+
}
|
| 755 |
+
|
| 756 |
+
if (job.status === 'failed') {
|
| 757 |
+
refreshProgressText.textContent = 'Error: ' + (job.error || 'Unknown error');
|
| 758 |
+
refreshProgressFill.style.background = '#ef4444';
|
| 759 |
+
refreshProgressFill.style.width = '100%';
|
| 760 |
+
refreshBtn.disabled = false;
|
| 761 |
+
return;
|
| 762 |
+
}
|
| 763 |
+
|
| 764 |
+
const stage = job.progress_stage || '';
|
| 765 |
+
refreshProgressText.textContent = stageNames[stage] || stage;
|
| 766 |
+
|
| 767 |
+
if (job.progress_total > 0) {
|
| 768 |
+
const pct = Math.round((job.progress_current / job.progress_total) * 100);
|
| 769 |
+
refreshProgressFill.style.width = pct + '%';
|
| 770 |
+
refreshProgressText.textContent = `${stageNames[stage] || stage}: ${job.progress_current} / ${job.progress_total}`;
|
| 771 |
+
}
|
| 772 |
+
|
| 773 |
+
setTimeout(pollJob, 500);
|
| 774 |
+
};
|
| 775 |
+
|
| 776 |
+
pollJob();
|
| 777 |
+
} catch (err) {
|
| 778 |
+
refreshProgressText.textContent = 'Error: ' + err.message;
|
| 779 |
+
refreshProgressFill.style.background = '#ef4444';
|
| 780 |
+
refreshProgressFill.style.width = '100%';
|
| 781 |
+
refreshBtn.disabled = false;
|
| 782 |
+
}
|
| 783 |
+
});
|
| 784 |
+
|
| 785 |
+
// Wake functionality
|
| 786 |
const wakeAllBtn = document.getElementById('wake-all-btn');
|
| 787 |
const wakeProgress = document.getElementById('wake-progress');
|
| 788 |
const wakeProgressFill = document.getElementById('wake-progress-fill');
|