diff --git a/src/components/httprequestviewer/lib/csvExport.ts b/src/components/httprequestviewer/lib/csvExport.ts index d5fd0dd..0e6134f 100644 --- a/src/components/httprequestviewer/lib/csvExport.ts +++ b/src/components/httprequestviewer/lib/csvExport.ts @@ -14,14 +14,14 @@ const DEFAULT_COLUMNS = [ 'priority', 'protocol', 'connectionNumber', - 'requestNumber', - 'startTime', - 'queueTime', + 'requestNumberOnConnection', + 'timing.start', + 'timing.queueTime', 'dnsTime', 'connectionTime', - 'serverLatency', - 'duration', - 'totalResponseTime', + 'timing.serverLatency', + 'timing.duration', + 'timing.totalResponseTime', 'dataRate', 'size', 'contentLength', @@ -55,6 +55,34 @@ const formatCSVValue = (value: any): string => { return stringValue } +// Calculate derived values for CSV export +const calculateDerivedValue = (request: HTTPRequest, path: string): any => { + switch (path) { + case 'dnsTime': + if (request.timing.dnsStart !== undefined && request.timing.dnsEnd !== undefined && + request.timing.dnsStart >= 0 && request.timing.dnsEnd >= 0) { + return request.timing.dnsEnd - request.timing.dnsStart + } + return null + case 'connectionTime': + if (request.timing.connectStart !== undefined && request.timing.connectEnd !== undefined && + request.timing.connectStart >= 0 && request.timing.connectEnd >= 0) { + return request.timing.connectEnd - request.timing.connectStart + } + return null + case 'dataRate': + if (!request.timing.duration || request.timing.duration <= 0) return null + const bytes = request.contentLength && request.contentLength > 0 ? request.contentLength : request.encodedDataLength + if (!bytes) return null + const durationSeconds = request.timing.duration / 1000000 + return bytes / durationSeconds // bytes per second + case 'size': + return request.encodedDataLength || request.contentLength || null + default: + return getNestedValue(request, path) + } +} + // Get nested property value from object const getNestedValue = (obj: any, path: string): any => { return path.split('.').reduce((current, key) => { @@ -81,12 +109,40 @@ export const exportRequestsToCSV = ( // Add headers if requested if (includeHeaders) { const headers = selectedColumns.map(col => { - // Clean up column names for headers - return col - .replace(/([A-Z])/g, ' $1') // Add space before capitals - .replace(/^\w/, c => c.toUpperCase()) // Capitalize first letter - .replace(/\./g, ' ') // Replace dots with spaces - .trim() + // Add units to timing-related headers + switch (col) { + case 'timing.start': + return 'Start Time (μs)' + case 'timing.queueTime': + return 'Queue Time (μs)' + case 'dnsTime': + return 'DNS Time (μs)' + case 'connectionTime': + return 'Connection Time (μs)' + case 'timing.serverLatency': + return 'Server Latency (μs)' + case 'timing.duration': + return 'Duration (μs)' + case 'timing.totalResponseTime': + return 'Total Response Time (μs)' + case 'timing.downloadTime': + return 'Download Time (μs)' + case 'dataRate': + return 'Data Rate (bytes/sec)' + case 'size': + return 'Size (bytes)' + case 'contentLength': + return 'Content Length (bytes)' + case 'encodedDataLength': + return 'Encoded Data Length (bytes)' + default: + // Clean up column names for other headers + return col + .replace(/([A-Z])/g, ' $1') // Add space before capitals + .replace(/^\w/, c => c.toUpperCase()) // Capitalize first letter + .replace(/\./g, ' ') // Replace dots with spaces + .trim() + } }) lines.push(headers.map(formatCSVValue).join(',')) } @@ -94,7 +150,7 @@ export const exportRequestsToCSV = ( // Add data rows for (const request of requests) { const values = selectedColumns.map(column => { - const value = getNestedValue(request, column) + const value = calculateDerivedValue(request, column) return formatCSVValue(value) }) lines.push(values.join(','))