chore: render wait for on trace timeline (#6222)
This commit is contained in:
parent
17ead28285
commit
90913160c4
|
|
@ -103,8 +103,8 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
|
|||
}
|
||||
}
|
||||
|
||||
_waitForEventInfoBefore(waitId: string, name: string, stack: StackFrame[]) {
|
||||
this._connection.sendMessageToServer(this._guid, 'waitForEventInfo', { info: { name, waitId, phase: 'before', stack } }, undefined).catch(() => {});
|
||||
_waitForEventInfoBefore(waitId: string, apiName: string, stack: StackFrame[]) {
|
||||
this._connection.sendMessageToServer(this._guid, 'waitForEventInfo', { info: { apiName, waitId, phase: 'before', stack } }, undefined).catch(() => {});
|
||||
}
|
||||
|
||||
_waitForEventInfoAfter(waitId: string, error?: string) {
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ export class Waiter {
|
|||
private _waitId: string;
|
||||
private _error: string | undefined;
|
||||
|
||||
constructor(channelOwner: ChannelOwner, name: string) {
|
||||
constructor(channelOwner: ChannelOwner, apiName: string) {
|
||||
this._waitId = createGuid();
|
||||
this._channelOwner = channelOwner;
|
||||
this._channelOwner._waitForEventInfoBefore(this._waitId, name, captureStackTrace().frames);
|
||||
this._channelOwner._waitForEventInfoBefore(this._waitId, apiName, captureStackTrace().frames);
|
||||
this._dispose = [
|
||||
() => this._channelOwner._waitForEventInfoAfter(this._waitId, this._error)
|
||||
];
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ export class DispatcherConnection {
|
|||
onmessage = (message: object) => {};
|
||||
private _validateParams: (type: string, method: string, params: any) => any;
|
||||
private _validateMetadata: (metadata: any) => { stack?: StackFrame[] };
|
||||
private _waitOperations = new Map<string, CallMetadata>();
|
||||
|
||||
sendMessageToClient(guid: string, method: string, params: any) {
|
||||
this.onmessage({ guid, method, params: this._replaceDispatchersWithGuids(params) });
|
||||
|
|
@ -197,7 +198,7 @@ export class DispatcherConnection {
|
|||
}
|
||||
|
||||
const sdkObject = dispatcher._object instanceof SdkObject ? dispatcher._object : undefined;
|
||||
const callMetadata: CallMetadata = {
|
||||
let callMetadata: CallMetadata = {
|
||||
id,
|
||||
...validMetadata,
|
||||
pageId: sdkObject?.attribution.page?.uniqueId,
|
||||
|
|
@ -211,8 +212,27 @@ export class DispatcherConnection {
|
|||
};
|
||||
|
||||
try {
|
||||
if (sdkObject)
|
||||
if (sdkObject) {
|
||||
// Process logs for waitForNavigation/waitForLoadState
|
||||
if (params?.info?.waitId) {
|
||||
const info = params.info;
|
||||
switch (info.phase) {
|
||||
case 'before':
|
||||
callMetadata.apiName = info.apiName;
|
||||
callMetadata.stack = info.stack;
|
||||
this._waitOperations.set(info.waitId, callMetadata);
|
||||
break;
|
||||
case 'log':
|
||||
const originalMetadata = this._waitOperations.get(info.waitId)!;
|
||||
originalMetadata.log.push(info.message);
|
||||
sdkObject.instrumentation.onCallLog('api', info.message, sdkObject, originalMetadata);
|
||||
// Fall through.
|
||||
case 'after':
|
||||
return;
|
||||
}
|
||||
}
|
||||
await sdkObject.instrumentation.onBeforeCall(sdkObject, callMetadata);
|
||||
}
|
||||
const result = await (dispatcher as any)[method](validParams, callMetadata);
|
||||
this.onmessage({ id, result: this._replaceDispatchersWithGuids(result) });
|
||||
} catch (e) {
|
||||
|
|
@ -223,8 +243,27 @@ export class DispatcherConnection {
|
|||
this.onmessage({ id, error: serializeError(e) });
|
||||
} finally {
|
||||
callMetadata.endTime = monotonicTime();
|
||||
if (sdkObject)
|
||||
if (sdkObject) {
|
||||
// Process logs for waitForNavigation/waitForLoadState
|
||||
if (params?.info?.waitId) {
|
||||
const info = params.info;
|
||||
switch (info.phase) {
|
||||
case 'before':
|
||||
callMetadata.endTime = 0;
|
||||
// Fall through.
|
||||
case 'log':
|
||||
return;
|
||||
case 'after':
|
||||
const originalMetadata = this._waitOperations.get(info.waitId)!;
|
||||
originalMetadata.endTime = callMetadata.endTime;
|
||||
originalMetadata.error = info.error;
|
||||
this._waitOperations.delete(info.waitId);
|
||||
callMetadata = originalMetadata;
|
||||
break;
|
||||
}
|
||||
}
|
||||
await sdkObject.instrumentation.onAfterCall(sdkObject, callMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export type Metadata = {
|
|||
export type WaitForEventInfo = {
|
||||
waitId: string,
|
||||
phase: 'before' | 'after' | 'log',
|
||||
name?: string,
|
||||
apiName?: string,
|
||||
stack?: StackFrame[],
|
||||
message?: string,
|
||||
error?: string,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ WaitForEventInfo:
|
|||
- before
|
||||
- after
|
||||
- log
|
||||
name: string?
|
||||
apiName: string?
|
||||
stack:
|
||||
type: array?
|
||||
items: StackFrame
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||
scheme.WaitForEventInfo = tObject({
|
||||
waitId: tString,
|
||||
phase: tEnum(['before', 'after', 'log']),
|
||||
name: tOptional(tString),
|
||||
apiName: tOptional(tString),
|
||||
stack: tOptional(tArray(tType('StackFrame'))),
|
||||
message: tOptional(tString),
|
||||
error: tOptional(tString),
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ import { CallMetadata, InstrumentationListener, SdkObject } from '../instrumenta
|
|||
import { isDebugMode, isUnderTest } from '../../utils/utils';
|
||||
|
||||
export class InspectorController implements InstrumentationListener {
|
||||
private _waitOperations = new Map<string, CallMetadata>();
|
||||
|
||||
async onContextCreated(context: BrowserContext): Promise<void> {
|
||||
if (isDebugMode())
|
||||
await RecorderSupplement.getOrCreate(context, { pauseOnNextStatement: true });
|
||||
|
|
@ -33,25 +31,6 @@ export class InspectorController implements InstrumentationListener {
|
|||
if (!context)
|
||||
return;
|
||||
|
||||
// Process logs for waitForNavigation/waitForLoadState
|
||||
if (metadata.params?.info?.waitId) {
|
||||
const info = metadata.params.info;
|
||||
switch (info.phase) {
|
||||
case 'before':
|
||||
metadata.method = info.name;
|
||||
metadata.stack = info.stack;
|
||||
this._waitOperations.set(info.waitId, metadata);
|
||||
break;
|
||||
case 'log':
|
||||
const originalMetadata = this._waitOperations.get(info.waitId)!;
|
||||
originalMetadata.log.push(info.message);
|
||||
this.onCallLog('api', info.message, sdkObject, originalMetadata);
|
||||
// Fall through.
|
||||
case 'after':
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldOpenInspector(sdkObject, metadata))
|
||||
await RecorderSupplement.getOrCreate(context, { pauseOnNextStatement: true });
|
||||
|
||||
|
|
@ -62,26 +41,6 @@ export class InspectorController implements InstrumentationListener {
|
|||
async onAfterCall(sdkObject: SdkObject, metadata: CallMetadata): Promise<void> {
|
||||
if (!sdkObject.attribution.context)
|
||||
return;
|
||||
|
||||
// Process logs for waitForNavigation/waitForLoadState
|
||||
if (metadata.params?.info?.waitId) {
|
||||
const info = metadata.params.info;
|
||||
switch (info.phase) {
|
||||
case 'before':
|
||||
metadata.endTime = 0;
|
||||
// Fall through.
|
||||
case 'log':
|
||||
return;
|
||||
case 'after':
|
||||
const originalMetadata = this._waitOperations.get(info.waitId)!;
|
||||
originalMetadata.endTime = metadata.endTime;
|
||||
originalMetadata.error = info.error;
|
||||
this._waitOperations.delete(info.waitId);
|
||||
metadata = originalMetadata;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const recorder = await RecorderSupplement.getNoCreate(sdkObject.attribution.context);
|
||||
await recorder?.onAfterCall(sdkObject, metadata);
|
||||
}
|
||||
|
|
@ -98,7 +57,7 @@ export class InspectorController implements InstrumentationListener {
|
|||
if (!sdkObject.attribution.context)
|
||||
return;
|
||||
const recorder = await RecorderSupplement.getNoCreate(sdkObject.attribution.context);
|
||||
await recorder?.updateCallLog([metadata]);
|
||||
recorder?.updateCallLog([metadata]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,8 +83,6 @@ export class TraceModel {
|
|||
}
|
||||
case 'action': {
|
||||
const metadata = event.metadata;
|
||||
if (metadata.method === 'waitForEventInfo')
|
||||
break;
|
||||
const { pageEntry } = this.pageEntries.get(metadata.pageId!)!;
|
||||
const actionId = event.contextId + '/' + metadata.pageId + '/' + pageEntry.actions.length;
|
||||
const action: ActionEntry = {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export const ActionList: React.FC<ActionListProps> = ({
|
|||
onMouseLeave={() => (highlightedAction === actionEntry) && onHighlighted(undefined)}
|
||||
>
|
||||
<div className={'action-error codicon codicon-issues'} hidden={!metadata.error} />
|
||||
<div className='action-title'>{metadata.method}</div>
|
||||
<div className='action-title'>{metadata.apiName}</div>
|
||||
{metadata.params.selector && <div className='action-selector' title={metadata.params.selector}>{metadata.params.selector}</div>}
|
||||
{metadata.method === 'goto' && metadata.params.url && <div className='action-url' title={metadata.params.url}>{metadata.params.url}</div>}
|
||||
</div>;
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@ export const FilmStrip: React.FunctionComponent<{
|
|||
}
|
||||
{previewImage && previewX !== undefined &&
|
||||
<div className='film-strip-hover' style={{
|
||||
width: previewImage.width,
|
||||
height: previewImage.height,
|
||||
width: previewSize.width,
|
||||
height: previewSize.height,
|
||||
top: measure.bottom + 5,
|
||||
left: Math.min(previewX, measure.width - previewSize.width - 10),
|
||||
}}>
|
||||
<img src={`/sha1/${previewImage.sha1}`} width={previewImage.width} height={previewImage.height} />
|
||||
<img src={`/sha1/${previewImage.sha1}`} width={previewSize.width} height={previewSize.height} />
|
||||
</div>
|
||||
}
|
||||
</div>;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
flex: none;
|
||||
flex-basis: 20px;
|
||||
flex-basis: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
|
@ -66,10 +66,11 @@
|
|||
|
||||
.timeline-bar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
height: 9px;
|
||||
top: 11px;
|
||||
background-color: red;
|
||||
border-radius: 3px;
|
||||
border-radius: 2px;
|
||||
min-width: 3px;
|
||||
--action-color: 'transparent';
|
||||
background-color: var(--action-color);
|
||||
}
|
||||
|
|
@ -104,16 +105,24 @@
|
|||
--action-color: var(--blue);
|
||||
}
|
||||
|
||||
.timeline-bar.evaluateExpression {
|
||||
--action-color: var(--yellow);
|
||||
}
|
||||
|
||||
.timeline-bar.dialog {
|
||||
top: 22px;
|
||||
--action-color: var(--transparent-blue);
|
||||
}
|
||||
|
||||
.timeline-bar.navigation {
|
||||
--action-color: var(--purple);
|
||||
top: 22px;
|
||||
--action-color: var(--blue);
|
||||
}
|
||||
|
||||
.timeline-bar.load {
|
||||
--action-color: var(--yellow);
|
||||
.timeline-bar.waitForEventInfo {
|
||||
bottom: inherit;
|
||||
top: 0;
|
||||
--action-color: var(--gray);
|
||||
}
|
||||
|
||||
.timeline-label {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export const Timeline: React.FunctionComponent<{
|
|||
rightTime: entry.metadata.endTime,
|
||||
leftPosition: timeToPosition(measure.width, boundaries, entry.metadata.startTime),
|
||||
rightPosition: timeToPosition(measure.width, boundaries, entry.metadata.endTime),
|
||||
label: entry.metadata.method + ' ' + detail,
|
||||
label: entry.metadata.apiName + ' ' + detail,
|
||||
type: entry.metadata.method,
|
||||
priority: 0,
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue