Skip to content

Commit

Permalink
chore: unify recorder & tracer uis (#5791)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman committed Mar 11, 2021
1 parent 43de259 commit ad69b2a
Show file tree
Hide file tree
Showing 27 changed files with 302 additions and 257 deletions.
2 changes: 1 addition & 1 deletion src/server/snapshot/snapshotRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ function snapshotScript() {
for (const iframe of root.querySelectorAll('iframe')) {
const src = iframe.getAttribute('src');
if (!src) {
iframe.setAttribute('src', 'data:text/html,<body>Snapshot is not available</body>');
iframe.setAttribute('src', 'data:text/html,<body style="background: #ddd"></body>');
} else {
// Append query parameters to inherit ?name= or ?time= values from parent.
iframe.setAttribute('src', window.location.origin + src + window.location.search);
Expand Down
2 changes: 1 addition & 1 deletion src/server/snapshot/snapshotServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class SnapshotServer {
}

function respondNotAvailable(): Response {
return new Response('<body>Snapshot is not available</body>', { status: 200, headers: { 'Content-Type': 'text/html' } });
return new Response('<body style="background: #ddd"></body>', { status: 200, headers: { 'Content-Type': 'text/html' } });
}

function removeHash(url: string) {
Expand Down
6 changes: 4 additions & 2 deletions src/server/supplements/recorder/recorderTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ export type UIState = {
snapshotUrl?: string;
};

export type CallLogStatus = 'in-progress' | 'done' | 'error' | 'paused';

export type CallLog = {
id: number;
title: string;
messages: string[];
status: 'in-progress' | 'done' | 'error' | 'paused';
status: CallLogStatus;
error?: string;
reveal?: boolean;
duration?: number;
Expand All @@ -44,7 +46,7 @@ export type CallLog = {
};
snapshots: {
before: boolean,
in: boolean,
action: boolean,
after: boolean,
}
};
Expand Down
60 changes: 60 additions & 0 deletions src/server/supplements/recorder/recorderUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { CallMetadata } from '../../instrumentation';
import { CallLog, CallLogStatus } from './recorderTypes';

export function metadataToCallLog(metadata: CallMetadata, status: CallLogStatus, snapshots: Set<string>): CallLog {
const title = metadata.apiName || metadata.method;
if (metadata.error)
status = 'error';
const params = {
url: metadata.params?.url,
selector: metadata.params?.selector,
};
let duration = metadata.endTime ? metadata.endTime - metadata.startTime : undefined;
if (typeof duration === 'number' && metadata.pauseStartTime && metadata.pauseEndTime) {
duration -= (metadata.pauseEndTime - metadata.pauseStartTime);
duration = Math.max(duration, 0);
}
const callLog: CallLog = {
id: metadata.id,
messages: metadata.log,
title,
status,
error: metadata.error,
params,
duration,
snapshots: {
before: showBeforeSnapshot(metadata) && snapshots.has(`before@${metadata.id}`),
action: showActionSnapshot(metadata) && snapshots.has(`action@${metadata.id}`),
after: showAfterSnapshot(metadata) && snapshots.has(`after@${metadata.id}`),
}
};
return callLog;
}

function showBeforeSnapshot(metadata: CallMetadata): boolean {
return metadata.method === 'close';
}

function showActionSnapshot(metadata: CallMetadata): boolean {
return ['click', 'dblclick', 'check', 'uncheck', 'fill', 'press'].includes(metadata.method);
}

function showAfterSnapshot(metadata: CallMetadata): boolean {
return ['goto', 'click', 'dblclick', 'dblclick', 'check', 'uncheck', 'fill', 'press'].includes(metadata.method);
}
56 changes: 10 additions & 46 deletions src/server/supplements/recorderSupplement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ import * as consoleApiSource from '../../generated/consoleApiSource';
import { RecorderApp } from './recorder/recorderApp';
import { CallMetadata, internalCallMetadata, SdkObject } from '../instrumentation';
import { Point } from '../../common/types';
import { CallLog, EventData, Mode, Source, UIState } from './recorder/recorderTypes';
import { CallLog, CallLogStatus, EventData, Mode, Source, UIState } from './recorder/recorderTypes';
import { isUnderTest, monotonicTime } from '../../utils/utils';
import { InMemorySnapshotter } from '../snapshot/inMemorySnapshotter';
import { metadataToCallLog } from './recorder/recorderUtils';

type BindingSource = { frame: Frame, page: Page };

Expand All @@ -56,7 +57,7 @@ export class RecorderSupplement {
private _recorderSources: Source[];
private _userSources = new Map<string, Source>();
private _snapshotter: InMemorySnapshotter;
private _hoveredSnapshot: { callLogId: number, phase: 'before' | 'after' | 'in' } | undefined;
private _hoveredSnapshot: { callLogId: number, phase: 'before' | 'after' | 'action' } | undefined;
private _snapshots = new Set<string>();
private _allMetadatas = new Map<number, CallMetadata>();

Expand Down Expand Up @@ -209,7 +210,7 @@ export class RecorderSupplement {
if (this._hoveredSnapshot) {
const metadata = this._allMetadatas.get(this._hoveredSnapshot.callLogId)!;
snapshotUrl = `${metadata.pageId}?name=${this._hoveredSnapshot.phase}@${this._hoveredSnapshot.callLogId}`;
actionPoint = this._hoveredSnapshot.phase === 'in' ? metadata?.point : undefined;
actionPoint = this._hoveredSnapshot.phase === 'action' ? metadata?.point : undefined;
} else {
for (const [metadata, sdkObject] of this._currentCallsMetadata) {
if (source.page === sdkObject.attribution.page) {
Expand Down Expand Up @@ -401,7 +402,7 @@ export class RecorderSupplement {
this._generator.signal(pageAlias, page.mainFrame(), { name: 'dialog', dialogAlias: String(++this._lastDialogOrdinal) });
}

_captureSnapshot(sdkObject: SdkObject, metadata: CallMetadata, phase: 'before' | 'after' | 'in') {
_captureSnapshot(sdkObject: SdkObject, metadata: CallMetadata, phase: 'before' | 'after' | 'action') {
if (sdkObject.attribution.page) {
const snapshotName = `${phase}@${metadata.id}`;
this._snapshots.add(snapshotName);
Expand All @@ -428,7 +429,7 @@ export class RecorderSupplement {
async onAfterCall(sdkObject: SdkObject, metadata: CallMetadata): Promise<void> {
if (this._mode === 'recording')
return;
await this._captureSnapshot(sdkObject, metadata, 'after');
this._captureSnapshot(sdkObject, metadata, 'after');
if (!metadata.error)
this._currentCallsMetadata.delete(metadata);
this._pausedCallsMetadata.delete(metadata);
Expand Down Expand Up @@ -473,49 +474,24 @@ export class RecorderSupplement {
async onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata): Promise<void> {
if (this._mode === 'recording')
return;
await this._captureSnapshot(sdkObject, metadata, 'in');
this._captureSnapshot(sdkObject, metadata, 'action');
if (this._pauseOnNextStatement)
await this.pause(metadata);
}

async updateCallLog(metadatas: CallMetadata[]): Promise<void> {
updateCallLog(metadatas: CallMetadata[]) {
if (this._mode === 'recording')
return;
const logs: CallLog[] = [];
for (const metadata of metadatas) {
if (!metadata.method)
continue;
const title = metadata.apiName || metadata.method;
let status: 'done' | 'in-progress' | 'paused' | 'error' = 'done';
let status: CallLogStatus = 'done';
if (this._currentCallsMetadata.has(metadata))
status = 'in-progress';
if (this._pausedCallsMetadata.has(metadata))
status = 'paused';
if (metadata.error)
status = 'error';
const params = {
url: metadata.params?.url,
selector: metadata.params?.selector,
};
let duration = metadata.endTime ? metadata.endTime - metadata.startTime : undefined;
if (typeof duration === 'number' && metadata.pauseStartTime && metadata.pauseEndTime) {
duration -= (metadata.pauseEndTime - metadata.pauseStartTime);
duration = Math.max(duration, 0);
}
logs.push({
id: metadata.id,
messages: metadata.log,
title,
status,
error: metadata.error,
params,
duration,
snapshots: {
before: showBeforeSnapshot(metadata) && this._snapshots.has(`before@${metadata.id}`),
in: showInSnapshot(metadata) && this._snapshots.has(`in@${metadata.id}`),
after: showAfterSnapshot(metadata) && this._snapshots.has(`after@${metadata.id}`),
}
});
logs.push(metadataToCallLog(metadata, status, this._snapshots));
}
this._recorderApp?.updateCallLogs(logs);
}
Expand Down Expand Up @@ -548,15 +524,3 @@ function shouldPauseOnCall(sdkObject: SdkObject, metadata: CallMetadata): boolea
function shouldPauseOnStep(sdkObject: SdkObject, metadata: CallMetadata): boolean {
return metadata.method === 'goto' || metadata.method === 'close';
}

function showBeforeSnapshot(metadata: CallMetadata): boolean {
return metadata.method === 'close';
}

function showInSnapshot(metadata: CallMetadata): boolean {
return ['click', 'dblclick', 'check', 'uncheck', 'fill', 'press'].includes(metadata.method);
}

function showAfterSnapshot(metadata: CallMetadata): boolean {
return ['goto', 'click', 'dblclick', 'dblclick', 'check', 'uncheck', 'fill', 'press'].includes(metadata.method);
}
2 changes: 1 addition & 1 deletion src/server/trace/recorder/tracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class ContextTracer {
await this._snapshotter.start();
}

async _captureSnapshot(name: string, sdkObject: SdkObject, metadata: CallMetadata, element?: ElementHandle): Promise<void> {
async _captureSnapshot(name: 'before' | 'after' | 'action', sdkObject: SdkObject, metadata: CallMetadata, element?: ElementHandle): Promise<void> {
if (!sdkObject.attribution.page)
return;
const snapshotName = `${name}@${metadata.id}`;
Expand Down
2 changes: 1 addition & 1 deletion src/server/trace/viewer/traceViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class TraceViewer {
const traceViewerPlaywright = createPlaywright(true);
const args = [
'--app=data:text/html,',
'--window-position=1280,10',
'--window-size=1280,800'
];
if (isUnderTest())
args.push(`--remote-debugging-port=0`);
Expand Down
6 changes: 2 additions & 4 deletions src/web/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

:root {
--toolbar-bg-color: #fafafa;
--toolbar-color: #777;
--toolbar-color: #555;

--light-background: #f3f2f1;
--background: #edebe9;
Expand All @@ -27,7 +27,7 @@
--purple: #9C27B0;
--yellow: #FFC107;
--white: #FFFFFF;
--blue: #2196F3;
--blue: #0b7ad5;
--transparent-blue: #2196F355;
--orange: #d24726;
--black: #1E1E1E;
Expand All @@ -53,7 +53,6 @@ html, body {
margin: 0;
overflow: hidden;
display: flex;
background: var(--background);
overscroll-behavior-x: none;
}

Expand All @@ -64,7 +63,6 @@ html, body {
}

body {
background-color: var(--background);
color: var(--color);
font-size: 14px;
font-family: SegoeUI-SemiBold-final,Segoe UI Semibold,SegoeUI-Regular-final,Segoe UI,"Segoe UI Web (West European)",Segoe,-apple-system,BlinkMacSystemFont,Roboto,Helvetica Neue,Tahoma,Helvetica,Arial,sans-serif;
Expand Down
3 changes: 2 additions & 1 deletion src/web/components/source.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
font-size: 11px;
line-height: 16px;
background: white;
user-select: text;
}

.source-line {
Expand All @@ -36,7 +37,7 @@
padding: 0 8px;
width: 30px;
text-align: right;
background: #edebe9;
background: #f6f5f4;
user-select: none;
}

Expand Down
25 changes: 23 additions & 2 deletions src/web/components/splitView.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
position: relative;
}

.split-view.horizontal {
flex-direction: row;
}

.split-view-main {
display: flex;
flex: auto;
Expand All @@ -32,12 +36,29 @@
border-top: 1px solid #ddd;
}

.split-view.vertical > .split-view-sidebar {
border-top: 1px solid #ddd;
}

.split-view.horizontal > .split-view-sidebar {
border-left: 1px solid #ddd;
}

.split-view-resizer {
position: absolute;
z-index: 100;
}

.split-view.vertical > .split-view-resizer {
left: 0;
right: 0;
height: 12px;
cursor: resize;
cursor: ns-resize;
z-index: 100;
}

.split-view.horizontal > .split-view-resizer {
top: 0;
bottom: 0;
width: 12px;
cursor: ew-resize;
}
15 changes: 10 additions & 5 deletions src/web/components/splitView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,38 @@ import * as React from 'react';
export interface SplitViewProps {
sidebarSize: number,
sidebarHidden?: boolean
orientation?: 'vertical' | 'horizontal',
}

const kMinSidebarSize = 50;

export const SplitView: React.FC<SplitViewProps> = ({
sidebarSize,
sidebarHidden,
orientation = 'vertical',
children
}) => {
let [size, setSize] = React.useState<number>(Math.max(kMinSidebarSize, sidebarSize));
const [resizing, setResizing] = React.useState<{ offsetY: number, size: number } | null>(null);
const [resizing, setResizing] = React.useState<{ offset: number, size: number } | null>(null);

const childrenArray = React.Children.toArray(children);
document.body.style.userSelect = resizing ? 'none' : 'inherit';
return <div className='split-view'>
const resizerStyle = orientation === 'vertical' ?
{bottom: resizing ? 0 : size - 4, top: resizing ? 0 : undefined, height: resizing ? 'initial' : 8 } :
{right: resizing ? 0 : size - 4, left: resizing ? 0 : undefined, width: resizing ? 'initial' : 8 };
return <div className={'split-view ' + orientation}>
<div className='split-view-main'>{childrenArray[0]}</div>
{ !sidebarHidden && <div style={{flexBasis: size}} className='split-view-sidebar'>{childrenArray[1]}</div> }
{ !sidebarHidden && <div
style={{bottom: resizing ? 0 : size - 4, top: resizing ? 0 : undefined, height: resizing ? 'initial' : 8 }}
style={resizerStyle}
className='split-view-resizer'
onMouseDown={event => setResizing({ offsetY: event.clientY, size })}
onMouseDown={event => setResizing({ offset: orientation === 'vertical' ? event.clientY : event.clientX, size })}
onMouseUp={() => setResizing(null)}
onMouseMove={event => {
if (!event.buttons)
setResizing(null);
else if (resizing)
setSize(Math.max(kMinSidebarSize, resizing.size - event.clientY + resizing.offsetY));
setSize(Math.max(kMinSidebarSize, resizing.size - (orientation === 'vertical' ? event.clientY : event.clientX) + resizing.offset));
}}
></div> }
</div>;
Expand Down
2 changes: 1 addition & 1 deletion src/web/components/toolbarButton.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
}

.toolbar-button:not(.disabled):hover {
color: #555;
color: #333;
}

.toolbar-button .codicon {
Expand Down
Loading

0 comments on commit ad69b2a

Please sign in to comment.