Statistics page redesign #60

Merged
quoije merged 17 commits from cursor/statistics-page-redesign-d08a into 2026 2025-12-22 18:16:37 -05:00
2 changed files with 13 additions and 7 deletions
Showing only changes of commit d8bc03fecc - Show all commits
+8 -7
View File
@@ -165,7 +165,7 @@ window.onload = async function () {
} }
async function fetchPlayerUi() { async function fetchPlayerUi() {
const res = await fetch('/api/settings/player-admin-status-ui', { method: 'GET' }); const res = await fetch('/api/settings/player-admin-status-ui', { method: 'GET', cache: 'no-store' });
const data = await res.json().catch(() => ({})); const data = await res.json().catch(() => ({}));
if (!res.ok) { if (!res.ok) {
const msg = data.message || data.error || `Erreur (${res.status})`; const msg = data.message || data.error || `Erreur (${res.status})`;
@@ -254,7 +254,7 @@ window.onload = async function () {
} }
async function fetchAppVersionState() { async function fetchAppVersionState() {
const res = await fetch('/api/settings/app-version', { method: 'GET' }); const res = await fetch('/api/settings/app-version', { method: 'GET', cache: 'no-store' });
const data = await res.json().catch(() => ({})); const data = await res.json().catch(() => ({}));
if (!res.ok) { if (!res.ok) {
const msg = data.message || data.error || `Erreur (${res.status})`; const msg = data.message || data.error || `Erreur (${res.status})`;
@@ -338,7 +338,7 @@ window.onload = async function () {
async function refreshAppVersionPreview() { async function refreshAppVersionPreview() {
if (!appVersionPreviewEl) return; if (!appVersionPreviewEl) return;
try { try {
const res = await fetch('/api/version', { method: 'GET' }); const res = await fetch('/api/version', { method: 'GET', cache: 'no-store' });
if (!res.ok) throw new Error(`Erreur (${res.status})`); if (!res.ok) throw new Error(`Erreur (${res.status})`);
const data = await res.json().catch(() => ({})); const data = await res.json().catch(() => ({}));
const line = `${data?.date || ''} - ${data?.version || ''} - ${data?.message || ''}`.trim(); const line = `${data?.date || ''} - ${data?.version || ''} - ${data?.message || ''}`.trim();
@@ -462,7 +462,7 @@ window.onload = async function () {
} }
async function fetchCompletionModal() { async function fetchCompletionModal() {
const res = await fetch('/api/settings/completion-modal', { method: 'GET' }); const res = await fetch('/api/settings/completion-modal', { method: 'GET', cache: 'no-store' });
if (!res.ok) throw new Error(`Erreur (${res.status})`); if (!res.ok) throw new Error(`Erreur (${res.status})`);
const data = await res.json().catch(() => ({})); const data = await res.json().catch(() => ({}));
return normalizeCompletionModal(data); return normalizeCompletionModal(data);
@@ -806,7 +806,7 @@ window.onload = async function () {
} }
async function fetchOscarDates() { async function fetchOscarDates() {
const res = await fetch('/api/settings/oscar-dates', { method: 'GET' }); const res = await fetch('/api/settings/oscar-dates', { method: 'GET', cache: 'no-store' });
const data = await res.json().catch(() => ({})); const data = await res.json().catch(() => ({}));
if (!res.ok) { if (!res.ok) {
const msg = data.message || data.error || `Erreur (${res.status})`; const msg = data.message || data.error || `Erreur (${res.status})`;
@@ -877,7 +877,7 @@ window.onload = async function () {
} }
async function fetchWinners() { async function fetchWinners() {
const res = await fetch('/api/settings/winners', { method: 'GET' }); const res = await fetch('/api/settings/winners', { method: 'GET', cache: 'no-store' });
const data = await res.json().catch(() => ({})); const data = await res.json().catch(() => ({}));
if (!res.ok) { if (!res.ok) {
const msg = data.message || data.error || `Erreur (${res.status})`; const msg = data.message || data.error || `Erreur (${res.status})`;
@@ -1130,7 +1130,7 @@ window.onload = async function () {
async function fetchActiveYear() { async function fetchActiveYear() {
try { try {
const res = await fetch('/api/settings/year', { method: 'GET' }); const res = await fetch('/api/settings/year', { method: 'GET', cache: 'no-store' });
if (!res.ok) throw new Error('Failed to fetch active year'); if (!res.ok) throw new Error('Failed to fetch active year');
const data = await res.json(); const data = await res.json();
const year = Number(data?.year); const year = Number(data?.year);
@@ -1537,6 +1537,7 @@ window.onload = async function () {
const res = await fetch('/api/admin/db/backups', { const res = await fetch('/api/admin/db/backups', {
method: 'GET', method: 'GET',
headers: { 'Authorization': `Bearer ${token}` }, headers: { 'Authorization': `Bearer ${token}` },
cache: 'no-store',
}); });
const data = await res.json().catch(() => ({})); const data = await res.json().catch(() => ({}));
if (!res.ok) { if (!res.ok) {
+5
View File
@@ -152,6 +152,9 @@ async function listBackupFiles() {
router.get("/db/backups", async (req, res) => { router.get("/db/backups", async (req, res) => {
try { try {
requireAdmin(req); requireAdmin(req);
// Admin + auth-scoped data: never allow caching.
res.setHeader("Cache-Control", "private, no-store, must-revalidate");
res.setHeader("Vary", "Authorization");
const backups = await listBackupFiles(); const backups = await listBackupFiles();
return res.status(200).json({ backups }); return res.status(200).json({ backups });
} catch (err) { } catch (err) {
@@ -227,6 +230,8 @@ router.post("/db/backup", async (req, res) => {
router.get("/db/backups/:name", async (req, res) => { router.get("/db/backups/:name", async (req, res) => {
try { try {
requireAdmin(req); requireAdmin(req);
res.setHeader("Cache-Control", "private, no-store, must-revalidate");
res.setHeader("Vary", "Authorization");
const safe = safeBackupFileName(req.params?.name); const safe = safeBackupFileName(req.params?.name);
if (!safe) return res.status(400).json({ message: "Invalid backup name" }); if (!safe) return res.status(400).json({ message: "Invalid backup name" });