From 332efe59eb810174140efed90254b93dad622fb5 Mon Sep 17 00:00:00 2001 From: Malin Date: Fri, 27 Feb 2026 09:47:49 +0100 Subject: [PATCH] feat: rich ratelimited log viewer table Renders ratelimited log entries as a structured table instead of raw JSON, showing: timestamp, sender (header_from), recipient, subject, IP address, rate-limit rule name (orange badge, tooltip with rl_info), and queue ID. Co-Authored-By: Claude Sonnet 4.6 --- assets/js/woocow-admin.js | 45 +++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/assets/js/woocow-admin.js b/assets/js/woocow-admin.js index f46f2ef..53a294c 100644 --- a/assets/js/woocow-admin.js +++ b/assets/js/woocow-admin.js @@ -913,6 +913,45 @@ } }); + // ── Ratelimited log renderer ────────────────────────────────────────── + + const renderRatelimitLog = (entries) => { + let html = `
+ Rate-Limited Messages + ${entries.length} entries +
+ + + + + + + + + + `; + + entries.forEach(e => { + const dt = e.time ? new Date(e.time * 1000).toLocaleString() : '—'; + const sender = e.header_from || e.from || '—'; + const subject = e.header_subject || '—'; + html += ` + + + + + + + + `; + }); + + html += '
TimeSenderRecipientSubjectIPRate Limit RuleQueue ID
${esc(dt)}${esc(sender)}${esc(e.rcpt || '—')}${esc(subject)}${esc(e.ip || '—')} + ${esc(e.rl_name || '—')} + ${esc(e.qid || '—')}
'; + $('#wc-log-wrap').html(html); + }; + // ── Log load ────────────────────────────────────────────────────────── $('#wc-log-load').on('click', () => { @@ -931,10 +970,8 @@ return; } - if (type === 'rspamd-history') { - renderRspamdLog(entries); - return; - } + if (type === 'rspamd-history') { renderRspamdLog(entries); return; } + if (type === 'ratelimited') { renderRatelimitLog(entries); return; } // Plain text log const typeLabel = $('#wc-log-type option:selected').text();