run_17_gates_default/artifact.visualization/js/ui.js

103 lines
3.3 KiB
JavaScript

'use strict';
/**
* @module ui
* Funktionen zur Aktualisierung der visuellen Komponenten (Karten und Diagramme)
*/
/**
* Aktualisiert die Kennzahlenkarten im DOM basierend auf API-Daten.
* @param {Object} retry_analysis_report - JSON Report aus der API /api/retry-stats
*/
export function renderSummaryCards(retry_analysis_report) {
const container = document.getElementById('stats-summary');
if (!container) return;
container.innerHTML = '';
const metrics = [
{ label: '\u0394t<0', value: retry_analysis_report?.delta_t_neg_rate ?? 'N/A', unit: '%' },
{ label: 'Warn Rate', value: retry_analysis_report?.warn_rate ?? 'N/A', unit: '%' },
{ label: 'Unknown Rate', value: retry_analysis_report?.unknown_rate ?? 'N/A', unit: '%' },
{ label: 'Heilungsrate', value: retry_analysis_report?.healing_rate ?? 'N/A', unit: '%' },
{ label: 'p95', value: retry_analysis_report?.p95 ?? 'N/A', unit: 'ms' },
{ label: 'p99', value: retry_analysis_report?.p99 ?? 'N/A', unit: 'ms' }
];
const frag = document.createDocumentFragment();
metrics.forEach(metric => {
const card = document.createElement('div');
card.className = 'summary-card';
const title = document.createElement('h3');
title.textContent = metric.label;
const value = document.createElement('p');
value.className = 'summary-card__value';
value.textContent = `${metric.value} ${metric.unit}`;
card.appendChild(title);
card.appendChild(value);
frag.appendChild(card);
});
container.appendChild(frag);
}
/**
* Erzeugt oder aktualisiert ein Diagramm in #retry-chart basierend auf API-Daten.
* @param {Object} retry_analysis_report - JSON Report aus der API /api/retry-stats
*/
export function renderRetryChart(retry_analysis_report) {
const chartContainer = document.getElementById('retry-chart');
if (!chartContainer) return;
chartContainer.innerHTML = '';
const canvas = document.createElement('canvas');
canvas.id = 'retryChartCanvas';
canvas.setAttribute('aria-label', 'Retry Statistik Diagramm');
chartContainer.appendChild(canvas);
const ctx = canvas.getContext('2d');
if (!ctx) return;
// Minimalistische Chart-Implementation ohne externe Libraries
const { stats = [] } = retry_analysis_report || {};
if (stats.length === 0) {
ctx.fillStyle = '#666';
ctx.font = '16px sans-serif';
ctx.fillText('Keine Daten verfügbar', 10, 30);
return;
}
const width = canvas.width = chartContainer.clientWidth || 400;
const height = canvas.height = 200;
const margin = 20;
const colorP95 = '#2c7';
const colorP99 = '#f93';
const maxValue = Math.max(...stats.map(s => Math.max(s.p95 ?? 0, s.p99 ?? 0)));
const barWidth = Math.max(5, (width - margin * 2) / stats.length);
stats.forEach((s, index) => {
const x = margin + index * barWidth;
const p95Height = ((s.p95 ?? 0) / maxValue) * (height - margin * 2);
const p99Height = ((s.p99 ?? 0) / maxValue) * (height - margin * 2);
// p95 bar
ctx.fillStyle = colorP95;
ctx.fillRect(x, height - p95Height - margin, barWidth * 0.4, p95Height);
// p99 bar
ctx.fillStyle = colorP99;
ctx.fillRect(x + barWidth * 0.5, height - p99Height - margin, barWidth * 0.4, p99Height);
});
// Axis Labels
ctx.fillStyle = '#000';
ctx.font = '12px sans-serif';
ctx.fillText('p95', 10, 12);
ctx.fillText('p99', 50, 12);
}