feat(dashboard): sélecteur de plage temporelle sur /campaigns
Avant : toutes les vues de campagnes étaient fixes à 7 jours.
Après : sélecteur 1j / 7j (défaut) / 14j / 30j / 90j en haut à droite.
- Ajout du paramètre ?days= (1–90, défaut 7) à :
GET /api/campaigns
GET /api/campaigns/graph
GET /api/campaigns/scatter
GET /api/campaigns/{cid}
- Le sélecteur recharge simultanément les 3 vues (cartes, scatter, graphe)
et le panneau de détail avec la même fenêtre temporelle
- Le compteur de campagnes indique la plage active : (4 campagnes — 30j)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@ -40,6 +40,14 @@
|
||||
Campagnes de bots
|
||||
</h1>
|
||||
<div class="ml-auto flex items-center gap-3">
|
||||
<!-- ── Sélecteur de plage temporelle ── -->
|
||||
<div class="flex items-center gap-1 bg-gray-800/60 rounded-lg p-1" id="days-selector">
|
||||
<button onclick="setDays(1)" data-days="1" class="days-btn px-2 py-1 rounded text-xs text-gray-400 hover:text-white hover:bg-gray-700 transition-colors">1j</button>
|
||||
<button onclick="setDays(7)" data-days="7" class="days-btn px-2 py-1 rounded text-xs text-white bg-purple-600">7j</button>
|
||||
<button onclick="setDays(14)" data-days="14" class="days-btn px-2 py-1 rounded text-xs text-gray-400 hover:text-white hover:bg-gray-700 transition-colors">14j</button>
|
||||
<button onclick="setDays(30)" data-days="30" class="days-btn px-2 py-1 rounded text-xs text-gray-400 hover:text-white hover:bg-gray-700 transition-colors">30j</button>
|
||||
<button onclick="setDays(90)" data-days="90" class="days-btn px-2 py-1 rounded text-xs text-gray-400 hover:text-white hover:bg-gray-700 transition-colors">90j</button>
|
||||
</div>
|
||||
<div class="text-center px-3">
|
||||
<div class="text-2xl font-bold text-purple-400" id="kpi-total">—</div>
|
||||
<div class="text-[10px] text-gray-500 uppercase tracking-wider">Campagnes</div>
|
||||
@ -238,13 +246,25 @@ function fmtCountry(cc) {
|
||||
* ════════════════════════════════════════════════════════════════════════════ */
|
||||
let _campaigns = [], _scatterData = [], _graphData = {nodes:[],edges:[]};
|
||||
let _scatterChart = null, _radarChart = null, _timelineChart = null;
|
||||
let _currentDays = 7;
|
||||
|
||||
function setDays(d) {
|
||||
_currentDays = d;
|
||||
document.querySelectorAll('.days-btn').forEach(b => {
|
||||
const active = parseInt(b.dataset.days) === d;
|
||||
b.className = `days-btn px-2 py-1 rounded text-xs transition-colors ${active ? 'text-white bg-purple-600' : 'text-gray-400 hover:text-white hover:bg-gray-700'}`;
|
||||
});
|
||||
closeDetail();
|
||||
loadAll();
|
||||
}
|
||||
|
||||
async function loadAll() {
|
||||
document.getElementById('camp-count').textContent = '(chargement…)';
|
||||
try {
|
||||
const [campResp, scatterResp, graphResp] = await Promise.all([
|
||||
fetch('/api/campaigns').then(r=>r.json()),
|
||||
fetch('/api/campaigns/scatter').then(r=>r.json()),
|
||||
fetch('/api/campaigns/graph').then(r=>r.json()),
|
||||
fetch(`/api/campaigns?days=${_currentDays}`).then(r=>r.json()),
|
||||
fetch(`/api/campaigns/scatter?days=${_currentDays}`).then(r=>r.json()),
|
||||
fetch(`/api/campaigns/graph?days=${_currentDays}`).then(r=>r.json()),
|
||||
]);
|
||||
_campaigns = campResp.campaigns || [];
|
||||
_scatterData = scatterResp.data || [];
|
||||
@ -256,13 +276,15 @@ async function loadAll() {
|
||||
document.getElementById('kpi-total').textContent = _campaigns.length;
|
||||
document.getElementById('kpi-ips').textContent = totalIPs.toLocaleString();
|
||||
document.getElementById('kpi-detections').textContent = totalDet.toLocaleString();
|
||||
document.getElementById('camp-count').textContent = `(${_campaigns.length} actives)`;
|
||||
const label = _currentDays === 1 ? '24h' : `${_currentDays}j`;
|
||||
document.getElementById('camp-count').textContent = `(${_campaigns.length} campagne${_campaigns.length!==1?'s':''} — ${label})`;
|
||||
|
||||
renderCampGrid();
|
||||
renderScatter();
|
||||
renderGraph();
|
||||
} catch(e) {
|
||||
console.error('Campaign load error:', e);
|
||||
document.getElementById('camp-count').textContent = '(erreur)';
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,7 +533,7 @@ async function selectCampaign(cid) {
|
||||
document.getElementById('detail-link').href = `/cluster/${cid}`;
|
||||
|
||||
try {
|
||||
const resp = await fetch(`/api/campaigns/${cid}`);
|
||||
const resp = await fetch(`/api/campaigns/${cid}?days=${_currentDays}`);
|
||||
const data = await resp.json();
|
||||
const p = data.profile || {};
|
||||
const members = data.members || [];
|
||||
|
||||
Reference in New Issue
Block a user