import React from 'react' import type { HTTPRequest } from './types/httpRequest' import InitiatorView from './InitiatorView' import styles from './RequestRowDetails.module.css' // Import utility functions import { formatDuration, formatSize } from './lib/formatUtils' import { getTotalResponseTimeClass, getQueueAnalysisIcon, getCDNIcon, getCDNDisplayName, getPriorityIcon } from './lib/colorUtils' interface RequestRowDetailsProps { request: HTTPRequest visibleColumns: Record } const RequestRowDetails: React.FC = ({ request, visibleColumns }) => { // Calculate the number of visible columns for colSpan const visibleColumnCount = Object.values(visibleColumns).filter(Boolean).length return (
{/* Request Details */}

Request Details

Request ID: {request.requestId}
Method: {request.method}
Priority: {getPriorityIcon(request.priority)} {request.priority || '-'}
MIME Type: {request.mimeType || '-'}
Content-Length: {request.contentLength ? formatSize(request.contentLength) : '-'}
From Cache: {request.fromCache ? 'Yes' : 'No'}
Connection Reused: {request.connectionReused ? 'Yes' : 'No'}
{/* Initiator Information */} {/* Network Timing */}

Network Timing

Start Time: {formatDuration(request.timing.startOffset)}
Queue Time: {formatDuration(request.timing.queueTime)} {request.queueAnalysis && ( {getQueueAnalysisIcon(request.queueAnalysis)} )}
Server Latency: {formatDuration(request.timing.serverLatency)}
Network Duration: {formatDuration(request.timing.duration)}
Total Response Time: {formatDuration(request.timing.totalResponseTime)}
Network Duration Only: {formatDuration(request.timing.networkDuration)}
{/* DNS Timing */}
DNS: { request.timing.dnsStart !== undefined && request.timing.dnsEnd !== undefined && request.timing.dnsStart >= 0 && request.timing.dnsEnd >= 0 ? formatDuration((request.timing.dnsEnd || 0) - (request.timing.dnsStart || 0)) : cached }
{/* Connection Timing */}
Connection: { request.timing.connectStart !== undefined && request.timing.connectEnd !== undefined && request.timing.connectStart >= 0 && request.timing.connectEnd >= 0 ? formatDuration((request.timing.connectEnd || 0) - (request.timing.connectStart || 0)) : {request.connectionReused ? 'reused' : 'cached'} }
{/* SSL Timing (only show if HTTPS and timing available) */} {(request.url.startsWith('https://') || request.protocol === 'h2') && (
SSL: { request.timing.sslStart !== undefined && request.timing.sslEnd !== undefined && request.timing.sslStart >= 0 && request.timing.sslEnd >= 0 ? formatDuration((request.timing.sslEnd || 0) - (request.timing.sslStart || 0)) : reused }
)} {/* Send Timing */} {request.timing.sendStart !== undefined && request.timing.sendEnd !== undefined && request.timing.sendStart >= 0 && request.timing.sendEnd >= 0 && (
Send: {formatDuration((request.timing.sendEnd || 0) - (request.timing.sendStart || 0))}
)} {/* Receive Headers Timing */} {request.timing.receiveHeadersStart !== undefined && request.timing.receiveHeadersEnd !== undefined && request.timing.receiveHeadersStart >= 0 && request.timing.receiveHeadersEnd >= 0 && (
Receive Headers: {formatDuration((request.timing.receiveHeadersEnd || 0) - (request.timing.receiveHeadersStart || 0))}
)}
{/* Queue Analysis */} {request.queueAnalysis && request.queueAnalysis.reason !== 'unknown' && (

Queue Analysis {getQueueAnalysisIcon(request.queueAnalysis)}

Reason: {request.queueAnalysis.description}
Concurrent Requests: {request.queueAnalysis.concurrentRequests}
{request.queueAnalysis.relatedRequests && request.queueAnalysis.relatedRequests.length > 0 && (
Related Request IDs:{' '} {request.queueAnalysis.relatedRequests.join(', ')} {request.queueAnalysis.concurrentRequests > request.queueAnalysis.relatedRequests.length && ` (+${request.queueAnalysis.concurrentRequests - request.queueAnalysis.relatedRequests.length} more)`}
)}
)} {/* CDN Analysis */} {request.cdnAnalysis && request.cdnAnalysis.provider !== 'unknown' && (

CDN Analysis {getCDNIcon(request.cdnAnalysis)}

Provider: {getCDNDisplayName(request.cdnAnalysis.provider)}
Source: {request.cdnAnalysis.isEdge ? 'Edge Server' : 'Origin Server'}
{request.cdnAnalysis.cacheStatus && request.cdnAnalysis.cacheStatus !== 'unknown' && (
Cache Status: {request.cdnAnalysis.cacheStatus.toUpperCase()}
)} {request.cdnAnalysis.edgeLocation && (
Edge Location: {request.cdnAnalysis.edgeLocation}
)}
Confidence: {(request.cdnAnalysis.confidence * 100).toFixed(0)}%
Detection Method: {request.cdnAnalysis.detectionMethod}
{/* Debug info for canadiantire.ca requests */} {(
Debug - CDN Detection Analysis:
Current Detection: {request.cdnAnalysis?.provider} (confidence: {((request.cdnAnalysis?.confidence || 0) * 100).toFixed(0)}%)
All CDN-Related Headers:
{request.responseHeaders && request.responseHeaders.map((header, idx) => { const headerName = header.name.toLowerCase() // Show all potentially CDN-related headers if (headerName.includes('akamai') || headerName.includes('fastly') || headerName.includes('server') || headerName.includes('via') || headerName.includes('x-cache') || headerName.includes('x-serial') || headerName.includes('x-served-by') || headerName.includes('cf-') || headerName.includes('x-amz-cf') || headerName.includes('azure') || headerName.includes('x-goog') || headerName.includes('cdn') || headerName.includes('edge') || headerName.includes('cache')) { const isAkamaiIndicator = headerName.includes('akamai') || headerName.includes('x-serial') || (headerName === 'x-cache' && header.value.includes('tcp_')) || (headerName === 'x-served-by' && header.value.includes('cache-')) return (
{header.name}: {header.value} {isAkamaiIndicator && ( ← AKAMAI )}
) } return null })}
)}
)} {/* Response Headers */} {request.responseHeaders && request.responseHeaders.length > 0 && (

Response Headers ({request.responseHeaders.length})

{request.responseHeaders.map((header, index) => (
{header.name}:
{header.value}
))}
)}
) } export default RequestRowDetails