Frontend refactored to ES6 modules (no bundler): js/main.js — entry point, wires all modules js/auth.js — OIDC login, token management js/ws.js — /ws, /ws/test, /ws/trace connections + HUD handler js/chat.js — messages, send, streaming js/graph.js — Cytoscape visualization + animation js/trace.js — trace panel js/dashboard.js — workspace controls rendering js/awareness.js — state panel, sensors, meters js/tests.js — test status display js/util.js — shared utilities New 2-row layout: Top: test status | connection status Middle: Workspace | Node Details | Graph Bottom: Chat | Awareness | Trace PA routing: routes ALL tool requests to expert (DB, UI, buttons, machines) Dashboard integration test: 15/15 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
35 lines
1.0 KiB
JavaScript
35 lines
1.0 KiB
JavaScript
/** Shared utility functions. */
|
|
|
|
export function scroll(el) { el.scrollTop = el.scrollHeight; }
|
|
|
|
export function esc(s) {
|
|
const d = document.createElement('span');
|
|
d.textContent = s;
|
|
return d.innerHTML;
|
|
}
|
|
|
|
export function truncate(s, n) {
|
|
return s.length > n ? s.slice(0, n) + '\u2026' : s;
|
|
}
|
|
|
|
export function renderMarkdown(text) {
|
|
let html = esc(text);
|
|
// Code blocks
|
|
html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) =>
|
|
'<pre class="md-code"><code>' + code.trim() + '</code></pre>');
|
|
// Inline code
|
|
html = html.replace(/`([^`]+)`/g, '<code class="md-inline">$1</code>');
|
|
// Bold
|
|
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
|
// Italic
|
|
html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
|
|
// Bullet lists
|
|
html = html.replace(/^[\*\-]\s+(.+)$/gm, '<li>$1</li>');
|
|
html = html.replace(/(<li>.*<\/li>\n?)+/g, m => '<ul>' + m + '</ul>');
|
|
// Numbered lists
|
|
html = html.replace(/^\d+\.\s+(.+)$/gm, '<li>$1</li>');
|
|
// Line breaks (but not inside pre/code)
|
|
html = html.replace(/\n/g, '<br>');
|
|
return html;
|
|
}
|