fix(stats): load full session timelines by default

This commit is contained in:
2026-03-17 22:37:34 -07:00
parent 8f39416ff5
commit f9b582582b
5 changed files with 55 additions and 5 deletions

View File

@@ -439,6 +439,51 @@ test('registerIpcHandlers validates and clamps stats request limits', async () =
]);
});
test('registerIpcHandlers requests the full timeline when no limit is provided', async () => {
const { registrar, handlers } = createFakeIpcRegistrar();
const calls: Array<[string, number | undefined, number]> = [];
registerIpcHandlers(
createRegisterIpcDeps({
immersionTracker: {
recordYomitanLookup: () => {},
getSessionSummaries: async () => [],
getDailyRollups: async () => [],
getMonthlyRollups: async () => [],
getQueryHints: async () => ({
totalSessions: 0,
activeSessions: 0,
episodesToday: 0,
activeAnimeCount: 0,
totalCards: 0,
totalActiveMin: 0,
activeDays: 0,
totalEpisodesWatched: 0,
totalAnimeCompleted: 0,
}),
getSessionTimeline: async (sessionId: number, limit?: number) => {
calls.push(['timeline', limit, sessionId]);
return [];
},
getSessionEvents: async () => [],
getVocabularyStats: async () => [],
getKanjiStats: async () => [],
getMediaLibrary: async () => [],
getMediaDetail: async () => null,
getMediaSessions: async () => [],
getMediaDailyRollups: async () => [],
getCoverArt: async () => null,
markActiveVideoWatched: async () => false,
},
}),
registrar,
);
await handlers.handle.get(IPC_CHANNELS.request.statsGetSessionTimeline)!({}, 7, undefined);
assert.deepEqual(calls, [['timeline', undefined, 7]]);
});
test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => {
const { registrar, handlers } = createFakeIpcRegistrar();
const saves: unknown[] = [];

View File

@@ -517,7 +517,7 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
async (_event, sessionId: unknown, limit: unknown) => {
const parsedSessionId = parsePositiveInteger(sessionId);
if (parsedSessionId === null) return [];
const parsedLimit = parsePositiveIntLimit(limit, 200, 1000);
const parsedLimit = limit === undefined ? undefined : parsePositiveIntLimit(limit, 200, 1000);
return deps.immersionTracker?.getSessionTimeline(parsedSessionId, parsedLimit) ?? [];
},
);

View File

@@ -189,7 +189,8 @@ export function createStatsApp(
app.get('/api/stats/sessions/:id/timeline', async (c) => {
const id = parseIntQuery(c.req.param('id'), 0);
if (id <= 0) return c.json([], 400);
const limit = parseIntQuery(c.req.query('limit'), 200, 1000);
const rawLimit = c.req.query('limit');
const limit = rawLimit === undefined ? undefined : parseIntQuery(rawLimit, 200, 1000);
const timeline = await tracker.getSessionTimeline(id, limit);
return c.json(timeline);
});