Compare commits

...

2 Commits

Author SHA1 Message Date
CyberMind
f5c7f6f6b5
Merge pull request #614 from CyberMind-FR/feature/613-threat-analyst-add-country-flags-to-top
Some checks are pending
License Headers / check (push) Waiting to run
ui(threat-analyst): country flags in Top source countries
2026-06-16 07:55:51 +02:00
d889d32714 ui(threat-analyst): country flags in Top source countries (closes #613)
flagEmoji() maps ISO alpha-2 -> regional-indicator emoji; renderTop gains a
withFlag arg used for the countries list.
2026-06-16 07:55:11 +02:00
2 changed files with 21 additions and 5 deletions

View File

@ -1,3 +1,10 @@
secubox-threat-analyst (1.4.6-1~bookworm1) bookworm; urgency=medium
* ui: add country flag emoji to the Top source countries list (#613) —
ISO 3166-1 alpha-2 → regional-indicator emoji before each code.
-- Gerald KERMA <devel@cybermind.fr> Tue, 16 Jun 2026 09:30:00 +0200
secubox-threat-analyst (1.4.5-1~bookworm1) bookworm; urgency=medium secubox-threat-analyst (1.4.5-1~bookworm1) bookworm; urgency=medium
* ui: limit the Recent attacks table to 5 rows (#611), matching the Top-N * ui: limit the Recent attacks table to 5 rows (#611), matching the Top-N

View File

@ -421,12 +421,21 @@
for (const v of items) { if (!v) continue; counts[v] = (counts[v] || 0) + 1; } for (const v of items) { if (!v) continue; counts[v] = (counts[v] || 0) + 1; }
return Object.entries(counts).sort((a, b) => b[1] - a[1]).slice(0, n); return Object.entries(counts).sort((a, b) => b[1] - a[1]).slice(0, n);
} }
function renderTop(elId, pairs) { // ISO 3166-1 alpha-2 → flag emoji (regional indicator symbols). #613
function flagEmoji(cc) {
if (!cc || !/^[A-Za-z]{2}$/.test(cc)) return '';
const A = 0x1F1E6;
return String.fromCodePoint(A + cc.toUpperCase().charCodeAt(0) - 65,
A + cc.toUpperCase().charCodeAt(1) - 65);
}
function renderTop(elId, pairs, withFlag = false) {
const el = document.getElementById(elId); const el = document.getElementById(elId);
if (!pairs.length) { el.innerHTML = '<li class="empty">no data</li>'; return; } if (!pairs.length) { el.innerHTML = '<li class="empty">no data</li>'; return; }
el.innerHTML = pairs.map(([k, v]) => el.innerHTML = pairs.map(([k, v]) => {
`<li><span class="k">${esc(k)}</span><span class="v">${v}</span></li>` const fl = withFlag ? flagEmoji(k) : '';
).join(''); const label = fl ? `<span class="flag-emoji">${fl}</span> ${esc(k)}` : esc(k);
return `<li><span class="k">${label}</span><span class="v">${v}</span></li>`;
}).join('');
} }
// Loaders // Loaders
@ -496,7 +505,7 @@
document.getElementById('s-unique-ips').textContent = ipSet.size; document.getElementById('s-unique-ips').textContent = ipSet.size;
document.getElementById('s-countries').textContent = countrySet.size; document.getElementById('s-countries').textContent = countrySet.size;
renderTop('top-ips', topN(ips, 5)); renderTop('top-ips', topN(ips, 5));
renderTop('top-countries', topN(countries, 5)); renderTop('top-countries', topN(countries, 5), true);
renderTop('top-types', topN(types, 5)); renderTop('top-types', topN(types, 5));
renderTop('top-targets', topN(targets, 5)); renderTop('top-targets', topN(targets, 5));
} }