168 lines
8.1 KiB
PowerShell
168 lines
8.1 KiB
PowerShell
param(
|
|
[Parameter(Mandatory)][string]$JsonData,
|
|
[Parameter(Mandatory)][string]$OutputPath
|
|
)
|
|
|
|
# Escape for safe embedding in JS string literal
|
|
$escaped = $JsonData -replace '\\', '\\\\' -replace "'", "\\\'" -replace "`r`n", '\n' -replace "`n", '\n'
|
|
|
|
$html = @'
|
|
<!DOCTYPE html>
|
|
<html lang="de"><head><meta charset="UTF-8"><title>Mail-Organizer Protokoll</title>
|
|
<style>
|
|
*{box-sizing:border-box;margin:0;padding:0}
|
|
body{font-family:Segoe UI,system-ui,sans-serif;background:#1e1e1e;color:#d4d4d4;padding:24px;max-width:1100px;margin:0 auto}
|
|
h1{font-size:1.3em;margin-bottom:4px;color:#e0e0e0}
|
|
.sub{color:#999;font-size:.85em;margin-bottom:20px}
|
|
.ctl{display:flex;gap:12px;align-items:center;margin-bottom:16px;flex-wrap:wrap}
|
|
.ctl label{font-weight:600;font-size:.82em;color:#ccc}
|
|
select{padding:5px 10px;border:1px solid #444;border-radius:4px;font-size:.82em;background:#2d2d2d;color:#d4d4d4}
|
|
.sbar{display:flex;gap:16px;background:#252526;border:1px solid #333;border-radius:6px;padding:14px 18px;margin-bottom:16px;flex-wrap:wrap;align-items:center}
|
|
.sbar .it{font-size:.85em}.sbar .it strong{font-size:1.1em;color:#e0e0e0}
|
|
.b{display:inline-block;padding:2px 8px;border-radius:10px;font-size:.72em;font-weight:600;color:#fff;vertical-align:middle}
|
|
.bok{background:#2ea043}.ber{background:#d13438}.bwa{background:#ca5010}.bdr{background:#8764b8}.bin{background:#2b88d8}
|
|
.rc{background:#252526;border:1px solid #333;border-radius:6px;margin-bottom:8px;overflow:hidden}
|
|
.rh{padding:11px 16px;cursor:pointer;display:flex;justify-content:space-between;align-items:center;user-select:none}
|
|
.rh:hover{background:#2a2d2e}.rh h3{font-size:.9em;font-weight:600;color:#e0e0e0}.rh .tg{display:flex;gap:5px}
|
|
.rb{display:none;border-top:1px solid #333}.rb.open{display:block}
|
|
.mr{padding:9px 16px;border-bottom:1px solid #333;font-size:.83em}.mr:last-child{border-bottom:none}
|
|
.ms{font-weight:600;color:#e0e0e0}.mm{color:#888;font-size:.92em;margin-top:1px}
|
|
.ac{margin-top:5px;display:flex;flex-wrap:wrap;gap:5px}
|
|
.at{display:inline-block;padding:2px 7px;border-radius:3px;font-size:.78em}
|
|
.at.ok{background:#1a3a1a;color:#4ec94e}.at.error{background:#3a1a1a;color:#f48771}
|
|
.at.dryrun{background:#2a1f3a;color:#b48eda}.at.warn{background:#3a2a1a;color:#e8a33d}
|
|
.nm{padding:12px 16px;color:#666;font-size:.83em;font-style:italic}
|
|
.em{color:#f48771;font-size:.83em;padding:8px 16px}
|
|
a.sl{color:#4daafc;text-decoration:none}a.sl:hover{text-decoration:underline}
|
|
.err-box{background:#3a1a1a;color:#f48771;border:1px solid #d13438;border-radius:6px;padding:16px;margin:20px 0;font-size:.9em}
|
|
</style></head><body>
|
|
<h1>Mail-Organizer Protokoll</h1>
|
|
<div class="sub" id="gen"></div>
|
|
<div class="ctl"><label>Lauf:</label><select id="rs"></select><label>Status:</label>
|
|
<select id="fl"><option value="all">Alle</option><option value="ok">Nur OK</option><option value="error">Nur Fehler</option><option value="dryrun">Nur DryRun</option></select></div>
|
|
<div id="o"></div>
|
|
<script>
|
|
var DATA;
|
|
try {
|
|
DATA = JSON.parse('
|
|
'@
|
|
|
|
$html += $escaped
|
|
|
|
$html += @'
|
|
');
|
|
} catch(ex) {
|
|
document.getElementById('o').innerHTML = '<div class="err-box"><strong>Fehler beim Laden der Protokolldaten:</strong><br>' + ex.message + '</div>';
|
|
}
|
|
|
|
if (DATA && DATA.length) {
|
|
var sel = document.getElementById('rs');
|
|
var flt = document.getElementById('fl');
|
|
var out = document.getElementById('o');
|
|
|
|
document.getElementById('gen').textContent = 'Generiert: ' + new Date().toLocaleString('de-DE');
|
|
|
|
DATA.sort(function(a,b) { return b.timestamp.localeCompare(a.timestamp); });
|
|
for (var i = 0; i < DATA.length; i++) {
|
|
var r = DATA[i];
|
|
var opt = document.createElement('option');
|
|
opt.value = i;
|
|
var d = r.dryRun ? ' [DRY RUN]' : '';
|
|
var e = r.summary.errors > 0 ? ' \u26A0 ' + r.summary.errors + ' Fehler' : '';
|
|
opt.textContent = r.timestamp + d + ' \u2014 ' + r.summary.processed + ' Mail(s)' + e;
|
|
sel.appendChild(opt);
|
|
}
|
|
|
|
sel.addEventListener('change', render);
|
|
flt.addEventListener('change', render);
|
|
render();
|
|
}
|
|
|
|
function render() {
|
|
var r = DATA[sel.value];
|
|
if (!r) return;
|
|
var f = flt.value;
|
|
var h = '<div class="sbar">';
|
|
h += '<div class="it">' + (r.dryRun ? '<span class="b bdr">DRY RUN</span> ' : '') + '<strong>' + esc(r.timestamp) + '</strong></div>';
|
|
h += '<div class="it">Mailbox: <strong>' + esc(r.mailbox) + '</strong></div>';
|
|
h += '<div class="it">Verarbeitet: <strong>' + r.summary.processed + '</strong></div>';
|
|
h += '<div class="it">Alerts: <strong>' + r.summary.alerts + '</strong></div>';
|
|
h += '<div class="it">' + (r.summary.errors > 0 ? '<span class="b ber">' + r.summary.errors + ' Fehler</span>' : '<span class="b bok">Fehlerfrei</span>') + '</div>';
|
|
h += '</div>';
|
|
var rules = r.rules || [];
|
|
for (var ri = 0; ri < rules.length; ri++) {
|
|
var rule = rules[ri];
|
|
var mails = fm(rule.mails || [], f);
|
|
var total = (rule.mails || []).length;
|
|
var errs = 0;
|
|
for (var ei = 0; ei < (rule.mails||[]).length; ei++) { if ((rule.mails||[])[ei].status === 'error') errs++; }
|
|
var badge = rule.error ? '<span class="b ber">API-Fehler</span>' : errs > 0 ? '<span class="b bwa">' + errs + '/' + total + ' Fehler</span>' : total > 0 ? '<span class="b bok">' + total + ' OK</span>' : '<span class="b bin">0 Mails</span>';
|
|
h += '<div class="rc"><div class="rh" onclick="tgl(this)"><h3>' + esc(rule.ruleName) + '</h3>';
|
|
h += '<div class="tg"><span class="b bin">' + total + '</span>' + badge + '</div></div>';
|
|
h += '<div class="rb' + (total > 0 || rule.error ? ' open' : '') + '">';
|
|
if (rule.error) h += '<div class="em">' + esc(rule.error) + '</div>';
|
|
if (mails.length === 0 && !rule.error) h += '<div class="nm">' + (f !== 'all' ? 'Keine Mails mit Filter "' + f + '"' : 'Keine passenden E-Mails') + '</div>';
|
|
for (var mi = 0; mi < mails.length; mi++) {
|
|
var m = mails[mi];
|
|
var dt = m.received ? new Date(m.received).toLocaleString('de-DE') : '';
|
|
h += '<div class="mr"><div class="ms">' + esc(m.subject) + '</div>';
|
|
h += '<div class="mm">' + esc(m.from) + ' · ' + dt + '</div>';
|
|
h += '<div class="ac">' + acHtml(m.actions) + '</div></div>';
|
|
}
|
|
h += '</div></div>';
|
|
}
|
|
out.innerHTML = h;
|
|
}
|
|
|
|
function fm(mails, f) {
|
|
if (f === 'all') return mails;
|
|
var res = [];
|
|
for (var i = 0; i < mails.length; i++) {
|
|
var m = mails[i];
|
|
if (f === 'error' && m.status === 'error') res.push(m);
|
|
if (f === 'ok' && m.status === 'ok') res.push(m);
|
|
if (f === 'dryrun') { for (var j=0;j<(m.actions||[]).length;j++) { if(m.actions[j].status==='dryrun'){res.push(m);break;} } }
|
|
}
|
|
return f === 'all' ? mails : res;
|
|
}
|
|
|
|
function acHtml(actions) {
|
|
if (!actions || !actions.length) return '<span style="color:#aaa;font-size:.78em">Keine Aktionen</span>';
|
|
var parts = [];
|
|
for (var i = 0; i < actions.length; i++) {
|
|
var a = actions[i], l = a.action, d = '';
|
|
if (a.action === 'uploadToSharePoint') {
|
|
l = 'SharePoint';
|
|
if (a.files && a.files.length) {
|
|
var fparts = [];
|
|
for (var fi = 0; fi < a.files.length; fi++) {
|
|
var ff = a.files[fi];
|
|
var name = typeof ff === 'string' ? ff : (ff.name || '');
|
|
var url = (typeof ff === 'object' && ff !== null) ? ff.url : null;
|
|
fparts.push(url ? '<a class="sl" href="' + esc(url) + '" target="_blank">' + esc(name) + '</a>' : esc(name));
|
|
}
|
|
d = fparts.join(', ');
|
|
} else if (a.target) d = a.target;
|
|
} else if (a.action === 'saveAttachments') {
|
|
l = 'Anhaenge'; d = a.files ? a.files + ' Datei(en)' : '';
|
|
} else if (a.action === 'onSuccess') {
|
|
l = 'Erfolg'; d = (a.details || []).join(', ');
|
|
} else if (a.action === 'alert') {
|
|
l = 'Alert'; d = a.to || '';
|
|
}
|
|
if (a.error) d = a.error;
|
|
if (a.message) d = a.message;
|
|
parts.push('<span class="at ' + (a.status || 'ok') + '">' + esc(l) + (d ? ': ' + d : '') + '</span>');
|
|
}
|
|
return parts.join('');
|
|
}
|
|
|
|
function tgl(el) { var b = el.nextElementSibling; b.className = b.className.indexOf('open') >= 0 ? 'rb' : 'rb open'; }
|
|
function esc(s) { if (!s) return ''; var d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
|
|
</script></body></html>
|
|
'@
|
|
|
|
# Write without BOM
|
|
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
|
|
[System.IO.File]::WriteAllText($OutputPath, $html, $utf8NoBom)
|