chore(traceviewer): drop intermediate iframe, add drop handler (#9455)

This commit is contained in:
Pavel Feldman 2021-10-12 20:21:06 -08:00 committed by GitHub
parent 617380ffee
commit cdfe075b2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 50 additions and 89 deletions

View File

@ -113,6 +113,18 @@ export class HttpServer {
}
private _onRequest(request: http.IncomingMessage, response: http.ServerResponse) {
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
if (request.headers.origin)
response.setHeader('Access-Control-Allow-Headers', request.headers.origin);
if (request.method === 'OPTIONS') {
response.writeHead(200);
response.end();
return;
}
request.on('error', () => response.end());
try {
if (!request.url) {

View File

@ -220,6 +220,23 @@ function snapshotScript() {
element.scrollLeft = +element.getAttribute(scrollLeftAttribute)!;
element.removeAttribute(scrollLeftAttribute);
}
const search = new URL(window.location.href).searchParams;
const pointX = search.get('pointX');
const pointY = search.get('pointY');
if (pointX) {
const pointElement = document.createElement('x-pw-pointer');
pointElement.style.position = 'fixed';
pointElement.style.backgroundColor = 'red';
pointElement.style.width = '20px';
pointElement.style.height = '20px';
pointElement.style.borderRadius = '10px';
pointElement.style.margin = '-10px 0 0 -10px';
pointElement.style.zIndex = '2147483647';
pointElement.style.left = pointX + 'px';
pointElement.style.top = pointY + 'px';
document.documentElement.appendChild(pointElement);
}
};
window.addEventListener('load', onLoad);
}

View File

@ -30,36 +30,6 @@ export class SnapshotServer {
this._snapshotStorage = snapshotStorage;
}
static serveSnapshotRoot(): Response {
return new Response(`
<style>
html, body {
margin: 0;
padding: 0;
}
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
}
</style>
<body>
<script>
(${rootScript})();
</script>
</body>
`, {
status: 200,
headers: {
'Cache-Control': 'public, max-age=31536000',
'Content-Type': 'text/html'
}
});
}
serveSnapshot(pathname: string, searchParams: URLSearchParams, snapshotUrl: string): Response {
const snapshot = this._snapshot(pathname.substring('/snapshot'.length), searchParams);
if (!snapshot)
@ -132,33 +102,6 @@ declare global {
}
}
function rootScript() {
const pointElement = document.createElement('div');
pointElement.style.position = 'fixed';
pointElement.style.backgroundColor = 'red';
pointElement.style.width = '20px';
pointElement.style.height = '20px';
pointElement.style.borderRadius = '10px';
pointElement.style.margin = '-10px 0 0 -10px';
pointElement.style.zIndex = '2147483647';
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
(window as any).showSnapshot = async (url: string, options: { point?: Point } = {}) => {
iframe.src = url;
if (options.point) {
pointElement.style.left = options.point.x + 'px';
pointElement.style.top = options.point.y + 'px';
document.documentElement.appendChild(pointElement);
} else {
pointElement.remove();
}
};
window.addEventListener('message', event => {
window.showSnapshot(window.location.href + event.data.snapshotUrl);
}, false);
}
function removeHash(url: string) {
try {
const u = new URL(url);

View File

@ -31,7 +31,7 @@ let snapshotServer: SnapshotServer | undefined;
async function loadTrace(trace: string): Promise<TraceModel> {
const traceModel = new TraceModel();
const url = trace.startsWith('http') ? trace : `/file?path=${trace}`;
const url = trace.startsWith('http') || trace.startsWith('blob') ? trace : `/file?path=${trace}`;
await traceModel.load(url);
return traceModel;
}
@ -53,8 +53,6 @@ async function doFetch(event: FetchEvent): Promise<Response> {
headers: { 'Content-Type': 'application/json' }
});
}
if (pathname === '/snapshot/')
return SnapshotServer.serveSnapshotRoot();
if (pathname.startsWith('/snapshotSize/'))
return snapshotServer!.serveSnapshotSize(pathname, searchParams);
if (pathname.startsWith('/snapshot/'))

View File

@ -43,7 +43,7 @@ export class TraceModel {
}
async load(traceURL: string) {
const response = await fetch(traceURL);
const response = await fetch(traceURL, { mode: 'cors' });
const blob = await response.blob();
const zipReader = new zipjs.ZipReader(new zipjs.BlobReader(blob), { useWebWorkers: false }) as zip.ZipReader;
let traceEntry: zip.Entry | undefined;

View File

@ -124,13 +124,8 @@
}
.no-actions-entry {
height: 400px;
display: grid;
place-items: center;
text-align: center;
}
.no-actions-entry-text {
font-weight: bold;
font-size: 1.3rem;
flex: auto;
display: flex;
align-items: center;
justify-content: center;
}

View File

@ -72,16 +72,7 @@ export const ActionList: React.FC<ActionListProps> = ({
}}
ref={actionListRef}
>
{actions.length === 0 && <div className='no-actions-entry'>
<div>
<div className='no-actions-entry-text'>
No actions recorded
</div>
<div>
Make sure that the right context was used when recording the trace.
</div>
</div>
</div>}
{actions.length === 0 && <div className='no-actions-entry'>No actions recorded</div>}
{actions.map(action => {
const { metadata } = action;
const selectedSuffix = action === selectedAction ? ' selected' : '';

View File

@ -66,8 +66,7 @@ export const SnapshotTab: React.FunctionComponent<{
if (!iframeRef.current)
return;
try {
const point = pointX === undefined ? undefined : { x: pointX, y: pointY };
(iframeRef.current.contentWindow as any).showSnapshot(snapshotUrl, { point });
iframeRef.current.src = snapshotUrl + (pointX === undefined ? '' : `&pointX=${pointX}&pointY=${pointY}`);
} catch (e) {
}
})();
@ -102,7 +101,7 @@ export const SnapshotTab: React.FunctionComponent<{
height: snapshotSize.height + 'px',
transform: `translate(${-snapshotSize.width * (1 - scale) / 2 + (measure.width - scaledSize.width) / 2}px, ${-snapshotSize.height * (1 - scale) / 2 + (measure.height - scaledSize.height) / 2}px) scale(${scale})`,
}}>
<iframe ref={iframeRef} id='snapshot' name='snapshot' src='/snapshot/'></iframe>
<iframe ref={iframeRef} id='snapshot' name='snapshot'></iframe>
</div>
</div>
</div>;

View File

@ -31,19 +31,19 @@ import * as modelUtil from './modelUtil';
export const Workbench: React.FunctionComponent<{
}> = () => {
const [traceURL, setTraceURL] = React.useState<string>(new URL(window.location.href).searchParams.get('trace')!);
const [contextEntry, setContextEntry] = React.useState<ContextEntry>(emptyContext);
const [selectedAction, setSelectedAction] = React.useState<ActionTraceEvent | undefined>();
const [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEvent | undefined>();
const [selectedTab, setSelectedTab] = React.useState<string>('logs');
const trace = new URL(window.location.href).searchParams.get('trace');
React.useEffect(() => {
(async () => {
const contextEntry = (await fetch(`/context?trace=${trace}`).then(response => response.json())) as ContextEntry;
const contextEntry = (await fetch(`/context?trace=${traceURL}`).then(response => response.json())) as ContextEntry;
modelUtil.indexModel(contextEntry);
setContextEntry(contextEntry);
})();
}, [trace]);
}, [traceURL]);
const actions = React.useMemo(() => {
const actions: ActionTraceEvent[] = [];
@ -61,7 +61,13 @@ export const Workbench: React.FunctionComponent<{
const consoleCount = errors + warnings;
const networkCount = selectedAction ? modelUtil.resourcesForAction(selectedAction).length : 0;
return <div className='vbox workbench'>
return <div className='vbox workbench'
onDragOver={event => { event.preventDefault(); }}
onDrop={event => {
event.preventDefault();
const url = URL.createObjectURL(event.dataTransfer.files[0]);
setTraceURL(url.toString());
}}>
<div className='hbox header'>
<div className='logo'>🎭</div>
<div className='product'>Playwright</div>

View File

@ -84,9 +84,9 @@ class TraceViewerPage {
async snapshotFrame(actionName: string, ordinal: number = 0, hasSubframe: boolean = false): Promise<Frame> {
await this.selectAction(actionName, ordinal);
while (this.page.frames().length < (hasSubframe ? 4 : 3))
while (this.page.frames().length < (hasSubframe ? 3 : 2))
await this.page.waitForEvent('frameattached');
return this.page.mainFrame().childFrames()[0].childFrames()[0];
return this.page.mainFrame().childFrames()[0];
}
}