// ========== LOG INSIGHTS PANEL ========== (function() { injectModal('log-insights-modal', `

๐Ÿ” Log Insights

Top Visitors

`); const modal = document.getElementById('log-insights-modal'); const openBtn = document.getElementById('log-insights-btn'); const closeBtn = document.getElementById('li-close'); const refreshBtn = document.getElementById('li-refresh'); const disposeBtn = document.getElementById('li-dispose-btn'); const periodSel = document.getElementById('li-period'); const insightsDiv = document.getElementById('li-insights'); const summaryDiv = document.getElementById('li-summary'); const ipsDiv = document.getElementById('li-ips-table'); const storageDiv = document.getElementById('li-storage'); if (openBtn) { openBtn.addEventListener('click', () => { modal.style.display = 'flex'; loadInsights(); }); } closeBtn.addEventListener('click', () => modal.style.display = 'none'); refreshBtn.addEventListener('click', loadInsights); periodSel.addEventListener('change', loadInsights); disposeBtn.addEventListener('click', showDisposePreview); async function loadInsights() { const hours = periodSel.value; insightsDiv.innerHTML = '
Analyzing logs...
'; summaryDiv.innerHTML = ''; ipsDiv.innerHTML = ''; storageDiv.innerHTML = ''; try { const res = await fetch('/api/v1/log-insights?hours=' + hours); const data = await res.json(); if (!data.success) { insightsDiv.innerHTML = '
Error: ' + data.error + '
'; return; } // Render insights as plain English cards let insightsHtml = ''; (data.insights || []).forEach(function(ins) { const sevColor = ins.severity === 'warning' ? 'var(--warn-fg, #f0c674)' : ins.severity === 'critical' ? 'var(--bad-fg, #ff6b6b)' : ins.severity === 'ok' ? 'var(--good-fg, #98c379)' : 'var(--muted)'; insightsHtml += '
' + '' + ins.title + '
' + '' + ins.plain + '
'; }); insightsDiv.innerHTML = insightsHtml; // Summary stats var s = data.summary; summaryDiv.innerHTML = statCard('Requests', s.totalRequests) + statCard('Unique IPs', s.uniqueIPs) + statCard('Security Events', s.securityEvents) + statCard('Failed Actions', s.failedActions); // Top IPs table var ips = data.topIPs || []; if (ips.length === 0) { ipsDiv.innerHTML = '
No activity in this period.
'; } else { var html = ''; html += ''; ips.forEach(function(ip) { var failStyle = ip.failures > 0 ? 'color: var(--bad-fg, #ff6b6b); font-weight: 600;' : ''; var actions = (ip.topActions || []).map(function(a) { return a[0]; }).join(', '); var lastSeen = ip.lastSeen ? new Date(ip.lastSeen).toLocaleString() : '?'; html += '' + '' + '' + '' + '' + '' + ''; }); html += '
IP AddressRequestsFailuresTop ActionsLast Seen
' + ip.ip + '' + ip.count + '' + ip.failures + '' + actions + '' + lastSeen + '
'; ipsDiv.innerHTML = html; } // Storage info var st = data.storage || {}; var stHtml = 'Log Storage
'; if (st.auditLog) stHtml += 'Audit log: ' + st.auditLog.sizeMB + ' MB (' + st.auditLog.entries + ' entries)
'; if (st.securityEvents) stHtml += 'Security events: ' + st.securityEvents.sizeMB + ' MB (' + st.securityEvents.entries + ' entries)'; storageDiv.innerHTML = stHtml; } catch (e) { insightsDiv.innerHTML = '
Failed to load: ' + e.message + '
'; } } function statCard(label, value) { return '
' + '
' + value + '
' + '
' + label + '
'; } async function showDisposePreview() { var keepDays = prompt('Delete logs older than how many days?', '30'); if (!keepDays) return; keepDays = parseInt(keepDays); if (isNaN(keepDays) || keepDays < 1) { alert('Invalid number'); return; } try { var res = await fetch('/api/v1/log-insights/dispose', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ keepDays: keepDays }) }); var data = await res.json(); if (!data.success) { alert('Error: ' + data.error); return; } var msg = data.message + '\n\n' + 'Audit entries to delete: ' + data.wouldDelete.auditEntries + '\n' + 'Security events to delete: ' + data.wouldDelete.securityEvents + '\n\n' + 'Click OK to confirm deletion.'; if (confirm(msg)) { await executeDispose(keepDays); } } catch (e) { alert('Failed: ' + e.message); } } async function executeDispose(keepDays) { try { var res = await fetch('/api/v1/log-insights/dispose', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ keepDays: keepDays, confirm: true }) }); var data = await res.json(); if (!data.success) { alert('Error: ' + data.error); return; } alert('Cleaned up!\n\nDeleted: ' + data.deleted.auditEntries + ' audit entries, ' + data.deleted.securityEvents + ' security events.\nRemaining: ' + data.remaining.auditEntries + ' audit, ' + data.remaining.securityEvents + ' security.'); loadInsights(); } catch (e) { alert('Failed: ' + e.message); } } function injectModal(id, html) { if (document.getElementById(id)) return; var div = document.createElement('div'); div.innerHTML = html; document.body.appendChild(div.firstElementChild); } })();