7 Commits

Author SHA1 Message Date
cedricAbonnel a578604ec3 chore : version 1.6.27 2026-05-19 18:50:53 +02:00
cedricAbonnel e8b361e720 feat : sparklines 14j stats + filtre IPs LAN (v1.6.27)
- Admin stats : sparklines SVG par page (120×28 px, courbe + dégradé),
  carte « Pages les plus visitées » en pleine largeur
- AccessLogParser : données par jour (pages_by_day) sur 14 jours
- AccessLogParser : IPs privées/LAN exclues de la répartition réseau
- ArticleManager : suppression opérateur nullsafe superflu (PHPStan)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 18:50:53 +02:00
cedricAbonnel 007895d24a Merge pull request 'v1.6.26 — page /books, section livres accueil, fix onglet books' (#102) from dev into main
Merge dev → main (v1.6.26)
2026-05-16 15:04:48 +00:00
cedricAbonnel 1eb6ca25f9 Merge pull request 'v1.6.25 — intégration IA éditeur, onglet admin IA, corrections CSP' (#98) from dev into main
Merge dev → main (v1.6.25)
2026-05-16 12:07:33 +00:00
cedricAbonnel d329872404 Merge pull request 'v1.6.12 — image de couverture modifiable en édition' (#80) from dev into main
Merge pull request 'v1.6.12 — image de couverture modifiable en édition' (#80) from dev into main
2026-05-15 21:09:45 +00:00
cedricAbonnel 8a42dfe981 Merge pull request 'v1.6.11 — slug immuable en édition' (#79) from dev into main
Merge pull request 'v1.6.11 — slug immuable en édition' (#79) from dev into main
2026-05-15 20:58:15 +00:00
cedricAbonnel 5203b2c514 Merge pull request 'v1.6.10 — fix suppression article (permissions répertoire)' (#78) from dev into main
Merge pull request 'v1.6.10 — fix suppression article (permissions répertoire)' (#78) from dev into main
2026-05-15 20:30:49 +00:00
2 changed files with 1 additions and 51 deletions
+1 -50
View File
@@ -50,47 +50,6 @@
+ '</svg>'; + '</svg>';
} }
function trendChart(totals) {
var trendEl = document.getElementById('stats-trend-container');
if (!trendEl || !totals.length) { return; }
var days = totals.length;
var maxV = Math.max.apply(null, totals) || 1;
var W = 1000; // viewBox, s'adapte en CSS
var H = 80;
var padX = 4;
var padY = 8;
var barW = Math.floor((W - 2 * padX) / days) - 2;
// Dates des jours (index 0 = il y a 13 jours)
var now = new Date();
var labels = totals.map(function (_, i) {
var d = new Date(now);
d.setDate(d.getDate() - (days - 1 - i));
return d.toLocaleDateString('fr-FR', { day: 'numeric', month: 'short' });
});
var bars = totals.map(function (v, i) {
var x = padX + i * (W - 2 * padX) / days + 1;
var bh = Math.max(2, (v / maxV) * (H - padY - 16));
var y = H - padY - bh;
var lx = x + barW / 2;
var label = labels[i];
var showLabel = (i === 0 || i === days - 1 || i === Math.floor(days / 2));
return '<rect x="' + x.toFixed(1) + '" y="' + y.toFixed(1) + '" width="' + barW + '" height="' + bh.toFixed(1) + '"'
+ ' fill="var(--bs-primary,#0d6efd)" opacity="0.75" rx="2"/>'
+ '<title>' + label + ' : ' + v + ' vis.</title>'
+ (showLabel
? '<text x="' + lx.toFixed(1) + '" y="' + (H - 1) + '" text-anchor="middle"'
+ ' font-size="10" fill="var(--bs-secondary-color,#6c757d)">' + label + '</text>'
: '');
}).join('');
trendEl.innerHTML = '<p class="small text-muted mb-2 fw-semibold">Trafic total — 14 derniers jours</p>'
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + W + ' ' + H + '"'
+ ' style="width:100%;height:80px;display:block">' + bars + '</svg>';
}
fetch('/trending?period=14d') fetch('/trending?period=14d')
.then(function (r) { return r.ok ? r.text() : Promise.reject(); }) .then(function (r) { return r.ok ? r.text() : Promise.reject(); })
.then(function (xml) { .then(function (xml) {
@@ -111,15 +70,7 @@
var daily = pm ? (pagesByDay[pm[0]] || null) : null; var daily = pm ? (pagesByDay[pm[0]] || null) : null;
return { title: title, link: link, slug: slug, vis: vis, daily: daily }; return { title: title, link: link, slug: slug, vis: vis, daily: daily };
}); });
var maxV = Math.max.apply(null, rows.map(function (r) { return r.vis; })) || 1;
// Graphique global : somme de tous les articles par jour
var nDays = 14;
var totals = new Array(nDays).fill(0);
Object.values(pagesByDay).forEach(function (arr) {
arr.forEach(function (v, i) { if (i < nDays) { totals[i] += v; } });
});
trendChart(totals);
var html = '<div class="table-responsive"><table class="table table-sm table-hover mb-0 small w-100"><tbody>'; var html = '<div class="table-responsive"><table class="table table-sm table-hover mb-0 small w-100"><tbody>';
rows.forEach(function (row, i) { rows.forEach(function (row, i) {
var vis = row.vis.toLocaleString('fr-FR'); var vis = row.vis.toLocaleString('fr-FR');
-1
View File
@@ -35,7 +35,6 @@ $_activeGroup = trim($_GET['group'] ?? '');
<div class="card-body p-0" id="stats-pages-container"> <div class="card-body p-0" id="stats-pages-container">
<p class="text-muted p-3 mb-0">Chargement…</p> <p class="text-muted p-3 mb-0">Chargement…</p>
</div> </div>
<div class="card-footer bg-transparent border-top px-3 pt-3 pb-2" id="stats-trend-container"></div>
</div> </div>
<div class="row g-4"> <div class="row g-4">