chrome-devtools-frontend 1.0.1519267 → 1.0.1520139
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/owner/COMMON_OWNERS +1 -2
- package/config/typescript/tsconfig.eslint.json +12 -1
- package/docs/ui_engineering.md +1011 -0
- package/front_end/core/host/GdpClient.ts +12 -3
- package/front_end/core/sdk/NetworkManager.ts +1 -0
- package/front_end/core/sdk/NetworkRequest.ts +10 -0
- package/front_end/entrypoints/main/MainImpl.ts +6 -1
- package/front_end/entrypoints/main/main-meta.ts +3 -3
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +60 -34
- package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +4 -4
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +127 -29
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +100 -55
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +317 -640
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +23 -19
- package/front_end/models/ai_assistance/performance/AICallTree.snapshot.txt +75 -0
- package/front_end/models/ai_assistance/performance/AICallTree.ts +14 -6
- package/front_end/models/ai_assistance/performance/AIContext.ts +62 -7
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +5 -5
- package/front_end/models/badges/Badge.ts +6 -1
- package/front_end/models/badges/StarterBadge.ts +5 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +5 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +14 -7
- package/front_end/panels/ai_assistance/PatchWidget.ts +17 -55
- package/front_end/panels/ai_assistance/components/ChatView.ts +44 -68
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +47 -1
- package/front_end/panels/ai_assistance/components/chatView.css +12 -0
- package/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/animation/animationTimeline.css +4 -0
- package/front_end/panels/application/preloading/components/PreloadingString.ts +2 -5
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +5 -0
- package/front_end/panels/common/aiCodeCompletionTeaser.css +6 -1
- package/front_end/panels/console/ConsolePrompt.ts +6 -0
- package/front_end/panels/console/ConsoleView.ts +4 -2
- package/front_end/panels/coverage/CoverageListView.ts +133 -158
- package/front_end/panels/coverage/CoverageView.ts +39 -16
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +2 -0
- package/front_end/panels/network/NetworkDataGridNode.ts +22 -0
- package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
- package/front_end/panels/recorder/components/CreateRecordingView.ts +2 -0
- package/front_end/panels/search/SearchResultsPane.ts +48 -15
- package/front_end/panels/search/SearchView.ts +33 -30
- package/front_end/panels/search/searchView.css +0 -2
- package/front_end/panels/settings/components/SyncSection.ts +3 -3
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +1 -4
- package/front_end/panels/sources/DebuggerPlugin.ts +4 -0
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +0 -8
- package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -5
- package/front_end/panels/timeline/TimelinePanel.ts +2 -0
- package/front_end/panels/timeline/TimelineTreeView.ts +1 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +4 -4
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/package.json +3 -2
- package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/PipeTransport.ts +15 -17
- package/front_end/third_party/puppeteer/package/src/revisions.ts +2 -2
- package/front_end/third_party/puppeteer/package/src/util/Function.ts +1 -1
- package/front_end/tsconfig.json +12 -1
- package/front_end/ui/legacy/InspectorView.ts +86 -13
- package/front_end/ui/legacy/TabbedPane.ts +2 -1
- package/front_end/ui/visual_logging/KnownContextValues.ts +6 -0
- package/front_end/ui/visual_logging/LoggingEvents.ts +1 -1
- package/package.json +1 -1
@@ -2,6 +2,7 @@
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
3
3
|
// found in the LICENSE file.
|
4
4
|
/* eslint-disable rulesdir/no-imperative-dom-api */
|
5
|
+
/* eslint-disable rulesdir/no-lit-render-outside-of-view */
|
5
6
|
|
6
7
|
import * as Common from '../../core/common/common.js';
|
7
8
|
import * as i18n from '../../core/i18n/i18n.js';
|
@@ -10,13 +11,23 @@ import * as TextUtils from '../../models/text_utils/text_utils.js';
|
|
10
11
|
import * as Workspace from '../../models/workspace/workspace.js';
|
11
12
|
import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
|
12
13
|
import * as UI from '../../ui/legacy/legacy.js';
|
14
|
+
import {Directives, html, nothing, render} from '../../ui/lit/lit.js';
|
13
15
|
|
14
16
|
import coverageListViewStyles from './coverageListView.css.js';
|
15
|
-
import {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
import {CoverageType} from './CoverageModel.js';
|
18
|
+
|
19
|
+
export interface CoverageListItem {
|
20
|
+
url: Platform.DevToolsPath.UrlString;
|
21
|
+
type: CoverageType;
|
22
|
+
size: number;
|
23
|
+
usedSize: number;
|
24
|
+
unusedSize: number;
|
25
|
+
usedPercentage: number;
|
26
|
+
unusedPercentage: number;
|
27
|
+
sources: CoverageListItem[];
|
28
|
+
isContentScript: boolean;
|
29
|
+
generatedUrl?: Platform.DevToolsPath.UrlString;
|
30
|
+
}
|
20
31
|
|
21
32
|
const UIStrings = {
|
22
33
|
/**
|
@@ -113,6 +124,7 @@ const UIStrings = {
|
|
113
124
|
} as const;
|
114
125
|
const str_ = i18n.i18n.registerUIStrings('panels/coverage/CoverageListView.ts', UIStrings);
|
115
126
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
127
|
+
const {styleMap} = Directives;
|
116
128
|
|
117
129
|
export function coverageTypeToString(type: CoverageType): string {
|
118
130
|
const types = [];
|
@@ -128,15 +140,15 @@ export function coverageTypeToString(type: CoverageType): string {
|
|
128
140
|
}
|
129
141
|
|
130
142
|
export class CoverageListView extends UI.Widget.VBox {
|
131
|
-
private readonly
|
132
|
-
private readonly isVisibleFilter: (arg0:
|
143
|
+
private readonly nodeForUrl: Map<Platform.DevToolsPath.UrlString, GridNode>;
|
144
|
+
private readonly isVisibleFilter: (arg0: CoverageListItem) => boolean;
|
133
145
|
private highlightRegExp: RegExp|null;
|
134
146
|
private dataGrid: DataGrid.SortableDataGrid.SortableDataGrid<GridNode>;
|
135
147
|
|
136
|
-
constructor(isVisibleFilter: (arg0:
|
148
|
+
constructor(isVisibleFilter: (arg0: CoverageListItem) => boolean) {
|
137
149
|
super({useShadowDom: true});
|
138
150
|
this.registerRequiredCSS(coverageListViewStyles);
|
139
|
-
this.
|
151
|
+
this.nodeForUrl = new Map();
|
140
152
|
this.isVisibleFilter = isVisibleFilter;
|
141
153
|
this.highlightRegExp = null;
|
142
154
|
|
@@ -179,90 +191,87 @@ export class CoverageListView extends UI.Widget.VBox {
|
|
179
191
|
weight: 1,
|
180
192
|
},
|
181
193
|
] as DataGrid.DataGrid.ColumnDescriptor[];
|
182
|
-
this.dataGrid =
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
194
|
+
this.dataGrid =
|
195
|
+
DataGrid.SortableDataGrid.SortableDataGrid.create(['dummy'], [], i18nString(UIStrings.codeCoverage)) as
|
196
|
+
DataGrid.SortableDataGrid.SortableDataGrid<GridNode>;
|
197
|
+
this.dataGrid.removeColumn('dummy');
|
198
|
+
for (const column of columns) {
|
199
|
+
this.dataGrid.addColumn(column);
|
200
|
+
}
|
201
|
+
this.dataGrid.setColumnsVisibility(new Set(columns.map(column => column.id)));
|
188
202
|
this.dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.LAST);
|
189
203
|
this.dataGrid.setStriped(true);
|
190
204
|
this.dataGrid.element.classList.add('flex-auto');
|
191
205
|
this.dataGrid.addEventListener(DataGrid.DataGrid.Events.OPENED_NODE, this.onOpenedNode, this);
|
192
|
-
this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SORTING_CHANGED, this.sortingChanged, this);
|
193
206
|
|
194
207
|
const dataGridWidget = this.dataGrid.asWidget();
|
195
208
|
dataGridWidget.show(this.contentElement);
|
196
209
|
this.setDefaultFocusedChild(dataGridWidget);
|
197
210
|
}
|
198
211
|
|
199
|
-
update(coverageInfo:
|
212
|
+
update(coverageInfo: CoverageListItem[] = []): void {
|
200
213
|
let hadUpdates = false;
|
201
|
-
const maxSize = coverageInfo.reduce((acc, entry) => Math.max(acc, entry.size
|
214
|
+
const maxSize = coverageInfo.reduce((acc, entry) => Math.max(acc, entry.size), 0);
|
202
215
|
const rootNode = this.dataGrid.rootNode();
|
203
216
|
for (const entry of coverageInfo) {
|
204
|
-
let node = this.
|
217
|
+
let node = this.nodeForUrl.get(entry.url);
|
205
218
|
if (node) {
|
206
219
|
if (this.isVisibleFilter(node.coverageInfo)) {
|
207
|
-
hadUpdates = node.refreshIfNeeded(maxSize) || hadUpdates;
|
208
|
-
if (entry.
|
209
|
-
this.updateSourceNodes(entry.
|
220
|
+
hadUpdates = node.refreshIfNeeded(maxSize, entry) || hadUpdates;
|
221
|
+
if (entry.sources.length > 0) {
|
222
|
+
this.updateSourceNodes(entry.sources, maxSize, node);
|
210
223
|
}
|
211
224
|
}
|
212
225
|
continue;
|
213
226
|
}
|
214
227
|
node = new GridNode(entry, maxSize);
|
215
|
-
this.
|
228
|
+
this.nodeForUrl.set(entry.url, node);
|
216
229
|
if (this.isVisibleFilter(node.coverageInfo)) {
|
217
230
|
rootNode.appendChild(node);
|
218
|
-
if (entry.
|
219
|
-
void this.createSourceNodes(entry.
|
231
|
+
if (entry.sources.length > 0) {
|
232
|
+
void this.createSourceNodes(entry.sources, maxSize, node);
|
220
233
|
}
|
221
234
|
hadUpdates = true;
|
222
235
|
}
|
223
236
|
}
|
224
237
|
if (hadUpdates) {
|
225
|
-
this.
|
238
|
+
this.dataGrid.dispatchEventToListeners(DataGrid.DataGrid.Events.SORTING_CHANGED);
|
226
239
|
}
|
227
240
|
}
|
228
241
|
|
229
|
-
updateSourceNodes(
|
230
|
-
sourcesURLCoverageInfo: Map<Platform.DevToolsPath.UrlString, SourceURLCoverageInfo>, maxSize: number,
|
231
|
-
node: GridNode): void {
|
242
|
+
updateSourceNodes(sources: CoverageListItem[], maxSize: number, node: GridNode): void {
|
232
243
|
let shouldCreateSourceNodes = false;
|
233
|
-
for (const coverageInfo of
|
234
|
-
const sourceNode = this.
|
244
|
+
for (const coverageInfo of sources) {
|
245
|
+
const sourceNode = this.nodeForUrl.get(coverageInfo.url);
|
235
246
|
if (sourceNode) {
|
236
|
-
sourceNode.refreshIfNeeded(maxSize);
|
247
|
+
sourceNode.refreshIfNeeded(maxSize, coverageInfo);
|
237
248
|
} else {
|
238
249
|
shouldCreateSourceNodes = true;
|
239
250
|
break;
|
240
251
|
}
|
241
252
|
}
|
242
253
|
if (shouldCreateSourceNodes) {
|
243
|
-
void this.createSourceNodes(
|
254
|
+
void this.createSourceNodes(sources, maxSize, node);
|
244
255
|
}
|
245
256
|
}
|
246
257
|
|
247
|
-
async createSourceNodes(
|
248
|
-
|
249
|
-
node: GridNode): Promise<void> {
|
250
|
-
for (const coverageInfo of sourcesURLCoverageInfo.values()) {
|
258
|
+
async createSourceNodes(sources: CoverageListItem[], maxSize: number, node: GridNode): Promise<void> {
|
259
|
+
for (const coverageInfo of sources) {
|
251
260
|
const sourceNode = new GridNode(coverageInfo, maxSize);
|
252
261
|
node.appendChild(sourceNode);
|
253
|
-
this.
|
262
|
+
this.nodeForUrl.set(coverageInfo.url, sourceNode);
|
254
263
|
}
|
255
264
|
}
|
256
265
|
|
257
266
|
reset(): void {
|
258
|
-
this.
|
267
|
+
this.nodeForUrl.clear();
|
259
268
|
this.dataGrid.rootNode().removeChildren();
|
260
269
|
}
|
261
270
|
|
262
271
|
updateFilterAndHighlight(highlightRegExp: RegExp|null): void {
|
263
272
|
this.highlightRegExp = highlightRegExp;
|
264
273
|
let hadTreeUpdates = false;
|
265
|
-
for (const node of this.
|
274
|
+
for (const node of this.nodeForUrl.values()) {
|
266
275
|
const shouldBeVisible = this.isVisibleFilter(node.coverageInfo);
|
267
276
|
const isVisible = Boolean(node.parent);
|
268
277
|
if (shouldBeVisible) {
|
@@ -279,13 +288,13 @@ export class CoverageListView extends UI.Widget.VBox {
|
|
279
288
|
}
|
280
289
|
}
|
281
290
|
if (hadTreeUpdates) {
|
282
|
-
this.
|
291
|
+
this.dataGrid.dispatchEventToListeners(DataGrid.DataGrid.Events.SORTING_CHANGED);
|
283
292
|
}
|
284
293
|
}
|
285
294
|
|
286
295
|
private appendNodeByType(node: GridNode): void {
|
287
|
-
if (node.coverageInfo
|
288
|
-
const parentNode = this.
|
296
|
+
if (node.coverageInfo.generatedUrl) {
|
297
|
+
const parentNode = this.nodeForUrl.get(node.coverageInfo.generatedUrl);
|
289
298
|
parentNode?.appendChild(node);
|
290
299
|
} else {
|
291
300
|
this.dataGrid.rootNode().appendChild(node);
|
@@ -293,11 +302,9 @@ export class CoverageListView extends UI.Widget.VBox {
|
|
293
302
|
}
|
294
303
|
|
295
304
|
selectByUrl(url: string): void {
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
break;
|
300
|
-
}
|
305
|
+
const node = this.nodeForUrl.get(url as Platform.DevToolsPath.UrlString);
|
306
|
+
if (node) {
|
307
|
+
node.revealAndSelect();
|
301
308
|
}
|
302
309
|
}
|
303
310
|
|
@@ -311,7 +318,7 @@ export class CoverageListView extends UI.Widget.VBox {
|
|
311
318
|
return;
|
312
319
|
}
|
313
320
|
const coverageInfo = (node as GridNode).coverageInfo;
|
314
|
-
const sourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(coverageInfo.url
|
321
|
+
const sourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(coverageInfo.url);
|
315
322
|
if (!sourceCode) {
|
316
323
|
return;
|
317
324
|
}
|
@@ -321,21 +328,6 @@ export class CoverageListView extends UI.Widget.VBox {
|
|
321
328
|
}
|
322
329
|
void Common.Revealer.reveal(sourceCode);
|
323
330
|
}
|
324
|
-
|
325
|
-
private sortingChanged(): void {
|
326
|
-
const columnId = this.dataGrid.sortColumnId();
|
327
|
-
if (!columnId) {
|
328
|
-
return;
|
329
|
-
}
|
330
|
-
const sortFunction = GridNode.sortFunctionForColumn(columnId) as (
|
331
|
-
(arg0: DataGrid.SortableDataGrid.SortableDataGridNode<GridNode>,
|
332
|
-
arg1: DataGrid.SortableDataGrid.SortableDataGridNode<GridNode>) => number) |
|
333
|
-
null;
|
334
|
-
if (!sortFunction) {
|
335
|
-
return;
|
336
|
-
}
|
337
|
-
this.dataGrid.sortNodes(sortFunction, !this.dataGrid.isSortOrderAscending());
|
338
|
-
}
|
339
331
|
}
|
340
332
|
|
341
333
|
let percentageFormatter: Intl.NumberFormat|null = null;
|
@@ -360,18 +352,28 @@ function getBytesFormatter(): Intl.NumberFormat {
|
|
360
352
|
}
|
361
353
|
|
362
354
|
export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode<GridNode> {
|
363
|
-
coverageInfo:
|
355
|
+
coverageInfo: CoverageListItem;
|
364
356
|
private lastUsedSize!: number|undefined;
|
365
357
|
private url: Platform.DevToolsPath.UrlString;
|
366
358
|
private maxSize: number;
|
367
359
|
private highlightRegExp: RegExp|null;
|
368
360
|
|
369
|
-
constructor(coverageInfo:
|
361
|
+
constructor(coverageInfo: CoverageListItem, maxSize: number) {
|
370
362
|
super();
|
371
363
|
this.coverageInfo = coverageInfo;
|
372
|
-
this.url = coverageInfo.url
|
364
|
+
this.url = coverageInfo.url;
|
373
365
|
this.maxSize = maxSize;
|
374
366
|
this.highlightRegExp = null;
|
367
|
+
this.#updateData(coverageInfo);
|
368
|
+
}
|
369
|
+
|
370
|
+
#updateData(coverageInfo: CoverageListItem): void {
|
371
|
+
this.data['url'] = this.url;
|
372
|
+
this.data['type'] = coverageTypeToString(coverageInfo.type);
|
373
|
+
this.data['size'] = coverageInfo.size;
|
374
|
+
this.data['unused-size'] = coverageInfo.unusedSize;
|
375
|
+
this.data['bars'] = coverageInfo.unusedSize;
|
376
|
+
this.coverageInfo = coverageInfo;
|
375
377
|
}
|
376
378
|
|
377
379
|
setHighlight(highlightRegExp: RegExp|null): void {
|
@@ -382,102 +384,98 @@ export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode<Gri
|
|
382
384
|
this.refresh();
|
383
385
|
}
|
384
386
|
|
385
|
-
refreshIfNeeded(maxSize: number): boolean {
|
386
|
-
if (this.lastUsedSize ===
|
387
|
+
refreshIfNeeded(maxSize: number, coverageInfo: CoverageListItem): boolean {
|
388
|
+
if (this.lastUsedSize === coverageInfo.usedSize && maxSize === this.maxSize) {
|
387
389
|
return false;
|
388
390
|
}
|
389
|
-
this.lastUsedSize =
|
391
|
+
this.lastUsedSize = coverageInfo.usedSize;
|
390
392
|
this.maxSize = maxSize;
|
391
393
|
this.refresh();
|
394
|
+
this.#updateData(coverageInfo);
|
392
395
|
return true;
|
393
396
|
}
|
394
397
|
|
395
398
|
override createCell(columnId: string): HTMLElement {
|
396
399
|
const cell = this.createTD(columnId);
|
400
|
+
const info = this.coverageInfo;
|
401
|
+
const formatBytes = (value: number|undefined): string => {
|
402
|
+
return getBytesFormatter().format(value ?? 0);
|
403
|
+
};
|
404
|
+
const formatPercent = (value: number|undefined): string => {
|
405
|
+
return getPercentageFormatter().format(value ?? 0);
|
406
|
+
};
|
397
407
|
switch (columnId) {
|
398
408
|
case 'url': {
|
399
409
|
UI.Tooltip.Tooltip.install(cell, this.url);
|
400
|
-
|
401
|
-
const prefix = outer.createChild('div', 'url-prefix');
|
402
|
-
const suffix = outer.createChild('div', 'url-suffix');
|
410
|
+
this.setCellAccessibleName(this.url, cell, columnId);
|
403
411
|
const splitURL = /^(.*)(\/[^/]*)$/.exec(this.url);
|
404
|
-
|
405
|
-
|
412
|
+
render(
|
413
|
+
html`
|
414
|
+
<div class="url-outer">
|
415
|
+
<div class="url-prefix">${splitURL ? splitURL[1] : this.url}</div>
|
416
|
+
<div class="url-suffix">${splitURL ? splitURL[2] : ''}</div>
|
417
|
+
</div>`,
|
418
|
+
cell);
|
406
419
|
if (this.highlightRegExp) {
|
407
|
-
this.highlight(
|
420
|
+
this.highlight(cell, this.url);
|
408
421
|
}
|
409
|
-
this.setCellAccessibleName(this.url, cell, columnId);
|
410
422
|
break;
|
411
423
|
}
|
412
424
|
case 'type': {
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
425
|
+
UI.Tooltip.Tooltip.install(
|
426
|
+
cell,
|
427
|
+
info.type & CoverageType.JAVA_SCRIPT_PER_FUNCTION ? i18nString(UIStrings.jsCoverageWithPerFunction) :
|
428
|
+
info.type & CoverageType.JAVA_SCRIPT ? i18nString(UIStrings.jsCoverageWithPerBlock) :
|
429
|
+
'');
|
430
|
+
render(coverageTypeToString(this.coverageInfo.type), cell);
|
419
431
|
break;
|
420
432
|
}
|
421
433
|
case 'size': {
|
422
|
-
|
423
|
-
|
424
|
-
const sizeFormatted = getBytesFormatter().format(size);
|
425
|
-
sizeSpan.textContent = sizeFormatted;
|
426
|
-
const sizeAccessibleName = i18nString(UIStrings.sBytes, {n: size});
|
427
|
-
this.setCellAccessibleName(sizeAccessibleName, cell, columnId);
|
434
|
+
this.setCellAccessibleName(i18nString(UIStrings.sBytes, {n: info.size || 0}), cell, columnId);
|
435
|
+
render(html`<span>${formatBytes(info.size)}</span>`, cell);
|
428
436
|
break;
|
429
437
|
}
|
430
438
|
case 'unused-size': {
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
439
|
+
this.setCellAccessibleName(
|
440
|
+
i18nString(UIStrings.sBytesS, {n: info.unusedSize, percentage: formatPercent(info.unusedPercentage)}), cell,
|
441
|
+
columnId);
|
442
|
+
// clang-format off
|
443
|
+
render(html`
|
444
|
+
<span>${formatBytes(info.unusedSize)}</span>
|
445
|
+
<span class="percent-value">
|
446
|
+
${formatPercent(info.unusedPercentage)}
|
447
|
+
</span>`, cell);
|
448
|
+
// clang-format on
|
440
449
|
break;
|
441
450
|
}
|
442
451
|
case 'bars': {
|
443
|
-
const barContainer = cell.createChild('div', 'bar-container');
|
444
|
-
const unusedPercent = getPercentageFormatter().format(this.coverageInfo.unusedPercentage());
|
445
|
-
const usedPercent = getPercentageFormatter().format(this.coverageInfo.usedPercentage());
|
446
|
-
if (this.coverageInfo.unusedSize() > 0) {
|
447
|
-
const unusedSizeBar = barContainer.createChild('div', 'bar bar-unused-size');
|
448
|
-
unusedSizeBar.style.width = ((this.coverageInfo.unusedSize() / this.maxSize) * 100 || 0) + '%';
|
449
|
-
if (this.coverageInfo.type() & CoverageType.JAVA_SCRIPT_PER_FUNCTION) {
|
450
|
-
UI.Tooltip.Tooltip.install(
|
451
|
-
unusedSizeBar,
|
452
|
-
i18nString(
|
453
|
-
UIStrings.sBytesSBelongToFunctionsThatHave,
|
454
|
-
{PH1: this.coverageInfo.unusedSize(), PH2: unusedPercent}));
|
455
|
-
} else if (this.coverageInfo.type() & CoverageType.JAVA_SCRIPT) {
|
456
|
-
UI.Tooltip.Tooltip.install(
|
457
|
-
unusedSizeBar,
|
458
|
-
i18nString(
|
459
|
-
UIStrings.sBytesSBelongToBlocksOf, {PH1: this.coverageInfo.unusedSize(), PH2: unusedPercent}));
|
460
|
-
}
|
461
|
-
}
|
462
|
-
if (this.coverageInfo.usedSize() > 0) {
|
463
|
-
const usedSizeBar = barContainer.createChild('div', 'bar bar-used-size');
|
464
|
-
usedSizeBar.style.width = ((this.coverageInfo.usedSize() / this.maxSize) * 100 || 0) + '%';
|
465
|
-
if (this.coverageInfo.type() & CoverageType.JAVA_SCRIPT_PER_FUNCTION) {
|
466
|
-
UI.Tooltip.Tooltip.install(
|
467
|
-
usedSizeBar,
|
468
|
-
i18nString(
|
469
|
-
UIStrings.sBytesSBelongToFunctionsThatHaveExecuted,
|
470
|
-
{PH1: this.coverageInfo.usedSize(), PH2: usedPercent}));
|
471
|
-
} else if (this.coverageInfo.type() & CoverageType.JAVA_SCRIPT) {
|
472
|
-
UI.Tooltip.Tooltip.install(
|
473
|
-
usedSizeBar,
|
474
|
-
i18nString(
|
475
|
-
UIStrings.sBytesSBelongToBlocksOfJavascript,
|
476
|
-
{PH1: this.coverageInfo.usedSize(), PH2: usedPercent}));
|
477
|
-
}
|
478
|
-
}
|
479
452
|
this.setCellAccessibleName(
|
480
|
-
i18nString(
|
453
|
+
i18nString(
|
454
|
+
UIStrings.sOfFileUnusedSOfFileUsed,
|
455
|
+
{PH1: formatPercent(info.unusedPercentage), PH2: formatPercent(info.usedPercentage)}),
|
456
|
+
cell, columnId);
|
457
|
+
// clang-format off
|
458
|
+
render(html`
|
459
|
+
<div class="bar-container">
|
460
|
+
${info.unusedSize > 0 ? html`
|
461
|
+
<div class="bar bar-unused-size"
|
462
|
+
title=${
|
463
|
+
info.type & CoverageType.JAVA_SCRIPT_PER_FUNCTION ? i18nString(UIStrings.sBytesSBelongToFunctionsThatHave, {PH1: info.unusedSize, PH2: formatPercent(info.unusedPercentage)}) :
|
464
|
+
info.type & CoverageType.JAVA_SCRIPT ? i18nString(UIStrings.sBytesSBelongToBlocksOf, {PH1: info.unusedSize, PH2: formatPercent(info.unusedPercentage)}) :
|
465
|
+
''}
|
466
|
+
style=${styleMap({width: ((info.unusedSize / this.maxSize) * 100 || 0) + '%'})}>
|
467
|
+
</div>` : nothing}
|
468
|
+
${info.usedSize > 0 ? html`
|
469
|
+
<div class="bar bar-used-size"
|
470
|
+
title=${
|
471
|
+
info.type & CoverageType.JAVA_SCRIPT_PER_FUNCTION ? i18nString(UIStrings.sBytesSBelongToFunctionsThatHaveExecuted, {PH1: info.usedSize, PH2: formatPercent(info.usedPercentage)}) :
|
472
|
+
info.type & CoverageType.JAVA_SCRIPT ? i18nString(UIStrings.sBytesSBelongToBlocksOfJavascript, {PH1: info.usedSize, PH2: formatPercent(info.usedPercentage)}) :
|
473
|
+
''}
|
474
|
+
{ PH1: info.usedSize, PH2: formatPercent(info.usedPercentage) })}
|
475
|
+
style=${styleMap({width:((info.usedSize / this.maxSize) * 100 || 0) + '%'})}>
|
476
|
+
</div>` : nothing}
|
477
|
+
</div>`, cell);
|
478
|
+
// clang-format on
|
481
479
|
}
|
482
480
|
}
|
483
481
|
return cell;
|
@@ -494,27 +492,4 @@ export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode<Gri
|
|
494
492
|
const range = new TextUtils.TextRange.SourceRange(matches.index, matches[0].length);
|
495
493
|
UI.UIUtils.highlightRangesWithStyleClass(element, [range], 'filter-highlight');
|
496
494
|
}
|
497
|
-
|
498
|
-
static sortFunctionForColumn(columnId: string): ((arg0: GridNode, arg1: GridNode) => number)|null {
|
499
|
-
const compareURL = (a: GridNode, b: GridNode): number => a.url.localeCompare(b.url);
|
500
|
-
switch (columnId) {
|
501
|
-
case 'url':
|
502
|
-
return compareURL;
|
503
|
-
case 'type':
|
504
|
-
return (a: GridNode, b: GridNode) => {
|
505
|
-
const typeA = coverageTypeToString(a.coverageInfo.type());
|
506
|
-
const typeB = coverageTypeToString(b.coverageInfo.type());
|
507
|
-
return typeA.localeCompare(typeB) || compareURL(a, b);
|
508
|
-
};
|
509
|
-
case 'size':
|
510
|
-
return (a: GridNode, b: GridNode) => a.coverageInfo.size() - b.coverageInfo.size() || compareURL(a, b);
|
511
|
-
case 'bars':
|
512
|
-
case 'unused-size':
|
513
|
-
return (a: GridNode, b: GridNode) =>
|
514
|
-
a.coverageInfo.unusedSize() - b.coverageInfo.unusedSize() || compareURL(a, b);
|
515
|
-
default:
|
516
|
-
console.assert(false, 'Unknown sort field: ' + columnId);
|
517
|
-
return null;
|
518
|
-
}
|
519
|
-
}
|
520
495
|
}
|
@@ -17,8 +17,15 @@ import * as UI from '../../ui/legacy/legacy.js';
|
|
17
17
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
18
18
|
|
19
19
|
import {CoverageDecorationManager} from './CoverageDecorationManager.js';
|
20
|
-
import {CoverageListView} from './CoverageListView.js';
|
21
|
-
import {
|
20
|
+
import {type CoverageListItem, CoverageListView} from './CoverageListView.js';
|
21
|
+
import {
|
22
|
+
type CoverageInfo,
|
23
|
+
CoverageModel,
|
24
|
+
CoverageType,
|
25
|
+
Events,
|
26
|
+
SourceURLCoverageInfo,
|
27
|
+
type URLCoverageInfo,
|
28
|
+
} from './CoverageModel.js';
|
22
29
|
import coverageViewStyles from './coverageView.css.js';
|
23
30
|
|
24
31
|
const UIStrings = {
|
@@ -254,7 +261,7 @@ export class CoverageView extends UI.Widget.VBox {
|
|
254
261
|
this.bfcacheReloadPromptPage = this.buildReloadPromptPage(i18nString(UIStrings.bfcacheNoCapture), 'bfcache-page');
|
255
262
|
this.activationReloadPromptPage =
|
256
263
|
this.buildReloadPromptPage(i18nString(UIStrings.activationNoCapture), 'prerender-page');
|
257
|
-
this.listView = new CoverageListView(this.isVisible.bind(this
|
264
|
+
this.listView = new CoverageListView(this.isVisible.bind(this));
|
258
265
|
|
259
266
|
this.statusToolbarElement = this.contentElement.createChild('div', 'coverage-toolbar-summary');
|
260
267
|
this.statusMessageElement = this.statusToolbarElement.createChild('div', 'coverage-message');
|
@@ -435,7 +442,22 @@ export class CoverageView extends UI.Widget.VBox {
|
|
435
442
|
}
|
436
443
|
|
437
444
|
private updateListView(): void {
|
438
|
-
this.listView.update(this.model?.entries() || []);
|
445
|
+
this.listView.update(this.model?.entries().map(this.toCoverageListItem, this) || []);
|
446
|
+
}
|
447
|
+
|
448
|
+
private toCoverageListItem(info: URLCoverageInfo): CoverageListItem {
|
449
|
+
return {
|
450
|
+
url: info.url(),
|
451
|
+
type: info.type(),
|
452
|
+
size: info.size(),
|
453
|
+
usedSize: info.usedSize(),
|
454
|
+
unusedSize: info.unusedSize(),
|
455
|
+
usedPercentage: info.usedPercentage(),
|
456
|
+
unusedPercentage: info.unusedPercentage(),
|
457
|
+
sources: [...info.sourcesURLCoverageInfo.values()].map(this.toCoverageListItem, this),
|
458
|
+
isContentScript: info.isContentScript(),
|
459
|
+
generatedUrl: info instanceof SourceURLCoverageInfo ? info.generatedURLCoverageInfo.url() : undefined,
|
460
|
+
};
|
439
461
|
}
|
440
462
|
|
441
463
|
async stopRecording(): Promise<void> {
|
@@ -514,7 +536,7 @@ export class CoverageView extends UI.Widget.VBox {
|
|
514
536
|
|
515
537
|
private updateViews(updatedEntries: CoverageInfo[]): void {
|
516
538
|
this.updateStats();
|
517
|
-
this.listView.update(this.model?.entries() || []);
|
539
|
+
this.listView.update(this.model?.entries().map(this.toCoverageListItem, this) || []);
|
518
540
|
this.exportAction.setEnabled(this.model !== null && this.model.entries().length > 0);
|
519
541
|
this.decorationManager?.update(updatedEntries);
|
520
542
|
}
|
@@ -527,14 +549,15 @@ export class CoverageView extends UI.Widget.VBox {
|
|
527
549
|
for (const info of this.model.entries()) {
|
528
550
|
all.total += info.size();
|
529
551
|
all.unused += info.unusedSize();
|
530
|
-
|
552
|
+
const listItem = this.toCoverageListItem(info);
|
553
|
+
if (this.isVisible(listItem)) {
|
531
554
|
if (this.textFilterRegExp?.test(info.url())) {
|
532
555
|
filtered.total += info.size();
|
533
556
|
filtered.unused += info.unusedSize();
|
534
557
|
} else {
|
535
558
|
// If it doesn't match the filter, calculate the stats from visible children if there are any
|
536
559
|
for (const childInfo of info.sourcesURLCoverageInfo.values()) {
|
537
|
-
if (this.isVisible(
|
560
|
+
if (this.isVisible(this.toCoverageListItem(childInfo))) {
|
538
561
|
filtered.total += childInfo.size();
|
539
562
|
filtered.unused += childInfo.unusedSize();
|
540
563
|
}
|
@@ -583,27 +606,27 @@ export class CoverageView extends UI.Widget.VBox {
|
|
583
606
|
this.updateStats();
|
584
607
|
}
|
585
608
|
|
586
|
-
private isVisible(
|
587
|
-
const url = coverageInfo.url
|
609
|
+
private isVisible(coverageInfo: CoverageListItem): boolean {
|
610
|
+
const url = coverageInfo.url;
|
588
611
|
if (url.startsWith(CoverageView.EXTENSION_BINDINGS_URL_PREFIX)) {
|
589
612
|
return false;
|
590
613
|
}
|
591
|
-
if (coverageInfo.isContentScript
|
614
|
+
if (coverageInfo.isContentScript && !this.showContentScriptsSetting.get()) {
|
592
615
|
return false;
|
593
616
|
}
|
594
|
-
if (this.typeFilterValue && !(coverageInfo.type
|
617
|
+
if (this.typeFilterValue && !(coverageInfo.type & this.typeFilterValue)) {
|
595
618
|
return false;
|
596
619
|
}
|
597
620
|
// If it's a parent, check if any children are visible
|
598
|
-
if (coverageInfo.
|
599
|
-
for (const sourceURLCoverageInfo of coverageInfo.
|
600
|
-
if (this.isVisible(
|
621
|
+
if (coverageInfo.sources.length > 0) {
|
622
|
+
for (const sourceURLCoverageInfo of coverageInfo.sources) {
|
623
|
+
if (this.isVisible(sourceURLCoverageInfo)) {
|
601
624
|
return true;
|
602
625
|
}
|
603
626
|
}
|
604
627
|
}
|
605
628
|
|
606
|
-
return
|
629
|
+
return !this.textFilterRegExp || this.textFilterRegExp.test(url);
|
607
630
|
}
|
608
631
|
|
609
632
|
async exportReport(): Promise<void> {
|
@@ -618,7 +641,7 @@ export class CoverageView extends UI.Widget.VBox {
|
|
618
641
|
}
|
619
642
|
|
620
643
|
selectCoverageItemByUrl(url: string): void {
|
621
|
-
this.listView.selectByUrl(url);
|
644
|
+
this.listView.selectByUrl(url as Platform.DevToolsPath.UrlString);
|
622
645
|
}
|
623
646
|
|
624
647
|
static readonly EXTENSION_BINDINGS_URL_PREFIX = 'extensions::';
|
@@ -6,6 +6,7 @@ import * as Common from '../../core/common/common.js';
|
|
6
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
7
7
|
import * as Platform from '../../core/platform/platform.js';
|
8
8
|
import * as SDK from '../../core/sdk/sdk.js';
|
9
|
+
import * as Badges from '../../models/badges/badges.js';
|
9
10
|
import * as Lit from '../../ui/lit/lit.js';
|
10
11
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
11
12
|
|
@@ -202,6 +203,7 @@ export class NetworkThrottlingSelect extends Common.ObjectWrapper.ObjectWrapper<
|
|
202
203
|
|
203
204
|
const onSelect = (conditions: SDK.NetworkManager.Conditions): void => {
|
204
205
|
this.dispatchEventToListeners(Events.CONDITIONS_CHANGED, conditions);
|
206
|
+
Badges.UserBadges.instance().recordAction(Badges.BadgeAction.NETWORK_SPEED_THROTTLED);
|
205
207
|
};
|
206
208
|
|
207
209
|
const throttlingGroups = [
|
@@ -771,6 +771,24 @@ export class NetworkRequestNode extends NetworkNode {
|
|
771
771
|
return aScore - bScore || aRequest.identityCompare(bRequest);
|
772
772
|
}
|
773
773
|
|
774
|
+
static IsAdRelatedComparator(a: NetworkNode, b: NetworkNode): number {
|
775
|
+
// TODO(allada) Handle this properly for group nodes.
|
776
|
+
const aRequest = a.requestOrFirstKnownChildRequest();
|
777
|
+
const bRequest = b.requestOrFirstKnownChildRequest();
|
778
|
+
if (!aRequest || !bRequest) {
|
779
|
+
return !aRequest ? -1 : 1;
|
780
|
+
}
|
781
|
+
const aIsAdRelated = aRequest.isAdRelated();
|
782
|
+
const bIsAdRelated = bRequest.isAdRelated();
|
783
|
+
if (aIsAdRelated > bIsAdRelated) {
|
784
|
+
return 1;
|
785
|
+
}
|
786
|
+
if (bIsAdRelated > aIsAdRelated) {
|
787
|
+
return -1;
|
788
|
+
}
|
789
|
+
return aRequest.identityCompare(bRequest);
|
790
|
+
}
|
791
|
+
|
774
792
|
static RequestPropertyComparator(propertyName: string, a: NetworkNode, b: NetworkNode): number {
|
775
793
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
776
794
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
@@ -1038,6 +1056,10 @@ export class NetworkRequestNode extends NetworkNode {
|
|
1038
1056
|
this.renderAddressSpaceCell(cell, this.requestInternal.remoteAddressSpace());
|
1039
1057
|
break;
|
1040
1058
|
}
|
1059
|
+
case 'is-ad-related': {
|
1060
|
+
this.setTextAndTitle(cell, this.requestInternal.isAdRelated().toLocaleString());
|
1061
|
+
break;
|
1062
|
+
}
|
1041
1063
|
case 'cookies': {
|
1042
1064
|
this.setTextAndTitle(cell, this.arrayLength(this.requestInternal.includedRequestCookies()));
|
1043
1065
|
break;
|
@@ -148,6 +148,10 @@ const UIStrings = {
|
|
148
148
|
* @description Text in Network Log View Columns of the Network panel
|
149
149
|
*/
|
150
150
|
remoteAddressSpace: 'Remote Address Space',
|
151
|
+
/**
|
152
|
+
* @description Text to show whether a request is ad-related
|
153
|
+
*/
|
154
|
+
isAdRelated: 'Is Ad-Related',
|
151
155
|
} as const;
|
152
156
|
const str_ = i18n.i18n.registerUIStrings('panels/network/NetworkLogViewColumns.ts', UIStrings);
|
153
157
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
@@ -1183,6 +1187,11 @@ const DEFAULT_COLUMNS = [
|
|
1183
1187
|
title: i18n.i18n.lockedLazyString('User-Agent'),
|
1184
1188
|
sortingFunction: NetworkRequestNode.RequestHeaderStringComparator.bind(null, 'user-agent'),
|
1185
1189
|
},
|
1190
|
+
{
|
1191
|
+
id: 'is-ad-related',
|
1192
|
+
title: i18nLazyString(UIStrings.isAdRelated),
|
1193
|
+
sortingFunction: NetworkRequestNode.IsAdRelatedComparator,
|
1194
|
+
},
|
1186
1195
|
// This header is a placeholder to let datagrid know that it can be sorted by this column, but never shown.
|
1187
1196
|
{
|
1188
1197
|
id: 'waterfall',
|