feat: ping body syntax highlighting
This commit is contained in:
parent
79b7f21591
commit
5e10723021
|
|
@ -173,6 +173,48 @@
|
|||
const _initialQuery = <%~ JSON.stringify(m.query || null) %>;
|
||||
<%~ include('./partials/monitor-form-js') %>
|
||||
|
||||
// ── Syntax highlighting ────────────────────────────────────────
|
||||
function highlightJson(str) {
|
||||
try { str = JSON.stringify(JSON.parse(str), null, 2); } catch {}
|
||||
return escapeHtml(str).replace(
|
||||
/("(?:\\.|[^"\\])*")\s*:/g,
|
||||
'<span class="text-blue-400">$1</span>:'
|
||||
).replace(
|
||||
/:\s*("(?:\\.|[^"\\])*")/g,
|
||||
': <span class="text-green-400">$1</span>'
|
||||
).replace(
|
||||
/:\s*(true|false)/g,
|
||||
': <span class="text-yellow-400">$1</span>'
|
||||
).replace(
|
||||
/:\s*(null)/g,
|
||||
': <span class="text-gray-500">$1</span>'
|
||||
).replace(
|
||||
/:\s*(-?\d+\.?\d*(?:[eE][+-]?\d+)?)/g,
|
||||
': <span class="text-purple-400">$1</span>'
|
||||
);
|
||||
}
|
||||
|
||||
function highlightXml(str) {
|
||||
return escapeHtml(str)
|
||||
.replace(/<(\/?)([\w:-]+)/g, '<$1<span class="text-red-400">$2</span>')
|
||||
.replace(/([\w:-]+)(=)("[^&]*")/g, '<span class="text-yellow-400">$1</span>$2<span class="text-green-400">$3</span>');
|
||||
}
|
||||
|
||||
function highlightBody(body, contentType) {
|
||||
const ct = (contentType || '').toLowerCase();
|
||||
if (ct.includes('json')) return highlightJson(body);
|
||||
if (ct.includes('xml') || ct.includes('html')) return highlightXml(body);
|
||||
return escapeHtml(body);
|
||||
}
|
||||
|
||||
function getContentType(headers) {
|
||||
if (!headers) return '';
|
||||
for (const [k, v] of Object.entries(headers)) {
|
||||
if (k.toLowerCase() === 'content-type') return String(v);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// ── Ping detail modal ──────────────────────────────────────────
|
||||
function openPingModal(ping) {
|
||||
const modalBody = document.getElementById('ping-modal-body');
|
||||
|
|
@ -223,9 +265,11 @@
|
|||
}
|
||||
|
||||
// Response body — loaded on demand
|
||||
const contentType = getContentType(headers);
|
||||
const ctLabel = contentType ? ` <span class="text-gray-600">(${escapeHtml(contentType.split(';')[0].trim())})</span>` : '';
|
||||
html += '<div id="ping-body-section">';
|
||||
if (ping.id) {
|
||||
html += '<div class="text-xs text-gray-500 mb-1">Response Body</div>';
|
||||
html += `<div class="text-xs text-gray-500 mb-1">Response Body${ctLabel}</div>`;
|
||||
html += '<div id="ping-body-content" class="bg-gray-800/50 border border-border-subtle rounded-lg px-3 py-2 text-xs font-mono text-gray-500 min-h-[2rem] flex items-center">Loading...</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
|
@ -236,12 +280,13 @@
|
|||
|
||||
// Fetch body asynchronously
|
||||
if (ping.id) {
|
||||
const ct = getContentType(headers);
|
||||
api(`/pings/${ping.id}/body`).then(data => {
|
||||
const el = document.getElementById('ping-body-content');
|
||||
if (!el) return;
|
||||
if (data.body) {
|
||||
el.className = 'bg-gray-800/50 border border-border-subtle rounded-lg px-3 py-2 text-xs font-mono text-gray-300 whitespace-pre-wrap break-all max-h-80 overflow-y-auto';
|
||||
el.textContent = data.body;
|
||||
el.innerHTML = highlightBody(data.body, ct);
|
||||
} else {
|
||||
el.textContent = 'No body stored';
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue