From 1cead99c98a0e7468281bc955acbc6ab4909c268 Mon Sep 17 00:00:00 2001 From: sudacode Date: Mon, 6 Jul 2026 01:15:24 -0700 Subject: [PATCH] fix(stats): validate max-titles against allowlist instead of positive-in - `loadMaxTitles` now rejects values not in `MAX_TITLES_OPTIONS` (e.g. arbitrary integers like 8) - Add test covering unsupported-but-numeric stored values --- changes/stats-trend-title-limits.md | 4 ++++ .../components/trends/anime-visibility.test.ts | 15 +++++++++++++-- stats/src/components/trends/anime-visibility.ts | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 changes/stats-trend-title-limits.md diff --git a/changes/stats-trend-title-limits.md b/changes/stats-trend-title-limits.md new file mode 100644 index 00000000..a1b6ebfc --- /dev/null +++ b/changes/stats-trend-title-limits.md @@ -0,0 +1,4 @@ +type: fixed +area: stats + +- Show all trend chart titles by default, persist hidden-title choices, and add a per-chart top-title limit selector. diff --git a/stats/src/components/trends/anime-visibility.test.ts b/stats/src/components/trends/anime-visibility.test.ts index 846f734c..5ee5d608 100644 --- a/stats/src/components/trends/anime-visibility.test.ts +++ b/stats/src/components/trends/anime-visibility.test.ts @@ -107,11 +107,22 @@ test('max titles preference round-trips and clears when set to null', () => { } }); -test('loadMaxTitles rejects non-positive or non-numeric stored values', () => { - const { restore } = installLocalStorage({ 'subminer-stats-trends-max-titles': 'banana' }); +test('loadMaxTitles rejects unsupported stored values', () => { + const { restore } = installLocalStorage({ 'subminer-stats-trends-max-titles': '8' }); try { assert.equal(loadMaxTitles(), null); } finally { restore(); } }); + +test('loadMaxTitles rejects non-positive or non-numeric stored values', () => { + for (const storedValue of ['0', 'banana']) { + const { restore } = installLocalStorage({ 'subminer-stats-trends-max-titles': storedValue }); + try { + assert.equal(loadMaxTitles(), null); + } finally { + restore(); + } + } +}); diff --git a/stats/src/components/trends/anime-visibility.ts b/stats/src/components/trends/anime-visibility.ts index b7099d9a..1908f30a 100644 --- a/stats/src/components/trends/anime-visibility.ts +++ b/stats/src/components/trends/anime-visibility.ts @@ -37,7 +37,7 @@ export function loadMaxTitles(): number | null { const raw = getStorage()?.getItem(MAX_TITLES_KEY); if (raw === null || raw === undefined) return null; const value = Number(raw); - return Number.isInteger(value) && value > 0 ? value : null; + return (MAX_TITLES_OPTIONS as readonly number[]).includes(value) ? value : null; } catch { return null; }