100 lines
2.8 KiB
JavaScript
100 lines
2.8 KiB
JavaScript
/**
|
|
* UI Rendering Module for Visualization UI
|
|
* Handles rendering of Alerts table and Outlier summary panel.
|
|
*
|
|
* @module ui
|
|
*/
|
|
|
|
/**
|
|
* Renders the Max-only alert data into a table structure within #alert-dashboard.
|
|
* @param {Array<Object>} alerts - Array of alert objects from /alert-data endpoint.
|
|
*/
|
|
export function renderAlertDashboard(alerts = []) {
|
|
const container = document.getElementById('alert-dashboard');
|
|
if (!container) return;
|
|
|
|
container.innerHTML = '';
|
|
const status = document.createElement('div');
|
|
status.className = 'visualization_ui__status';
|
|
|
|
if (!Array.isArray(alerts) || alerts.length === 0) {
|
|
status.textContent = 'Keine Alert-Daten vorhanden.';
|
|
container.appendChild(status);
|
|
return;
|
|
}
|
|
|
|
const table = document.createElement('table');
|
|
table.className = 'visualization_ui__table';
|
|
|
|
const thead = document.createElement('thead');
|
|
thead.innerHTML = `
|
|
<tr>
|
|
<th>corr_id</th>
|
|
<th>stratum</th>
|
|
<th>expires_at_dist_hours</th>
|
|
<th>retry_total_overhead_ms</th>
|
|
</tr>
|
|
`;
|
|
table.appendChild(thead);
|
|
|
|
const tbody = document.createElement('tbody');
|
|
for (const alert of alerts) {
|
|
const row = document.createElement('tr');
|
|
row.innerHTML = `
|
|
<td>${escapeHTML(alert.corr_id ?? '')}</td>
|
|
<td>${escapeHTML(alert.stratum ?? '')}</td>
|
|
<td>${escapeHTML(alert.expires_at_dist_hours ?? '')}</td>
|
|
<td>${escapeHTML(alert.retry_total_overhead_ms ?? '')}</td>
|
|
`;
|
|
tbody.appendChild(row);
|
|
}
|
|
|
|
table.appendChild(tbody);
|
|
container.appendChild(table);
|
|
}
|
|
|
|
/**
|
|
* Displays outlier analysis summary metrics inside #outlier-summary panel.
|
|
* @param {Object} report - Report object fetched from /outlier-report endpoint.
|
|
*/
|
|
export function renderOutlierSummary(report = {}) {
|
|
const container = document.getElementById('outlier-summary');
|
|
if (!container) return;
|
|
container.innerHTML = '';
|
|
|
|
const summary = document.createElement('div');
|
|
summary.className = 'visualization_ui__outlier-summary';
|
|
|
|
if (!Object.keys(report).length) {
|
|
summary.textContent = 'Noch keine Outlier-Daten verfügbar.';
|
|
container.appendChild(summary);
|
|
return;
|
|
}
|
|
|
|
const list = document.createElement('dl');
|
|
for (const [key, value] of Object.entries(report)) {
|
|
const term = document.createElement('dt');
|
|
term.textContent = key;
|
|
const desc = document.createElement('dd');
|
|
desc.textContent = typeof value === 'number' ? value.toFixed(3) : String(value);
|
|
list.appendChild(term);
|
|
list.appendChild(desc);
|
|
}
|
|
|
|
summary.appendChild(list);
|
|
container.appendChild(summary);
|
|
}
|
|
|
|
/**
|
|
* Escapes potential HTML in strings to prevent XSS injection.
|
|
* @param {string} str
|
|
* @returns {string}
|
|
*/
|
|
function escapeHTML(str) {
|
|
return String(str)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|