diff --git a/frontend/admin.html b/frontend/admin.html
index 49a0751..bb10741 100644
--- a/frontend/admin.html
+++ b/frontend/admin.html
@@ -1111,7 +1111,7 @@
try {
const j = await api(`/api/admin/cache/health?limit=50&offset=${cacheOffset}`);
if (!j.ok) throw Error(j.error || 'Cache health unavailable.');
- const ready = j.statuses.find(x => x.status === 'ready') || {}, pending = j.statuses.find(x => ['queued', 'downloading', 'validating'].includes(x.status)), failed = j.statuses.find(x => x.status === 'failed') || {};
+ const ready = j.statuses.find(x => x.status === 'ready') || {}, pending = j.statuses.filter(x => ['queued', 'downloading', 'validating'].includes(x.status)).reduce((sum, item) => ({ count: sum.count + Number(item.count || 0), bytes: sum.bytes + Number(item.bytes || 0) }), { count: 0, bytes: 0 }), failed = j.statuses.find(x => x.status === 'failed') || {};
$('cacheMetrics').innerHTML = [
['Cache used', `${bytes(j.bytes)} / ${bytes(j.budget)}`, `${Math.round(j.utilization * 100)}% of configured budget`],
['Ready', Number(ready.count || 0).toLocaleString(), bytes(ready.bytes || 0)],
diff --git a/tests/admin-cache.spec.js b/tests/admin-cache.spec.js
index bfe7f84..120da4b 100644
--- a/tests/admin-cache.spec.js
+++ b/tests/admin-cache.spec.js
@@ -5,7 +5,7 @@ test('cache actions pin, unpin, confirm eviction and request a source re-downloa
await page.route('**/api/**', async route => {
const req = route.request(), url = new URL(req.url()); let body = { ok: true };
if (url.pathname === '/api/admin/me') body = { enabled: true, admin: true };
- else if (url.pathname === '/api/admin/cache/health') body = { ok: true, total: 1, offset: 0, budget: 1000, pinnedBudget: 900, bytes: 700, pinnedBytes: state.pinned ? 700 : 0, utilization: .7, statuses: [{ status: 'ready', count: 1, bytes: 700 }], media: [{ id: 'CacheItem001', status: 'ready', bytes: 700, lastAccess: 1791900000000, gen: 4, pinned: state.pinned }] };
+ else if (url.pathname === '/api/admin/cache/health') body = { ok: true, total: 1, offset: 0, budget: 1000, pinnedBudget: 900, bytes: 950, pinnedBytes: state.pinned ? 700 : 0, utilization: .95, statuses: [{ status: 'ready', count: 1, bytes: 700 }, { status: 'queued', count: 2, bytes: 100 }, { status: 'downloading', count: 3, bytes: 150 }, { status: 'failed', count: 1, bytes: 0 }], media: [{ id: 'CacheItem001', status: 'ready', bytes: 700, lastAccess: 1791900000000, gen: 4, pinned: state.pinned }] };
else if (url.pathname === '/api/admin/cache/CacheItem001/pin' && req.method() === 'POST') { state.pinned = req.postDataJSON().pinned; body.pinned = state.pinned; }
else if (url.pathname === '/api/admin/cache/CacheItem001/evict' && req.method() === 'POST') state.evicted = true;
else if (url.pathname === '/api/admin/media/CacheItem001/redownload' && req.method() === 'POST') state.redownloaded = true;
@@ -16,6 +16,7 @@ test('cache actions pin, unpin, confirm eviction and request a source re-downloa
});
await page.goto('/admin.html#cache');
await expect(page.locator('#cacheTable')).toContainText('CacheItem001');
+ await expect(page.locator('#cacheMetrics')).toContainText('5 / 1');
await page.locator('[data-cache-pin]').click(); await expect(page.locator('[data-cache-pin]')).toHaveText('Unpin');
await page.locator('[data-cache-pin]').click(); await expect(page.locator('[data-cache-pin]')).toHaveText('Pin');
page.once('dialog', dialog => dialog.accept()); await page.locator('[data-cache-evict]').click();