cdn

Log | Files | Refs | Activity

commit 13acc29f020451350fb51e464ee6be3cf1c384b8
parent 66105c90daf7950f1a4938c6324594debbeab9d9
Author: Amit Dutta <mail@amit.is-a.dev>
Date:   Fri,  4 Sep 2026 17:09:26 +0530

Merge pull request #14 from notamitgamer/patch

Add upload spinner and improve upload status display
Diffstat:
Mapp/storage.py | 33++++++++++++++++++++++++++++-----
Mapp/templates/index.html | 22++++++++++++++++++++--
2 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/app/storage.py b/app/storage.py @@ -9,15 +9,32 @@ HF_TOKEN = os.getenv("HF_TOKEN") api = HfApi(token=HF_TOKEN) +# LRU Cache implementation _cache = {} CACHE_TTL = 60 +MAX_CACHE_SIZE = 500 def _get_cache(key): - if key in _cache and _cache[key][0] > time.time(): - return _cache[key][1] + if key in _cache: + expiry, value = _cache[key] + if expiry > time.time(): + # Move to the end of the dictionary to mark it as most recently used (LRU) + _cache[key] = _cache.pop(key) + return value + else: + # Expired + del _cache[key] return None def _set_cache(key, value): + if key in _cache: + # Remove it first so we can re-insert it at the end + del _cache[key] + elif len(_cache) >= MAX_CACHE_SIZE: + # Dictionary is full. Remove the oldest item (which is at the front) + oldest_key = next(iter(_cache)) + del _cache[oldest_key] + _cache[key] = (time.time() + CACHE_TTL, value) async def is_file(path: str) -> bool: @@ -116,8 +133,14 @@ REPO_STATS_CACHE_TTL = 300 def repo_stats(): cache_key = "repo_stats" now = time.time() - if cache_key in _cache and _cache[cache_key][0] > now: - return _cache[cache_key][1] + if cache_key in _cache: + expiry, value = _cache[cache_key] + if expiry > now: + # Move to end as part of LRU update + _cache[cache_key] = _cache.pop(cache_key) + return value + else: + del _cache[cache_key] try: items = list(api.list_repo_tree( @@ -135,7 +158,7 @@ def repo_stats(): total_size += getattr(item, "size", 0) or 0 result = {"file_count": file_count, "size_str": format_size(total_size)} - _cache[cache_key] = (now + REPO_STATS_CACHE_TTL, result) + _set_cache(cache_key, result) return result def upload_temp_file(temp_path: str, filename: str) -> str: diff --git a/app/templates/index.html b/app/templates/index.html @@ -230,6 +230,7 @@ .file-row { display: flex; justify-content: space-between; padding: 0.75rem; border: 1px solid var(--border); border-radius: 4px; margin-bottom: 0.5rem; + align-items: center; } .file-row.done { border-color: #2ea043; } .file-row.error { border-color: var(--danger); } @@ -327,6 +328,16 @@ border-color: #ffc9c2; } + .upload-spinner { + display: inline-block; + width: 12px; height: 12px; + border: 2px solid var(--accent-pink); + border-top-color: transparent; + border-radius: 50%; + margin-right: 6px; + vertical-align: middle; + } + footer { margin-top: 4rem; padding-top: 1rem; @@ -591,7 +602,14 @@ xhr.upload.onprogress = (e) => { if (!e.lengthComputable) return; const pct = Math.round((e.loaded / e.total) * 100); - files.forEach(f => { rows[f.name].querySelector('.status').textContent = pct + '%'; }); + files.forEach(f => { + const statusNode = rows[f.name].querySelector('.status'); + if (pct === 100) { + statusNode.innerHTML = `<span class="upload-spinner spin-anim"></span><span style="color: var(--accent-pink);">saving to HF...</span>`; + } else { + statusNode.textContent = pct + '%'; + } + }); }; xhr.onload = () => { @@ -771,7 +789,7 @@ if (e.key !== '/') return; const tag = (document.activeElement && document.activeElement.tagName) || ''; if (tag === 'INPUT' || tag === 'TEXTAREA') return; - const filterInput = document.getElementById('filter-input');a + const filterInput = document.getElementById('filter-input'); if (filterInput) { e.preventDefault(); filterInput.focus();
© notamitgamer • Site Built: 2026-09-05 01:53:16 UTC • git-mirror commit: c170d72 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror