diff --git a/src/components/httprequestviewer/HTTPRequestViewer.module.css b/src/components/httprequestviewer/HTTPRequestViewer.module.css index e69de29..8fee649 100644 --- a/src/components/httprequestviewer/HTTPRequestViewer.module.css +++ b/src/components/httprequestviewer/HTTPRequestViewer.module.css @@ -0,0 +1,129 @@ +.container { + padding: 20px; +} + +.errorContainer { + display: flex; + justify-content: center; + align-items: center; + min-height: 400px; +} + +.errorMessage { + background: #fee; + border: 1px solid #fcc; + padding: 20px; + border-radius: 8px; + text-align: center; +} + +.errorMessage h3 { + color: #c33; + margin-bottom: 10px; +} + +.exportControls { + display: flex; + justify-content: flex-end; + margin: 15px 0; + padding: 10px 0; + border-bottom: 1px solid #e0e0e0; +} + +.downloadButton { + background: #4CAF50; + color: white; + border: none; + padding: 10px 16px; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + font-weight: 500; + transition: background-color 0.2s ease; + display: flex; + align-items: center; + gap: 6px; +} + +.downloadButton:hover:not(:disabled) { + background: #45a049; +} + +.downloadButton:disabled { + background: #cccccc; + cursor: not-allowed; +} + +.modalOverlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.7); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.modalContainer { + background: white; + border-radius: 12px; + width: 95vw; + height: 95vh; + display: flex; + flex-direction: column; + overflow: hidden; + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); +} + +.modalHeader { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20px; + border-bottom: 1px solid #e0e0e0; + background: #f8f9fa; +} + +.modalTitle { + margin: 0; + color: #333; + font-size: 18px; +} + +.modalCloseButton { + background: #dc3545; + color: white; + border: none; + padding: 8px 16px; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + font-weight: 500; +} + +.modalCloseButton:hover { + background: #c82333; +} + +.modalContent { + flex: 1; + padding: 0; + overflow: hidden; +} + +.modalLegend { + background: #f8f9fa; + border-top: 1px solid #e0e0e0; + padding: 15px 20px; + font-size: 13px; + line-height: 1.5; + max-height: 200px; + overflow-y: auto; +} + +.modalLegend div { + margin-bottom: 4px; +} \ No newline at end of file diff --git a/src/components/httprequestviewer/HTTPRequestViewer.tsx b/src/components/httprequestviewer/HTTPRequestViewer.tsx index 253a135..bfa2555 100644 --- a/src/components/httprequestviewer/HTTPRequestViewer.tsx +++ b/src/components/httprequestviewer/HTTPRequestViewer.tsx @@ -58,6 +58,7 @@ import type { HTTPRequest, ScreenshotEvent } from './types/httpRequest' import HTTPRequestLoading from "./HTTPRequestLoading.tsx"; import sortRequests from "./lib/sortRequests.ts"; import PaginationControls from "./PaginationControls.tsx"; +import { exportRequestsToCSV, downloadCSV } from './lib/csvExport'; interface HTTPRequestViewerProps { @@ -382,6 +383,15 @@ export default function HTTPRequestViewer({ traceId }: HTTPRequestViewerProps) { setExpandedRows(newExpanded) } + const handleDownloadCSV = () => { + const csvContent = exportRequestsToCSV(filteredRequests, { + includeHeaders: true + }) + const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5) + const filename = `http-requests-${timestamp}.csv` + downloadCSV(csvContent, filename) + } + if (loading) { return ( @@ -439,6 +449,17 @@ export default function HTTPRequestViewer({ traceId }: HTTPRequestViewerProps) { handleSSIMRecalculate={handleSSIMRecalculate} /> + {/* Export Controls */} +