Download static/admin.js from khantbhko/dublab: direct link, hf CLI and curl.
- Browser
- Download file 4.54 kB
-
https://huggingface.co/khantbhko/dublab/resolve/main/static/admin.js
- Command line
-
hf download hf://khantbhko/dublab/static/admin.js
-
curl -L -o admin.js https://huggingface.co/khantbhko/dublab/resolve/main/static/admin.js
4.54 kB
| /* DubLab reviews dashboard */ | |
| const key = new URLSearchParams(location.search).get('key') || ''; | |
| let allReviews = []; | |
| let filter = 'all'; | |
| const $ = (s) => document.querySelector(s); | |
| function esc(s) { | |
| const d = document.createElement('div'); | |
| d.textContent = s == null ? '' : String(s); | |
| return d.innerHTML; | |
| } | |
| function fmtTime(ts) { | |
| const d = new Date(ts * 1000); | |
| const p = (n) => String(n).padStart(2, '0'); | |
| return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`; | |
| } | |
| async function load() { | |
| try { | |
| const r = await fetch('/admin/api/reviews?key=' + encodeURIComponent(key)); | |
| if (!r.ok) { $('#list').innerHTML = '<p class="empty">not found</p>'; return; } | |
| const j = await r.json(); | |
| allReviews = j.reviews || []; | |
| renderStats(j.stats || {}); | |
| renderUsage(j.usage || {}); | |
| renderList(); | |
| } catch (e) { | |
| $('#list').innerHTML = '<p class="empty">load failed</p>'; | |
| } | |
| } | |
| function renderStats(s) { | |
| $('#st-total').textContent = s.total ?? 0; | |
| $('#st-avg').textContent = s.avg ?? '–'; | |
| $('#st-5').textContent = (s.dist && s.dist['5']) ?? 0; | |
| const dist = $('#dist'); | |
| dist.innerHTML = ''; | |
| const max = Math.max(1, ...[1, 2, 3, 4, 5].map((i) => (s.dist && s.dist[String(i)]) || 0)); | |
| for (let i = 5; i >= 1; i--) { | |
| const c = (s.dist && s.dist[String(i)]) || 0; | |
| const row = document.createElement('div'); | |
| row.className = 'drow'; | |
| row.innerHTML = `<span class="lbl">⭐${i}</span><div class="dbar"><span style="width:${(c / max) * 100}%"></span></div><span class="cnt">${c}</span>`; | |
| dist.appendChild(row); | |
| } | |
| } | |
| function renderUsage(u) { | |
| $('#u-jobs').textContent = u.jobs ?? 0; | |
| $('#u-users').textContent = u.users ?? 0; | |
| $('#u-done').textContent = u.done ?? 0; | |
| $('#u-fail').textContent = u.fail ?? 0; | |
| $('#u-today').textContent = u.today ?? 0; | |
| $('#u-week').textContent = u.week ?? 0; | |
| const box = $('#recent'); | |
| const evs = u.recent || []; | |
| const status = {}; | |
| const durs = {}; | |
| evs.forEach((e) => { | |
| if (!e.job_id) return; | |
| if (e.event === 'done' || e.event === 'fail') status[e.job_id] = e.event; | |
| if (e.event === 'done' && e.dur) durs[e.job_id] = e.dur; | |
| }); | |
| const jobs = evs.filter((e) => e.event === 'job').slice(0, 12); | |
| if (!jobs.length) { box.innerHTML = '<p class="empty">job မရှိသေးဘူး</p>'; return; } | |
| box.innerHTML = ''; | |
| jobs.forEach((e) => { | |
| const st = status[e.job_id] || ''; | |
| const mark = st === 'done' ? '✅' : st === 'fail' ? '❌' : '⏳'; | |
| const dur = durs[e.job_id] ? ' · ' + durs[e.job_id] + 's video' : ''; | |
| const el = document.createElement('div'); | |
| el.className = 'rev'; | |
| el.innerHTML = | |
| `<div class="meta"><span>${mark} ${esc(fmtTime(e.ts))} · ${esc(e.ip || '?')} · ${esc(e.kind || '')}${dur}</span></div>`; | |
| box.appendChild(el); | |
| }); | |
| } | |
| function renderList() { | |
| const list = $('#list'); | |
| const rows = allReviews.filter((r) => { | |
| if (filter === 'all') return true; | |
| if (filter === 'msg') return (r.message || '').trim().length > 0; | |
| return r.stars === +filter; | |
| }); | |
| if (!rows.length) { list.innerHTML = '<p class="empty">မရှိသေးဘူး</p>'; return; } | |
| list.innerHTML = ''; | |
| rows.forEach((r) => { | |
| const el = document.createElement('div'); | |
| el.className = 'rev'; | |
| const stars = r.stars ? '⭐'.repeat(r.stars) : '<span style="color:var(--dim)">no rating</span>'; | |
| el.innerHTML = | |
| `<div class="meta"><span>${esc(fmtTime(r.ts))} · ${esc(r.ip || '?')}${r.job_id ? ' · job ' + esc(r.job_id) : ''}</span>` + | |
| `<button class="del" title="delete">🗑️</button></div>` + | |
| `<div class="stars">${stars}</div>` + | |
| `<div class="msg">${esc(r.message || '—')}</div>`; | |
| el.querySelector('.del').addEventListener('click', async () => { | |
| if (!confirm('ဒီ review ကို ဖျက်မလား?')) return; | |
| try { | |
| const dr = await fetch('/admin/api/reviews/' + encodeURIComponent(r.id || '') + | |
| '?key=' + encodeURIComponent(key), { method: 'DELETE' }); | |
| if (dr.ok) load(); | |
| } catch (e) { /* ignore */ } | |
| }); | |
| list.appendChild(el); | |
| }); | |
| } | |
| $('#filters').querySelectorAll('button').forEach((b) => b.addEventListener('click', () => { | |
| $('#filters').querySelectorAll('button').forEach((x) => x.classList.remove('on')); | |
| b.classList.add('on'); | |
| filter = b.dataset.f; | |
| renderList(); | |
| })); | |
| $('#refresh').addEventListener('click', load); | |
| load(); | |
| setInterval(() => { if (!document.hidden) load(); }, 30000); | |