diff --git a/frontend/index.html b/frontend/index.html index 2da34ac..9b6b535 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -738,13 +738,25 @@ async function qsSample() { document.getElementById('qs-result').innerHTML = '

No events found for this source in the selected window.

' return } - // Collect all field names across events - const allFields = [...new Set(r.events.flatMap(e => Object.keys(e)))].sort() - const rows = r.events.map(ev => { + // Collect all field names across events — pin message last for readability + const allFieldsRaw = [...new Set(r.events.flatMap(e => Object.keys(e)))].sort() + const allFields = [...allFieldsRaw.filter(f => f !== 'message'), ...allFieldsRaw.filter(f => f === 'message')] + const rows = r.events.map((ev, ri) => { const cells = allFields.map(f => { const v = ev[f] const empty = v === null || v === undefined || v === '' || v === 'null' - return `${empty ? '∅' : esc(String(v).slice(0,40))}` + const raw = String(v ?? '') + if (f === 'message' && !empty) { + return ` +
+ ${esc(raw.slice(0, 80))}${raw.length > 80 ? '…' : ''} + +
+ ` + } + return `${empty ? '∅' : esc(raw.slice(0,40))}` }).join('') return `${cells}` }).join('') @@ -762,6 +774,16 @@ async function qsSample() { } finally { setBtn('btn-qs', false, 'Sample') } } +function qsCopyMsg(btn, idx) { + const msg = btn.dataset.msg + navigator.clipboard.writeText(msg).then(() => { + const orig = btn.textContent + btn.textContent = '✓' + btn.classList.add('text-emerald-400') + setTimeout(() => { btn.textContent = orig; btn.classList.remove('text-emerald-400') }, 1500) + }) +} + // ── Field Population Rate ────────────────────────────────────────────────── async function qpAnalyze() {