addes folder backup attachments logging
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Verarbeitungslog — IMAP Mail Filter{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Verarbeitungslog</h1>
|
||||
|
||||
<div style="display:flex; gap:1rem; align-items:end; flex-wrap:wrap; margin-bottom:1rem;">
|
||||
<label style="margin-bottom:0;">
|
||||
Konto
|
||||
<select id="log-account" onchange="loadLogs()" style="margin-bottom:0;">
|
||||
<option value="">Alle Konten</option>
|
||||
{% for acc in accounts %}
|
||||
<option value="{{ acc.id }}">{{ acc.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<label style="margin-bottom:0;">
|
||||
Level
|
||||
<select id="log-level" onchange="loadLogs()" style="margin-bottom:0;">
|
||||
<option value="">Alle</option>
|
||||
<option value="success">Erfolg</option>
|
||||
<option value="info">Info</option>
|
||||
<option value="warning">Warnung</option>
|
||||
<option value="error">Fehler</option>
|
||||
</select>
|
||||
</label>
|
||||
<div role="group" style="margin-bottom:0;">
|
||||
<button class="outline small" onclick="loadLogs()">Aktualisieren</button>
|
||||
<button class="outline small contrast" onclick="clearLogs()">Log leeren</button>
|
||||
</div>
|
||||
<label style="margin-bottom:0; margin-left:auto;">
|
||||
<input type="checkbox" id="auto-refresh" onchange="toggleAutoRefresh()" style="margin-bottom:0;">
|
||||
Auto-Refresh (5s)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="log-stats" style="margin-bottom:1rem;"></div>
|
||||
|
||||
<div id="log-container">
|
||||
<p aria-busy="true">Logs werden geladen...</p>
|
||||
</div>
|
||||
|
||||
<div id="log-paging" style="display:flex; justify-content:center; gap:1rem; margin-top:1rem;"></div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<style>
|
||||
.log-table {
|
||||
width: 100%;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.log-table th, .log-table td {
|
||||
padding: 0.4rem 0.6rem;
|
||||
vertical-align: top;
|
||||
}
|
||||
.log-row { border-left: 3px solid transparent; }
|
||||
.log-row[data-level="success"] { border-left-color: #28a745; }
|
||||
.log-row[data-level="info"] { border-left-color: #17a2b8; }
|
||||
.log-row[data-level="warning"] { border-left-color: #ffc107; }
|
||||
.log-row[data-level="error"] { border-left-color: #dc3545; }
|
||||
|
||||
.log-level {
|
||||
display: inline-block;
|
||||
padding: 0.1rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.log-level-success { background: #d4edda; color: #155724; }
|
||||
.log-level-info { background: #d1ecf1; color: #0c5460; }
|
||||
.log-level-warning { background: #fff3cd; color: #856404; }
|
||||
.log-level-error { background: #f8d7da; color: #721c24; }
|
||||
|
||||
.log-detail { font-size: 0.8rem; opacity: 0.7; }
|
||||
.log-mail-info { font-size: 0.8rem; color: var(--pico-muted-color); }
|
||||
</style>
|
||||
<script>
|
||||
let currentOffset = 0;
|
||||
const PAGE_SIZE = 50;
|
||||
let refreshTimer = null;
|
||||
|
||||
async function loadLogs(offset = 0) {
|
||||
currentOffset = offset;
|
||||
const accountId = document.getElementById('log-account').value;
|
||||
const level = document.getElementById('log-level').value;
|
||||
const container = document.getElementById('log-container');
|
||||
|
||||
let url = `/api/logs/?limit=${PAGE_SIZE}&offset=${offset}`;
|
||||
if (accountId) url += `&account_id=${accountId}`;
|
||||
if (level) url += `&level=${level}`;
|
||||
|
||||
try {
|
||||
const resp = await fetch(url);
|
||||
const data = await resp.json();
|
||||
renderStats(data.total);
|
||||
renderLogs(data.logs);
|
||||
renderPaging(data.total, offset);
|
||||
} catch(e) {
|
||||
container.innerHTML = `<p>Fehler beim Laden: ${e.message}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderStats(total) {
|
||||
document.getElementById('log-stats').innerHTML = `<small>${total} Einträge gesamt</small>`;
|
||||
}
|
||||
|
||||
function renderLogs(logs) {
|
||||
const container = document.getElementById('log-container');
|
||||
if (!logs.length) {
|
||||
container.innerHTML = '<article><p>Keine Log-Einträge vorhanden.</p></article>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `<table class="log-table">
|
||||
<thead><tr>
|
||||
<th style="width:140px;">Zeit</th>
|
||||
<th style="width:60px;">Level</th>
|
||||
<th style="width:120px;">Konto</th>
|
||||
<th>Nachricht</th>
|
||||
<th style="width:120px;">Regel</th>
|
||||
</tr></thead><tbody>`;
|
||||
|
||||
for (const log of logs) {
|
||||
const time = log.created_at ? new Date(log.created_at).toLocaleString('de-DE', {
|
||||
day: '2-digit', month: '2-digit', year: '2-digit',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit'
|
||||
}) : '';
|
||||
|
||||
const levelClass = `log-level-${log.level}`;
|
||||
const levelLabel = {success: 'OK', info: 'Info', warning: 'Warn', error: 'Fehler'}[log.level] || log.level;
|
||||
|
||||
let message = escapeHtml(log.message);
|
||||
if (log.mail_subject || log.mail_from) {
|
||||
message += `<div class="log-mail-info">`;
|
||||
if (log.mail_from) message += `Von: ${escapeHtml(log.mail_from)}<br>`;
|
||||
if (log.mail_subject) message += `Betreff: ${escapeHtml(log.mail_subject)}`;
|
||||
message += `</div>`;
|
||||
}
|
||||
if (log.details) {
|
||||
message += `<div class="log-detail">${escapeHtml(log.details)}</div>`;
|
||||
}
|
||||
|
||||
html += `<tr class="log-row" data-level="${log.level}">
|
||||
<td><small>${time}</small></td>
|
||||
<td><span class="log-level ${levelClass}">${levelLabel}</span></td>
|
||||
<td><small>${escapeHtml(log.account_name || '')}</small></td>
|
||||
<td>${message}</td>
|
||||
<td><small>${escapeHtml(log.rule_name || '')}</small></td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
html += '</tbody></table>';
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
function renderPaging(total, offset) {
|
||||
const paging = document.getElementById('log-paging');
|
||||
if (total <= PAGE_SIZE) {
|
||||
paging.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
const page = Math.floor(offset / PAGE_SIZE) + 1;
|
||||
const totalPages = Math.ceil(total / PAGE_SIZE);
|
||||
let html = '';
|
||||
if (offset > 0) {
|
||||
html += `<button class="outline small" onclick="loadLogs(${offset - PAGE_SIZE})">Neuere</button>`;
|
||||
}
|
||||
html += `<small>Seite ${page} / ${totalPages}</small>`;
|
||||
if (offset + PAGE_SIZE < total) {
|
||||
html += `<button class="outline small" onclick="loadLogs(${offset + PAGE_SIZE})">Ältere</button>`;
|
||||
}
|
||||
paging.innerHTML = html;
|
||||
}
|
||||
|
||||
async function clearLogs() {
|
||||
if (!confirm('Log wirklich leeren?')) return;
|
||||
const accountId = document.getElementById('log-account').value;
|
||||
let url = '/api/logs/';
|
||||
if (accountId) url += `?account_id=${accountId}`;
|
||||
await fetch(url, {method: 'DELETE'});
|
||||
loadLogs();
|
||||
}
|
||||
|
||||
function toggleAutoRefresh() {
|
||||
if (document.getElementById('auto-refresh').checked) {
|
||||
refreshTimer = setInterval(() => loadLogs(currentOffset), 5000);
|
||||
} else {
|
||||
clearInterval(refreshTimer);
|
||||
refreshTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// Initial load
|
||||
loadLogs();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user