Phase A.2 - Add expandable Request/Response Headers view

This commit is contained in:
2025-12-28 02:54:45 +11:00
parent aefa41f273
commit fbd73f4cdc
2 changed files with 53 additions and 0 deletions

View File

@@ -53,6 +53,10 @@ function parseHAR(lighthouseResult) {
isThirdParty: checkIfThirdParty(request.url, lighthouseResult.finalUrl), isThirdParty: checkIfThirdParty(request.url, lighthouseResult.finalUrl),
renderBlocking: request.renderBlocking === 'blocking', renderBlocking: request.renderBlocking === 'blocking',
// HTTP Headers
requestHeaders: request.requestHeaders || {},
responseHeaders: request.responseHeaders || {},
// Extracted from response headers if available // Extracted from response headers if available
cacheControl: request.responseHeaders?.['cache-control'], cacheControl: request.responseHeaders?.['cache-control'],
contentEncoding: request.responseHeaders?.['content-encoding'] contentEncoding: request.responseHeaders?.['content-encoding']

View File

@@ -415,6 +415,24 @@ function showRequestDetails(requestId) {
<span class="detail-value">${(entry.size.compressionRatio * 100).toFixed(1)}% (${formatBytes(entry.size.resourceSize - entry.size.transferSize)} saved)</span> <span class="detail-value">${(entry.size.compressionRatio * 100).toFixed(1)}% (${formatBytes(entry.size.resourceSize - entry.size.transferSize)} saved)</span>
</div>` : ''} </div>` : ''}
</div> </div>
<div class="detail-section">
<h3 onclick="toggleHeaderSection('request-headers')" style="cursor: pointer; user-select: none;">
Request Headers <span id="request-headers-icon">▼</span>
</h3>
<div id="request-headers-content" class="headers-content" style="display: none;">
${formatHeaders(entry.requestHeaders)}
</div>
</div>
<div class="detail-section">
<h3 onclick="toggleHeaderSection('response-headers')" style="cursor: pointer; user-select: none;">
Response Headers <span id="response-headers-icon">▼</span>
</h3>
<div id="response-headers-content" class="headers-content" style="display: none;">
${formatHeaders(entry.responseHeaders)}
</div>
</div>
`; `;
document.getElementById('dialogContent').innerHTML = content; document.getElementById('dialogContent').innerHTML = content;
@@ -463,5 +481,36 @@ function formatBytes(bytes) {
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
} }
function formatHeaders(headers) {
if (!headers || Object.keys(headers).length === 0) {
return '<p style="color: var(--color-text-secondary); font-style: italic;">No headers available</p>';
}
let html = '<div class="headers-list">';
Object.entries(headers).forEach(([key, value]) => {
html += `
<div class="header-row">
<span class="header-key">${key}:</span>
<span class="header-value">${value}</span>
</div>
`;
});
html += '</div>';
return html;
}
function toggleHeaderSection(sectionId) {
const content = document.getElementById(`${sectionId}-content`);
const icon = document.getElementById(`${sectionId}-icon`);
if (content.style.display === 'none') {
content.style.display = 'block';
icon.textContent = '▲';
} else {
content.style.display = 'none';
icon.textContent = '▼';
}
}
// Initialize on page load // Initialize on page load
document.addEventListener('DOMContentLoaded', init); document.addEventListener('DOMContentLoaded', init);