Add metrics_visualization/js/ui.js
This commit is contained in:
parent
8896e957bc
commit
1bbe7a7086
1 changed files with 124 additions and 0 deletions
124
metrics_visualization/js/ui.js
Normal file
124
metrics_visualization/js/ui.js
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* @module ui
|
||||
* Verantwortlich für Rendering und Interaktion der UI-Komponenten.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Rendert oder aktualisiert das Diagramm basierend auf Metrikdaten.
|
||||
* @param {Array<Object>} metricsData - Metrikdaten aus der API.
|
||||
* @param {HTMLElement} chartContainer - Zielcontainer (z. B. Canvas- oder SVG-Element).
|
||||
*/
|
||||
export function renderChart(metricsData, chartContainer) {
|
||||
if (!chartContainer) return;
|
||||
chartContainer.innerHTML = '';
|
||||
if (!Array.isArray(metricsData) || metricsData.length === 0) {
|
||||
const msg = document.createElement('p');
|
||||
msg.textContent = 'Keine Metrikdaten verfügbar.';
|
||||
chartContainer.appendChild(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// Beispiel: einfache Balkenvisualisierung auf Basis von warn_rate
|
||||
const maxWarnRate = Math.max(...metricsData.map(m => m.warn_rate ?? 0));
|
||||
const chart = document.createElement('div');
|
||||
chart.classList.add('metrics-visualization__bars');
|
||||
|
||||
metricsData.forEach(run => {
|
||||
const bar = document.createElement('div');
|
||||
bar.classList.add('metrics-visualization__bar');
|
||||
const height = maxWarnRate > 0 ? (run.warn_rate / maxWarnRate) * 100 : 0;
|
||||
bar.style.setProperty('--bar-height', `${height}%`);
|
||||
bar.setAttribute('title', `Run ${run.run_id}: warn_rate ${run.warn_rate}`);
|
||||
|
||||
const label = document.createElement('span');
|
||||
label.classList.add('metrics-visualization__bar-label');
|
||||
label.textContent = run.run_id;
|
||||
|
||||
bar.appendChild(label);
|
||||
chart.appendChild(bar);
|
||||
});
|
||||
chartContainer.appendChild(chart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Füllt die Tabelle mit Metrikdaten und Run-Vergleichen.
|
||||
* @param {Array<Object>} metricsData - Metrikdaten aus der API.
|
||||
* @param {HTMLTableSectionElement} tableBody - tbody-Element zur Befüllung.
|
||||
*/
|
||||
export function renderTable(metricsData, tableBody) {
|
||||
if (!tableBody) return;
|
||||
tableBody.innerHTML = '';
|
||||
|
||||
if (!Array.isArray(metricsData) || metricsData.length === 0) {
|
||||
const row = document.createElement('tr');
|
||||
const cell = document.createElement('td');
|
||||
cell.colSpan = 6;
|
||||
cell.textContent = 'Keine Daten vorhanden';
|
||||
row.appendChild(cell);
|
||||
tableBody.appendChild(row);
|
||||
return;
|
||||
}
|
||||
|
||||
metricsData.forEach(run => {
|
||||
const row = document.createElement('tr');
|
||||
|
||||
const idCell = document.createElement('td');
|
||||
idCell.textContent = run.run_id;
|
||||
const setupCell = document.createElement('td');
|
||||
setupCell.textContent = run.setup_fingerprint;
|
||||
const warnCell = document.createElement('td');
|
||||
warnCell.textContent = run.warn_rate?.toFixed(3) ?? '-';
|
||||
const unknownCell = document.createElement('td');
|
||||
unknownCell.textContent = run.unknown_rate?.toFixed(3) ?? '-';
|
||||
const deltaCell = document.createElement('td');
|
||||
deltaCell.textContent = run.delta_t_stats ?? '-';
|
||||
const timeCell = document.createElement('td');
|
||||
const date = new Date(run.timestamp);
|
||||
timeCell.textContent = isNaN(date.getTime()) ? '-' : date.toLocaleString();
|
||||
|
||||
row.append(idCell, setupCell, warnCell, unknownCell, deltaCell, timeCell);
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtert Metrikdaten anhand der vom Nutzer gewählten Kriterien.
|
||||
* @param {Array<Object>} allMetrics - Alle verfügbaren Metrikdaten.
|
||||
* @param {Object} filters - Vom Nutzer gewählte Filterkriterien.
|
||||
* @param {('all'|'pinned'|'unpinned')} [filters.type='all'] - Filtern nach pinned/unpinned.
|
||||
* @param {string|null} [filters.setupFingerprint=null] - Optionaler Setup-Fingerprint zum Vergleich.
|
||||
* @returns {Array<Object>} Gefilterte Metrikdaten.
|
||||
*/
|
||||
export function applyFilters(allMetrics, filters = {}) {
|
||||
const { type = 'all', setupFingerprint = null } = filters;
|
||||
let result = Array.isArray(allMetrics) ? [...allMetrics] : [];
|
||||
|
||||
if (setupFingerprint) {
|
||||
result = result.filter(d => d.setup_fingerprint === setupFingerprint);
|
||||
}
|
||||
if (type === 'pinned') {
|
||||
result = result.filter(d => d.pinned === true);
|
||||
} else if (type === 'unpinned') {
|
||||
result = result.filter(d => d.pinned === false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialisiert UI-Events für Filterung.
|
||||
* @param {Function} onFilterChange - Callback, z. B. fetchMetrics(Filter).
|
||||
*/
|
||||
export function initFilterListeners(onFilterChange) {
|
||||
const filterForm = document.querySelector('#filter-panel');
|
||||
if (!filterForm) return;
|
||||
|
||||
filterForm.addEventListener('change', () => {
|
||||
const type = filterForm.querySelector('[name="runFilter"]:checked')?.value ?? 'all';
|
||||
const setupFingerprint = filterForm.querySelector('[name="setupFingerprint"]')?.value || null;
|
||||
onFilterChange({ type, setupFingerprint });
|
||||
});
|
||||
}
|
||||
|
||||
// Bar-Darstellung Style-Vorgabe per CSS Variable (wird über CSS Datei gehandhabt).
|
||||
Loading…
Reference in a new issue