chrome-devtools-frontend 1.0.1519267 → 1.0.1520535
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 +26 -5
- 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 +50 -48
- package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +4 -4
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +128 -30
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +98 -63
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +317 -640
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +36 -21
- 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/badges/UserBadges.ts +5 -4
- 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 +45 -69
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +47 -1
- package/front_end/panels/ai_assistance/components/chatView.css +13 -1
- 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 +146 -198
- package/front_end/panels/coverage/CoverageView.ts +48 -18
- 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 +4 -4
- 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/panels/timeline/components/ExportTraceOptions.ts +56 -4
- package/front_end/panels/timeline/components/exportTraceOptions.css +5 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/lighthouse/README.chromium +8 -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,16 +140,14 @@ 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: URLCoverageInfo) => boolean;
|
143
|
+
private readonly nodeForUrl: Map<Platform.DevToolsPath.UrlString, GridNode>;
|
133
144
|
private highlightRegExp: RegExp|null;
|
134
145
|
private dataGrid: DataGrid.SortableDataGrid.SortableDataGrid<GridNode>;
|
135
146
|
|
136
|
-
constructor(
|
147
|
+
constructor() {
|
137
148
|
super({useShadowDom: true});
|
138
149
|
this.registerRequiredCSS(coverageListViewStyles);
|
139
|
-
this.
|
140
|
-
this.isVisibleFilter = isVisibleFilter;
|
150
|
+
this.nodeForUrl = new Map();
|
141
151
|
this.highlightRegExp = null;
|
142
152
|
|
143
153
|
const columns = [
|
@@ -179,113 +189,82 @@ export class CoverageListView extends UI.Widget.VBox {
|
|
179
189
|
weight: 1,
|
180
190
|
},
|
181
191
|
] as DataGrid.DataGrid.ColumnDescriptor[];
|
182
|
-
this.dataGrid =
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
192
|
+
this.dataGrid =
|
193
|
+
DataGrid.SortableDataGrid.SortableDataGrid.create(['dummy'], [], i18nString(UIStrings.codeCoverage)) as
|
194
|
+
DataGrid.SortableDataGrid.SortableDataGrid<GridNode>;
|
195
|
+
this.dataGrid.removeColumn('dummy');
|
196
|
+
for (const column of columns) {
|
197
|
+
this.dataGrid.addColumn(column);
|
198
|
+
}
|
199
|
+
this.dataGrid.setColumnsVisibility(new Set(columns.map(column => column.id)));
|
188
200
|
this.dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.LAST);
|
189
201
|
this.dataGrid.setStriped(true);
|
190
202
|
this.dataGrid.element.classList.add('flex-auto');
|
191
203
|
this.dataGrid.addEventListener(DataGrid.DataGrid.Events.OPENED_NODE, this.onOpenedNode, this);
|
192
|
-
this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SORTING_CHANGED, this.sortingChanged, this);
|
193
204
|
|
194
205
|
const dataGridWidget = this.dataGrid.asWidget();
|
195
206
|
dataGridWidget.show(this.contentElement);
|
196
207
|
this.setDefaultFocusedChild(dataGridWidget);
|
197
208
|
}
|
198
209
|
|
199
|
-
update(coverageInfo:
|
210
|
+
update(coverageInfo: CoverageListItem[], highlightRegExp: RegExp|null): void {
|
211
|
+
this.highlightRegExp = highlightRegExp;
|
212
|
+
const maxSize = coverageInfo.reduce((acc, entry) => Math.max(acc, entry.size), 0);
|
213
|
+
|
214
|
+
const coverageUrls = new Set(coverageInfo.map(info => info.url));
|
215
|
+
for (const [url, node] of this.nodeForUrl.entries()) {
|
216
|
+
if (!coverageUrls.has(url)) {
|
217
|
+
node.remove();
|
218
|
+
this.nodeForUrl.delete(url);
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
200
222
|
let hadUpdates = false;
|
201
|
-
const maxSize = coverageInfo.reduce((acc, entry) => Math.max(acc, entry.size()), 0);
|
202
|
-
const rootNode = this.dataGrid.rootNode();
|
203
223
|
for (const entry of coverageInfo) {
|
204
|
-
let node = this.
|
224
|
+
let node = this.nodeForUrl.get(entry.url);
|
205
225
|
if (node) {
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
this.updateSourceNodes(entry.sourcesURLCoverageInfo, maxSize, node);
|
210
|
-
}
|
226
|
+
hadUpdates = node.refreshIfNeeded(maxSize, entry) || hadUpdates;
|
227
|
+
if (entry.sources.length > 0) {
|
228
|
+
this.updateSourceNodes(entry.sources, maxSize, node);
|
211
229
|
}
|
230
|
+
node.setHighlight(this.highlightRegExp);
|
212
231
|
continue;
|
213
232
|
}
|
214
233
|
node = new GridNode(entry, maxSize);
|
215
|
-
this.
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
void this.createSourceNodes(entry.sourcesURLCoverageInfo, maxSize, node);
|
220
|
-
}
|
221
|
-
hadUpdates = true;
|
234
|
+
this.nodeForUrl.set(entry.url, node);
|
235
|
+
this.appendNodeByType(node);
|
236
|
+
if (entry.sources.length > 0) {
|
237
|
+
this.updateSourceNodes(entry.sources, maxSize, node);
|
222
238
|
}
|
239
|
+
node.setHighlight(this.highlightRegExp);
|
240
|
+
hadUpdates = true;
|
223
241
|
}
|
224
242
|
if (hadUpdates) {
|
225
|
-
this.
|
243
|
+
this.dataGrid.dispatchEventToListeners(DataGrid.DataGrid.Events.SORTING_CHANGED);
|
226
244
|
}
|
227
245
|
}
|
228
246
|
|
229
|
-
updateSourceNodes(
|
230
|
-
|
231
|
-
|
232
|
-
let shouldCreateSourceNodes = false;
|
233
|
-
for (const coverageInfo of sourcesURLCoverageInfo.values()) {
|
234
|
-
const sourceNode = this.nodeForCoverageInfo.get(coverageInfo);
|
247
|
+
updateSourceNodes(sources: CoverageListItem[], maxSize: number, node: GridNode): void {
|
248
|
+
for (const coverageInfo of sources) {
|
249
|
+
const sourceNode = this.nodeForUrl.get(coverageInfo.url);
|
235
250
|
if (sourceNode) {
|
236
|
-
sourceNode.refreshIfNeeded(maxSize);
|
251
|
+
sourceNode.refreshIfNeeded(maxSize, coverageInfo);
|
237
252
|
} else {
|
238
|
-
|
239
|
-
|
253
|
+
const sourceNode = new GridNode(coverageInfo, maxSize);
|
254
|
+
node.appendChild(sourceNode);
|
255
|
+
this.nodeForUrl.set(coverageInfo.url, sourceNode);
|
240
256
|
}
|
241
257
|
}
|
242
|
-
if (shouldCreateSourceNodes) {
|
243
|
-
void this.createSourceNodes(sourcesURLCoverageInfo, maxSize, node);
|
244
|
-
}
|
245
|
-
}
|
246
|
-
|
247
|
-
async createSourceNodes(
|
248
|
-
sourcesURLCoverageInfo: Map<Platform.DevToolsPath.UrlString, SourceURLCoverageInfo>, maxSize: number,
|
249
|
-
node: GridNode): Promise<void> {
|
250
|
-
for (const coverageInfo of sourcesURLCoverageInfo.values()) {
|
251
|
-
const sourceNode = new GridNode(coverageInfo, maxSize);
|
252
|
-
node.appendChild(sourceNode);
|
253
|
-
this.nodeForCoverageInfo.set(coverageInfo, sourceNode);
|
254
|
-
}
|
255
258
|
}
|
256
259
|
|
257
260
|
reset(): void {
|
258
|
-
this.
|
261
|
+
this.nodeForUrl.clear();
|
259
262
|
this.dataGrid.rootNode().removeChildren();
|
260
263
|
}
|
261
264
|
|
262
|
-
updateFilterAndHighlight(highlightRegExp: RegExp|null): void {
|
263
|
-
this.highlightRegExp = highlightRegExp;
|
264
|
-
let hadTreeUpdates = false;
|
265
|
-
for (const node of this.nodeForCoverageInfo.values()) {
|
266
|
-
const shouldBeVisible = this.isVisibleFilter(node.coverageInfo);
|
267
|
-
const isVisible = Boolean(node.parent);
|
268
|
-
if (shouldBeVisible) {
|
269
|
-
node.setHighlight(this.highlightRegExp);
|
270
|
-
}
|
271
|
-
if (shouldBeVisible === isVisible) {
|
272
|
-
continue;
|
273
|
-
}
|
274
|
-
hadTreeUpdates = true;
|
275
|
-
if (!shouldBeVisible) {
|
276
|
-
node.remove();
|
277
|
-
} else {
|
278
|
-
this.appendNodeByType(node);
|
279
|
-
}
|
280
|
-
}
|
281
|
-
if (hadTreeUpdates) {
|
282
|
-
this.sortingChanged();
|
283
|
-
}
|
284
|
-
}
|
285
|
-
|
286
265
|
private appendNodeByType(node: GridNode): void {
|
287
|
-
if (node.coverageInfo
|
288
|
-
const parentNode = this.
|
266
|
+
if (node.coverageInfo.generatedUrl) {
|
267
|
+
const parentNode = this.nodeForUrl.get(node.coverageInfo.generatedUrl);
|
289
268
|
parentNode?.appendChild(node);
|
290
269
|
} else {
|
291
270
|
this.dataGrid.rootNode().appendChild(node);
|
@@ -293,11 +272,9 @@ export class CoverageListView extends UI.Widget.VBox {
|
|
293
272
|
}
|
294
273
|
|
295
274
|
selectByUrl(url: string): void {
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
break;
|
300
|
-
}
|
275
|
+
const node = this.nodeForUrl.get(url as Platform.DevToolsPath.UrlString);
|
276
|
+
if (node) {
|
277
|
+
node.revealAndSelect();
|
301
278
|
}
|
302
279
|
}
|
303
280
|
|
@@ -311,7 +288,7 @@ export class CoverageListView extends UI.Widget.VBox {
|
|
311
288
|
return;
|
312
289
|
}
|
313
290
|
const coverageInfo = (node as GridNode).coverageInfo;
|
314
|
-
const sourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(coverageInfo.url
|
291
|
+
const sourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(coverageInfo.url);
|
315
292
|
if (!sourceCode) {
|
316
293
|
return;
|
317
294
|
}
|
@@ -321,21 +298,6 @@ export class CoverageListView extends UI.Widget.VBox {
|
|
321
298
|
}
|
322
299
|
void Common.Revealer.reveal(sourceCode);
|
323
300
|
}
|
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
301
|
}
|
340
302
|
|
341
303
|
let percentageFormatter: Intl.NumberFormat|null = null;
|
@@ -360,18 +322,28 @@ function getBytesFormatter(): Intl.NumberFormat {
|
|
360
322
|
}
|
361
323
|
|
362
324
|
export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode<GridNode> {
|
363
|
-
coverageInfo:
|
325
|
+
coverageInfo: CoverageListItem;
|
364
326
|
private lastUsedSize!: number|undefined;
|
365
327
|
private url: Platform.DevToolsPath.UrlString;
|
366
328
|
private maxSize: number;
|
367
329
|
private highlightRegExp: RegExp|null;
|
368
330
|
|
369
|
-
constructor(coverageInfo:
|
331
|
+
constructor(coverageInfo: CoverageListItem, maxSize: number) {
|
370
332
|
super();
|
371
333
|
this.coverageInfo = coverageInfo;
|
372
|
-
this.url = coverageInfo.url
|
334
|
+
this.url = coverageInfo.url;
|
373
335
|
this.maxSize = maxSize;
|
374
336
|
this.highlightRegExp = null;
|
337
|
+
this.#updateData(coverageInfo);
|
338
|
+
}
|
339
|
+
|
340
|
+
#updateData(coverageInfo: CoverageListItem): void {
|
341
|
+
this.data['url'] = this.url;
|
342
|
+
this.data['type'] = coverageTypeToString(coverageInfo.type);
|
343
|
+
this.data['size'] = coverageInfo.size;
|
344
|
+
this.data['unused-size'] = coverageInfo.unusedSize;
|
345
|
+
this.data['bars'] = coverageInfo.unusedSize;
|
346
|
+
this.coverageInfo = coverageInfo;
|
375
347
|
}
|
376
348
|
|
377
349
|
setHighlight(highlightRegExp: RegExp|null): void {
|
@@ -379,105 +351,104 @@ export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode<Gri
|
|
379
351
|
return;
|
380
352
|
}
|
381
353
|
this.highlightRegExp = highlightRegExp;
|
354
|
+
for (const child of this.children) {
|
355
|
+
(child as GridNode).setHighlight(this.highlightRegExp);
|
356
|
+
}
|
382
357
|
this.refresh();
|
383
358
|
}
|
384
359
|
|
385
|
-
refreshIfNeeded(maxSize: number): boolean {
|
386
|
-
if (this.lastUsedSize ===
|
360
|
+
refreshIfNeeded(maxSize: number, coverageInfo: CoverageListItem): boolean {
|
361
|
+
if (this.lastUsedSize === coverageInfo.usedSize && maxSize === this.maxSize) {
|
387
362
|
return false;
|
388
363
|
}
|
389
|
-
this.lastUsedSize =
|
364
|
+
this.lastUsedSize = coverageInfo.usedSize;
|
390
365
|
this.maxSize = maxSize;
|
391
366
|
this.refresh();
|
367
|
+
this.#updateData(coverageInfo);
|
392
368
|
return true;
|
393
369
|
}
|
394
370
|
|
395
371
|
override createCell(columnId: string): HTMLElement {
|
396
372
|
const cell = this.createTD(columnId);
|
373
|
+
const info = this.coverageInfo;
|
374
|
+
const formatBytes = (value: number|undefined): string => {
|
375
|
+
return getBytesFormatter().format(value ?? 0);
|
376
|
+
};
|
377
|
+
const formatPercent = (value: number|undefined): string => {
|
378
|
+
return getPercentageFormatter().format(value ?? 0);
|
379
|
+
};
|
397
380
|
switch (columnId) {
|
398
381
|
case 'url': {
|
399
382
|
UI.Tooltip.Tooltip.install(cell, this.url);
|
400
|
-
|
401
|
-
const prefix = outer.createChild('div', 'url-prefix');
|
402
|
-
const suffix = outer.createChild('div', 'url-suffix');
|
383
|
+
this.setCellAccessibleName(this.url, cell, columnId);
|
403
384
|
const splitURL = /^(.*)(\/[^/]*)$/.exec(this.url);
|
404
|
-
|
405
|
-
|
385
|
+
render(
|
386
|
+
html`
|
387
|
+
<div class="url-outer">
|
388
|
+
<div class="url-prefix">${splitURL ? splitURL[1] : this.url}</div>
|
389
|
+
<div class="url-suffix">${splitURL ? splitURL[2] : ''}</div>
|
390
|
+
</div>`,
|
391
|
+
cell);
|
406
392
|
if (this.highlightRegExp) {
|
407
|
-
this.highlight(
|
393
|
+
this.highlight(cell, this.url);
|
408
394
|
}
|
409
|
-
this.setCellAccessibleName(this.url, cell, columnId);
|
410
395
|
break;
|
411
396
|
}
|
412
397
|
case 'type': {
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
398
|
+
UI.Tooltip.Tooltip.install(
|
399
|
+
cell,
|
400
|
+
info.type & CoverageType.JAVA_SCRIPT_PER_FUNCTION ? i18nString(UIStrings.jsCoverageWithPerFunction) :
|
401
|
+
info.type & CoverageType.JAVA_SCRIPT ? i18nString(UIStrings.jsCoverageWithPerBlock) :
|
402
|
+
'');
|
403
|
+
render(coverageTypeToString(this.coverageInfo.type), cell);
|
419
404
|
break;
|
420
405
|
}
|
421
406
|
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);
|
407
|
+
this.setCellAccessibleName(i18nString(UIStrings.sBytes, {n: info.size || 0}), cell, columnId);
|
408
|
+
render(html`<span>${formatBytes(info.size)}</span>`, cell);
|
428
409
|
break;
|
429
410
|
}
|
430
411
|
case 'unused-size': {
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
412
|
+
this.setCellAccessibleName(
|
413
|
+
i18nString(UIStrings.sBytesS, {n: info.unusedSize, percentage: formatPercent(info.unusedPercentage)}), cell,
|
414
|
+
columnId);
|
415
|
+
// clang-format off
|
416
|
+
render(html`
|
417
|
+
<span>${formatBytes(info.unusedSize)}</span>
|
418
|
+
<span class="percent-value">
|
419
|
+
${formatPercent(info.unusedPercentage)}
|
420
|
+
</span>`, cell);
|
421
|
+
// clang-format on
|
440
422
|
break;
|
441
423
|
}
|
442
424
|
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
425
|
this.setCellAccessibleName(
|
480
|
-
i18nString(
|
426
|
+
i18nString(
|
427
|
+
UIStrings.sOfFileUnusedSOfFileUsed,
|
428
|
+
{PH1: formatPercent(info.unusedPercentage), PH2: formatPercent(info.usedPercentage)}),
|
429
|
+
cell, columnId);
|
430
|
+
// clang-format off
|
431
|
+
render(html`
|
432
|
+
<div class="bar-container">
|
433
|
+
${info.unusedSize > 0 ? html`
|
434
|
+
<div class="bar bar-unused-size"
|
435
|
+
title=${
|
436
|
+
info.type & CoverageType.JAVA_SCRIPT_PER_FUNCTION ? i18nString(UIStrings.sBytesSBelongToFunctionsThatHave, {PH1: info.unusedSize, PH2: formatPercent(info.unusedPercentage)}) :
|
437
|
+
info.type & CoverageType.JAVA_SCRIPT ? i18nString(UIStrings.sBytesSBelongToBlocksOf, {PH1: info.unusedSize, PH2: formatPercent(info.unusedPercentage)}) :
|
438
|
+
''}
|
439
|
+
style=${styleMap({width: ((info.unusedSize / this.maxSize) * 100 || 0) + '%'})}>
|
440
|
+
</div>` : nothing}
|
441
|
+
${info.usedSize > 0 ? html`
|
442
|
+
<div class="bar bar-used-size"
|
443
|
+
title=${
|
444
|
+
info.type & CoverageType.JAVA_SCRIPT_PER_FUNCTION ? i18nString(UIStrings.sBytesSBelongToFunctionsThatHaveExecuted, {PH1: info.usedSize, PH2: formatPercent(info.usedPercentage)}) :
|
445
|
+
info.type & CoverageType.JAVA_SCRIPT ? i18nString(UIStrings.sBytesSBelongToBlocksOfJavascript, {PH1: info.usedSize, PH2: formatPercent(info.usedPercentage)}) :
|
446
|
+
''}
|
447
|
+
{ PH1: info.usedSize, PH2: formatPercent(info.usedPercentage) })}
|
448
|
+
style=${styleMap({width:((info.usedSize / this.maxSize) * 100 || 0) + '%'})}>
|
449
|
+
</div>` : nothing}
|
450
|
+
</div>`, cell);
|
451
|
+
// clang-format on
|
481
452
|
}
|
482
453
|
}
|
483
454
|
return cell;
|
@@ -494,27 +465,4 @@ export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode<Gri
|
|
494
465
|
const range = new TextUtils.TextRange.SourceRange(matches.index, matches[0].length);
|
495
466
|
UI.UIUtils.highlightRangesWithStyleClass(element, [range], 'filter-highlight');
|
496
467
|
}
|
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
468
|
}
|
@@ -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(
|
264
|
+
this.listView = new CoverageListView();
|
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,29 @@ export class CoverageView extends UI.Widget.VBox {
|
|
435
442
|
}
|
436
443
|
|
437
444
|
private updateListView(): void {
|
438
|
-
|
445
|
+
const entries =
|
446
|
+
(this.model?.entries() || [])
|
447
|
+
.map(entry => this.toCoverageListItem(entry))
|
448
|
+
.filter(info => this.isVisible(info))
|
449
|
+
.map(
|
450
|
+
(entry: CoverageListItem) =>
|
451
|
+
({...entry, sources: entry.sources.filter((entry: CoverageListItem) => this.isVisible(entry))}));
|
452
|
+
this.listView.update(entries, this.textFilterRegExp);
|
453
|
+
}
|
454
|
+
|
455
|
+
private toCoverageListItem(info: URLCoverageInfo): CoverageListItem {
|
456
|
+
return {
|
457
|
+
url: info.url(),
|
458
|
+
type: info.type(),
|
459
|
+
size: info.size(),
|
460
|
+
usedSize: info.usedSize(),
|
461
|
+
unusedSize: info.unusedSize(),
|
462
|
+
usedPercentage: info.usedPercentage(),
|
463
|
+
unusedPercentage: info.unusedPercentage(),
|
464
|
+
sources: [...info.sourcesURLCoverageInfo.values()].map(this.toCoverageListItem, this),
|
465
|
+
isContentScript: info.isContentScript(),
|
466
|
+
generatedUrl: info instanceof SourceURLCoverageInfo ? info.generatedURLCoverageInfo.url() : undefined,
|
467
|
+
};
|
439
468
|
}
|
440
469
|
|
441
470
|
async stopRecording(): Promise<void> {
|
@@ -514,7 +543,7 @@ export class CoverageView extends UI.Widget.VBox {
|
|
514
543
|
|
515
544
|
private updateViews(updatedEntries: CoverageInfo[]): void {
|
516
545
|
this.updateStats();
|
517
|
-
this.
|
546
|
+
this.updateListView();
|
518
547
|
this.exportAction.setEnabled(this.model !== null && this.model.entries().length > 0);
|
519
548
|
this.decorationManager?.update(updatedEntries);
|
520
549
|
}
|
@@ -527,14 +556,15 @@ export class CoverageView extends UI.Widget.VBox {
|
|
527
556
|
for (const info of this.model.entries()) {
|
528
557
|
all.total += info.size();
|
529
558
|
all.unused += info.unusedSize();
|
530
|
-
|
559
|
+
const listItem = this.toCoverageListItem(info);
|
560
|
+
if (this.isVisible(listItem)) {
|
531
561
|
if (this.textFilterRegExp?.test(info.url())) {
|
532
562
|
filtered.total += info.size();
|
533
563
|
filtered.unused += info.unusedSize();
|
534
564
|
} else {
|
535
565
|
// If it doesn't match the filter, calculate the stats from visible children if there are any
|
536
566
|
for (const childInfo of info.sourcesURLCoverageInfo.values()) {
|
537
|
-
if (this.isVisible(
|
567
|
+
if (this.isVisible(this.toCoverageListItem(childInfo))) {
|
538
568
|
filtered.total += childInfo.size();
|
539
569
|
filtered.unused += childInfo.unusedSize();
|
540
570
|
}
|
@@ -565,7 +595,7 @@ export class CoverageView extends UI.Widget.VBox {
|
|
565
595
|
}
|
566
596
|
const text = this.filterInput.value();
|
567
597
|
this.textFilterRegExp = text ? Platform.StringUtilities.createPlainTextSearchRegex(text, 'i') : null;
|
568
|
-
this.
|
598
|
+
this.updateListView();
|
569
599
|
this.updateStats();
|
570
600
|
}
|
571
601
|
|
@@ -579,31 +609,31 @@ export class CoverageView extends UI.Widget.VBox {
|
|
579
609
|
const option = this.filterByTypeComboBox.selectedOption();
|
580
610
|
const type = option?.value;
|
581
611
|
this.typeFilterValue = parseInt(type || '', 10) || null;
|
582
|
-
this.
|
612
|
+
this.updateListView();
|
583
613
|
this.updateStats();
|
584
614
|
}
|
585
615
|
|
586
|
-
private isVisible(
|
587
|
-
const url = coverageInfo.url
|
616
|
+
private isVisible(coverageInfo: CoverageListItem): boolean {
|
617
|
+
const url = coverageInfo.url;
|
588
618
|
if (url.startsWith(CoverageView.EXTENSION_BINDINGS_URL_PREFIX)) {
|
589
619
|
return false;
|
590
620
|
}
|
591
|
-
if (coverageInfo.isContentScript
|
621
|
+
if (coverageInfo.isContentScript && !this.showContentScriptsSetting.get()) {
|
592
622
|
return false;
|
593
623
|
}
|
594
|
-
if (this.typeFilterValue && !(coverageInfo.type
|
624
|
+
if (this.typeFilterValue && !(coverageInfo.type & this.typeFilterValue)) {
|
595
625
|
return false;
|
596
626
|
}
|
597
627
|
// If it's a parent, check if any children are visible
|
598
|
-
if (coverageInfo.
|
599
|
-
for (const sourceURLCoverageInfo of coverageInfo.
|
600
|
-
if (this.isVisible(
|
628
|
+
if (coverageInfo.sources.length > 0) {
|
629
|
+
for (const sourceURLCoverageInfo of coverageInfo.sources) {
|
630
|
+
if (this.isVisible(sourceURLCoverageInfo)) {
|
601
631
|
return true;
|
602
632
|
}
|
603
633
|
}
|
604
634
|
}
|
605
635
|
|
606
|
-
return
|
636
|
+
return !this.textFilterRegExp || this.textFilterRegExp.test(url);
|
607
637
|
}
|
608
638
|
|
609
639
|
async exportReport(): Promise<void> {
|
@@ -618,7 +648,7 @@ export class CoverageView extends UI.Widget.VBox {
|
|
618
648
|
}
|
619
649
|
|
620
650
|
selectCoverageItemByUrl(url: string): void {
|
621
|
-
this.listView.selectByUrl(url);
|
651
|
+
this.listView.selectByUrl(url as Platform.DevToolsPath.UrlString);
|
622
652
|
}
|
623
653
|
|
624
654
|
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 = [
|