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