feat(admin): overview dashboard sections + system temperature/load sensors (0.85.0) (#11)
All checks were successful
deploy / test-backend (push) Successful in 25m9s
deploy / test-frontend (push) Successful in 10m13s
deploy / build-and-push (push) Successful in 10m25s
deploy / deploy (push) Successful in 12s

This commit was merged in pull request #11.
This commit is contained in:
2026-06-16 18:46:28 +00:00
parent 8445f338f6
commit cde4aca98b
17 changed files with 1270 additions and 59 deletions

View File

@@ -15,6 +15,7 @@ import {
listAdminMangas,
listAdminChapters,
getSystemStats,
getOverviewStats,
getStorageStats,
backfillStorage,
resyncManga,
@@ -88,7 +89,14 @@ const systemFixture = {
percent_used: 50.0
},
memory: { total_bytes: 8_000_000, used_bytes: 4_000_000, percent_used: 50.0 },
cpu: { percent_used: 12.3 },
cpu: {
percent_used: 12.3,
load_avg: { one: 0.81, five: 0.66, fifteen: 0.59 },
per_core: [10.0, 14.5, 8.2, 20.1]
},
temperatures: [
{ label: 'CPU Package', celsius: 52.0, max_celsius: 71.0, critical_celsius: 100.0 }
],
alerts: []
};
@@ -258,6 +266,10 @@ describe('admin api client', () => {
expect(s.disk?.percent_used).toBe(50);
expect(s.memory.percent_used).toBe(50);
expect(s.cpu.percent_used).toBe(12.3);
expect(s.cpu.load_avg.one).toBe(0.81);
expect(s.cpu.per_core).toHaveLength(4);
expect(s.temperatures[0].label).toBe('CPU Package');
expect(s.temperatures[0].critical_celsius).toBe(100);
expect(s.alerts).toEqual([]);
const url = fetchSpy.mock.calls[0][0] as string;
expect(url).toMatch(/\/v1\/admin\/system$/);
@@ -269,6 +281,43 @@ describe('admin api client', () => {
expect(s.disk).toBeNull();
});
it('getSystemStats tolerates an empty temperatures array (sensors unavailable)', async () => {
fetchSpy.mockResolvedValueOnce(ok({ ...systemFixture, temperatures: [] }));
const s = await getSystemStats();
expect(s.temperatures).toEqual([]);
});
it('getOverviewStats GETs /v1/admin/overview and parses the nested envelope', async () => {
const fixture = {
users: {
total: 7,
admins: 2,
newest_username: 'kenji',
newest_created_at: '2026-06-15T00:00:00Z'
},
mangas: {
total: 12,
synced: 10,
in_progress: 1,
dropped: 1,
total_chapters: 340,
total_pages: 9001,
newest_title: 'Sakamoto Days',
newest_seen_at: '2026-06-16T00:00:00Z'
},
analysis: { analyzed_pages: 5760, total_pages: 9001 }
};
fetchSpy.mockResolvedValueOnce(ok(fixture));
const s = await getOverviewStats();
expect(s.users.total).toBe(7);
expect(s.users.admins).toBe(2);
expect(s.mangas.synced).toBe(10);
expect(s.mangas.total_pages).toBe(9001);
expect(s.analysis.analyzed_pages).toBe(5760);
const url = fetchSpy.mock.calls[0][0] as string;
expect(url).toMatch(/\/v1\/admin\/overview$/);
});
// ---- force resync ----
it('resyncManga POSTs to /v1/admin/mangas/{id}/resync and returns the envelope', async () => {