diff --git a/packages/replay-next/components/sources/utils/points.ts b/packages/replay-next/components/sources/utils/points.ts index 6ad219ca612..e18b1a70325 100644 --- a/packages/replay-next/components/sources/utils/points.ts +++ b/packages/replay-next/components/sources/utils/points.ts @@ -1,6 +1,6 @@ import { ExecutionPoint, SourceId, TimeStampedPoint } from "@replayio/protocol"; -import { binarySearch, compareTimeStampedPoints, sameSupplementalIndex } from "protocol/utils"; +import { binarySearch, compareTimeStampedPoints, breakdownSupplementalId } from "protocol/utils"; import { isExecutionPointsGreaterThan, isExecutionPointsLessThan, @@ -27,7 +27,8 @@ export function findClosestHitPoint( return [hitPoint, index]; } - if (!sameSupplementalIndex(executionPoint.point, hitPoint.point)) { + if (breakdownSupplementalId(executionPoint.point).supplementalIndex || + breakdownSupplementalId(hitPoint.point).supplementalIndex) { return [hitPoint, index]; } diff --git a/packages/replay-next/src/utils/time.ts b/packages/replay-next/src/utils/time.ts index d95da91e4b3..96af4bc69e4 100644 --- a/packages/replay-next/src/utils/time.ts +++ b/packages/replay-next/src/utils/time.ts @@ -6,7 +6,7 @@ import differenceInWeeks from "date-fns/differenceInWeeks"; import differenceInYears from "date-fns/differenceInYears"; import padStart from "lodash/padStart"; import prettyMilliseconds from "pretty-ms"; -import { compareExecutionPoints as baseCompareExecutionPoints } from "protocol/utils"; +import { compareExecutionPoints as baseCompareExecutionPoints, sameSupplementalIndex } from "protocol/utils"; export const compareExecutionPoints = baseCompareExecutionPoints; @@ -23,6 +23,9 @@ export function isExecutionPointsWithinRange( beginPoint: ExecutionPoint, endPoint: ExecutionPoint ): boolean { + if (!sameSupplementalIndex(point, beginPoint)) { + return true; + } return !( isExecutionPointsLessThan(point, beginPoint) || isExecutionPointsGreaterThan(point, endPoint) ); diff --git a/packages/shared/client/ReplayClient.ts b/packages/shared/client/ReplayClient.ts index 7d09fbbd5ff..a4465ad25a5 100644 --- a/packages/shared/client/ReplayClient.ts +++ b/packages/shared/client/ReplayClient.ts @@ -177,6 +177,15 @@ export class ReplayClient implements ReplayClientInterface { return sessionId || await this.waitForSession(); } + private getSessionIdSupplementalIndex(sessionId: string) { + for (let i = 0; i < this.supplemental.length; i++) { + if (sessionId == this.supplemental[i].sessionId) { + return i + 1; + } + } + return 0; + } + get loadedRegions(): LoadedRegions | null { return this._loadedRegions; } @@ -234,6 +243,7 @@ export class ReplayClient implements ReplayClientInterface { sessionId, pauseId ); + this.transformSupplementalPauseData(response.result.data, sessionId); return response.result; } else { const response = await client.Pause.evaluateInFrame( @@ -246,6 +256,7 @@ export class ReplayClient implements ReplayClientInterface { sessionId, pauseId ); + this.transformSupplementalPauseData(response.result.data, sessionId); return response.result; } } @@ -558,24 +569,28 @@ export class ReplayClient implements ReplayClientInterface { async findStepInTarget(transformedPoint: ExecutionPoint): Promise { const { id: point, sessionId } = await this.breakdownSupplementalIdAndSession(transformedPoint); const { target } = await client.Debugger.findStepInTarget({ point }, sessionId); + this.transformSupplementalPointDescription(target, sessionId); return target; } async findStepOutTarget(transformedPoint: ExecutionPoint): Promise { const { id: point, sessionId } = await this.breakdownSupplementalIdAndSession(transformedPoint); const { target } = await client.Debugger.findStepOutTarget({ point }, sessionId); + this.transformSupplementalPointDescription(target, sessionId); return target; } async findStepOverTarget(transformedPoint: ExecutionPoint): Promise { const { id: point, sessionId } = await this.breakdownSupplementalIdAndSession(transformedPoint); const { target } = await client.Debugger.findStepOverTarget({ point }, sessionId); + this.transformSupplementalPointDescription(target, sessionId); return target; } async findReverseStepOverTarget(transformedPoint: ExecutionPoint): Promise { const { id: point, sessionId } = await this.breakdownSupplementalIdAndSession(transformedPoint); const { target } = await client.Debugger.findReverseStepOverTarget({ point }, sessionId); + this.transformSupplementalPointDescription(target, sessionId); return target; } @@ -606,9 +621,43 @@ export class ReplayClient implements ReplayClientInterface { return sources; } + private transformSupplementalLocation(location: Location, supplementalIndex: number) { + location.sourceId = transformSupplementalId(location.sourceId, supplementalIndex); + } + + private transformSupplementalMappedLocation(mappedLocation: MappedLocation | undefined, supplementalIndex: number) { + for (const location of mappedLocation || []) { + this.transformSupplementalLocation(location, supplementalIndex); + } + } + + private transformSupplementalPauseData(data: PauseData, sessionId: string) { + const supplementalIndex = this.getSessionIdSupplementalIndex(sessionId); + if (!supplementalIndex) { + return; + } + for (const frame of data.frames || []) { + this.transformSupplementalMappedLocation(frame.location, supplementalIndex); + this.transformSupplementalMappedLocation(frame.functionLocation, supplementalIndex); + } + for (const object of data.objects || []) { + this.transformSupplementalMappedLocation(object.preview?.functionLocation, supplementalIndex); + } + } + + private transformSupplementalPointDescription(point: PointDescription, sessionId: string) { + const supplementalIndex = this.getSessionIdSupplementalIndex(sessionId); + if (!supplementalIndex) { + return; + } + point.point = transformSupplementalId(point.point, supplementalIndex); + this.transformSupplementalMappedLocation(point.frame, supplementalIndex); + } + async getAllFrames(pauseId: PauseId): Promise { const sessionId = await this.getPauseSessionId(pauseId); const result = await client.Pause.getAllFrames({}, sessionId, pauseId); + this.transformSupplementalPauseData(result.data, sessionId); return result; } @@ -671,6 +720,7 @@ export class ReplayClient implements ReplayClientInterface { async getTopFrame(pauseId: PauseId): Promise { const sessionId = await this.getPauseSessionId(pauseId); const result = await client.Pause.getTopFrame({}, sessionId, pauseId); + this.transformSupplementalPauseData(result.data, sessionId); return result; } @@ -767,7 +817,9 @@ export class ReplayClient implements ReplayClientInterface { async getExceptionValue(pauseId: PauseId): Promise { const sessionId = await this.getPauseSessionId(pauseId); - return client.Pause.getExceptionValue({}, sessionId, pauseId); + const result = await client.Pause.getExceptionValue({}, sessionId, pauseId); + this.transformSupplementalPauseData(result.data, sessionId); + return result; } private async syncFocusWindow(): Promise { @@ -781,6 +833,9 @@ export class ReplayClient implements ReplayClientInterface { async getFrameSteps(pauseId: PauseId, frameId: FrameId): Promise { const sessionId = await this.getPauseSessionId(pauseId); const { steps } = await client.Pause.getFrameSteps({ frameId }, sessionId, pauseId); + for (const step of steps) { + this.transformSupplementalPointDescription(step, sessionId); + } return steps; } @@ -798,6 +853,7 @@ export class ReplayClient implements ReplayClientInterface { sessionId, pauseId ); + this.transformSupplementalPauseData(result.data, sessionId); return result; } @@ -812,6 +868,7 @@ export class ReplayClient implements ReplayClientInterface { sessionId, pauseId || undefined ); + this.transformSupplementalPauseData(result.data, sessionId); return result.data; } diff --git a/src/devtools/client/debugger/src/components/SecondaryPanes/FrameTimeline.tsx b/src/devtools/client/debugger/src/components/SecondaryPanes/FrameTimeline.tsx index dd4d526898c..60f9fb96a4d 100644 --- a/src/devtools/client/debugger/src/components/SecondaryPanes/FrameTimeline.tsx +++ b/src/devtools/client/debugger/src/components/SecondaryPanes/FrameTimeline.tsx @@ -32,9 +32,11 @@ import { PauseAndFrameId, PauseFrame, getExecutionPoint, + getTime, getSelectedFrameId, } from "../../reducers/pause"; import { getSelectedFrameSuspense } from "../../selectors/pause"; +import { compareTimeStampedPoints } from "protocol/utils"; function getBoundingClientRect(element?: HTMLElement) { if (!element) { @@ -51,6 +53,7 @@ interface FrameTimelineState { interface FrameTimelineProps { executionPoint: string | null; + time: number; selectedLocation: PartialLocation | null; selectedFrame: PauseFrame | null; frameSteps: PointDescription[] | undefined; @@ -176,7 +179,7 @@ class FrameTimelineRenderer extends Component BigInt(position.point) <= BigInt(executionPoint) + position => compareTimeStampedPoints(position, { point: executionPoint, time }) <= 0 ); // Check if the current executionPoint's corresponding index is similar to the @@ -236,6 +239,7 @@ function FrameTimeline({ selectedFrameId }: { selectedFrameId: PauseAndFrameId | const replayClient = useContext(ReplayClientContext); const sourcesState = useAppSelector(state => state.sources); const executionPoint = useAppSelector(getExecutionPoint); + const time = useAppSelector(getTime); const selectedLocation = useAppSelector(getSelectedLocation); const selectedFrame = useAppSelector(state => getSelectedFrameSuspense(replayClient, state, selectedFrameId) @@ -256,6 +260,7 @@ function FrameTimeline({ selectedFrameId }: { selectedFrameId: PauseAndFrameId | return (