mirror of
https://github.com/microsoft/playwright-cli.git
synced 2026-09-14 19:59:39 +08:00
chore(trace): extract network tab
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
--control-background: #3C3C3C;
|
||||
--settings: #E7E7E7;
|
||||
--sidebar-width: 250px;
|
||||
--box-shadow: rgba(0, 0, 0, 0.133) 0px 1.6px 3.6px 0px, rgba(0, 0, 0, 0.11) 0px 0.3px 0.9px 0px;
|
||||
}
|
||||
|
||||
html, body {
|
||||
|
||||
@@ -31,7 +31,6 @@ tabbed-pane tab-strip {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
box-shadow: rgba(0, 0, 0, 0.133) 0px 1.6px 3.6px 0px, rgba(0, 0, 0, 0.11) 0px 0.3px 0.9px 0px;
|
||||
}
|
||||
|
||||
tabbed-pane tab-strip > list-view {
|
||||
|
||||
@@ -29,7 +29,6 @@ action-list > list-view {
|
||||
}
|
||||
|
||||
action-entry {
|
||||
--action-color: transparent;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -41,7 +40,6 @@ action-list action-entry {
|
||||
border: 3px solid var(--background);
|
||||
margin-top: var(--layout-gap);
|
||||
user-select: none;
|
||||
border-left-color: var(--action-color);
|
||||
padding: 0 5px 5px 5px;
|
||||
}
|
||||
|
||||
@@ -70,7 +68,7 @@ action-list action-title {
|
||||
action-list action-entry action-header {
|
||||
display: block;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
margin: 5px 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -88,6 +86,7 @@ action-list action-thumbnail {
|
||||
justify-content: center;
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
box-shadow: var(--box-shadow);
|
||||
}
|
||||
|
||||
action-list action-thumbnail img {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.network-tab network-request {
|
||||
box-shadow: var(--box-shadow);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 10px;
|
||||
background: #fdfcfc;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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 { ActionEntry } from "../../traceModel";
|
||||
import { NetworkResourceTraceEvent } from "../../traceTypes";
|
||||
import { dom } from '../components/dom';
|
||||
import { ListView } from "../components/listView";
|
||||
import { Tab } from './propertiesTabbedPane';
|
||||
import './networkTab.css';
|
||||
|
||||
export class NetworkTab implements Tab {
|
||||
label = 'Network';
|
||||
private _listView: ListView<NetworkResourceTraceEvent>;
|
||||
|
||||
constructor() {
|
||||
this._listView = new ListView<NetworkResourceTraceEvent>(this);
|
||||
this._listView.element.classList.add('network-tab');
|
||||
}
|
||||
|
||||
render(resource: NetworkResourceTraceEvent, element: HTMLElement): HTMLElement {
|
||||
if (element)
|
||||
return element;
|
||||
return dom`<network-request>${resource.url}</network-request>`
|
||||
}
|
||||
|
||||
async setAction(actionEntry: ActionEntry | undefined) {
|
||||
this._listView.clear();
|
||||
if (actionEntry)
|
||||
this._listView.appendAll(actionEntry.resources);
|
||||
}
|
||||
|
||||
content(): HTMLElement {
|
||||
return this._listView.element;
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
import { ActionEntry } from "../../traceModel";
|
||||
import { NetworkResourceTraceEvent } from "../../traceTypes";
|
||||
import { dom, Element$ } from '../components/dom';
|
||||
import { Size } from "../components/geometry";
|
||||
import { ListView } from "../components/listView";
|
||||
import { TabbedPane, TabOptions } from "../components/tabbedPane";
|
||||
import { NetworkTab } from './networkTab';
|
||||
import { SourceTab } from './sourceTab';
|
||||
|
||||
export class PropertiesTabbedPane {
|
||||
element: HTMLElement;
|
||||
@@ -55,7 +55,7 @@ export class PropertiesTabbedPane {
|
||||
}
|
||||
}
|
||||
|
||||
interface Tab extends TabOptions {
|
||||
export interface Tab extends TabOptions {
|
||||
setAction(action: ActionEntry | undefined): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -90,90 +90,3 @@ class SnapshotTab implements Tab {
|
||||
return this._element;
|
||||
}
|
||||
}
|
||||
|
||||
class SourceTab implements Tab {
|
||||
label = 'Source';
|
||||
|
||||
readonly _element: Element$;
|
||||
private _editor: monaco.editor.IStandaloneCodeEditor;
|
||||
private _fileName: string | undefined;
|
||||
private _decorations: string[] = [];
|
||||
|
||||
constructor() {
|
||||
this._element = dom`<vbox></vbox>`;
|
||||
monaco.editor.setTheme('vs-light');
|
||||
this._editor = monaco.editor.create(this._element, {
|
||||
value: '',
|
||||
language: 'javascript',
|
||||
readOnly: true
|
||||
});
|
||||
window.addEventListener('resize', () => this.resize());
|
||||
}
|
||||
|
||||
async setAction(actionEntry: ActionEntry | undefined) {
|
||||
if (!actionEntry) {
|
||||
this._editor.setValue('');
|
||||
return;
|
||||
}
|
||||
const { action } = actionEntry;
|
||||
const frames = action.stack!.split('\n').slice(1);
|
||||
const frame = frames.filter(frame => !frame.includes('playwright/lib/client/'))[0];
|
||||
if (!frame) {
|
||||
this._editor.setValue(action.stack!);
|
||||
return;
|
||||
}
|
||||
const match = frame.match(/at ([^:]+):(\d+):\d+/);
|
||||
if (!match) {
|
||||
this._editor.setValue(action.stack!);
|
||||
return;
|
||||
}
|
||||
const fileName = match[1];
|
||||
if (this._fileName !== fileName) {
|
||||
this._fileName = fileName;
|
||||
const content = await (window as any).readFile(fileName);
|
||||
this._editor.setValue(content);
|
||||
}
|
||||
|
||||
const lineNumber = parseInt(match[2],10);
|
||||
this._decorations = this._editor.deltaDecorations(this._decorations, [
|
||||
{ range: new monaco.Range(lineNumber, 1, lineNumber, 1), options: {
|
||||
isWholeLine: true,
|
||||
className: 'monaco-execution-line'
|
||||
}},
|
||||
]);
|
||||
this._editor.revealLine(lineNumber, 1);
|
||||
}
|
||||
|
||||
content(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
resize() {
|
||||
this._editor.layout();
|
||||
}
|
||||
}
|
||||
|
||||
class NetworkTab implements Tab {
|
||||
label = 'Network';
|
||||
private _listView: ListView<NetworkResourceTraceEvent>;
|
||||
|
||||
constructor() {
|
||||
this._listView = new ListView<NetworkResourceTraceEvent>(this);
|
||||
}
|
||||
|
||||
render(resource: NetworkResourceTraceEvent, element: HTMLElement): HTMLElement {
|
||||
if (element)
|
||||
return element;
|
||||
return dom`<span>${resource.url}</span>`
|
||||
}
|
||||
|
||||
async setAction(actionEntry: ActionEntry | undefined) {
|
||||
this._listView.clear();
|
||||
if (actionEntry)
|
||||
this._listView.appendAll(actionEntry.resources);
|
||||
}
|
||||
|
||||
content(): HTMLElement {
|
||||
return this._listView.element;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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 * as monaco from 'monaco-editor';
|
||||
import { ActionEntry } from "../../traceModel";
|
||||
import { dom, Element$ } from '../components/dom';
|
||||
import { Tab } from './propertiesTabbedPane';
|
||||
|
||||
export class SourceTab implements Tab {
|
||||
label = 'Source';
|
||||
|
||||
readonly _element: Element$;
|
||||
private _editor: monaco.editor.IStandaloneCodeEditor;
|
||||
private _fileName: string | undefined;
|
||||
private _decorations: string[] = [];
|
||||
|
||||
constructor() {
|
||||
this._element = dom`<vbox></vbox>`;
|
||||
monaco.editor.setTheme('vs-light');
|
||||
this._editor = monaco.editor.create(this._element, {
|
||||
value: '',
|
||||
language: 'javascript',
|
||||
readOnly: true
|
||||
});
|
||||
window.addEventListener('resize', () => this.resize());
|
||||
}
|
||||
|
||||
async setAction(actionEntry: ActionEntry | undefined) {
|
||||
if (!actionEntry) {
|
||||
this._editor.setValue('');
|
||||
return;
|
||||
}
|
||||
const { action } = actionEntry;
|
||||
const frames = action.stack!.split('\n').slice(1);
|
||||
const frame = frames.filter(frame => !frame.includes('playwright/lib/client/'))[0];
|
||||
if (!frame) {
|
||||
this._editor.setValue(action.stack!);
|
||||
return;
|
||||
}
|
||||
const match = frame.match(/at ([^:]+):(\d+):\d+/);
|
||||
if (!match) {
|
||||
this._editor.setValue(action.stack!);
|
||||
return;
|
||||
}
|
||||
const fileName = match[1];
|
||||
if (this._fileName !== fileName) {
|
||||
this._fileName = fileName;
|
||||
const content = await (window as any).readFile(fileName);
|
||||
this._editor.setValue(content);
|
||||
}
|
||||
|
||||
const lineNumber = parseInt(match[2],10);
|
||||
this._decorations = this._editor.deltaDecorations(this._decorations, [
|
||||
{ range: new monaco.Range(lineNumber, 1, lineNumber, 1), options: {
|
||||
isWholeLine: true,
|
||||
className: 'monaco-execution-line'
|
||||
}},
|
||||
]);
|
||||
this._editor.revealLine(lineNumber, 1);
|
||||
}
|
||||
|
||||
content(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
resize() {
|
||||
this._editor.layout();
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@
|
||||
.workbench tab-strip {
|
||||
margin-left: calc(-1*var(--sidebar-width));
|
||||
padding-left: var(--sidebar-width);
|
||||
box-shadow: var(--box-shadow);
|
||||
}
|
||||
|
||||
.workbench .logo {
|
||||
@@ -49,4 +50,4 @@ tab-strip {
|
||||
|
||||
.monaco-execution-line {
|
||||
background-color: #ff69b460;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user