From 62b18b376d3bb103489a408346d08cb8ca59cd2e Mon Sep 17 00:00:00 2001 From: cpadm <57954026+cpAdm@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:09:31 +0100 Subject: [PATCH 1/2] refactor(trace-viewer): Use resource id instead of ordinal for resource hover --- packages/trace-viewer/src/ui/networkTab.tsx | 10 ++++------ packages/trace-viewer/src/ui/timeline.tsx | 22 ++++++++++++--------- packages/trace-viewer/src/ui/workbench.tsx | 6 +++--- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/trace-viewer/src/ui/networkTab.tsx b/packages/trace-viewer/src/ui/networkTab.tsx index c182b46736054..af5bd13297eb1 100644 --- a/packages/trace-viewer/src/ui/networkTab.tsx +++ b/packages/trace-viewer/src/ui/networkTab.tsx @@ -34,7 +34,6 @@ type NetworkTabModel = { }; type RenderedEntry = { - ordinal: number, name: { name: string, url: string }, method: string, status: { code: number, text: string }, @@ -67,7 +66,7 @@ export function useNetworkTabModel(model: TraceModel | undefined, selectedTime: export const NetworkTab: React.FunctionComponent<{ boundaries: Boundaries, networkModel: NetworkTabModel, - onResourceHovered?: (ordinal: number | undefined) => void, + onResourceHovered?: (key: string | undefined) => void, sdkLanguage: Language, }> = ({ boundaries, networkModel, onResourceHovered, sdkLanguage }) => { const [sorting, setSorting] = React.useState(undefined); @@ -75,7 +74,7 @@ export const NetworkTab: React.FunctionComponent<{ const [filterState, setFilterState] = React.useState(defaultFilterState); const { renderedEntries } = React.useMemo(() => { - const renderedEntries = networkModel.resources.map((entry, i) => renderEntry(entry, boundaries, networkModel.contextIdMap, i)).filter(filterEntry(filterState)); + const renderedEntries = networkModel.resources.map(entry => renderEntry(entry, boundaries, networkModel.contextIdMap)).filter(filterEntry(filterState)); if (sorting) sort(renderedEntries, sorting); return { renderedEntries }; @@ -101,7 +100,7 @@ export const NetworkTab: React.FunctionComponent<{ items={renderedEntries} selectedItem={visibleSelectedEntry} onSelected={item => setSelectedResourceKey(item.resource.id)} - onHighlighted={item => onResourceHovered?.(item?.ordinal)} + onHighlighted={item => onResourceHovered?.(item?.resource.id)} columns={visibleColumns(!!visibleSelectedEntry, renderedEntries)} columnTitle={columnTitle} columnWidths={columnWidths} @@ -264,7 +263,7 @@ function hasMultipleContexts(renderedEntries: RenderedEntry[]): boolean { return false; } -const renderEntry = (resource: ResourceEntry, boundaries: Boundaries, contextIdGenerator: ContextIdMap, ordinal: number): RenderedEntry => { +const renderEntry = (resource: ResourceEntry, boundaries: Boundaries, contextIdGenerator: ContextIdMap): RenderedEntry => { const routeStatus = formatRouteStatus(resource); let resourceName: string; try { @@ -283,7 +282,6 @@ const renderEntry = (resource: ResourceEntry, boundaries: Boundaries, contextIdG contentType = charset[1]; return { - ordinal, name: { name: resourceName, url: resource.request.url }, method: resource.request.method, status: { code: resource.response.status, text: resource.response.statusText }, diff --git a/packages/trace-viewer/src/ui/timeline.tsx b/packages/trace-viewer/src/ui/timeline.tsx index c22bad94c78b2..e37a4b2dd972d 100644 --- a/packages/trace-viewer/src/ui/timeline.tsx +++ b/packages/trace-viewer/src/ui/timeline.tsx @@ -20,16 +20,15 @@ import * as React from 'react'; import type { Boundaries } from './geometry'; import { FilmStrip } from './filmStrip'; import type { FilmStripPreviewPoint } from './filmStrip'; -import type { ActionTraceEventInContext, TraceModel } from '@isomorphic/trace/traceModel'; +import type { ActionTraceEventInContext, ResourceEntry, TraceModel } from '@isomorphic/trace/traceModel'; import './timeline.css'; import type { Language } from '@isomorphic/locatorGenerators'; -import type { Entry } from '@trace/har'; import type { ConsoleEntry } from './consoleTab'; import type { ActionGroup } from '@isomorphic/protocolFormatter'; type TimelineBar = { action?: ActionTraceEventInContext; - resource?: Entry; + resource?: ResourceEntry; consoleMessage?: ConsoleEntry; leftPosition: number; rightPosition: number; @@ -42,16 +41,16 @@ type TimelineBar = { export const Timeline: React.FunctionComponent<{ model: TraceModel | undefined, consoleEntries: ConsoleEntry[] | undefined, - networkResources: Entry[] | undefined, + networkResources: ResourceEntry[] | undefined, boundaries: Boundaries, highlightedAction: ActionTraceEventInContext | undefined, - highlightedResourceOrdinal: number | undefined, + highlightedResourceKey: string | undefined, highlightedConsoleEntryOrdinal: number | undefined, onSelected: (action: ActionTraceEventInContext) => void, selectedTime: Boundaries | undefined, setSelectedTime: (time: Boundaries | undefined) => void, sdkLanguage: Language, -}> = ({ model, boundaries, consoleEntries, networkResources, onSelected, highlightedAction, highlightedResourceOrdinal, highlightedConsoleEntryOrdinal, selectedTime, setSelectedTime, sdkLanguage }) => { +}> = ({ model, boundaries, consoleEntries, networkResources, onSelected, highlightedAction, highlightedResourceKey, highlightedConsoleEntryOrdinal, selectedTime, setSelectedTime, sdkLanguage }) => { const [measure, ref] = useMeasure(); const [dragWindow, setDragWindow] = React.useState<{ startX: number, endX: number, pivot?: number, type: 'resize' | 'move' } | undefined>(); const [previewPoint, setPreviewPoint] = React.useState(); @@ -115,18 +114,23 @@ export const Timeline: React.FunctionComponent<{ return bars; }, [model, actions, consoleEntries, boundaries, measure]); + const highlightedResource = React.useMemo( + () => highlightedResourceKey ? networkResources?.find(resource => resource.id === highlightedResourceKey) : undefined, + [networkResources, highlightedResourceKey] + ); + React.useMemo(() => { for (const bar of bars) { if (highlightedAction) bar.active = bar.action === highlightedAction; - else if (highlightedResourceOrdinal !== undefined) - bar.active = bar.resource === networkResources?.[highlightedResourceOrdinal]; + else if (highlightedResource) + bar.active = bar.resource === highlightedResource; else if (highlightedConsoleEntryOrdinal !== undefined) bar.active = bar.consoleMessage === consoleEntries?.[highlightedConsoleEntryOrdinal]; else bar.active = false; } - }, [bars, highlightedAction, highlightedResourceOrdinal, highlightedConsoleEntryOrdinal, consoleEntries, networkResources]); + }, [bars, highlightedAction, highlightedResource, highlightedConsoleEntryOrdinal, consoleEntries]); const onMouseDown = React.useCallback((event: React.MouseEvent) => { setPreviewPoint(undefined); diff --git a/packages/trace-viewer/src/ui/workbench.tsx b/packages/trace-viewer/src/ui/workbench.tsx index 9858690c2fcf9..98175a3d11381 100644 --- a/packages/trace-viewer/src/ui/workbench.tsx +++ b/packages/trace-viewer/src/ui/workbench.tsx @@ -86,7 +86,7 @@ const PartitionedWorkbench: React.FunctionComponent('revealedErrorKey'); const [highlightedConsoleMessageOrdinal, setHighlightedConsoleMessageOrdinal] = usePartitionedState('highlightedConsoleMessageOrdinal'); const [revealedAttachmentCallId, setRevealedAttachmentCallId] = usePartitionedState<{ callId: string } | undefined>('revealedAttachmentCallId'); - const [highlightedResourceOrdinal, setHighlightedResourceOrdinal] = usePartitionedState('highlightedResourceOrdinal'); + const [highlightedResourceKey, setHighlightedResourceKey] = usePartitionedState('highlightedResourceKey'); const [treeState, setTreeState] = usePartitionedState('treeState', { expandedItems: new Map() }); togglePartition(partition); @@ -258,7 +258,7 @@ const PartitionedWorkbench: React.FunctionComponent + render: () => }; const attachmentsTab: TabbedPaneTabModel = { id: 'attachments', @@ -352,7 +352,7 @@ const PartitionedWorkbench: React.FunctionComponent Date: Mon, 23 Feb 2026 20:08:41 +0100 Subject: [PATCH 2/2] perf(trace-viewer): Only store and compare key of resource of bar --- packages/trace-viewer/src/ui/timeline.tsx | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/trace-viewer/src/ui/timeline.tsx b/packages/trace-viewer/src/ui/timeline.tsx index e37a4b2dd972d..5b8479304832e 100644 --- a/packages/trace-viewer/src/ui/timeline.tsx +++ b/packages/trace-viewer/src/ui/timeline.tsx @@ -28,7 +28,7 @@ import type { ActionGroup } from '@isomorphic/protocolFormatter'; type TimelineBar = { action?: ActionTraceEventInContext; - resource?: ResourceEntry; + resourceKey?: string; consoleMessage?: ConsoleEntry; leftPosition: number; rightPosition: number; @@ -89,7 +89,7 @@ export const Timeline: React.FunctionComponent<{ const startTime = resource._monotonicTime!; const endTime = resource._monotonicTime! + resource.time; bars.push({ - resource, + resourceKey: resource.id, leftTime: startTime, rightTime: endTime, leftPosition: timeToPosition(measure.width, boundaries, startTime), @@ -114,23 +114,18 @@ export const Timeline: React.FunctionComponent<{ return bars; }, [model, actions, consoleEntries, boundaries, measure]); - const highlightedResource = React.useMemo( - () => highlightedResourceKey ? networkResources?.find(resource => resource.id === highlightedResourceKey) : undefined, - [networkResources, highlightedResourceKey] - ); - React.useMemo(() => { for (const bar of bars) { if (highlightedAction) bar.active = bar.action === highlightedAction; - else if (highlightedResource) - bar.active = bar.resource === highlightedResource; + else if (highlightedResourceKey) + bar.active = bar.resourceKey === highlightedResourceKey; else if (highlightedConsoleEntryOrdinal !== undefined) bar.active = bar.consoleMessage === consoleEntries?.[highlightedConsoleEntryOrdinal]; else bar.active = false; } - }, [bars, highlightedAction, highlightedResource, highlightedConsoleEntryOrdinal, consoleEntries]); + }, [bars, highlightedAction, highlightedResourceKey, highlightedConsoleEntryOrdinal, consoleEntries]); const onMouseDown = React.useCallback((event: React.MouseEvent) => { setPreviewPoint(undefined); @@ -263,7 +258,7 @@ export const Timeline: React.FunctionComponent<{ return