UNPKG

profoundjs

Version:

Profound.js Framework and Server

216 lines (183 loc) 7.04 kB
"use strict"; document.addEventListener("DOMContentLoaded", () => { if (!sessionStorage["atrium-token"]) { const currentUrl = window.location.pathname + window.location.search; window.location.href = "/auto-testing/login?redirect=" + encodeURIComponent(currentUrl); return; } const reportContainer = document.getElementById("report-container"); const refreshButton = document.getElementById("refresh-button"); const urlParams = new URLSearchParams(window.location.search); const runIds = urlParams.getAll("runId"); if (runIds.length < 2) { reportContainer.innerHTML = '<div class="error-message">Please provide at least 2 run IDs as query parameters (e.g. ?runId=A&runId=B).</div>'; return; } function formatTime(ms) { if (ms == null || ms === "" || ms === "0" || ms === 0) return "--"; const num = parseFloat(ms); if (isNaN(num)) return "--"; if (num >= 1000) { return (num / 1000).toFixed(2) + "s"; } return Math.round(num) + "ms"; } function formatDiff(diff) { if (diff === 0) return ""; const sign = diff > 0 ? "+" : ""; if (Math.abs(diff) >= 1000) { return sign + (diff / 1000).toFixed(2) + "s"; } return sign + Math.round(diff) + "ms"; } function fetchPerformanceData() { reportContainer.innerHTML = '<div class="spinner"></div>'; const headers = { "Content-Type": "application/json" }; if (sessionStorage["atrium-token"]) { headers["Authorization"] = "Basic " + sessionStorage["atrium-token"]; } fetch("/auto-testing/performance-data", { method: "POST", headers, body: JSON.stringify({ runIds: runIds }) }) .then(res => res.json()) .then(data => { if (data.error) { reportContainer.innerHTML = '<div class="error-message">' + data.error + "</div>"; return; } renderReport(data); }) .catch(err => { console.error("Error fetching performance data:", err); reportContainer.innerHTML = '<div class="error-message">Unable to fetch performance data. Please check your connection.</div>'; }); } function formatRunTimestamp(arstart) { if (!arstart) return ""; const arstartParts = arstart.split("-"); const arstartTimeParts = arstartParts[3].split("."); const d = new Date(`${arstartParts[0]}-${arstartParts[1]}-${arstartParts[2]} ${arstartTimeParts[0]}:${arstartTimeParts[1]}:${arstartTimeParts[2]}`); if (isNaN(d.getTime())) return ""; return d.toLocaleString(); } function renderReport(data) { const runs = data.runs; const orderedRunIds = data.runIds.filter(id => runs[id]); if (orderedRunIds.length === 0) { reportContainer.innerHTML = '<div class="error-message">No run data found.</div>'; return; } // Get step count from the first run const firstRun = runs[orderedRunIds[0]]; const stepCount = firstRun.steps.length; // Build header let html = '<table id="perf-table">'; html += "<thead><tr>"; html += "<th>Step</th>"; html += "<th>Step Name</th>"; for (const runId of orderedRunIds) { const run = runs[runId]; const timestamp = formatRunTimestamp(run.arstart); html += '<th class="run-header">' + (run.environment || "N/A"); if (timestamp) { html += '<br><span class="run-timestamp">' + timestamp + "</span>"; } html += '<br><span class="run-id">' + runId + "</span>"; html += "</th>"; } html += "</tr></thead>"; html += "<tbody>"; // Collect totals per run const totals = {}; for (const runId of orderedRunIds) { totals[runId] = 0; } // Build rows for each step for (let i = 0; i < stepCount; i++) { const stepName = firstRun.steps[i].name || ("Step " + firstRun.steps[i].seq); // Collect times for this step across all runs const times = {}; for (const runId of orderedRunIds) { const step = runs[runId].steps[i]; const time = step ? parseFloat(step.runtime) : NaN; times[runId] = isNaN(time) ? null : time; if (times[runId] != null && times[runId] > 0) { totals[runId] += times[runId]; } } // Find min and max among valid times (> 0) const validTimes = orderedRunIds .map(id => times[id]) .filter(t => t != null && t > 0); const minTime = validTimes.length > 0 ? Math.min(...validTimes) : null; const maxTime = validTimes.length > 0 ? Math.max(...validTimes) : null; // Compute the reference (fastest) time for diffs const refTime = minTime; html += "<tr>"; html += "<td>" + (i + 1) + "</td>"; html += '<td class="step-name">' + escapeHtml(stepName) + "</td>"; for (const runId of orderedRunIds) { const t = times[runId]; if (t == null || t === 0) { html += '<td class="time-cell">--</td>'; continue; } let cssClass = "time-cell"; // Only color-code if there are at least 2 valid times and they differ if (validTimes.length >= 2 && minTime !== maxTime) { if (t === minTime) cssClass += " fastest"; else if (t === maxTime) cssClass += " slowest"; } let diffHtml = ""; if (refTime != null && refTime > 0 && t !== refTime) { const diff = t - refTime; diffHtml = ' <span class="time-diff">(' + formatDiff(diff) + ")</span>"; } html += '<td class="' + cssClass + '">' + formatTime(t) + diffHtml + "</td>"; } html += "</tr>"; } // Total row const totalValues = orderedRunIds .map(id => totals[id]) .filter(t => t > 0); const minTotal = totalValues.length > 0 ? Math.min(...totalValues) : null; const maxTotal = totalValues.length > 0 ? Math.max(...totalValues) : null; const refTotal = minTotal; html += '<tr class="total-row">'; html += "<td></td>"; html += '<td class="step-name">Total</td>'; for (const runId of orderedRunIds) { const t = totals[runId]; if (t === 0) { html += '<td class="time-cell">--</td>'; continue; } let cssClass = "time-cell"; if (totalValues.length >= 2 && minTotal !== maxTotal) { if (t === minTotal) cssClass += " fastest"; else if (t === maxTotal) cssClass += " slowest"; } let diffHtml = ""; if (refTotal != null && refTotal > 0 && t !== refTotal) { const diff = t - refTotal; diffHtml = ' <span class="time-diff">(' + formatDiff(diff) + ")</span>"; } html += '<td class="' + cssClass + '">' + formatTime(t) + diffHtml + "</td>"; } html += "</tr>"; html += "</tbody></table>"; reportContainer.innerHTML = html; } function escapeHtml(text) { const div = document.createElement("div"); div.textContent = text; return div.innerHTML; } refreshButton.addEventListener("click", fetchPerformanceData); fetchPerformanceData(); });