'use strict'; /** * @module ui * Verantwortlich für Rendering und Interaktion der UI-Komponenten. */ /** * Rendert oder aktualisiert das Diagramm basierend auf Metrikdaten. * @param {Array} 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} 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} 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} 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).