@websublime/vite-plugin-open-api-devtools 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ModelsPage-DgFhUiBH.js → ModelsPage-DtwVBgEq.js} +6 -6
- package/dist/{ModelsPage-DgFhUiBH.js.map → ModelsPage-DtwVBgEq.js.map} +1 -1
- package/dist/{RoutesPage-DpasQCnt.js → RoutesPage-DVaFf1b6.js} +4 -4
- package/dist/{RoutesPage-DpasQCnt.js.map → RoutesPage-DVaFf1b6.js.map} +1 -1
- package/dist/{SimulatorPage-CDTgl8ax.js → SimulatorPage-QuwXPwEn.js} +4 -4
- package/dist/{SimulatorPage-CDTgl8ax.js.map → SimulatorPage-QuwXPwEn.js.map} +1 -1
- package/dist/{TimelinePage-CLlD6uZ8.js → TimelinePage-CYGTXXoL.js} +7 -7
- package/dist/{TimelinePage-CLlD6uZ8.js.map → TimelinePage-CYGTXXoL.js.map} +1 -1
- package/dist/{check-D8w72KaI.js → check-C8somSxy.js} +2 -2
- package/dist/{check-D8w72KaI.js.map → check-C8somSxy.js.map} +1 -1
- package/dist/devtools.css +1 -1
- package/dist/devtools.js +1 -1
- package/dist/devtools.umd.cjs +1 -1
- package/dist/devtools.umd.cjs.map +1 -1
- package/dist/{format-Bs9S93C7.js → format-9UQBRrMl.js} +2 -2
- package/dist/{format-Bs9S93C7.js.map → format-9UQBRrMl.js.map} +1 -1
- package/dist/{main-DUNgny3E.js → main-B4KUU1eG.js} +5 -5
- package/dist/{main-DUNgny3E.js.map → main-B4KUU1eG.js.map} +1 -1
- package/dist/spa/assets/{ModelsPage-BslYlawu.css → ModelsPage-8J4ivXTd.css} +1 -1
- package/dist/spa/assets/{ModelsPage-Ef8Z_K5t.js → ModelsPage-CGAzOf6p.js} +3 -3
- package/dist/spa/assets/{ModelsPage-Ef8Z_K5t.js.map → ModelsPage-CGAzOf6p.js.map} +1 -1
- package/dist/spa/assets/{RoutesPage-Rs-CBlOu.js → RoutesPage-DRs9ZFX4.js} +2 -2
- package/dist/spa/assets/{RoutesPage-Rs-CBlOu.js.map → RoutesPage-DRs9ZFX4.js.map} +1 -1
- package/dist/spa/assets/{SimulatorPage-CNh6VflM.js → SimulatorPage-DFNoxcRv.js} +2 -2
- package/dist/spa/assets/{SimulatorPage-CNh6VflM.js.map → SimulatorPage-DFNoxcRv.js.map} +1 -1
- package/dist/spa/assets/{TimelinePage-2YaDXdDB.js → TimelinePage-nthQiIag.js} +2 -2
- package/dist/spa/assets/{TimelinePage-2YaDXdDB.js.map → TimelinePage-nthQiIag.js.map} +1 -1
- package/dist/spa/assets/check-DPkOzfFg.js +2 -0
- package/dist/spa/assets/{check-CLk5nWxQ.js.map → check-DPkOzfFg.js.map} +1 -1
- package/dist/spa/assets/{format-YtVMCGJx.js → format-BBKRcMH2.js} +2 -2
- package/dist/spa/assets/{format-YtVMCGJx.js.map → format-BBKRcMH2.js.map} +1 -1
- package/dist/spa/assets/{index-sPgNGnaU.js → index-OjSRPocP.js} +3 -3
- package/dist/spa/assets/{index-sPgNGnaU.js.map → index-OjSRPocP.js.map} +1 -1
- package/dist/spa/assets/{trash-2-DCsOAZPr.js → trash-2-DVdyPNM4.js} +2 -2
- package/dist/spa/assets/{trash-2-DCsOAZPr.js.map → trash-2-DVdyPNM4.js.map} +1 -1
- package/dist/spa/assets/{triangle-alert-DD8Mz05K.js → triangle-alert-COSegcUH.js} +2 -2
- package/dist/spa/assets/{triangle-alert-DD8Mz05K.js.map → triangle-alert-COSegcUH.js.map} +1 -1
- package/dist/spa/assets/x-DC0rfJtM.js +2 -0
- package/dist/spa/assets/{x-5pbhNHo3.js.map → x-DC0rfJtM.js.map} +1 -1
- package/dist/spa/index.html +1 -1
- package/dist/{trash-2-BaiQpXqE.js → trash-2-BXKjlLnv.js} +2 -2
- package/dist/{trash-2-BaiQpXqE.js.map → trash-2-BXKjlLnv.js.map} +1 -1
- package/dist/{triangle-alert-CIaC9iQP.js → triangle-alert-BmO71UYi.js} +2 -2
- package/dist/{triangle-alert-CIaC9iQP.js.map → triangle-alert-BmO71UYi.js.map} +1 -1
- package/dist/{x-BI73Bc0z.js → x-cjNeCV9f.js} +2 -2
- package/dist/{x-BI73Bc0z.js.map → x-cjNeCV9f.js.map} +1 -1
- package/package.json +12 -12
- package/dist/spa/assets/check-CLk5nWxQ.js +0 -2
- package/dist/spa/assets/x-5pbhNHo3.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimelinePage-CLlD6uZ8.js","sources":["../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/circle-check-big.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/copy.js","../src/stores/timeline.ts","../src/components/TimelineDetail.vue","../src/components/TimelineEntry.vue","../src/pages/TimelinePage.vue"],"sourcesContent":["/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleCheckBig = createLucideIcon(\"circle-check-big\", [\n [\"path\", { d: \"M21.801 10A10 10 0 1 1 17 3.335\", key: \"yps3ct\" }],\n [\"path\", { d: \"m9 11 3 3L22 4\", key: \"1pflzl\" }]\n]);\n\nexport { CircleCheckBig as default };\n//# sourceMappingURL=circle-check-big.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Copy = createLucideIcon(\"copy\", [\n [\"rect\", { width: \"14\", height: \"14\", x: \"8\", y: \"8\", rx: \"2\", ry: \"2\", key: \"17jyea\" }],\n [\"path\", { d: \"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\", key: \"zix9uf\" }]\n]);\n\nexport { Copy as default };\n//# sourceMappingURL=copy.js.map\n","/**\n * Timeline Store\n *\n * What: Pinia store for managing request/response timeline data\n * How: Receives and stores timeline events from the server via WebSocket\n * Why: Provides reactive access to timeline data for the Timeline Page\n *\n * @module stores/timeline\n */\n\nimport { defineStore } from 'pinia';\nimport { computed, ref } from 'vue';\n\n/**\n * HTTP method type for timeline entries\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'TRACE';\n\n/**\n * Request log entry from the server\n */\nexport interface RequestLogEntry {\n id: string;\n method: string;\n path: string;\n operationId: string;\n timestamp: number;\n headers: Record<string, string>;\n query: Record<string, string | string[]>;\n body?: unknown;\n}\n\n/**\n * Response log entry from the server\n */\nexport interface ResponseLogEntry {\n id: string;\n requestId: string;\n status: number;\n duration: number;\n headers: Record<string, string>;\n body: unknown;\n simulated: boolean;\n}\n\n/**\n * Combined timeline entry with request and optional response\n */\nexport interface TimelineEntry {\n id: string;\n request: RequestLogEntry;\n response: ResponseLogEntry | null;\n status: number | null;\n duration: number | null;\n simulated: boolean;\n}\n\n/**\n * Timeline data from server\n */\nexport interface TimelineData {\n entries: Array<{ type: 'request' | 'response'; data: RequestLogEntry | ResponseLogEntry }>;\n count: number;\n total: number;\n}\n\n/**\n * Filter options for timeline entries\n */\nexport interface TimelineFilter {\n methods: HttpMethod[];\n statusCodes: ('1xx' | '2xx' | '3xx' | '4xx' | '5xx')[];\n searchQuery: string;\n simulatedOnly: boolean | null;\n}\n\n/**\n * Timeline store for request/response tracking\n *\n * Provides:\n * - Timeline entry storage and retrieval\n * - Real-time updates via WebSocket events\n * - Search and filter functionality\n * - Selected entry tracking for detail view\n * - Timeline limit management\n */\nexport const useTimelineStore = defineStore('timeline', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /** All timeline entries (request + response pairs) */\n const entries = ref<TimelineEntry[]>([]);\n\n /** Loading state */\n const isLoading = ref(false);\n\n /** Error state */\n const error = ref<string | null>(null);\n\n /** Active filters */\n const filter = ref<TimelineFilter>({\n methods: [],\n statusCodes: [],\n searchQuery: '',\n simulatedOnly: null,\n });\n\n /** Currently selected entry ID */\n const selectedEntryId = ref<string | null>(null);\n\n /** Maximum number of entries to keep */\n const maxEntries = ref(500);\n\n /** Buffer for responses that arrived before their requests */\n const responseBuffer = new Map<string, ResponseLogEntry>();\n\n // ==========================================================================\n // Getters / Computed\n // ==========================================================================\n\n /**\n * Get status category from status code\n */\n function getStatusCategory(status: number): '1xx' | '2xx' | '3xx' | '4xx' | '5xx' {\n if (status < 200) return '1xx';\n if (status < 300) return '2xx';\n if (status < 400) return '3xx';\n if (status < 500) return '4xx';\n return '5xx';\n }\n\n /**\n * Filtered entries based on search and filters\n */\n const filteredEntries = computed(() => {\n let result = entries.value;\n\n // Apply search query (matches path or operationId)\n if (filter.value.searchQuery.trim()) {\n const query = filter.value.searchQuery.toLowerCase().trim();\n result = result.filter((entry) => {\n return (\n entry.request.path.toLowerCase().includes(query) ||\n entry.request.operationId.toLowerCase().includes(query)\n );\n });\n }\n\n // Apply method filter\n if (filter.value.methods.length > 0) {\n result = result.filter((entry) =>\n filter.value.methods.includes(entry.request.method.toUpperCase() as HttpMethod),\n );\n }\n\n // Apply status code filter\n if (filter.value.statusCodes.length > 0) {\n result = result.filter((entry) => {\n if (entry.status === null) return false;\n const category = getStatusCategory(entry.status);\n return filter.value.statusCodes.includes(category);\n });\n }\n\n // Apply simulated filter\n if (filter.value.simulatedOnly !== null) {\n result = result.filter((entry) => entry.simulated === filter.value.simulatedOnly);\n }\n\n return result;\n });\n\n /**\n * Currently selected entry\n */\n const selectedEntry = computed(() => {\n if (!selectedEntryId.value) return null;\n return entries.value.find((e) => e.id === selectedEntryId.value) ?? null;\n });\n\n /**\n * Total number of entries (including pending responses)\n */\n const totalCount = computed(() => entries.value.length);\n\n /**\n * Count of entries with responses\n */\n const completedCount = computed(() => entries.value.filter((e) => e.response !== null).length);\n\n /**\n * Count of pending requests (no response yet)\n */\n const pendingCount = computed(() => entries.value.filter((e) => e.response === null).length);\n\n /**\n * Count of entries by status category\n */\n const statusCounts = computed(() => {\n const counts = {\n '1xx': 0,\n '2xx': 0,\n '3xx': 0,\n '4xx': 0,\n '5xx': 0,\n };\n\n for (const entry of entries.value) {\n if (entry.status !== null) {\n const category = getStatusCategory(entry.status);\n counts[category]++;\n }\n }\n\n return counts;\n });\n\n /**\n * Average response duration in milliseconds\n */\n const averageDuration = computed(() => {\n const completedEntries = entries.value.filter((e) => e.duration !== null);\n if (completedEntries.length === 0) return 0;\n\n const totalDuration = completedEntries.reduce((sum, e) => sum + (e.duration ?? 0), 0);\n return Math.round(totalDuration / completedEntries.length);\n });\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Add a request to the timeline\n */\n function addRequest(request: RequestLogEntry): void {\n const entry: TimelineEntry = {\n id: request.id,\n request,\n response: null,\n status: null,\n duration: null,\n simulated: false,\n };\n\n // Check if there's a buffered response for this request\n const bufferedResponse = responseBuffer.get(request.id);\n if (bufferedResponse) {\n mergeResponse(entry, bufferedResponse);\n // Clear consumed buffered response\n responseBuffer.delete(request.id);\n }\n\n // Add to beginning of array (newest first)\n entries.value.unshift(entry);\n\n // Trim to max entries\n if (entries.value.length > maxEntries.value) {\n entries.value = entries.value.slice(0, maxEntries.value);\n }\n }\n\n /**\n * Add a response to an existing request\n */\n function addResponse(response: ResponseLogEntry): void {\n const entry = entries.value.find((e) => e.id === response.requestId);\n if (entry) {\n // Entry exists, merge immediately\n mergeResponse(entry, response);\n // Clear from buffer if it was buffered\n responseBuffer.delete(response.requestId);\n } else {\n // Entry doesn't exist yet, buffer the response\n responseBuffer.set(response.requestId, response);\n\n // Prevent unbounded buffer growth: create stub entry if buffer exceeds threshold\n // This ensures orphaned responses don't cause memory leaks in real-time scenarios\n if (responseBuffer.size > 100) {\n const stubEntry = createStubEntry(response);\n entries.value.unshift(stubEntry);\n responseBuffer.delete(response.requestId);\n\n // Trim to max entries\n if (entries.value.length > maxEntries.value) {\n entries.value = entries.value.slice(0, maxEntries.value);\n }\n }\n }\n }\n\n /**\n * Merge a response into an entry\n */\n function mergeResponse(entry: TimelineEntry, response: ResponseLogEntry): void {\n entry.response = response;\n entry.status = response.status;\n entry.duration = response.duration;\n entry.simulated = response.simulated;\n }\n\n /**\n * Create a stub entry for an orphaned response\n */\n function createStubEntry(response: ResponseLogEntry): TimelineEntry {\n // Create a minimal request stub for the orphaned response\n const stubRequest: RequestLogEntry = {\n id: response.requestId,\n method: 'UNKNOWN',\n path: '/unknown',\n operationId: 'unknown',\n timestamp: Date.now(), // Use current time as fallback\n headers: {},\n query: {},\n body: undefined,\n };\n\n return {\n id: response.requestId,\n request: stubRequest,\n response,\n status: response.status,\n duration: response.duration,\n simulated: response.simulated,\n };\n }\n\n /**\n * Process buffered responses and merge with existing entries or create stubs\n */\n function processBufferedResponses(requestMap: Map<string, TimelineEntry>): void {\n for (const [requestId, response] of responseBuffer) {\n const entry = requestMap.get(requestId);\n if (entry) {\n mergeResponse(entry, response);\n responseBuffer.delete(requestId);\n } else {\n // No matching request found, create stub entry\n requestMap.set(requestId, createStubEntry(response));\n responseBuffer.delete(requestId);\n }\n }\n }\n\n /**\n * Process incoming responses and merge, buffer, or create stub entries\n */\n function processIncomingResponses(\n requestMap: Map<string, TimelineEntry>,\n incomingResponses: Map<string, ResponseLogEntry>,\n ): void {\n for (const [requestId, response] of incomingResponses) {\n const entry = requestMap.get(requestId);\n if (entry) {\n mergeResponse(entry, response);\n } else {\n // Buffer the response for potential future request\n // Note: During initial load, we'll create stubs later\n responseBuffer.set(requestId, response);\n }\n }\n }\n\n /**\n * Create stub entries for any remaining buffered responses\n * This ensures no response is lost even if its request never arrives\n */\n function createStubsForOrphanedResponses(requestMap: Map<string, TimelineEntry>): void {\n for (const [requestId, response] of responseBuffer) {\n if (!requestMap.has(requestId)) {\n requestMap.set(requestId, createStubEntry(response));\n responseBuffer.delete(requestId);\n }\n }\n }\n\n /**\n * Set timeline data from server response\n * Used when fetching initial timeline data\n */\n function setTimelineData(data: TimelineData): void {\n const requestMap = new Map<string, TimelineEntry>();\n const incomingResponses = new Map<string, ResponseLogEntry>();\n\n // First pass: collect all requests and responses\n for (const item of data.entries) {\n if (item.type === 'request') {\n const request = item.data as RequestLogEntry;\n requestMap.set(request.id, {\n id: request.id,\n request,\n response: null,\n status: null,\n duration: null,\n simulated: false,\n });\n } else if (item.type === 'response') {\n const response = item.data as ResponseLogEntry;\n incomingResponses.set(response.requestId, response);\n }\n }\n\n // Second pass: merge responses with requests\n processBufferedResponses(requestMap);\n processIncomingResponses(requestMap, incomingResponses);\n\n // Third pass: create stub entries for any remaining orphaned responses\n // This ensures no response is lost even if its request never arrives\n createStubsForOrphanedResponses(requestMap);\n\n // Convert map to array and sort by timestamp (newest first)\n const sorted = Array.from(requestMap.values()).sort(\n (a, b) => b.request.timestamp - a.request.timestamp,\n );\n\n // Apply maxEntries limit\n entries.value = sorted.slice(0, maxEntries.value);\n\n error.value = null;\n }\n\n /**\n * Clear all timeline entries\n */\n function clearTimeline(): void {\n entries.value = [];\n selectedEntryId.value = null;\n responseBuffer.clear();\n }\n\n /**\n * Set loading state\n */\n function setLoading(loading: boolean): void {\n isLoading.value = loading;\n }\n\n /**\n * Set error state\n */\n function setError(errorMessage: string): void {\n error.value = errorMessage;\n isLoading.value = false;\n }\n\n /**\n * Clear error state\n */\n function clearError(): void {\n error.value = null;\n }\n\n /**\n * Set search query\n */\n function setSearchQuery(query: string): void {\n filter.value.searchQuery = query;\n }\n\n /**\n * Toggle method filter\n */\n function toggleMethodFilter(method: HttpMethod): void {\n const index = filter.value.methods.indexOf(method);\n if (index === -1) {\n filter.value.methods.push(method);\n } else {\n filter.value.methods.splice(index, 1);\n }\n }\n\n /**\n * Toggle status code filter\n */\n function toggleStatusFilter(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): void {\n const index = filter.value.statusCodes.indexOf(status);\n if (index === -1) {\n filter.value.statusCodes.push(status);\n } else {\n filter.value.statusCodes.splice(index, 1);\n }\n }\n\n /**\n * Set simulated filter\n */\n function setSimulatedFilter(simulated: boolean | null): void {\n filter.value.simulatedOnly = simulated;\n }\n\n /**\n * Clear all filters\n */\n function clearFilters(): void {\n filter.value = {\n methods: [],\n statusCodes: [],\n searchQuery: '',\n simulatedOnly: null,\n };\n }\n\n /**\n * Check if any filter is active\n */\n function hasActiveFilters(): boolean {\n return (\n filter.value.searchQuery.trim() !== '' ||\n filter.value.methods.length > 0 ||\n filter.value.statusCodes.length > 0 ||\n filter.value.simulatedOnly !== null\n );\n }\n\n /**\n * Select an entry by ID\n */\n function selectEntry(id: string | null): void {\n selectedEntryId.value = id;\n }\n\n /**\n * Set maximum entries limit\n */\n function setMaxEntries(limit: number): void {\n // Clamp limit to a safe minimum\n const clamped = Math.max(1, limit);\n maxEntries.value = clamped;\n\n // Trim if necessary\n if (entries.value.length > clamped) {\n entries.value = entries.value.slice(0, clamped);\n }\n }\n\n // ==========================================================================\n // Return\n // ==========================================================================\n\n return {\n // State\n entries,\n isLoading,\n error,\n filter,\n selectedEntryId,\n maxEntries,\n\n // Getters\n filteredEntries,\n selectedEntry,\n totalCount,\n completedCount,\n pendingCount,\n statusCounts,\n averageDuration,\n\n // Actions\n addRequest,\n addResponse,\n setTimelineData,\n clearTimeline,\n setLoading,\n setError,\n clearError,\n setSearchQuery,\n toggleMethodFilter,\n toggleStatusFilter,\n setSimulatedFilter,\n clearFilters,\n hasActiveFilters,\n selectEntry,\n setMaxEntries,\n };\n});\n","<!--\n TimelineDetail.vue - Timeline Entry Detail Panel\n\n What: Displays full request and response details for a selected timeline entry\n How: Shows headers, query params, body content in organized collapsible sections\n Why: Allows developers to inspect API traffic in detail for debugging\n-->\n\n<script setup lang=\"ts\">\nimport { Check, ChevronDown, ChevronRight, Clock, Copy, Zap } from 'lucide-vue-next';\n\nimport { computed, ref } from 'vue';\n\nimport type { TimelineEntry } from '@/stores/timeline';\n\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** The timeline entry to display */\n entry: TimelineEntry | null;\n}\n\nconst props = defineProps<Props>();\n\n/**\n * Section expansion state\n */\nconst expandedSections = ref({\n requestHeaders: true,\n requestQuery: true,\n requestBody: true,\n responseHeaders: true,\n responseBody: true,\n});\n\n/**\n * Copy feedback state\n */\nconst copiedField = ref<string | null>(null);\n\n/**\n * Format timestamp for display\n */\nconst formattedTimestamp = computed(() => {\n if (!props.entry) return '';\n const date = new Date(props.entry.request.timestamp);\n return date.toLocaleString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: 3,\n hour12: false,\n });\n});\n\n/**\n * Format duration for display\n */\nconst formattedDuration = computed(() => {\n if (props.entry?.duration == null) return 'pending...';\n if (props.entry.duration < 1000) {\n return `${props.entry.duration}ms`;\n }\n return `${(props.entry.duration / 1000).toFixed(2)}s`;\n});\n\n/**\n * Get status badge class based on status code\n */\nconst statusClass = computed(() => {\n if (!props.entry?.status) return 'status-badge--pending';\n if (props.entry.status < 200) return 'status-badge--1xx';\n if (props.entry.status < 300) return 'status-badge--2xx';\n if (props.entry.status < 400) return 'status-badge--3xx';\n if (props.entry.status < 500) return 'status-badge--4xx';\n return 'status-badge--5xx';\n});\n\n/**\n * Check if request has query parameters\n */\nconst hasQueryParams = computed(() => {\n if (!props.entry?.request.query) return false;\n return Object.keys(props.entry.request.query).length > 0;\n});\n\n/**\n * Check if request has headers\n */\nconst hasRequestHeaders = computed(() => {\n if (!props.entry?.request.headers) return false;\n return Object.keys(props.entry.request.headers).length > 0;\n});\n\n/**\n * Check if request has body\n */\nconst hasRequestBody = computed(() => {\n return props.entry?.request.body !== undefined && props.entry?.request.body !== null;\n});\n\n/**\n * Check if response has headers\n */\nconst hasResponseHeaders = computed(() => {\n if (!props.entry?.response?.headers) return false;\n return Object.keys(props.entry.response.headers).length > 0;\n});\n\n/**\n * Check if response has body\n */\nconst hasResponseBody = computed(() => {\n return props.entry?.response?.body !== undefined && props.entry?.response?.body !== null;\n});\n\n/**\n * Format JSON for display\n */\nfunction formatJson(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Toggle section expansion\n */\nfunction toggleSection(section: keyof typeof expandedSections.value): void {\n expandedSections.value[section] = !expandedSections.value[section];\n}\n\n/**\n * Copy text to clipboard\n */\nasync function copyToClipboard(text: string, fieldId: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n copiedField.value = fieldId;\n setTimeout(() => {\n copiedField.value = null;\n }, 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n}\n\n/**\n * Copy full entry as JSON\n */\nasync function copyFullEntry(): Promise<void> {\n if (!props.entry) return;\n const data = {\n request: props.entry.request,\n response: props.entry.response,\n };\n await copyToClipboard(JSON.stringify(data, null, 2), 'full');\n}\n</script>\n\n<template>\n <div class=\"timeline-detail\">\n <!-- Empty state -->\n <div v-if=\"!entry\" class=\"timeline-detail__empty\">\n <Clock :size=\"48\" class=\"timeline-detail__empty-icon\" />\n <h3 class=\"timeline-detail__empty-title\">Select an entry</h3>\n <p class=\"timeline-detail__empty-description\">\n Click on a timeline entry to view its details.\n </p>\n </div>\n\n <!-- Entry details -->\n <div v-else class=\"timeline-detail__content\">\n <!-- Header with summary -->\n <div class=\"timeline-detail__header\">\n <div class=\"timeline-detail__summary\">\n <span :class=\"['method-badge', `method-badge--${entry.request.method.toLowerCase()}`]\">\n {{ getMethodLabel(entry.request.method) }}\n </span>\n <span class=\"timeline-detail__path font-mono\">{{ entry.request.path }}</span>\n </div>\n\n <div class=\"timeline-detail__meta\">\n <span v-if=\"entry.status !== null\" :class=\"['status-badge', statusClass]\">\n {{ entry.status }}\n </span>\n <span v-else class=\"status-badge status-badge--pending\">pending</span>\n\n <span class=\"timeline-detail__duration\">\n <Clock :size=\"14\" />\n {{ formattedDuration }}\n </span>\n\n <span v-if=\"entry.simulated\" class=\"timeline-detail__simulated\" title=\"Simulated response\">\n <Zap :size=\"14\" />\n Simulated\n </span>\n </div>\n\n <div class=\"timeline-detail__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--sm\"\n title=\"Copy as JSON\"\n @click=\"copyFullEntry\"\n >\n <component :is=\"copiedField === 'full' ? Check : Copy\" :size=\"14\" />\n {{ copiedField === 'full' ? 'Copied!' : 'Copy JSON' }}\n </button>\n </div>\n </div>\n\n <!-- Info section -->\n <div class=\"timeline-detail__info\">\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Timestamp</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ formattedTimestamp }}</span>\n </div>\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Operation ID</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ entry.request.operationId }}</span>\n </div>\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Request ID</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ entry.id }}</span>\n </div>\n </div>\n\n <!-- Request section -->\n <div class=\"timeline-detail__section\">\n <h3 class=\"timeline-detail__section-title\">Request</h3>\n\n <!-- Query Parameters -->\n <div v-if=\"hasQueryParams\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.requestQuery\"\n aria-controls=\"requestQuery-panel\"\n @click=\"toggleSection('requestQuery')\"\n >\n <component\n :is=\"expandedSections.requestQuery ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Query Parameters</span>\n <span class=\"text-muted\">({{ Object.keys(entry.request.query).length }})</span>\n </button>\n <div\n id=\"requestQuery-panel\"\n v-show=\"expandedSections.requestQuery\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.request.query\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">\n {{ Array.isArray(value) ? value.join(', ') : value }}\n </span>\n </div>\n </div>\n </div>\n\n <!-- Request Headers -->\n <div v-if=\"hasRequestHeaders\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.requestHeaders\"\n aria-controls=\"requestHeaders-panel\"\n @click=\"toggleSection('requestHeaders')\"\n >\n <component\n :is=\"expandedSections.requestHeaders ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Headers</span>\n <span class=\"text-muted\">({{ Object.keys(entry.request.headers).length }})</span>\n </button>\n <div\n id=\"requestHeaders-panel\"\n v-show=\"expandedSections.requestHeaders\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.request.headers\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">{{ value }}</span>\n </div>\n </div>\n </div>\n\n <!-- Request Body -->\n <div v-if=\"hasRequestBody\" class=\"timeline-detail__subsection\">\n <div class=\"timeline-detail__subsection-header\" role=\"group\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-toggle\"\n :aria-expanded=\"expandedSections.requestBody\"\n aria-controls=\"requestBody-panel\"\n @click=\"toggleSection('requestBody')\"\n >\n <component\n :is=\"expandedSections.requestBody ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Body</span>\n </button>\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--icon btn--sm\"\n title=\"Copy body\"\n @click.stop=\"copyToClipboard(formatJson(entry.request.body), 'reqBody')\"\n >\n <component :is=\"copiedField === 'reqBody' ? Check : Copy\" :size=\"12\" />\n </button>\n </div>\n <div\n id=\"requestBody-panel\"\n v-show=\"expandedSections.requestBody\"\n class=\"timeline-detail__subsection-content\"\n >\n <pre class=\"timeline-detail__json\">{{ formatJson(entry.request.body) }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Response section -->\n <div v-if=\"entry.response\" class=\"timeline-detail__section\">\n <h3 class=\"timeline-detail__section-title\">Response</h3>\n\n <!-- Response Headers -->\n <div v-if=\"hasResponseHeaders\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.responseHeaders\"\n aria-controls=\"responseHeaders-panel\"\n @click=\"toggleSection('responseHeaders')\"\n >\n <component\n :is=\"expandedSections.responseHeaders ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Headers</span>\n <span class=\"text-muted\">({{ Object.keys(entry.response.headers).length }})</span>\n </button>\n <div\n id=\"responseHeaders-panel\"\n v-show=\"expandedSections.responseHeaders\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.response.headers\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">{{ value }}</span>\n </div>\n </div>\n </div>\n\n <!-- Response Body -->\n <div v-if=\"hasResponseBody\" class=\"timeline-detail__subsection\">\n <div class=\"timeline-detail__subsection-header\" role=\"group\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-toggle\"\n :aria-expanded=\"expandedSections.responseBody\"\n aria-controls=\"responseBody-panel\"\n @click=\"toggleSection('responseBody')\"\n >\n <component\n :is=\"expandedSections.responseBody ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Body</span>\n </button>\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--icon btn--sm\"\n title=\"Copy body\"\n @click.stop=\"copyToClipboard(formatJson(entry.response.body), 'resBody')\"\n >\n <component :is=\"copiedField === 'resBody' ? Check : Copy\" :size=\"12\" />\n </button>\n </div>\n <div\n id=\"responseBody-panel\"\n v-show=\"expandedSections.responseBody\"\n class=\"timeline-detail__subsection-content\"\n >\n <pre class=\"timeline-detail__json\">{{ formatJson(entry.response.body) }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Pending response state -->\n <div v-else class=\"timeline-detail__section timeline-detail__section--pending\">\n <h3 class=\"timeline-detail__section-title\">Response</h3>\n <div class=\"timeline-detail__pending\">\n <Clock :size=\"24\" class=\"timeline-detail__pending-icon\" />\n <span class=\"text-muted\">Waiting for response...</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.timeline-detail {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Empty state */\n.timeline-detail__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--devtools-space-xl);\n text-align: center;\n}\n\n.timeline-detail__empty-icon {\n color: var(--devtools-text-muted);\n opacity: 0.5;\n margin-bottom: var(--devtools-space-md);\n}\n\n.timeline-detail__empty-title {\n font-size: var(--font-size-3);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-sm) 0;\n}\n\n.timeline-detail__empty-description {\n font-size: var(--font-size-1);\n color: var(--devtools-text-muted);\n margin: 0;\n}\n\n/* Content */\n.timeline-detail__content {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow-y: auto;\n}\n\n/* Header */\n.timeline-detail__header {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__summary {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-detail__path {\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n word-break: break-all;\n}\n\n.timeline-detail__meta {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n}\n\n.timeline-detail__duration {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.timeline-detail__simulated {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-warning);\n}\n\n.timeline-detail__actions {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n/* Info section */\n.timeline-detail__info {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__info-item {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-detail__info-label {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.timeline-detail__info-value {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n}\n\n/* Section */\n.timeline-detail__section {\n padding: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__section:last-child {\n border-bottom: none;\n}\n\n.timeline-detail__section-title {\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-md) 0;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n/* Subsection */\n.timeline-detail__subsection {\n margin-bottom: var(--devtools-space-sm);\n}\n\n.timeline-detail__subsection:last-child {\n margin-bottom: 0;\n}\n\n.timeline-detail__subsection-header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n width: 100%;\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n}\n\n.timeline-detail__subsection-toggle {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n flex: 1;\n padding: 0;\n background: none;\n border: none;\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n text-align: left;\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-detail__subsection-toggle:hover {\n color: var(--devtools-text-hover);\n}\n\n.timeline-detail__subsection-content {\n margin-top: var(--devtools-space-xs);\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n}\n\n/* Key-value rows */\n.timeline-detail__kv-row {\n display: grid;\n grid-template-columns: minmax(120px, auto) 1fr;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xs) 0;\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__kv-row:last-child {\n border-bottom: none;\n}\n\n.timeline-detail__kv-key {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text-muted);\n word-break: break-all;\n}\n\n.timeline-detail__kv-value {\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n word-break: break-all;\n}\n\n/* JSON display */\n.timeline-detail__json {\n margin: 0;\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-bg);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-mono);\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n white-space: pre-wrap;\n word-break: break-all;\n overflow-x: auto;\n}\n\n/* Status badges */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: 2px var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n font-family: var(--devtools-font-mono);\n}\n\n.status-badge--pending {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n.status-badge--1xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--2xx {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.status-badge--3xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--4xx {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.status-badge--5xx {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n color: var(--devtools-error);\n}\n\n/* Pending response */\n.timeline-detail__pending {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-lg);\n}\n\n.timeline-detail__pending-icon {\n color: var(--devtools-text-muted);\n animation: pulse 2s ease-in-out infinite;\n}\n\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n</style>\n","<!--\n TimelineEntry.vue - Timeline Entry Component\n\n What: Displays a single request/response entry in the timeline\n How: Shows method, path, status, duration with color-coded badges\n Why: Provides consistent visualization of API traffic in the timeline list\n-->\n\n<script setup lang=\"ts\">\nimport { AlertTriangle, CheckCircle, Clock, Zap } from 'lucide-vue-next';\nimport { computed } from 'vue';\n\nimport type { TimelineEntry } from '@/stores/timeline';\n\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** The timeline entry to display */\n entry: TimelineEntry;\n /** Whether this entry is currently selected */\n isSelected?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isSelected: false,\n});\n\n/**\n * Component events\n */\nconst emit = defineEmits<{\n /** Emitted when the entry is clicked */\n (e: 'select', id: string): void;\n}>();\n\n/**\n * Format timestamp for display\n */\nconst formattedTime = computed(() => {\n const date = new Date(props.entry.request.timestamp);\n return date.toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: 3,\n });\n});\n\n/**\n * Format duration for display\n */\nconst formattedDuration = computed(() => {\n if (props.entry.duration === null) {\n return 'pending...';\n }\n if (props.entry.duration < 1000) {\n return `${props.entry.duration}ms`;\n }\n return `${(props.entry.duration / 1000).toFixed(2)}s`;\n});\n\n/**\n * Get status badge class based on status code\n */\nconst statusClass = computed(() => {\n if (props.entry.status === null) return 'status-badge--pending';\n if (props.entry.status < 200) return 'status-badge--1xx';\n if (props.entry.status < 300) return 'status-badge--2xx';\n if (props.entry.status < 400) return 'status-badge--3xx';\n if (props.entry.status < 500) return 'status-badge--4xx';\n return 'status-badge--5xx';\n});\n\n/**\n * Status icon component based on status code\n */\nconst statusIcon = computed(() => {\n if (props.entry.status === null) return Clock;\n if (props.entry.status < 400) return CheckCircle;\n return AlertTriangle;\n});\n\n/**\n * Whether the response is pending\n */\nconst isPending = computed(() => props.entry.response === null);\n\n/**\n * Handle entry click\n */\nfunction handleClick(): void {\n emit('select', props.entry.id);\n}\n</script>\n\n<template>\n <button\n type=\"button\"\n :class=\"[\n 'timeline-entry',\n { 'timeline-entry--selected': isSelected },\n { 'timeline-entry--pending': isPending },\n { 'timeline-entry--simulated': entry.simulated }\n ]\"\n @click=\"handleClick\"\n >\n <!-- Timestamp -->\n <div class=\"timeline-entry__time font-mono text-muted\">\n {{ formattedTime }}\n </div>\n\n <!-- Method badge -->\n <div class=\"timeline-entry__method\">\n <span :class=\"['method-badge', `method-badge--${entry.request.method.toLowerCase()}`]\">\n {{ getMethodLabel(entry.request.method) }}\n </span>\n </div>\n\n <!-- Path -->\n <div class=\"timeline-entry__path font-mono\">\n {{ entry.request.path }}\n </div>\n\n <!-- Status badge -->\n <div class=\"timeline-entry__status\">\n <span v-if=\"entry.status !== null\" :class=\"['status-badge', statusClass]\">\n <component :is=\"statusIcon\" :size=\"12\" />\n {{ entry.status }}\n </span>\n <span v-else class=\"status-badge status-badge--pending\">\n <Clock :size=\"12\" />\n pending\n </span>\n </div>\n\n <!-- Duration -->\n <div class=\"timeline-entry__duration font-mono text-muted\">\n {{ formattedDuration }}\n </div>\n\n <!-- Simulated indicator -->\n <div v-if=\"entry.simulated\" class=\"timeline-entry__simulated\" title=\"Simulated response\">\n <Zap :size=\"14\" />\n </div>\n </button>\n</template>\n\n<style scoped>\n.timeline-entry {\n display: grid;\n grid-template-columns: 100px 80px 1fr auto 80px auto;\n align-items: center;\n gap: var(--devtools-space-md);\n width: 100%;\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n background: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n text-align: left;\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-entry:hover {\n background-color: var(--devtools-surface-elevated);\n border-color: var(--devtools-border-hover);\n}\n\n.timeline-entry:focus {\n outline: none;\n}\n\n.timeline-entry:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.timeline-entry--selected {\n background-color: color-mix(in srgb, var(--devtools-primary) 10%, transparent);\n border-color: var(--devtools-primary);\n}\n\n.timeline-entry--selected:hover {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n}\n\n.timeline-entry--pending {\n opacity: 0.7;\n}\n\n.timeline-entry--simulated {\n border-left: 3px solid var(--devtools-warning);\n}\n\n/* Time column */\n.timeline-entry__time {\n font-size: var(--font-size-0);\n}\n\n/* Path column */\n.timeline-entry__path {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Status column */\n.timeline-entry__status {\n display: flex;\n align-items: center;\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: 2px var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n font-family: var(--devtools-font-mono);\n}\n\n.status-badge--pending {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n.status-badge--1xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--2xx {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.status-badge--3xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--4xx {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.status-badge--5xx {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n color: var(--devtools-error);\n}\n\n/* Duration column */\n.timeline-entry__duration {\n font-size: var(--font-size-0);\n text-align: right;\n}\n\n/* Simulated indicator */\n.timeline-entry__simulated {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--devtools-warning);\n}\n</style>\n","<!--\n TimelinePage.vue - Request/Response Timeline Page\n\n What: Displays a real-time timeline of API requests and responses\n How: Subscribes to WebSocket events and displays request/response logs with filtering\n Why: Allows developers to monitor and debug API traffic in real-time\n-->\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronUp, Clock, Filter, Search, Trash2, X } from 'lucide-vue-next';\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue';\n\nimport TimelineDetail from '@/components/TimelineDetail.vue';\nimport TimelineEntryComponent from '@/components/TimelineEntry.vue';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport {\n type HttpMethod,\n type RequestLogEntry,\n type ResponseLogEntry,\n type TimelineData,\n useTimelineStore,\n} from '@/stores/timeline';\n\n// Store and WebSocket\nconst timelineStore = useTimelineStore();\nconst { send, on, connected } = useWebSocket();\n\n// Local UI state\nconst showFilters = ref(false);\nconst searchInputRef = ref<HTMLInputElement | null>(null);\n\n// HTTP methods for filter\nconst httpMethods: HttpMethod[] = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n 'TRACE',\n];\n\n// Status categories for filter\nconst statusCategories = ['2xx', '3xx', '4xx', '5xx'] as const;\n\n/**\n * Fetch timeline data when connected\n */\nfunction fetchTimeline(): void {\n if (connected.value) {\n timelineStore.setLoading(true);\n send({ type: 'get:timeline' });\n }\n}\n\n/**\n * Handle timeline data from server\n */\nfunction handleTimelineData(data: TimelineData): void {\n timelineStore.setTimelineData(data);\n timelineStore.setLoading(false);\n}\n\n/**\n * Handle incoming request event\n */\nfunction handleRequest(data: RequestLogEntry): void {\n timelineStore.addRequest(data);\n}\n\n/**\n * Handle incoming response event\n */\nfunction handleResponse(data: ResponseLogEntry): void {\n timelineStore.addResponse(data);\n}\n\n/**\n * Handle timeline cleared event\n */\nfunction handleTimelineCleared(): void {\n timelineStore.clearTimeline();\n}\n\n/**\n * Clear timeline on server and locally\n */\nfunction clearTimeline(): void {\n send({ type: 'clear:timeline' });\n timelineStore.clearTimeline();\n}\n\n/**\n * Handle entry selection\n */\nfunction handleSelectEntry(id: string): void {\n timelineStore.selectEntry(id);\n}\n\n/**\n * Handle search input\n */\nfunction handleSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n timelineStore.setSearchQuery(target.value);\n}\n\n/**\n * Clear search\n */\nfunction clearSearch(): void {\n timelineStore.setSearchQuery('');\n searchInputRef.value?.focus();\n}\n\n/**\n * Toggle method filter\n */\nfunction toggleMethod(method: HttpMethod): void {\n timelineStore.toggleMethodFilter(method);\n}\n\n/**\n * Check if method is active in filter\n */\nfunction isMethodActive(method: HttpMethod): boolean {\n return timelineStore.filter.methods.includes(method);\n}\n\n/**\n * Toggle status filter\n */\nfunction toggleStatus(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): void {\n timelineStore.toggleStatusFilter(status);\n}\n\n/**\n * Check if status is active in filter\n */\nfunction isStatusActive(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): boolean {\n return timelineStore.filter.statusCodes.includes(status);\n}\n\n/**\n * Toggle simulated filter\n */\nfunction toggleSimulatedFilter(): void {\n const current = timelineStore.filter.simulatedOnly;\n timelineStore.setSimulatedFilter(current === true ? null : true);\n}\n\n/**\n * Clear all filters\n */\nfunction clearAllFilters(): void {\n timelineStore.clearFilters();\n}\n\n/**\n * Toggle filter panel visibility\n */\nfunction toggleFilters(): void {\n showFilters.value = !showFilters.value;\n}\n\n/**\n * Computed: Has active filters\n */\nconst hasActiveFilters = computed(() => timelineStore.hasActiveFilters());\n\n/**\n * Computed: Filter badge count\n */\nconst filterBadgeCount = computed(() => {\n return (\n timelineStore.filter.methods.length +\n timelineStore.filter.statusCodes.length +\n (timelineStore.filter.simulatedOnly !== null ? 1 : 0)\n );\n});\n\n// Event cleanup functions for WebSocket subscriptions\nlet unsubTimeline: (() => void) | null = null;\nlet unsubRequest: (() => void) | null = null;\nlet unsubResponse: (() => void) | null = null;\nlet unsubCleared: (() => void) | null = null;\n\n// Subscribe to timeline events and setup cleanup\nonMounted(() => {\n // Subscribe to WebSocket events\n unsubTimeline = on<TimelineData>('timeline', handleTimelineData);\n unsubRequest = on<RequestLogEntry>('request', handleRequest);\n unsubResponse = on<ResponseLogEntry>('response', handleResponse);\n unsubCleared = on('timeline:cleared', handleTimelineCleared);\n\n // Fetch timeline when already connected\n if (connected.value) {\n fetchTimeline();\n }\n});\n\n// Cleanup event subscriptions on unmount\nonUnmounted(() => {\n unsubTimeline?.();\n unsubRequest?.();\n unsubResponse?.();\n unsubCleared?.();\n});\n\n// Re-fetch when connection is established\nwatch(connected, (isConnected) => {\n if (isConnected) {\n fetchTimeline();\n }\n});\n</script>\n\n<template>\n <div class=\"timeline-page\">\n <!-- Toolbar -->\n <div class=\"timeline-toolbar\">\n <!-- Search -->\n <div class=\"timeline-search\">\n <Search :size=\"16\" class=\"timeline-search__icon\" />\n <input\n ref=\"searchInputRef\"\n type=\"text\"\n class=\"timeline-search__input input\"\n placeholder=\"Search by path or operation...\"\n :value=\"timelineStore.filter.searchQuery\"\n @input=\"handleSearchInput\"\n />\n <button\n v-if=\"timelineStore.filter.searchQuery\"\n type=\"button\"\n class=\"timeline-search__clear btn btn--ghost btn--icon\"\n title=\"Clear search\"\n @click=\"clearSearch\"\n >\n <X :size=\"14\" />\n </button>\n </div>\n\n <!-- Filter toggle -->\n <button\n type=\"button\"\n :class=\"[\n 'timeline-filter-toggle btn btn--secondary',\n { 'timeline-filter-toggle--active': hasActiveFilters }\n ]\"\n :aria-expanded=\"showFilters\"\n @click=\"toggleFilters\"\n >\n <Filter :size=\"16\" />\n <span>Filters</span>\n <span v-if=\"filterBadgeCount > 0\" class=\"timeline-filter-toggle__badge\">\n {{ filterBadgeCount }}\n </span>\n <component :is=\"showFilters ? ChevronUp : ChevronDown\" :size=\"14\" />\n </button>\n\n <!-- Stats -->\n <div class=\"timeline-stats\">\n <span class=\"timeline-stats__item\">\n {{ timelineStore.filteredEntries.length }} requests\n </span>\n <span v-if=\"timelineStore.averageDuration > 0\" class=\"timeline-stats__separator\">|</span>\n <span v-if=\"timelineStore.averageDuration > 0\" class=\"timeline-stats__item\">\n avg {{ timelineStore.averageDuration }}ms\n </span>\n </div>\n\n <!-- Clear button -->\n <button\n type=\"button\"\n class=\"btn btn--secondary btn--icon\"\n title=\"Clear timeline\"\n :disabled=\"timelineStore.entries.length === 0\"\n @click=\"clearTimeline\"\n >\n <Trash2 :size=\"16\" />\n </button>\n </div>\n\n <!-- Filter panel -->\n <div v-if=\"showFilters\" class=\"timeline-filters\">\n <!-- Method filters -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Methods</h4>\n <div class=\"timeline-filters__methods\">\n <button\n v-for=\"method in httpMethods\"\n :key=\"method\"\n type=\"button\"\n :class=\"[\n 'method-badge',\n `method-badge--${method.toLowerCase()}`,\n { 'method-badge--inactive': !isMethodActive(method) && timelineStore.filter.methods.length > 0 }\n ]\"\n @click=\"toggleMethod(method)\"\n >\n {{ method }}\n </button>\n </div>\n </div>\n\n <!-- Status filters -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Status</h4>\n <div class=\"timeline-filters__status\">\n <button\n v-for=\"status in statusCategories\"\n :key=\"status\"\n type=\"button\"\n :class=\"[\n 'timeline-filters__status-btn',\n `timeline-filters__status-btn--${status}`,\n { 'timeline-filters__status-btn--active': isStatusActive(status) }\n ]\"\n @click=\"toggleStatus(status)\"\n >\n {{ status }}\n <span class=\"timeline-filters__status-count\">\n ({{ timelineStore.statusCounts[status] }})\n </span>\n </button>\n </div>\n </div>\n\n <!-- Simulated filter -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Type</h4>\n <div class=\"timeline-filters__type\">\n <button\n type=\"button\"\n :class=\"[\n 'timeline-filters__status-btn',\n { 'timeline-filters__status-btn--active': timelineStore.filter.simulatedOnly }\n ]\"\n @click=\"toggleSimulatedFilter\"\n >\n Simulated only\n </button>\n </div>\n </div>\n\n <!-- Clear filters -->\n <div v-if=\"hasActiveFilters\" class=\"timeline-filters__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost\"\n @click=\"clearAllFilters\"\n >\n <X :size=\"14\" />\n Clear all filters\n </button>\n </div>\n </div>\n\n <!-- Main content -->\n <div class=\"timeline-content\">\n <!-- Loading state -->\n <div v-if=\"timelineStore.isLoading\" class=\"timeline-loading\">\n <div class=\"timeline-loading__spinner\" />\n <span class=\"text-muted\">Loading timeline...</span>\n </div>\n\n <!-- Error state -->\n <div v-else-if=\"timelineStore.error\" class=\"timeline-error\">\n <p class=\"timeline-error__message\">{{ timelineStore.error }}</p>\n <button type=\"button\" class=\"btn btn--primary\" @click=\"fetchTimeline\">\n Retry\n </button>\n </div>\n\n <!-- Empty state -->\n <div v-else-if=\"timelineStore.entries.length === 0\" class=\"timeline-empty empty-state\">\n <Clock :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No requests yet</h3>\n <p class=\"empty-state__description\">\n API requests will appear here in real-time as they are made.\n </p>\n </div>\n\n <!-- No results state -->\n <div v-else-if=\"timelineStore.filteredEntries.length === 0\" class=\"timeline-empty empty-state\">\n <Search :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No matching requests</h3>\n <p class=\"empty-state__description\">\n Try adjusting your search or filters.\n </p>\n <button\n v-if=\"hasActiveFilters\"\n type=\"button\"\n class=\"btn btn--secondary\"\n @click=\"clearAllFilters\"\n >\n Clear filters\n </button>\n </div>\n\n <!-- Split panel layout -->\n <template v-else>\n <!-- Timeline list panel -->\n <div class=\"timeline-list-panel\">\n <div class=\"timeline-list\">\n <TimelineEntryComponent\n v-for=\"entry in timelineStore.filteredEntries\"\n :key=\"entry.id\"\n :entry=\"entry\"\n :is-selected=\"timelineStore.selectedEntryId === entry.id\"\n @select=\"handleSelectEntry\"\n />\n </div>\n </div>\n\n <!-- Timeline detail panel -->\n <div class=\"timeline-detail-panel\">\n <TimelineDetail :entry=\"timelineStore.selectedEntry\" />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.timeline-page {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Toolbar */\n.timeline-toolbar {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-search {\n position: relative;\n flex: 1;\n max-width: 400px;\n}\n\n.timeline-search__icon {\n position: absolute;\n left: var(--devtools-space-sm);\n top: 50%;\n transform: translateY(-50%);\n color: var(--devtools-text-muted);\n pointer-events: none;\n}\n\n.timeline-search__input {\n padding-left: calc(var(--devtools-space-sm) + 24px);\n padding-right: calc(var(--devtools-space-sm) + 24px);\n}\n\n.timeline-search__clear {\n position: absolute;\n right: var(--devtools-space-xs);\n top: 50%;\n transform: translateY(-50%);\n padding: var(--devtools-space-xs);\n}\n\n.timeline-filter-toggle {\n flex-shrink: 0;\n}\n\n.timeline-filter-toggle--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.timeline-filter-toggle__badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-primary);\n color: var(--devtools-text-inverted);\n border-radius: 9px;\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n}\n\n.timeline-stats {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n margin-left: auto;\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.timeline-stats__separator {\n opacity: 0.5;\n}\n\n/* Filter panel */\n.timeline-filters {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: var(--devtools-space-lg);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-filters__section {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__title {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.timeline-filters__methods {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-filters__methods .method-badge {\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-filters__methods .method-badge--inactive {\n opacity: 0.4;\n}\n\n.timeline-filters__status {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__type {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__status-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-filters__status-btn:hover {\n background-color: var(--devtools-surface-elevated);\n color: var(--devtools-text);\n}\n\n.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.timeline-filters__status-btn--2xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n border-color: var(--devtools-success);\n color: var(--devtools-success);\n}\n\n.timeline-filters__status-btn--3xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n border-color: var(--devtools-info);\n color: var(--devtools-info);\n}\n\n.timeline-filters__status-btn--4xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n border-color: var(--devtools-warning);\n color: var(--devtools-warning);\n}\n\n.timeline-filters__status-btn--5xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n border-color: var(--devtools-error);\n color: var(--devtools-error);\n}\n\n.timeline-filters__status-count {\n font-size: var(--font-size-00);\n opacity: 0.7;\n}\n\n.timeline-filters__actions {\n display: flex;\n align-items: flex-end;\n margin-left: auto;\n}\n\n/* Main content */\n.timeline-content {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n/* Loading state */\n.timeline-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n}\n\n.timeline-loading__spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--devtools-border);\n border-top-color: var(--devtools-primary);\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Error state */\n.timeline-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xl);\n}\n\n.timeline-error__message {\n color: var(--devtools-error);\n margin: 0;\n}\n\n/* Empty state */\n.timeline-empty {\n width: 100%;\n}\n\n/* Split panels */\n.timeline-list-panel {\n width: 50%;\n min-width: 300px;\n max-width: 600px;\n border-right: 1px solid var(--devtools-border);\n background-color: var(--devtools-bg);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.timeline-list {\n flex: 1;\n overflow-y: auto;\n padding: var(--devtools-space-sm);\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-detail-panel {\n flex: 1;\n overflow: hidden;\n background-color: var(--devtools-bg);\n}\n</style>\n"],"names":["CircleCheckBig","createLucideIcon","Copy","useTimelineStore","defineStore","entries","ref","isLoading","error","filter","selectedEntryId","maxEntries","responseBuffer","getStatusCategory","status","filteredEntries","computed","result","query","entry","category","selectedEntry","e","totalCount","completedCount","pendingCount","statusCounts","counts","averageDuration","completedEntries","totalDuration","sum","addRequest","request","bufferedResponse","mergeResponse","addResponse","response","stubEntry","createStubEntry","stubRequest","processBufferedResponses","requestMap","requestId","processIncomingResponses","incomingResponses","createStubsForOrphanedResponses","setTimelineData","data","item","sorted","a","b","clearTimeline","setLoading","loading","setError","errorMessage","clearError","setSearchQuery","toggleMethodFilter","method","index","toggleStatusFilter","setSimulatedFilter","simulated","clearFilters","hasActiveFilters","selectEntry","id","setMaxEntries","limit","clamped","props","__props","expandedSections","copiedField","formattedTimestamp","formattedDuration","statusClass","hasQueryParams","hasRequestHeaders","hasRequestBody","hasResponseHeaders","hasResponseBody","formatJson","value","toggleSection","section","copyToClipboard","text","fieldId","err","copyFullEntry","_openBlock","_createElementBlock","_hoisted_1","_hoisted_3","_createElementVNode","_hoisted_4","_hoisted_5","_toDisplayString","_unref","getMethodLabel","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_createVNode","Clock","_createTextVNode","_hoisted_10","Zap","_hoisted_11","_createBlock","_resolveDynamicComponent","Check","_hoisted_12","_hoisted_13","_cache","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","ChevronDown","ChevronRight","_hoisted_22","_withDirectives","_hoisted_23","_Fragment","_renderList","key","_hoisted_24","_hoisted_25","_vShow","_hoisted_26","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_withModifiers","$event","_hoisted_35","_hoisted_36","_hoisted_37","_hoisted_38","_hoisted_40","_hoisted_41","_hoisted_42","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_47","_hoisted_48","_hoisted_49","_hoisted_50","_hoisted_2","emit","__emit","formattedTime","statusIcon","CheckCircle","AlertTriangle","isPending","handleClick","_normalizeClass","timelineStore","send","on","connected","useWebSocket","showFilters","searchInputRef","httpMethods","statusCategories","fetchTimeline","handleTimelineData","handleRequest","handleResponse","handleTimelineCleared","handleSelectEntry","handleSearchInput","event","target","clearSearch","toggleMethod","isMethodActive","toggleStatus","isStatusActive","toggleSimulatedFilter","current","clearAllFilters","toggleFilters","filterBadgeCount","unsubTimeline","unsubRequest","unsubResponse","unsubCleared","onMounted","onUnmounted","watch","isConnected","Search","X","Filter","ChevronUp","Trash2","_hoisted_21","_hoisted_27","TimelineEntryComponent","TimelineDetail"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
1
|
+
{"version":3,"file":"TimelinePage-CYGTXXoL.js","sources":["../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/circle-check-big.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/copy.js","../src/stores/timeline.ts","../src/components/TimelineDetail.vue","../src/components/TimelineEntry.vue","../src/pages/TimelinePage.vue"],"sourcesContent":["/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleCheckBig = createLucideIcon(\"circle-check-big\", [\n [\"path\", { d: \"M21.801 10A10 10 0 1 1 17 3.335\", key: \"yps3ct\" }],\n [\"path\", { d: \"m9 11 3 3L22 4\", key: \"1pflzl\" }]\n]);\n\nexport { CircleCheckBig as default };\n//# sourceMappingURL=circle-check-big.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Copy = createLucideIcon(\"copy\", [\n [\"rect\", { width: \"14\", height: \"14\", x: \"8\", y: \"8\", rx: \"2\", ry: \"2\", key: \"17jyea\" }],\n [\"path\", { d: \"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\", key: \"zix9uf\" }]\n]);\n\nexport { Copy as default };\n//# sourceMappingURL=copy.js.map\n","/**\n * Timeline Store\n *\n * What: Pinia store for managing request/response timeline data\n * How: Receives and stores timeline events from the server via WebSocket\n * Why: Provides reactive access to timeline data for the Timeline Page\n *\n * @module stores/timeline\n */\n\nimport { defineStore } from 'pinia';\nimport { computed, ref } from 'vue';\n\n/**\n * HTTP method type for timeline entries\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'TRACE';\n\n/**\n * Request log entry from the server\n */\nexport interface RequestLogEntry {\n id: string;\n method: string;\n path: string;\n operationId: string;\n timestamp: number;\n headers: Record<string, string>;\n query: Record<string, string | string[]>;\n body?: unknown;\n}\n\n/**\n * Response log entry from the server\n */\nexport interface ResponseLogEntry {\n id: string;\n requestId: string;\n status: number;\n duration: number;\n headers: Record<string, string>;\n body: unknown;\n simulated: boolean;\n}\n\n/**\n * Combined timeline entry with request and optional response\n */\nexport interface TimelineEntry {\n id: string;\n request: RequestLogEntry;\n response: ResponseLogEntry | null;\n status: number | null;\n duration: number | null;\n simulated: boolean;\n}\n\n/**\n * Timeline data from server\n */\nexport interface TimelineData {\n entries: Array<{ type: 'request' | 'response'; data: RequestLogEntry | ResponseLogEntry }>;\n count: number;\n total: number;\n}\n\n/**\n * Filter options for timeline entries\n */\nexport interface TimelineFilter {\n methods: HttpMethod[];\n statusCodes: ('1xx' | '2xx' | '3xx' | '4xx' | '5xx')[];\n searchQuery: string;\n simulatedOnly: boolean | null;\n}\n\n/**\n * Timeline store for request/response tracking\n *\n * Provides:\n * - Timeline entry storage and retrieval\n * - Real-time updates via WebSocket events\n * - Search and filter functionality\n * - Selected entry tracking for detail view\n * - Timeline limit management\n */\nexport const useTimelineStore = defineStore('timeline', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /** All timeline entries (request + response pairs) */\n const entries = ref<TimelineEntry[]>([]);\n\n /** Loading state */\n const isLoading = ref(false);\n\n /** Error state */\n const error = ref<string | null>(null);\n\n /** Active filters */\n const filter = ref<TimelineFilter>({\n methods: [],\n statusCodes: [],\n searchQuery: '',\n simulatedOnly: null,\n });\n\n /** Currently selected entry ID */\n const selectedEntryId = ref<string | null>(null);\n\n /** Maximum number of entries to keep */\n const maxEntries = ref(500);\n\n /** Buffer for responses that arrived before their requests */\n const responseBuffer = new Map<string, ResponseLogEntry>();\n\n // ==========================================================================\n // Getters / Computed\n // ==========================================================================\n\n /**\n * Get status category from status code\n */\n function getStatusCategory(status: number): '1xx' | '2xx' | '3xx' | '4xx' | '5xx' {\n if (status < 200) return '1xx';\n if (status < 300) return '2xx';\n if (status < 400) return '3xx';\n if (status < 500) return '4xx';\n return '5xx';\n }\n\n /**\n * Filtered entries based on search and filters\n */\n const filteredEntries = computed(() => {\n let result = entries.value;\n\n // Apply search query (matches path or operationId)\n if (filter.value.searchQuery.trim()) {\n const query = filter.value.searchQuery.toLowerCase().trim();\n result = result.filter((entry) => {\n return (\n entry.request.path.toLowerCase().includes(query) ||\n entry.request.operationId.toLowerCase().includes(query)\n );\n });\n }\n\n // Apply method filter\n if (filter.value.methods.length > 0) {\n result = result.filter((entry) =>\n filter.value.methods.includes(entry.request.method.toUpperCase() as HttpMethod),\n );\n }\n\n // Apply status code filter\n if (filter.value.statusCodes.length > 0) {\n result = result.filter((entry) => {\n if (entry.status === null) return false;\n const category = getStatusCategory(entry.status);\n return filter.value.statusCodes.includes(category);\n });\n }\n\n // Apply simulated filter\n if (filter.value.simulatedOnly !== null) {\n result = result.filter((entry) => entry.simulated === filter.value.simulatedOnly);\n }\n\n return result;\n });\n\n /**\n * Currently selected entry\n */\n const selectedEntry = computed(() => {\n if (!selectedEntryId.value) return null;\n return entries.value.find((e) => e.id === selectedEntryId.value) ?? null;\n });\n\n /**\n * Total number of entries (including pending responses)\n */\n const totalCount = computed(() => entries.value.length);\n\n /**\n * Count of entries with responses\n */\n const completedCount = computed(() => entries.value.filter((e) => e.response !== null).length);\n\n /**\n * Count of pending requests (no response yet)\n */\n const pendingCount = computed(() => entries.value.filter((e) => e.response === null).length);\n\n /**\n * Count of entries by status category\n */\n const statusCounts = computed(() => {\n const counts = {\n '1xx': 0,\n '2xx': 0,\n '3xx': 0,\n '4xx': 0,\n '5xx': 0,\n };\n\n for (const entry of entries.value) {\n if (entry.status !== null) {\n const category = getStatusCategory(entry.status);\n counts[category]++;\n }\n }\n\n return counts;\n });\n\n /**\n * Average response duration in milliseconds\n */\n const averageDuration = computed(() => {\n const completedEntries = entries.value.filter((e) => e.duration !== null);\n if (completedEntries.length === 0) return 0;\n\n const totalDuration = completedEntries.reduce((sum, e) => sum + (e.duration ?? 0), 0);\n return Math.round(totalDuration / completedEntries.length);\n });\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Add a request to the timeline\n */\n function addRequest(request: RequestLogEntry): void {\n const entry: TimelineEntry = {\n id: request.id,\n request,\n response: null,\n status: null,\n duration: null,\n simulated: false,\n };\n\n // Check if there's a buffered response for this request\n const bufferedResponse = responseBuffer.get(request.id);\n if (bufferedResponse) {\n mergeResponse(entry, bufferedResponse);\n // Clear consumed buffered response\n responseBuffer.delete(request.id);\n }\n\n // Add to beginning of array (newest first)\n entries.value.unshift(entry);\n\n // Trim to max entries\n if (entries.value.length > maxEntries.value) {\n entries.value = entries.value.slice(0, maxEntries.value);\n }\n }\n\n /**\n * Add a response to an existing request\n */\n function addResponse(response: ResponseLogEntry): void {\n const entry = entries.value.find((e) => e.id === response.requestId);\n if (entry) {\n // Entry exists, merge immediately\n mergeResponse(entry, response);\n // Clear from buffer if it was buffered\n responseBuffer.delete(response.requestId);\n } else {\n // Entry doesn't exist yet, buffer the response\n responseBuffer.set(response.requestId, response);\n\n // Prevent unbounded buffer growth: create stub entry if buffer exceeds threshold\n // This ensures orphaned responses don't cause memory leaks in real-time scenarios\n if (responseBuffer.size > 100) {\n const stubEntry = createStubEntry(response);\n entries.value.unshift(stubEntry);\n responseBuffer.delete(response.requestId);\n\n // Trim to max entries\n if (entries.value.length > maxEntries.value) {\n entries.value = entries.value.slice(0, maxEntries.value);\n }\n }\n }\n }\n\n /**\n * Merge a response into an entry\n */\n function mergeResponse(entry: TimelineEntry, response: ResponseLogEntry): void {\n entry.response = response;\n entry.status = response.status;\n entry.duration = response.duration;\n entry.simulated = response.simulated;\n }\n\n /**\n * Create a stub entry for an orphaned response\n */\n function createStubEntry(response: ResponseLogEntry): TimelineEntry {\n // Create a minimal request stub for the orphaned response\n const stubRequest: RequestLogEntry = {\n id: response.requestId,\n method: 'UNKNOWN',\n path: '/unknown',\n operationId: 'unknown',\n timestamp: Date.now(), // Use current time as fallback\n headers: {},\n query: {},\n body: undefined,\n };\n\n return {\n id: response.requestId,\n request: stubRequest,\n response,\n status: response.status,\n duration: response.duration,\n simulated: response.simulated,\n };\n }\n\n /**\n * Process buffered responses and merge with existing entries or create stubs\n */\n function processBufferedResponses(requestMap: Map<string, TimelineEntry>): void {\n for (const [requestId, response] of responseBuffer) {\n const entry = requestMap.get(requestId);\n if (entry) {\n mergeResponse(entry, response);\n responseBuffer.delete(requestId);\n } else {\n // No matching request found, create stub entry\n requestMap.set(requestId, createStubEntry(response));\n responseBuffer.delete(requestId);\n }\n }\n }\n\n /**\n * Process incoming responses and merge, buffer, or create stub entries\n */\n function processIncomingResponses(\n requestMap: Map<string, TimelineEntry>,\n incomingResponses: Map<string, ResponseLogEntry>,\n ): void {\n for (const [requestId, response] of incomingResponses) {\n const entry = requestMap.get(requestId);\n if (entry) {\n mergeResponse(entry, response);\n } else {\n // Buffer the response for potential future request\n // Note: During initial load, we'll create stubs later\n responseBuffer.set(requestId, response);\n }\n }\n }\n\n /**\n * Create stub entries for any remaining buffered responses\n * This ensures no response is lost even if its request never arrives\n */\n function createStubsForOrphanedResponses(requestMap: Map<string, TimelineEntry>): void {\n for (const [requestId, response] of responseBuffer) {\n if (!requestMap.has(requestId)) {\n requestMap.set(requestId, createStubEntry(response));\n responseBuffer.delete(requestId);\n }\n }\n }\n\n /**\n * Set timeline data from server response\n * Used when fetching initial timeline data\n */\n function setTimelineData(data: TimelineData): void {\n const requestMap = new Map<string, TimelineEntry>();\n const incomingResponses = new Map<string, ResponseLogEntry>();\n\n // First pass: collect all requests and responses\n for (const item of data.entries) {\n if (item.type === 'request') {\n const request = item.data as RequestLogEntry;\n requestMap.set(request.id, {\n id: request.id,\n request,\n response: null,\n status: null,\n duration: null,\n simulated: false,\n });\n } else if (item.type === 'response') {\n const response = item.data as ResponseLogEntry;\n incomingResponses.set(response.requestId, response);\n }\n }\n\n // Second pass: merge responses with requests\n processBufferedResponses(requestMap);\n processIncomingResponses(requestMap, incomingResponses);\n\n // Third pass: create stub entries for any remaining orphaned responses\n // This ensures no response is lost even if its request never arrives\n createStubsForOrphanedResponses(requestMap);\n\n // Convert map to array and sort by timestamp (newest first)\n const sorted = Array.from(requestMap.values()).sort(\n (a, b) => b.request.timestamp - a.request.timestamp,\n );\n\n // Apply maxEntries limit\n entries.value = sorted.slice(0, maxEntries.value);\n\n error.value = null;\n }\n\n /**\n * Clear all timeline entries\n */\n function clearTimeline(): void {\n entries.value = [];\n selectedEntryId.value = null;\n responseBuffer.clear();\n }\n\n /**\n * Set loading state\n */\n function setLoading(loading: boolean): void {\n isLoading.value = loading;\n }\n\n /**\n * Set error state\n */\n function setError(errorMessage: string): void {\n error.value = errorMessage;\n isLoading.value = false;\n }\n\n /**\n * Clear error state\n */\n function clearError(): void {\n error.value = null;\n }\n\n /**\n * Set search query\n */\n function setSearchQuery(query: string): void {\n filter.value.searchQuery = query;\n }\n\n /**\n * Toggle method filter\n */\n function toggleMethodFilter(method: HttpMethod): void {\n const index = filter.value.methods.indexOf(method);\n if (index === -1) {\n filter.value.methods.push(method);\n } else {\n filter.value.methods.splice(index, 1);\n }\n }\n\n /**\n * Toggle status code filter\n */\n function toggleStatusFilter(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): void {\n const index = filter.value.statusCodes.indexOf(status);\n if (index === -1) {\n filter.value.statusCodes.push(status);\n } else {\n filter.value.statusCodes.splice(index, 1);\n }\n }\n\n /**\n * Set simulated filter\n */\n function setSimulatedFilter(simulated: boolean | null): void {\n filter.value.simulatedOnly = simulated;\n }\n\n /**\n * Clear all filters\n */\n function clearFilters(): void {\n filter.value = {\n methods: [],\n statusCodes: [],\n searchQuery: '',\n simulatedOnly: null,\n };\n }\n\n /**\n * Check if any filter is active\n */\n function hasActiveFilters(): boolean {\n return (\n filter.value.searchQuery.trim() !== '' ||\n filter.value.methods.length > 0 ||\n filter.value.statusCodes.length > 0 ||\n filter.value.simulatedOnly !== null\n );\n }\n\n /**\n * Select an entry by ID\n */\n function selectEntry(id: string | null): void {\n selectedEntryId.value = id;\n }\n\n /**\n * Set maximum entries limit\n */\n function setMaxEntries(limit: number): void {\n // Clamp limit to a safe minimum\n const clamped = Math.max(1, limit);\n maxEntries.value = clamped;\n\n // Trim if necessary\n if (entries.value.length > clamped) {\n entries.value = entries.value.slice(0, clamped);\n }\n }\n\n // ==========================================================================\n // Return\n // ==========================================================================\n\n return {\n // State\n entries,\n isLoading,\n error,\n filter,\n selectedEntryId,\n maxEntries,\n\n // Getters\n filteredEntries,\n selectedEntry,\n totalCount,\n completedCount,\n pendingCount,\n statusCounts,\n averageDuration,\n\n // Actions\n addRequest,\n addResponse,\n setTimelineData,\n clearTimeline,\n setLoading,\n setError,\n clearError,\n setSearchQuery,\n toggleMethodFilter,\n toggleStatusFilter,\n setSimulatedFilter,\n clearFilters,\n hasActiveFilters,\n selectEntry,\n setMaxEntries,\n };\n});\n","<!--\n TimelineDetail.vue - Timeline Entry Detail Panel\n\n What: Displays full request and response details for a selected timeline entry\n How: Shows headers, query params, body content in organized collapsible sections\n Why: Allows developers to inspect API traffic in detail for debugging\n-->\n\n<script setup lang=\"ts\">\nimport { Check, ChevronDown, ChevronRight, Clock, Copy, Zap } from 'lucide-vue-next';\n\nimport { computed, ref } from 'vue';\n\nimport type { TimelineEntry } from '@/stores/timeline';\n\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** The timeline entry to display */\n entry: TimelineEntry | null;\n}\n\nconst props = defineProps<Props>();\n\n/**\n * Section expansion state\n */\nconst expandedSections = ref({\n requestHeaders: true,\n requestQuery: true,\n requestBody: true,\n responseHeaders: true,\n responseBody: true,\n});\n\n/**\n * Copy feedback state\n */\nconst copiedField = ref<string | null>(null);\n\n/**\n * Format timestamp for display\n */\nconst formattedTimestamp = computed(() => {\n if (!props.entry) return '';\n const date = new Date(props.entry.request.timestamp);\n return date.toLocaleString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: 3,\n hour12: false,\n });\n});\n\n/**\n * Format duration for display\n */\nconst formattedDuration = computed(() => {\n if (props.entry?.duration == null) return 'pending...';\n if (props.entry.duration < 1000) {\n return `${props.entry.duration}ms`;\n }\n return `${(props.entry.duration / 1000).toFixed(2)}s`;\n});\n\n/**\n * Get status badge class based on status code\n */\nconst statusClass = computed(() => {\n if (!props.entry?.status) return 'status-badge--pending';\n if (props.entry.status < 200) return 'status-badge--1xx';\n if (props.entry.status < 300) return 'status-badge--2xx';\n if (props.entry.status < 400) return 'status-badge--3xx';\n if (props.entry.status < 500) return 'status-badge--4xx';\n return 'status-badge--5xx';\n});\n\n/**\n * Check if request has query parameters\n */\nconst hasQueryParams = computed(() => {\n if (!props.entry?.request.query) return false;\n return Object.keys(props.entry.request.query).length > 0;\n});\n\n/**\n * Check if request has headers\n */\nconst hasRequestHeaders = computed(() => {\n if (!props.entry?.request.headers) return false;\n return Object.keys(props.entry.request.headers).length > 0;\n});\n\n/**\n * Check if request has body\n */\nconst hasRequestBody = computed(() => {\n return props.entry?.request.body !== undefined && props.entry?.request.body !== null;\n});\n\n/**\n * Check if response has headers\n */\nconst hasResponseHeaders = computed(() => {\n if (!props.entry?.response?.headers) return false;\n return Object.keys(props.entry.response.headers).length > 0;\n});\n\n/**\n * Check if response has body\n */\nconst hasResponseBody = computed(() => {\n return props.entry?.response?.body !== undefined && props.entry?.response?.body !== null;\n});\n\n/**\n * Format JSON for display\n */\nfunction formatJson(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Toggle section expansion\n */\nfunction toggleSection(section: keyof typeof expandedSections.value): void {\n expandedSections.value[section] = !expandedSections.value[section];\n}\n\n/**\n * Copy text to clipboard\n */\nasync function copyToClipboard(text: string, fieldId: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n copiedField.value = fieldId;\n setTimeout(() => {\n copiedField.value = null;\n }, 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n}\n\n/**\n * Copy full entry as JSON\n */\nasync function copyFullEntry(): Promise<void> {\n if (!props.entry) return;\n const data = {\n request: props.entry.request,\n response: props.entry.response,\n };\n await copyToClipboard(JSON.stringify(data, null, 2), 'full');\n}\n</script>\n\n<template>\n <div class=\"timeline-detail\">\n <!-- Empty state -->\n <div v-if=\"!entry\" class=\"timeline-detail__empty\">\n <Clock :size=\"48\" class=\"timeline-detail__empty-icon\" />\n <h3 class=\"timeline-detail__empty-title\">Select an entry</h3>\n <p class=\"timeline-detail__empty-description\">\n Click on a timeline entry to view its details.\n </p>\n </div>\n\n <!-- Entry details -->\n <div v-else class=\"timeline-detail__content\">\n <!-- Header with summary -->\n <div class=\"timeline-detail__header\">\n <div class=\"timeline-detail__summary\">\n <span :class=\"['method-badge', `method-badge--${entry.request.method.toLowerCase()}`]\">\n {{ getMethodLabel(entry.request.method) }}\n </span>\n <span class=\"timeline-detail__path font-mono\">{{ entry.request.path }}</span>\n </div>\n\n <div class=\"timeline-detail__meta\">\n <span v-if=\"entry.status !== null\" :class=\"['status-badge', statusClass]\">\n {{ entry.status }}\n </span>\n <span v-else class=\"status-badge status-badge--pending\">pending</span>\n\n <span class=\"timeline-detail__duration\">\n <Clock :size=\"14\" />\n {{ formattedDuration }}\n </span>\n\n <span v-if=\"entry.simulated\" class=\"timeline-detail__simulated\" title=\"Simulated response\">\n <Zap :size=\"14\" />\n Simulated\n </span>\n </div>\n\n <div class=\"timeline-detail__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--sm\"\n title=\"Copy as JSON\"\n @click=\"copyFullEntry\"\n >\n <component :is=\"copiedField === 'full' ? Check : Copy\" :size=\"14\" />\n {{ copiedField === 'full' ? 'Copied!' : 'Copy JSON' }}\n </button>\n </div>\n </div>\n\n <!-- Info section -->\n <div class=\"timeline-detail__info\">\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Timestamp</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ formattedTimestamp }}</span>\n </div>\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Operation ID</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ entry.request.operationId }}</span>\n </div>\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Request ID</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ entry.id }}</span>\n </div>\n </div>\n\n <!-- Request section -->\n <div class=\"timeline-detail__section\">\n <h3 class=\"timeline-detail__section-title\">Request</h3>\n\n <!-- Query Parameters -->\n <div v-if=\"hasQueryParams\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.requestQuery\"\n aria-controls=\"requestQuery-panel\"\n @click=\"toggleSection('requestQuery')\"\n >\n <component\n :is=\"expandedSections.requestQuery ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Query Parameters</span>\n <span class=\"text-muted\">({{ Object.keys(entry.request.query).length }})</span>\n </button>\n <div\n id=\"requestQuery-panel\"\n v-show=\"expandedSections.requestQuery\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.request.query\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">\n {{ Array.isArray(value) ? value.join(', ') : value }}\n </span>\n </div>\n </div>\n </div>\n\n <!-- Request Headers -->\n <div v-if=\"hasRequestHeaders\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.requestHeaders\"\n aria-controls=\"requestHeaders-panel\"\n @click=\"toggleSection('requestHeaders')\"\n >\n <component\n :is=\"expandedSections.requestHeaders ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Headers</span>\n <span class=\"text-muted\">({{ Object.keys(entry.request.headers).length }})</span>\n </button>\n <div\n id=\"requestHeaders-panel\"\n v-show=\"expandedSections.requestHeaders\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.request.headers\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">{{ value }}</span>\n </div>\n </div>\n </div>\n\n <!-- Request Body -->\n <div v-if=\"hasRequestBody\" class=\"timeline-detail__subsection\">\n <div class=\"timeline-detail__subsection-header\" role=\"group\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-toggle\"\n :aria-expanded=\"expandedSections.requestBody\"\n aria-controls=\"requestBody-panel\"\n @click=\"toggleSection('requestBody')\"\n >\n <component\n :is=\"expandedSections.requestBody ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Body</span>\n </button>\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--icon btn--sm\"\n title=\"Copy body\"\n @click.stop=\"copyToClipboard(formatJson(entry.request.body), 'reqBody')\"\n >\n <component :is=\"copiedField === 'reqBody' ? Check : Copy\" :size=\"12\" />\n </button>\n </div>\n <div\n id=\"requestBody-panel\"\n v-show=\"expandedSections.requestBody\"\n class=\"timeline-detail__subsection-content\"\n >\n <pre class=\"timeline-detail__json\">{{ formatJson(entry.request.body) }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Response section -->\n <div v-if=\"entry.response\" class=\"timeline-detail__section\">\n <h3 class=\"timeline-detail__section-title\">Response</h3>\n\n <!-- Response Headers -->\n <div v-if=\"hasResponseHeaders\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.responseHeaders\"\n aria-controls=\"responseHeaders-panel\"\n @click=\"toggleSection('responseHeaders')\"\n >\n <component\n :is=\"expandedSections.responseHeaders ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Headers</span>\n <span class=\"text-muted\">({{ Object.keys(entry.response.headers).length }})</span>\n </button>\n <div\n id=\"responseHeaders-panel\"\n v-show=\"expandedSections.responseHeaders\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.response.headers\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">{{ value }}</span>\n </div>\n </div>\n </div>\n\n <!-- Response Body -->\n <div v-if=\"hasResponseBody\" class=\"timeline-detail__subsection\">\n <div class=\"timeline-detail__subsection-header\" role=\"group\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-toggle\"\n :aria-expanded=\"expandedSections.responseBody\"\n aria-controls=\"responseBody-panel\"\n @click=\"toggleSection('responseBody')\"\n >\n <component\n :is=\"expandedSections.responseBody ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Body</span>\n </button>\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--icon btn--sm\"\n title=\"Copy body\"\n @click.stop=\"copyToClipboard(formatJson(entry.response.body), 'resBody')\"\n >\n <component :is=\"copiedField === 'resBody' ? Check : Copy\" :size=\"12\" />\n </button>\n </div>\n <div\n id=\"responseBody-panel\"\n v-show=\"expandedSections.responseBody\"\n class=\"timeline-detail__subsection-content\"\n >\n <pre class=\"timeline-detail__json\">{{ formatJson(entry.response.body) }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Pending response state -->\n <div v-else class=\"timeline-detail__section timeline-detail__section--pending\">\n <h3 class=\"timeline-detail__section-title\">Response</h3>\n <div class=\"timeline-detail__pending\">\n <Clock :size=\"24\" class=\"timeline-detail__pending-icon\" />\n <span class=\"text-muted\">Waiting for response...</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.timeline-detail {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Empty state */\n.timeline-detail__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--devtools-space-xl);\n text-align: center;\n}\n\n.timeline-detail__empty-icon {\n color: var(--devtools-text-muted);\n opacity: 0.5;\n margin-bottom: var(--devtools-space-md);\n}\n\n.timeline-detail__empty-title {\n font-size: var(--font-size-3);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-sm) 0;\n}\n\n.timeline-detail__empty-description {\n font-size: var(--font-size-1);\n color: var(--devtools-text-muted);\n margin: 0;\n}\n\n/* Content */\n.timeline-detail__content {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow-y: auto;\n}\n\n/* Header */\n.timeline-detail__header {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__summary {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-detail__path {\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n word-break: break-all;\n}\n\n.timeline-detail__meta {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n}\n\n.timeline-detail__duration {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.timeline-detail__simulated {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-warning);\n}\n\n.timeline-detail__actions {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n/* Info section */\n.timeline-detail__info {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__info-item {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-detail__info-label {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.timeline-detail__info-value {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n}\n\n/* Section */\n.timeline-detail__section {\n padding: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__section:last-child {\n border-bottom: none;\n}\n\n.timeline-detail__section-title {\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-md) 0;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n/* Subsection */\n.timeline-detail__subsection {\n margin-bottom: var(--devtools-space-sm);\n}\n\n.timeline-detail__subsection:last-child {\n margin-bottom: 0;\n}\n\n.timeline-detail__subsection-header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n width: 100%;\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n}\n\n.timeline-detail__subsection-toggle {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n flex: 1;\n padding: 0;\n background: none;\n border: none;\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n text-align: left;\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-detail__subsection-toggle:hover {\n color: var(--devtools-text-hover);\n}\n\n.timeline-detail__subsection-content {\n margin-top: var(--devtools-space-xs);\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n}\n\n/* Key-value rows */\n.timeline-detail__kv-row {\n display: grid;\n grid-template-columns: minmax(120px, auto) 1fr;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xs) 0;\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__kv-row:last-child {\n border-bottom: none;\n}\n\n.timeline-detail__kv-key {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text-muted);\n word-break: break-all;\n}\n\n.timeline-detail__kv-value {\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n word-break: break-all;\n}\n\n/* JSON display */\n.timeline-detail__json {\n margin: 0;\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-bg);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-mono);\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n white-space: pre-wrap;\n word-break: break-all;\n overflow-x: auto;\n}\n\n/* Status badges */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: 2px var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n font-family: var(--devtools-font-mono);\n}\n\n.status-badge--pending {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n.status-badge--1xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--2xx {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.status-badge--3xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--4xx {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.status-badge--5xx {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n color: var(--devtools-error);\n}\n\n/* Pending response */\n.timeline-detail__pending {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-lg);\n}\n\n.timeline-detail__pending-icon {\n color: var(--devtools-text-muted);\n animation: pulse 2s ease-in-out infinite;\n}\n\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n</style>\n","<!--\n TimelineEntry.vue - Timeline Entry Component\n\n What: Displays a single request/response entry in the timeline\n How: Shows method, path, status, duration with color-coded badges\n Why: Provides consistent visualization of API traffic in the timeline list\n-->\n\n<script setup lang=\"ts\">\nimport { AlertTriangle, CheckCircle, Clock, Zap } from 'lucide-vue-next';\nimport { computed } from 'vue';\n\nimport type { TimelineEntry } from '@/stores/timeline';\n\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** The timeline entry to display */\n entry: TimelineEntry;\n /** Whether this entry is currently selected */\n isSelected?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isSelected: false,\n});\n\n/**\n * Component events\n */\nconst emit = defineEmits<{\n /** Emitted when the entry is clicked */\n (e: 'select', id: string): void;\n}>();\n\n/**\n * Format timestamp for display\n */\nconst formattedTime = computed(() => {\n const date = new Date(props.entry.request.timestamp);\n return date.toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: 3,\n });\n});\n\n/**\n * Format duration for display\n */\nconst formattedDuration = computed(() => {\n if (props.entry.duration === null) {\n return 'pending...';\n }\n if (props.entry.duration < 1000) {\n return `${props.entry.duration}ms`;\n }\n return `${(props.entry.duration / 1000).toFixed(2)}s`;\n});\n\n/**\n * Get status badge class based on status code\n */\nconst statusClass = computed(() => {\n if (props.entry.status === null) return 'status-badge--pending';\n if (props.entry.status < 200) return 'status-badge--1xx';\n if (props.entry.status < 300) return 'status-badge--2xx';\n if (props.entry.status < 400) return 'status-badge--3xx';\n if (props.entry.status < 500) return 'status-badge--4xx';\n return 'status-badge--5xx';\n});\n\n/**\n * Status icon component based on status code\n */\nconst statusIcon = computed(() => {\n if (props.entry.status === null) return Clock;\n if (props.entry.status < 400) return CheckCircle;\n return AlertTriangle;\n});\n\n/**\n * Whether the response is pending\n */\nconst isPending = computed(() => props.entry.response === null);\n\n/**\n * Handle entry click\n */\nfunction handleClick(): void {\n emit('select', props.entry.id);\n}\n</script>\n\n<template>\n <button\n type=\"button\"\n :class=\"[\n 'timeline-entry',\n { 'timeline-entry--selected': isSelected },\n { 'timeline-entry--pending': isPending },\n { 'timeline-entry--simulated': entry.simulated }\n ]\"\n @click=\"handleClick\"\n >\n <!-- Timestamp -->\n <div class=\"timeline-entry__time font-mono text-muted\">\n {{ formattedTime }}\n </div>\n\n <!-- Method badge -->\n <div class=\"timeline-entry__method\">\n <span :class=\"['method-badge', `method-badge--${entry.request.method.toLowerCase()}`]\">\n {{ getMethodLabel(entry.request.method) }}\n </span>\n </div>\n\n <!-- Path -->\n <div class=\"timeline-entry__path font-mono\">\n {{ entry.request.path }}\n </div>\n\n <!-- Status badge -->\n <div class=\"timeline-entry__status\">\n <span v-if=\"entry.status !== null\" :class=\"['status-badge', statusClass]\">\n <component :is=\"statusIcon\" :size=\"12\" />\n {{ entry.status }}\n </span>\n <span v-else class=\"status-badge status-badge--pending\">\n <Clock :size=\"12\" />\n pending\n </span>\n </div>\n\n <!-- Duration -->\n <div class=\"timeline-entry__duration font-mono text-muted\">\n {{ formattedDuration }}\n </div>\n\n <!-- Simulated indicator -->\n <div v-if=\"entry.simulated\" class=\"timeline-entry__simulated\" title=\"Simulated response\">\n <Zap :size=\"14\" />\n </div>\n </button>\n</template>\n\n<style scoped>\n.timeline-entry {\n display: grid;\n grid-template-columns: 100px 80px 1fr auto 80px auto;\n align-items: center;\n gap: var(--devtools-space-md);\n width: 100%;\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n background: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n text-align: left;\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-entry:hover {\n background-color: var(--devtools-surface-elevated);\n border-color: var(--devtools-border-hover);\n}\n\n.timeline-entry:focus {\n outline: none;\n}\n\n.timeline-entry:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.timeline-entry--selected {\n background-color: color-mix(in srgb, var(--devtools-primary) 10%, transparent);\n border-color: var(--devtools-primary);\n}\n\n.timeline-entry--selected:hover {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n}\n\n.timeline-entry--pending {\n opacity: 0.7;\n}\n\n.timeline-entry--simulated {\n border-left: 3px solid var(--devtools-warning);\n}\n\n/* Time column */\n.timeline-entry__time {\n font-size: var(--font-size-0);\n}\n\n/* Path column */\n.timeline-entry__path {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Status column */\n.timeline-entry__status {\n display: flex;\n align-items: center;\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: 2px var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n font-family: var(--devtools-font-mono);\n}\n\n.status-badge--pending {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n.status-badge--1xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--2xx {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.status-badge--3xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--4xx {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.status-badge--5xx {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n color: var(--devtools-error);\n}\n\n/* Duration column */\n.timeline-entry__duration {\n font-size: var(--font-size-0);\n text-align: right;\n}\n\n/* Simulated indicator */\n.timeline-entry__simulated {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--devtools-warning);\n}\n</style>\n","<!--\n TimelinePage.vue - Request/Response Timeline Page\n\n What: Displays a real-time timeline of API requests and responses\n How: Subscribes to WebSocket events and displays request/response logs with filtering\n Why: Allows developers to monitor and debug API traffic in real-time\n-->\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronUp, Clock, Filter, Search, Trash2, X } from 'lucide-vue-next';\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue';\n\nimport TimelineDetail from '@/components/TimelineDetail.vue';\nimport TimelineEntryComponent from '@/components/TimelineEntry.vue';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport {\n type HttpMethod,\n type RequestLogEntry,\n type ResponseLogEntry,\n type TimelineData,\n useTimelineStore,\n} from '@/stores/timeline';\n\n// Store and WebSocket\nconst timelineStore = useTimelineStore();\nconst { send, on, connected } = useWebSocket();\n\n// Local UI state\nconst showFilters = ref(false);\nconst searchInputRef = ref<HTMLInputElement | null>(null);\n\n// HTTP methods for filter\nconst httpMethods: HttpMethod[] = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n 'TRACE',\n];\n\n// Status categories for filter\nconst statusCategories = ['2xx', '3xx', '4xx', '5xx'] as const;\n\n/**\n * Fetch timeline data when connected\n */\nfunction fetchTimeline(): void {\n if (connected.value) {\n timelineStore.setLoading(true);\n send({ type: 'get:timeline' });\n }\n}\n\n/**\n * Handle timeline data from server\n */\nfunction handleTimelineData(data: TimelineData): void {\n timelineStore.setTimelineData(data);\n timelineStore.setLoading(false);\n}\n\n/**\n * Handle incoming request event\n */\nfunction handleRequest(data: RequestLogEntry): void {\n timelineStore.addRequest(data);\n}\n\n/**\n * Handle incoming response event\n */\nfunction handleResponse(data: ResponseLogEntry): void {\n timelineStore.addResponse(data);\n}\n\n/**\n * Handle timeline cleared event\n */\nfunction handleTimelineCleared(): void {\n timelineStore.clearTimeline();\n}\n\n/**\n * Clear timeline on server and locally\n */\nfunction clearTimeline(): void {\n send({ type: 'clear:timeline' });\n timelineStore.clearTimeline();\n}\n\n/**\n * Handle entry selection\n */\nfunction handleSelectEntry(id: string): void {\n timelineStore.selectEntry(id);\n}\n\n/**\n * Handle search input\n */\nfunction handleSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n timelineStore.setSearchQuery(target.value);\n}\n\n/**\n * Clear search\n */\nfunction clearSearch(): void {\n timelineStore.setSearchQuery('');\n searchInputRef.value?.focus();\n}\n\n/**\n * Toggle method filter\n */\nfunction toggleMethod(method: HttpMethod): void {\n timelineStore.toggleMethodFilter(method);\n}\n\n/**\n * Check if method is active in filter\n */\nfunction isMethodActive(method: HttpMethod): boolean {\n return timelineStore.filter.methods.includes(method);\n}\n\n/**\n * Toggle status filter\n */\nfunction toggleStatus(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): void {\n timelineStore.toggleStatusFilter(status);\n}\n\n/**\n * Check if status is active in filter\n */\nfunction isStatusActive(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): boolean {\n return timelineStore.filter.statusCodes.includes(status);\n}\n\n/**\n * Toggle simulated filter\n */\nfunction toggleSimulatedFilter(): void {\n const current = timelineStore.filter.simulatedOnly;\n timelineStore.setSimulatedFilter(current === true ? null : true);\n}\n\n/**\n * Clear all filters\n */\nfunction clearAllFilters(): void {\n timelineStore.clearFilters();\n}\n\n/**\n * Toggle filter panel visibility\n */\nfunction toggleFilters(): void {\n showFilters.value = !showFilters.value;\n}\n\n/**\n * Computed: Has active filters\n */\nconst hasActiveFilters = computed(() => timelineStore.hasActiveFilters());\n\n/**\n * Computed: Filter badge count\n */\nconst filterBadgeCount = computed(() => {\n return (\n timelineStore.filter.methods.length +\n timelineStore.filter.statusCodes.length +\n (timelineStore.filter.simulatedOnly !== null ? 1 : 0)\n );\n});\n\n// Event cleanup functions for WebSocket subscriptions\nlet unsubTimeline: (() => void) | null = null;\nlet unsubRequest: (() => void) | null = null;\nlet unsubResponse: (() => void) | null = null;\nlet unsubCleared: (() => void) | null = null;\n\n// Subscribe to timeline events and setup cleanup\nonMounted(() => {\n // Subscribe to WebSocket events\n unsubTimeline = on<TimelineData>('timeline', handleTimelineData);\n unsubRequest = on<RequestLogEntry>('request', handleRequest);\n unsubResponse = on<ResponseLogEntry>('response', handleResponse);\n unsubCleared = on('timeline:cleared', handleTimelineCleared);\n\n // Fetch timeline when already connected\n if (connected.value) {\n fetchTimeline();\n }\n});\n\n// Cleanup event subscriptions on unmount\nonUnmounted(() => {\n unsubTimeline?.();\n unsubRequest?.();\n unsubResponse?.();\n unsubCleared?.();\n});\n\n// Re-fetch when connection is established\nwatch(connected, (isConnected) => {\n if (isConnected) {\n fetchTimeline();\n }\n});\n</script>\n\n<template>\n <div class=\"timeline-page\">\n <!-- Toolbar -->\n <div class=\"timeline-toolbar\">\n <!-- Search -->\n <div class=\"timeline-search\">\n <Search :size=\"16\" class=\"timeline-search__icon\" />\n <input\n ref=\"searchInputRef\"\n type=\"text\"\n class=\"timeline-search__input input\"\n placeholder=\"Search by path or operation...\"\n :value=\"timelineStore.filter.searchQuery\"\n @input=\"handleSearchInput\"\n />\n <button\n v-if=\"timelineStore.filter.searchQuery\"\n type=\"button\"\n class=\"timeline-search__clear btn btn--ghost btn--icon\"\n title=\"Clear search\"\n @click=\"clearSearch\"\n >\n <X :size=\"14\" />\n </button>\n </div>\n\n <!-- Filter toggle -->\n <button\n type=\"button\"\n :class=\"[\n 'timeline-filter-toggle btn btn--secondary',\n { 'timeline-filter-toggle--active': hasActiveFilters }\n ]\"\n :aria-expanded=\"showFilters\"\n @click=\"toggleFilters\"\n >\n <Filter :size=\"16\" />\n <span>Filters</span>\n <span v-if=\"filterBadgeCount > 0\" class=\"timeline-filter-toggle__badge\">\n {{ filterBadgeCount }}\n </span>\n <component :is=\"showFilters ? ChevronUp : ChevronDown\" :size=\"14\" />\n </button>\n\n <!-- Stats -->\n <div class=\"timeline-stats\">\n <span class=\"timeline-stats__item\">\n {{ timelineStore.filteredEntries.length }} requests\n </span>\n <span v-if=\"timelineStore.averageDuration > 0\" class=\"timeline-stats__separator\">|</span>\n <span v-if=\"timelineStore.averageDuration > 0\" class=\"timeline-stats__item\">\n avg {{ timelineStore.averageDuration }}ms\n </span>\n </div>\n\n <!-- Clear button -->\n <button\n type=\"button\"\n class=\"btn btn--secondary btn--icon\"\n title=\"Clear timeline\"\n :disabled=\"timelineStore.entries.length === 0\"\n @click=\"clearTimeline\"\n >\n <Trash2 :size=\"16\" />\n </button>\n </div>\n\n <!-- Filter panel -->\n <div v-if=\"showFilters\" class=\"timeline-filters\">\n <!-- Method filters -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Methods</h4>\n <div class=\"timeline-filters__methods\">\n <button\n v-for=\"method in httpMethods\"\n :key=\"method\"\n type=\"button\"\n :class=\"[\n 'method-badge',\n `method-badge--${method.toLowerCase()}`,\n { 'method-badge--inactive': !isMethodActive(method) && timelineStore.filter.methods.length > 0 }\n ]\"\n @click=\"toggleMethod(method)\"\n >\n {{ method }}\n </button>\n </div>\n </div>\n\n <!-- Status filters -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Status</h4>\n <div class=\"timeline-filters__status\">\n <button\n v-for=\"status in statusCategories\"\n :key=\"status\"\n type=\"button\"\n :class=\"[\n 'timeline-filters__status-btn',\n `timeline-filters__status-btn--${status}`,\n { 'timeline-filters__status-btn--active': isStatusActive(status) }\n ]\"\n @click=\"toggleStatus(status)\"\n >\n {{ status }}\n <span class=\"timeline-filters__status-count\">\n ({{ timelineStore.statusCounts[status] }})\n </span>\n </button>\n </div>\n </div>\n\n <!-- Simulated filter -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Type</h4>\n <div class=\"timeline-filters__type\">\n <button\n type=\"button\"\n :class=\"[\n 'timeline-filters__status-btn',\n { 'timeline-filters__status-btn--active': timelineStore.filter.simulatedOnly }\n ]\"\n @click=\"toggleSimulatedFilter\"\n >\n Simulated only\n </button>\n </div>\n </div>\n\n <!-- Clear filters -->\n <div v-if=\"hasActiveFilters\" class=\"timeline-filters__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost\"\n @click=\"clearAllFilters\"\n >\n <X :size=\"14\" />\n Clear all filters\n </button>\n </div>\n </div>\n\n <!-- Main content -->\n <div class=\"timeline-content\">\n <!-- Loading state -->\n <div v-if=\"timelineStore.isLoading\" class=\"timeline-loading\">\n <div class=\"timeline-loading__spinner\" />\n <span class=\"text-muted\">Loading timeline...</span>\n </div>\n\n <!-- Error state -->\n <div v-else-if=\"timelineStore.error\" class=\"timeline-error\">\n <p class=\"timeline-error__message\">{{ timelineStore.error }}</p>\n <button type=\"button\" class=\"btn btn--primary\" @click=\"fetchTimeline\">\n Retry\n </button>\n </div>\n\n <!-- Empty state -->\n <div v-else-if=\"timelineStore.entries.length === 0\" class=\"timeline-empty empty-state\">\n <Clock :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No requests yet</h3>\n <p class=\"empty-state__description\">\n API requests will appear here in real-time as they are made.\n </p>\n </div>\n\n <!-- No results state -->\n <div v-else-if=\"timelineStore.filteredEntries.length === 0\" class=\"timeline-empty empty-state\">\n <Search :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No matching requests</h3>\n <p class=\"empty-state__description\">\n Try adjusting your search or filters.\n </p>\n <button\n v-if=\"hasActiveFilters\"\n type=\"button\"\n class=\"btn btn--secondary\"\n @click=\"clearAllFilters\"\n >\n Clear filters\n </button>\n </div>\n\n <!-- Split panel layout -->\n <template v-else>\n <!-- Timeline list panel -->\n <div class=\"timeline-list-panel\">\n <div class=\"timeline-list\">\n <TimelineEntryComponent\n v-for=\"entry in timelineStore.filteredEntries\"\n :key=\"entry.id\"\n :entry=\"entry\"\n :is-selected=\"timelineStore.selectedEntryId === entry.id\"\n @select=\"handleSelectEntry\"\n />\n </div>\n </div>\n\n <!-- Timeline detail panel -->\n <div class=\"timeline-detail-panel\">\n <TimelineDetail :entry=\"timelineStore.selectedEntry\" />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.timeline-page {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Toolbar */\n.timeline-toolbar {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-search {\n position: relative;\n flex: 1;\n max-width: 400px;\n}\n\n.timeline-search__icon {\n position: absolute;\n left: var(--devtools-space-sm);\n top: 50%;\n transform: translateY(-50%);\n color: var(--devtools-text-muted);\n pointer-events: none;\n}\n\n.timeline-search__input {\n padding-left: calc(var(--devtools-space-sm) + 24px);\n padding-right: calc(var(--devtools-space-sm) + 24px);\n}\n\n.timeline-search__clear {\n position: absolute;\n right: var(--devtools-space-xs);\n top: 50%;\n transform: translateY(-50%);\n padding: var(--devtools-space-xs);\n}\n\n.timeline-filter-toggle {\n flex-shrink: 0;\n}\n\n.timeline-filter-toggle--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.timeline-filter-toggle__badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-primary);\n color: var(--devtools-text-inverted);\n border-radius: 9px;\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n}\n\n.timeline-stats {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n margin-left: auto;\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.timeline-stats__separator {\n opacity: 0.5;\n}\n\n/* Filter panel */\n.timeline-filters {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: var(--devtools-space-lg);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-filters__section {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__title {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.timeline-filters__methods {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-filters__methods .method-badge {\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-filters__methods .method-badge--inactive {\n opacity: 0.4;\n}\n\n.timeline-filters__status {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__type {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__status-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-filters__status-btn:hover {\n background-color: var(--devtools-surface-elevated);\n color: var(--devtools-text);\n}\n\n.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.timeline-filters__status-btn--2xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n border-color: var(--devtools-success);\n color: var(--devtools-success);\n}\n\n.timeline-filters__status-btn--3xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n border-color: var(--devtools-info);\n color: var(--devtools-info);\n}\n\n.timeline-filters__status-btn--4xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n border-color: var(--devtools-warning);\n color: var(--devtools-warning);\n}\n\n.timeline-filters__status-btn--5xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n border-color: var(--devtools-error);\n color: var(--devtools-error);\n}\n\n.timeline-filters__status-count {\n font-size: var(--font-size-00);\n opacity: 0.7;\n}\n\n.timeline-filters__actions {\n display: flex;\n align-items: flex-end;\n margin-left: auto;\n}\n\n/* Main content */\n.timeline-content {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n/* Loading state */\n.timeline-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n}\n\n.timeline-loading__spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--devtools-border);\n border-top-color: var(--devtools-primary);\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Error state */\n.timeline-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xl);\n}\n\n.timeline-error__message {\n color: var(--devtools-error);\n margin: 0;\n}\n\n/* Empty state */\n.timeline-empty {\n width: 100%;\n}\n\n/* Split panels */\n.timeline-list-panel {\n width: 50%;\n min-width: 300px;\n max-width: 600px;\n border-right: 1px solid var(--devtools-border);\n background-color: var(--devtools-bg);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.timeline-list {\n flex: 1;\n overflow-y: auto;\n padding: var(--devtools-space-sm);\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-detail-panel {\n flex: 1;\n overflow: hidden;\n background-color: var(--devtools-bg);\n}\n</style>\n"],"names":["CircleCheckBig","createLucideIcon","Copy","useTimelineStore","defineStore","entries","ref","isLoading","error","filter","selectedEntryId","maxEntries","responseBuffer","getStatusCategory","status","filteredEntries","computed","result","query","entry","category","selectedEntry","e","totalCount","completedCount","pendingCount","statusCounts","counts","averageDuration","completedEntries","totalDuration","sum","addRequest","request","bufferedResponse","mergeResponse","addResponse","response","stubEntry","createStubEntry","stubRequest","processBufferedResponses","requestMap","requestId","processIncomingResponses","incomingResponses","createStubsForOrphanedResponses","setTimelineData","data","item","sorted","a","b","clearTimeline","setLoading","loading","setError","errorMessage","clearError","setSearchQuery","toggleMethodFilter","method","index","toggleStatusFilter","setSimulatedFilter","simulated","clearFilters","hasActiveFilters","selectEntry","id","setMaxEntries","limit","clamped","props","__props","expandedSections","copiedField","formattedTimestamp","formattedDuration","statusClass","hasQueryParams","hasRequestHeaders","hasRequestBody","hasResponseHeaders","hasResponseBody","formatJson","value","toggleSection","section","copyToClipboard","text","fieldId","err","copyFullEntry","_openBlock","_createElementBlock","_hoisted_1","_hoisted_3","_createElementVNode","_hoisted_4","_hoisted_5","_toDisplayString","_unref","getMethodLabel","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_createVNode","Clock","_createTextVNode","_hoisted_10","Zap","_hoisted_11","_createBlock","_resolveDynamicComponent","Check","_hoisted_12","_hoisted_13","_cache","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","ChevronDown","ChevronRight","_hoisted_22","_withDirectives","_hoisted_23","_Fragment","_renderList","key","_hoisted_24","_hoisted_25","_vShow","_hoisted_26","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_withModifiers","$event","_hoisted_35","_hoisted_36","_hoisted_37","_hoisted_38","_hoisted_40","_hoisted_41","_hoisted_42","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_47","_hoisted_48","_hoisted_49","_hoisted_50","_hoisted_2","emit","__emit","formattedTime","statusIcon","CheckCircle","AlertTriangle","isPending","handleClick","_normalizeClass","timelineStore","send","on","connected","useWebSocket","showFilters","searchInputRef","httpMethods","statusCategories","fetchTimeline","handleTimelineData","handleRequest","handleResponse","handleTimelineCleared","handleSelectEntry","handleSearchInput","event","target","clearSearch","toggleMethod","isMethodActive","toggleStatus","isStatusActive","toggleSimulatedFilter","current","clearAllFilters","toggleFilters","filterBadgeCount","unsubTimeline","unsubRequest","unsubResponse","unsubCleared","onMounted","onUnmounted","watch","isConnected","Search","X","Filter","ChevronUp","Trash2","_hoisted_21","_hoisted_27","TimelineEntryComponent","TimelineDetail"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { c } from "./main-
|
|
1
|
+
import { c } from "./main-B4KUU1eG.js";
|
|
2
2
|
const o = c("check", [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]]);
|
|
3
3
|
export {
|
|
4
4
|
o as C
|
|
5
5
|
};
|
|
6
|
-
//# sourceMappingURL=check-
|
|
6
|
+
//# sourceMappingURL=check-C8somSxy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-
|
|
1
|
+
{"version":3,"file":"check-C8somSxy.js","sources":["../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/check.js"],"sourcesContent":["/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Check = createLucideIcon(\"check\", [[\"path\", { d: \"M20 6 9 17l-5-5\", key: \"1gmf2c\" }]]);\n\nexport { Check as default };\n//# sourceMappingURL=check.js.map\n"],"names":["Check","createLucideIcon"],"mappings":";AASK,MAACA,IAAQC,EAAiB,SAAS,CAAC,CAAC,QAAQ,EAAE,GAAG,mBAAmB,KAAK,SAAQ,CAAE,CAAC,CAAC;","x_google_ignoreList":[0]}
|