/* ESPILON Honeypot Dashboard — Charts */
import { escHtml, formatTime } from './utils.js';
// ── Severity Donut ──────────────────────────────────────────
export function renderSevDonut(container, stats) {
if (!container) return;
const sevs = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'];
const rawColors = {CRITICAL: '#f43f5e', HIGH: '#fb923c', MEDIUM: '#fbbf24', LOW: '#4ade80'};
const total = sevs.reduce((s, k) => s + (stats[k] || 0), 0);
if (!total) {
container.innerHTML = '
No events
';
return;
}
let gradParts = [], angle = 0;
sevs.forEach(s => {
const v = stats[s] || 0;
if (!v) return;
const seg = (v / total) * 360;
gradParts.push(rawColors[s] + ' ' + angle + 'deg ' + (angle + seg) + 'deg');
angle += seg;
});
let html = '';
html += '
'
+ '
'
+ '
' + total + '
'
+ '
events
';
html += '
';
sevs.forEach(s => {
const v = stats[s] || 0, pct = (v / total * 100).toFixed(1);
html += '
'
+ ''
+ '' + s + ''
+ '' + v + ''
+ '(' + pct + '%)
';
});
html += '
';
container.innerHTML = html;
}
// ── Timeline Bar Chart ──────────────────────────────────────
export function renderTimeline(container, data, height) {
if (!container) return;
height = height || 100;
if (!data || !data.length) {
container.innerHTML = 'No activity
';
return;
}
const maxTotal = Math.max(...data.map(d => d.total || 0), 1);
const barW = Math.max(Math.floor((container.offsetWidth || 600) / data.length) - 2, 3);
const labelEvery = Math.max(1, Math.floor(data.length / 8));
const chartH = height - 18;
let html = '';
data.forEach((d, i) => {
const t = d.total || 0, barH = t > 0 ? Math.max((t / maxTotal) * chartH, 2) : 0;
const crit = d.CRITICAL || 0, high = d.HIGH || 0, med = d.MEDIUM || 0, low = d.LOW || 0;
let timeLabel = '';
if (d.time && i % labelEvery === 0) {
const dt = new Date(typeof d.time === 'number' ? (d.time < 1e12 ? d.time * 1000 : d.time) : d.time);
timeLabel = String(dt.getHours()).padStart(2, '0') + ':' + String(dt.getMinutes()).padStart(2, '0');
}
const tooltip = (timeLabel || formatTime(d.time)) + ' \u2014 Total:' + t
+ ' (C:' + crit + ' H:' + high + ' M:' + med + ' L:' + low + ')';
html += '
';
if (t > 0) {
if (crit) html += '
';
if (high) html += '
';
if (med) html += '
';
if (low) html += '
';
}
if (timeLabel) {
html += '
' + timeLabel + '
';
}
html += '
';
});
html += '
';
container.innerHTML = html;
}