chrome-devtools-frontend 1.0.971727 → 1.0.973342
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/gni/devtools_grd_files.gni +2 -1
- package/front_end/core/i18n/locales/en-US.json +24 -0
- package/front_end/core/i18n/locales/en-XL.json +24 -0
- package/front_end/core/sdk/NetworkManager.ts +15 -7
- package/front_end/core/sdk/NetworkRequest.ts +16 -14
- package/front_end/core/sdk/ResourceTreeModel.ts +8 -10
- package/front_end/core/sdk/SourceMap.ts +9 -9
- package/front_end/entrypoints/lighthouse_worker/{LighthouseService.ts → LighthouseWorkerService.ts} +69 -38
- package/front_end/entrypoints/lighthouse_worker/lighthouse_worker.ts +1 -1
- package/front_end/models/bindings/CSSWorkspaceBinding.ts +2 -16
- package/front_end/models/bindings/SASSSourceMapping.ts +4 -3
- package/front_end/models/har/HARFormat.ts +4 -2
- package/front_end/models/har/Importer.ts +0 -1
- package/front_end/models/persistence/FileSystemWorkspaceBinding.ts +4 -4
- package/front_end/models/persistence/IsolatedFileSystem.ts +0 -1
- package/front_end/models/text_utils/StaticContentProvider.ts +5 -4
- package/front_end/models/workspace_diff/WorkspaceDiff.ts +20 -8
- package/front_end/panels/application/ServiceWorkerCacheViews.ts +2 -1
- package/front_end/panels/changes/ChangesView.ts +4 -4
- package/front_end/panels/elements/StylesSidebarPane.ts +27 -15
- package/front_end/panels/elements/components/LayoutPane.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +13 -2
- package/front_end/panels/lighthouse/LighthousePanel.ts +57 -8
- package/front_end/panels/lighthouse/LighthouseProtocolService.ts +94 -30
- package/front_end/panels/lighthouse/LighthouseStartView.ts +6 -2
- package/front_end/panels/lighthouse/LighthouseStartViewFR.ts +61 -0
- package/front_end/panels/lighthouse/LighthouseTimespanView.ts +99 -0
- package/front_end/panels/sources/NavigatorView.ts +4 -4
- package/front_end/third_party/codemirror.next/bundle.ts +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/json.js +2 -1
- package/front_end/third_party/codemirror.next/codemirror.next.d.ts +28 -2
- package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
- package/front_end/third_party/codemirror.next/package.json +10 -10
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1047 -1158
- package/front_end/third_party/lighthouse/locales/en-US.json +7 -1
- package/front_end/third_party/lighthouse/locales/en-XL.json +7 -1
- package/front_end/third_party/lighthouse/report/bundle.d.ts +0 -3
- package/front_end/third_party/lighthouse/report/bundle.js +38 -24
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
- package/front_end/ui/components/expandable_list/expandableList.css +1 -1
- package/front_end/ui/components/text_editor/config.ts +1 -0
- package/front_end/ui/legacy/components/source_frame/BinaryResourceViewFactory.ts +7 -4
- package/front_end/ui/legacy/tabbedPane.css +1 -0
- package/package.json +1 -1
- package/scripts/hosted_mode/server.js +13 -0
@@ -2,6 +2,8 @@
|
|
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
|
|
5
|
+
import type * as Platform from '../../core/platform/platform.js';
|
6
|
+
|
5
7
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
6
8
|
|
7
9
|
class HARBase {
|
@@ -197,7 +199,7 @@ export class HAREntry extends HARBase {
|
|
197
199
|
|
198
200
|
class HARRequest extends HARBase {
|
199
201
|
method: string;
|
200
|
-
url:
|
202
|
+
url: Platform.DevToolsPath.UrlString;
|
201
203
|
httpVersion: string;
|
202
204
|
cookies: HARCookie[];
|
203
205
|
headers: HARHeader[];
|
@@ -209,7 +211,7 @@ class HARRequest extends HARBase {
|
|
209
211
|
constructor(data: any) {
|
210
212
|
super(data);
|
211
213
|
this.method = String(data['method']);
|
212
|
-
this.url = String(data['url']);
|
214
|
+
this.url = String(data['url']) as Platform.DevToolsPath.UrlString;
|
213
215
|
this.httpVersion = String(data['httpVersion']);
|
214
216
|
this.cookies = Array.isArray(data['cookies']) ? data['cookies'].map(cookie => new HARCookie(cookie)) : [];
|
215
217
|
this.headers = Array.isArray(data['headers']) ? data['headers'].map(header => new HARHeader(header)) : [];
|
@@ -38,7 +38,6 @@ export class Importer {
|
|
38
38
|
lineNumber: initiatorEntry.lineNumber,
|
39
39
|
};
|
40
40
|
}
|
41
|
-
|
42
41
|
const request = SDK.NetworkRequest.NetworkRequest.createWithoutBackendRequest(
|
43
42
|
'har-' + requests.length, entry.request.url, documentURL, initiator);
|
44
43
|
const page = pageref ? pages.get(pageref) : undefined;
|
@@ -79,9 +79,9 @@ export class FileSystemWorkspaceBinding {
|
|
79
79
|
return fileSystem.supportsAutomapping();
|
80
80
|
}
|
81
81
|
|
82
|
-
static completeURL(project: Workspace.Workspace.Project, relativePath: string):
|
82
|
+
static completeURL(project: Workspace.Workspace.Project, relativePath: string): Platform.DevToolsPath.UrlString {
|
83
83
|
const fsProject = project as FileSystem;
|
84
|
-
return fsProject.fileSystemBaseURL
|
84
|
+
return Common.ParsedURL.ParsedURL.concatenate(fsProject.fileSystemBaseURL, relativePath);
|
85
85
|
}
|
86
86
|
|
87
87
|
static fileSystemPath(projectId: string): string {
|
@@ -155,7 +155,7 @@ export class FileSystemWorkspaceBinding {
|
|
155
155
|
|
156
156
|
export class FileSystem extends Workspace.Workspace.ProjectStore {
|
157
157
|
readonly fileSystemInternal: PlatformFileSystem;
|
158
|
-
readonly fileSystemBaseURL:
|
158
|
+
readonly fileSystemBaseURL: Platform.DevToolsPath.UrlString;
|
159
159
|
private readonly fileSystemParentURL: string;
|
160
160
|
private readonly fileSystemWorkspaceBinding: FileSystemWorkspaceBinding;
|
161
161
|
private readonly fileSystemPathInternal: string;
|
@@ -171,7 +171,7 @@ export class FileSystem extends Workspace.Workspace.ProjectStore {
|
|
171
171
|
super(workspace, id, Workspace.Workspace.projectTypes.FileSystem, displayName);
|
172
172
|
|
173
173
|
this.fileSystemInternal = isolatedFileSystem;
|
174
|
-
this.fileSystemBaseURL = this.fileSystemInternal.path()
|
174
|
+
this.fileSystemBaseURL = Common.ParsedURL.ParsedURL.concatenate(this.fileSystemInternal.path(), '/');
|
175
175
|
this.fileSystemParentURL = this.fileSystemBaseURL.substr(0, fileSystemPath.lastIndexOf('/') + 1);
|
176
176
|
this.fileSystemWorkspaceBinding = fileSystemWorkspaceBinding;
|
177
177
|
this.fileSystemPathInternal = fileSystemPath;
|
@@ -81,7 +81,6 @@ export class IsolatedFileSystem extends PlatformFileSystem {
|
|
81
81
|
|
82
82
|
constructor(
|
83
83
|
manager: IsolatedFileSystemManager, path: string, embedderPath: string, domFileSystem: FileSystem, type: string) {
|
84
|
-
// TODO(crbug.com/1253323): Cast to UrlString will be removed when migration to branded types is complete.
|
85
84
|
super(path, type);
|
86
85
|
this.manager = manager;
|
87
86
|
this.embedderPathInternal = embedderPath;
|
@@ -14,9 +14,9 @@ export class StaticContentProvider implements ContentProvider {
|
|
14
14
|
private readonly lazyContent: () => Promise<DeferredContent>;
|
15
15
|
|
16
16
|
constructor(
|
17
|
-
contentURL:
|
18
|
-
|
19
|
-
this.contentURLInternal = contentURL
|
17
|
+
contentURL: Platform.DevToolsPath.UrlString, contentType: Common.ResourceType.ResourceType,
|
18
|
+
lazyContent: () => Promise<DeferredContent>) {
|
19
|
+
this.contentURLInternal = contentURL;
|
20
20
|
this.contentTypeInternal = contentType;
|
21
21
|
this.lazyContent = lazyContent;
|
22
22
|
}
|
@@ -27,7 +27,8 @@ export class StaticContentProvider implements ContentProvider {
|
|
27
27
|
content: string,
|
28
28
|
isEncoded: boolean,
|
29
29
|
}> => Promise.resolve({content, isEncoded: false});
|
30
|
-
|
30
|
+
// TODO(crbug.com/1253323): Cast to UrlString will be removed when migration to branded types is complete.
|
31
|
+
return new StaticContentProvider(contentURL as Platform.DevToolsPath.UrlString, contentType, lazyContent);
|
31
32
|
}
|
32
33
|
|
33
34
|
contentURL(): Platform.DevToolsPath.UrlString {
|
@@ -13,6 +13,11 @@ interface DiffRequestOptions {
|
|
13
13
|
shouldFormatDiff: boolean;
|
14
14
|
}
|
15
15
|
|
16
|
+
interface DiffResponse {
|
17
|
+
diff: Diff.Diff.DiffArray;
|
18
|
+
formattedCurrentMapping?: FormatterModule.ScriptFormatter.FormatterSourceMapping;
|
19
|
+
}
|
20
|
+
|
16
21
|
export class WorkspaceDiffImpl extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
17
22
|
private readonly uiSourceCodeDiffs: WeakMap<Workspace.UISourceCode.UISourceCode, UISourceCodeDiff>;
|
18
23
|
private readonly loadingUISourceCodes:
|
@@ -35,7 +40,7 @@ export class WorkspaceDiffImpl extends Common.ObjectWrapper.ObjectWrapper<EventT
|
|
35
40
|
}
|
36
41
|
|
37
42
|
requestDiff(uiSourceCode: Workspace.UISourceCode.UISourceCode, diffRequestOptions: DiffRequestOptions):
|
38
|
-
Promise<
|
43
|
+
Promise<DiffResponse|null> {
|
39
44
|
return this.uiSourceCodeDiff(uiSourceCode).requestDiff(diffRequestOptions);
|
40
45
|
}
|
41
46
|
|
@@ -185,7 +190,7 @@ export type EventTypes = {
|
|
185
190
|
|
186
191
|
export class UISourceCodeDiff extends Common.ObjectWrapper.ObjectWrapper<UISourceCodeDiffEventTypes> {
|
187
192
|
private uiSourceCode: Workspace.UISourceCode.UISourceCode;
|
188
|
-
private requestDiffPromise: Promise<
|
193
|
+
private requestDiffPromise: Promise<DiffResponse|null>|null;
|
189
194
|
private pendingChanges: number|null;
|
190
195
|
dispose: boolean;
|
191
196
|
constructor(uiSourceCode: Workspace.UISourceCode.UISourceCode) {
|
@@ -218,7 +223,7 @@ export class UISourceCodeDiff extends Common.ObjectWrapper.ObjectWrapper<UISourc
|
|
218
223
|
}
|
219
224
|
}
|
220
225
|
|
221
|
-
requestDiff(diffRequestOptions: DiffRequestOptions): Promise<
|
226
|
+
requestDiff(diffRequestOptions: DiffRequestOptions): Promise<DiffResponse|null> {
|
222
227
|
if (!this.requestDiffPromise) {
|
223
228
|
this.requestDiffPromise = this.innerRequestDiff(diffRequestOptions);
|
224
229
|
}
|
@@ -237,7 +242,7 @@ export class UISourceCodeDiff extends Common.ObjectWrapper.ObjectWrapper<UISourc
|
|
237
242
|
return content.content || ('error' in content && content.error) || '';
|
238
243
|
}
|
239
244
|
|
240
|
-
private async innerRequestDiff({shouldFormatDiff}: DiffRequestOptions): Promise<
|
245
|
+
private async innerRequestDiff({shouldFormatDiff}: DiffRequestOptions): Promise<DiffResponse|null> {
|
241
246
|
if (this.dispose) {
|
242
247
|
return null;
|
243
248
|
}
|
@@ -270,15 +275,22 @@ export class UISourceCodeDiff extends Common.ObjectWrapper.ObjectWrapper<UISourc
|
|
270
275
|
if (current === null || baseline === null) {
|
271
276
|
return null;
|
272
277
|
}
|
278
|
+
let formattedCurrentMapping;
|
273
279
|
if (shouldFormatDiff) {
|
274
280
|
baseline = (await FormatterModule.ScriptFormatter.format(
|
275
281
|
this.uiSourceCode.contentType(), this.uiSourceCode.mimeType(), baseline))
|
276
282
|
.formattedContent;
|
277
|
-
|
278
|
-
|
279
|
-
|
283
|
+
const formatCurrentResult = await FormatterModule.ScriptFormatter.format(
|
284
|
+
this.uiSourceCode.contentType(), this.uiSourceCode.mimeType(), current);
|
285
|
+
current = formatCurrentResult.formattedContent;
|
286
|
+
formattedCurrentMapping = formatCurrentResult.formattedMapping;
|
280
287
|
}
|
281
|
-
|
288
|
+
const reNewline = /\r\n?|\n/;
|
289
|
+
const diff = Diff.Diff.DiffWrapper.lineDiff(baseline.split(reNewline), current.split(reNewline));
|
290
|
+
return {
|
291
|
+
diff,
|
292
|
+
formattedCurrentMapping,
|
293
|
+
};
|
282
294
|
}
|
283
295
|
}
|
284
296
|
|
@@ -381,7 +381,8 @@ export class ServiceWorkerCacheView extends UI.View.SimpleView {
|
|
381
381
|
|
382
382
|
private createRequest(entry: Protocol.CacheStorage.DataEntry): SDK.NetworkRequest.NetworkRequest {
|
383
383
|
const request = SDK.NetworkRequest.NetworkRequest.createWithoutBackendRequest(
|
384
|
-
'cache-storage-' + entry.requestURL, entry.requestURL
|
384
|
+
'cache-storage-' + entry.requestURL, entry.requestURL as Platform.DevToolsPath.UrlString,
|
385
|
+
'' as Platform.DevToolsPath.UrlString, null);
|
385
386
|
request.requestMethod = entry.requestMethod;
|
386
387
|
request.setRequestHeaders(entry.requestHeaders);
|
387
388
|
request.statusCode = entry.responseStatus;
|
@@ -173,7 +173,7 @@ export class ChangesView extends UI.Widget.VBox {
|
|
173
173
|
}
|
174
174
|
|
175
175
|
if (!this.selectedUISourceCode) {
|
176
|
-
this.renderDiffRows(
|
176
|
+
this.renderDiffRows();
|
177
177
|
return;
|
178
178
|
}
|
179
179
|
const uiSourceCode = this.selectedUISourceCode;
|
@@ -181,12 +181,12 @@ export class ChangesView extends UI.Widget.VBox {
|
|
181
181
|
this.hideDiff(i18nString(UIStrings.binaryData));
|
182
182
|
return;
|
183
183
|
}
|
184
|
-
const
|
184
|
+
const diffResponse = await this.workspaceDiff.requestDiff(
|
185
185
|
uiSourceCode, {shouldFormatDiff: Root.Runtime.experiments.isEnabled('preciseChanges')});
|
186
186
|
if (this.selectedUISourceCode !== uiSourceCode) {
|
187
187
|
return;
|
188
188
|
}
|
189
|
-
this.renderDiffRows(diff);
|
189
|
+
this.renderDiffRows(diffResponse?.diff);
|
190
190
|
}
|
191
191
|
|
192
192
|
private hideDiff(message: string): void {
|
@@ -197,7 +197,7 @@ export class ChangesView extends UI.Widget.VBox {
|
|
197
197
|
this.emptyWidget.showWidget();
|
198
198
|
}
|
199
199
|
|
200
|
-
private renderDiffRows(diff
|
200
|
+
private renderDiffRows(diff?: Diff.Diff.DiffArray): void {
|
201
201
|
if (!diff || (diff.length === 1 && diff[0][0] === Diff.Diff.Operation.Equal)) {
|
202
202
|
this.hideDiff(i18nString(UIStrings.noChanges));
|
203
203
|
} else {
|
@@ -1043,16 +1043,22 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
1043
1043
|
if (!url) {
|
1044
1044
|
return false;
|
1045
1045
|
}
|
1046
|
-
const
|
1047
|
-
if (!
|
1046
|
+
const changeTracker = this.#urlToChangeTracker.get(url);
|
1047
|
+
if (!changeTracker) {
|
1048
1048
|
return false;
|
1049
1049
|
}
|
1050
|
+
const {changedLines, formattedCurrentMapping} = changeTracker;
|
1050
1051
|
const uiLocation = Bindings.CSSWorkspaceBinding.CSSWorkspaceBinding.instance().propertyUILocation(property, true);
|
1051
1052
|
if (!uiLocation) {
|
1052
1053
|
return false;
|
1053
1054
|
}
|
1054
|
-
|
1055
|
-
|
1055
|
+
if (!formattedCurrentMapping) {
|
1056
|
+
// UILocation's lineNumber starts at 0, but changedLines start at 1.
|
1057
|
+
return changedLines.has(uiLocation.lineNumber + 1);
|
1058
|
+
}
|
1059
|
+
const formattedLineNumber =
|
1060
|
+
formattedCurrentMapping.originalToFormatted(uiLocation.lineNumber, uiLocation.columnNumber)[0];
|
1061
|
+
return changedLines.has(formattedLineNumber + 1);
|
1056
1062
|
}
|
1057
1063
|
|
1058
1064
|
private async refreshChangedLines(uiSourceCode: Workspace.UISourceCode.UISourceCode): Promise<void> {
|
@@ -1060,28 +1066,33 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
1060
1066
|
if (!changeTracker) {
|
1061
1067
|
return;
|
1062
1068
|
}
|
1063
|
-
const
|
1069
|
+
const diffResponse =
|
1070
|
+
await WorkspaceDiff.WorkspaceDiff.workspaceDiff().requestDiff(uiSourceCode, {shouldFormatDiff: true});
|
1064
1071
|
const changedLines = new Set<number>();
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1072
|
+
changeTracker.changedLines = changedLines;
|
1073
|
+
if (!diffResponse) {
|
1074
|
+
return;
|
1075
|
+
}
|
1076
|
+
const {diff, formattedCurrentMapping} = diffResponse;
|
1077
|
+
const {rows} = DiffView.DiffView.buildDiffRows(diff);
|
1078
|
+
for (const row of rows) {
|
1079
|
+
if (row.type === DiffView.DiffView.RowType.Addition) {
|
1080
|
+
changedLines.add(row.currentLineNumber);
|
1071
1081
|
}
|
1072
1082
|
}
|
1073
|
-
changeTracker.
|
1083
|
+
changeTracker.formattedCurrentMapping = formattedCurrentMapping;
|
1074
1084
|
}
|
1075
1085
|
|
1076
1086
|
private async getFormattedChanges(): Promise<string> {
|
1077
1087
|
let allChanges = '';
|
1078
1088
|
for (const [url, {uiSourceCode}] of this.#urlToChangeTracker) {
|
1079
|
-
const
|
1089
|
+
const diffResponse =
|
1080
1090
|
await WorkspaceDiff.WorkspaceDiff.workspaceDiff().requestDiff(uiSourceCode, {shouldFormatDiff: true});
|
1081
|
-
|
1091
|
+
// Diff array with real diff will contain at least 2 lines.
|
1092
|
+
if (!diffResponse || diffResponse?.diff.length < 2) {
|
1082
1093
|
continue;
|
1083
1094
|
}
|
1084
|
-
const changes = await formatCSSChangesFromDiff(diff);
|
1095
|
+
const changes = await formatCSSChangesFromDiff(diffResponse.diff);
|
1085
1096
|
if (changes.length > 0) {
|
1086
1097
|
allChanges += `/* ${escapeUrlAsCssComment(url)} */\n\n${changes}\n\n`;
|
1087
1098
|
}
|
@@ -1231,6 +1242,7 @@ type ChangeTracker = {
|
|
1231
1242
|
uiSourceCode: Workspace.UISourceCode.UISourceCode,
|
1232
1243
|
changedLines: Set<number>,
|
1233
1244
|
diffChangeCallback: () => Promise<void>,
|
1245
|
+
formattedCurrentMapping?: Formatter.ScriptFormatter.FormatterSourceMapping,
|
1234
1246
|
};
|
1235
1247
|
|
1236
1248
|
export async function formatCSSChangesFromDiff(diff: Diff.Diff.DiffArray): Promise<string> {
|
@@ -270,7 +270,7 @@ export class LayoutPane extends HTMLElement {
|
|
270
270
|
</span>
|
271
271
|
</label>
|
272
272
|
<label @keyup=${onColorLabelKeyUp} @keydown=${onColorLabelKeyDown} tabindex="0" title=${i18nString(UIStrings.chooseElementOverlayColor)} class="color-picker-label" style="background: ${element.color};">
|
273
|
-
<input @change=${onColorChange} @input=${onColorChange} class="color-picker" type="color" value=${element.color} />
|
273
|
+
<input @change=${onColorChange} @input=${onColorChange} tabindex="-1" class="color-picker" type="color" value=${element.color} />
|
274
274
|
</label>
|
275
275
|
<button tabindex="0" @click=${onElementClick} title=${i18nString(UIStrings.showElementInTheElementsPanel)} class="show-element"></button>
|
276
276
|
</div>`;
|
@@ -113,11 +113,15 @@ const UIStrings = {
|
|
113
113
|
*/
|
114
114
|
runLighthouseInMode: 'Run Lighthouse in navigation, timespan, or snapshot mode',
|
115
115
|
/**
|
116
|
-
* @description
|
116
|
+
* @description Label of a radio option for a Lighthouse mode that audits a page navigation.
|
117
117
|
*/
|
118
118
|
navigation: 'Navigation',
|
119
119
|
/**
|
120
|
-
* @description
|
120
|
+
* @description Label of a radio option for a Lighthouse mode that audits user interactions over a period of time.
|
121
|
+
*/
|
122
|
+
timespan: 'Timespan',
|
123
|
+
/**
|
124
|
+
* @description Label of a radio option for a Lighthouse mode that audits the current page state.
|
121
125
|
*/
|
122
126
|
snapshot: 'Snapshot',
|
123
127
|
/**
|
@@ -305,6 +309,7 @@ export class LighthouseController extends Common.ObjectWrapper.ObjectWrapper<Eve
|
|
305
309
|
internalDisableDeviceScreenEmulation: boolean,
|
306
310
|
emulatedFormFactor: (string|undefined),
|
307
311
|
legacyNavigation: boolean,
|
312
|
+
mode: string,
|
308
313
|
} {
|
309
314
|
const flags = {
|
310
315
|
// DevTools handles all the emulation. This tells Lighthouse to not bother with emulation.
|
@@ -317,6 +322,7 @@ export class LighthouseController extends Common.ObjectWrapper.ObjectWrapper<Eve
|
|
317
322
|
internalDisableDeviceScreenEmulation: boolean,
|
318
323
|
emulatedFormFactor: (string | undefined),
|
319
324
|
legacyNavigation: boolean,
|
325
|
+
mode: string,
|
320
326
|
};
|
321
327
|
}
|
322
328
|
|
@@ -447,6 +453,7 @@ export const RuntimeSettings: RuntimeSetting[] = [
|
|
447
453
|
},
|
448
454
|
options: [
|
449
455
|
{label: i18nLazyString(UIStrings.navigation), value: 'navigation'},
|
456
|
+
{label: i18nLazyString(UIStrings.timespan), value: 'timespan'},
|
450
457
|
{label: i18nLazyString(UIStrings.snapshot), value: 'snapshot'},
|
451
458
|
],
|
452
459
|
learnMore: undefined,
|
@@ -495,6 +502,8 @@ export enum Events {
|
|
495
502
|
PageAuditabilityChanged = 'PageAuditabilityChanged',
|
496
503
|
PageWarningsChanged = 'PageWarningsChanged',
|
497
504
|
AuditProgressChanged = 'AuditProgressChanged',
|
505
|
+
RequestLighthouseTimespanStart = 'RequestLighthouseTimespanStart',
|
506
|
+
RequestLighthouseTimespanEnd = 'RequestLighthouseTimespanEnd',
|
498
507
|
RequestLighthouseStart = 'RequestLighthouseStart',
|
499
508
|
RequestLighthouseCancel = 'RequestLighthouseCancel',
|
500
509
|
}
|
@@ -515,6 +524,8 @@ export type EventTypes = {
|
|
515
524
|
[Events.PageAuditabilityChanged]: PageAuditabilityChangedEvent,
|
516
525
|
[Events.PageWarningsChanged]: PageWarningsChangedEvent,
|
517
526
|
[Events.AuditProgressChanged]: AuditProgressChangedEvent,
|
527
|
+
[Events.RequestLighthouseTimespanStart]: boolean,
|
528
|
+
[Events.RequestLighthouseTimespanEnd]: boolean,
|
518
529
|
[Events.RequestLighthouseStart]: boolean,
|
519
530
|
[Events.RequestLighthouseCancel]: void,
|
520
531
|
};
|
@@ -14,6 +14,7 @@ import * as Emulation from '../emulation/emulation.js';
|
|
14
14
|
import type {AuditProgressChangedEvent, PageAuditabilityChangedEvent, PageWarningsChangedEvent} from './LighthouseController.js';
|
15
15
|
import {Events, LighthouseController} from './LighthouseController.js';
|
16
16
|
import lighthousePanelStyles from './lighthousePanel.css.js';
|
17
|
+
import type {LighthouseRun} from './LighthouseProtocolService.js';
|
17
18
|
import {ProtocolService} from './LighthouseProtocolService.js';
|
18
19
|
|
19
20
|
import type {ReportJSON, RunnerResultArtifacts} from './LighthouseReporterTypes.js';
|
@@ -23,6 +24,7 @@ import {Item, ReportSelector} from './LighthouseReportSelector.js';
|
|
23
24
|
import {StartView} from './LighthouseStartView.js';
|
24
25
|
import {StartViewFR} from './LighthouseStartViewFR.js';
|
25
26
|
import {StatusView} from './LighthouseStatusView.js';
|
27
|
+
import {TimespanView} from './LighthouseTimespanView.js';
|
26
28
|
|
27
29
|
const UIStrings = {
|
28
30
|
/**
|
@@ -65,6 +67,7 @@ export class LighthousePanel extends UI.Panel.Panel {
|
|
65
67
|
private readonly controller: LighthouseController;
|
66
68
|
private readonly startView: StartView;
|
67
69
|
private readonly statusView: StatusView;
|
70
|
+
private readonly timespanView: TimespanView|null;
|
68
71
|
private warningText: Nullable<string>;
|
69
72
|
private unauditableExplanation: Nullable<string>;
|
70
73
|
private readonly cachedRenderedReports: Map<ReportJSON, HTMLElement>;
|
@@ -81,6 +84,7 @@ export class LighthousePanel extends UI.Panel.Panel {
|
|
81
84
|
network: {conditions: SDK.NetworkManager.Conditions},
|
82
85
|
};
|
83
86
|
private isLHAttached?: boolean;
|
87
|
+
private currentLighthouseRun?: LighthouseRun;
|
84
88
|
|
85
89
|
private constructor() {
|
86
90
|
super('lighthouse');
|
@@ -89,8 +93,10 @@ export class LighthousePanel extends UI.Panel.Panel {
|
|
89
93
|
this.controller = new LighthouseController(this.protocolService);
|
90
94
|
if (Root.Runtime.experiments.isEnabled('lighthousePanelFR')) {
|
91
95
|
this.startView = new StartViewFR(this.controller);
|
96
|
+
this.timespanView = new TimespanView(this.controller);
|
92
97
|
} else {
|
93
98
|
this.startView = new StartView(this.controller);
|
99
|
+
this.timespanView = null;
|
94
100
|
}
|
95
101
|
this.statusView = new StatusView(this.controller);
|
96
102
|
|
@@ -105,12 +111,10 @@ export class LighthousePanel extends UI.Panel.Panel {
|
|
105
111
|
this.controller.addEventListener(Events.PageAuditabilityChanged, this.refreshStartAuditUI.bind(this));
|
106
112
|
this.controller.addEventListener(Events.PageWarningsChanged, this.refreshWarningsUI.bind(this));
|
107
113
|
this.controller.addEventListener(Events.AuditProgressChanged, this.refreshStatusUI.bind(this));
|
108
|
-
this.controller.addEventListener(Events.
|
109
|
-
|
110
|
-
|
111
|
-
this.controller.addEventListener(Events.RequestLighthouseCancel,
|
112
|
-
void this.cancelLighthouse();
|
113
|
-
});
|
114
|
+
this.controller.addEventListener(Events.RequestLighthouseTimespanStart, this.onLighthouseTimespanStart.bind(this));
|
115
|
+
this.controller.addEventListener(Events.RequestLighthouseTimespanEnd, this.onLighthouseTimespanEnd.bind(this));
|
116
|
+
this.controller.addEventListener(Events.RequestLighthouseStart, this.onLighthouseStart.bind(this));
|
117
|
+
this.controller.addEventListener(Events.RequestLighthouseCancel, this.onLighthouseCancel.bind(this));
|
114
118
|
|
115
119
|
this.renderToolbar();
|
116
120
|
this.auditResultsElement = this.contentElement.createChild('div', 'lighthouse-results-container');
|
@@ -132,6 +136,27 @@ export class LighthousePanel extends UI.Panel.Panel {
|
|
132
136
|
return Events;
|
133
137
|
}
|
134
138
|
|
139
|
+
private async onLighthouseTimespanStart(): Promise<void> {
|
140
|
+
this.timespanView?.show(this.contentElement);
|
141
|
+
await this.startLighthouse();
|
142
|
+
this.timespanView?.ready();
|
143
|
+
}
|
144
|
+
|
145
|
+
private async onLighthouseTimespanEnd(): Promise<void> {
|
146
|
+
this.timespanView?.hide();
|
147
|
+
await this.collectLighthouseResults();
|
148
|
+
}
|
149
|
+
|
150
|
+
private async onLighthouseStart(): Promise<void> {
|
151
|
+
await this.startLighthouse();
|
152
|
+
await this.collectLighthouseResults();
|
153
|
+
}
|
154
|
+
|
155
|
+
private async onLighthouseCancel(): Promise<void> {
|
156
|
+
this.timespanView?.hide();
|
157
|
+
void this.cancelLighthouse();
|
158
|
+
}
|
159
|
+
|
135
160
|
private refreshWarningsUI(evt: Common.EventTarget.EventTargetEvent<PageWarningsChangedEvent>): void {
|
136
161
|
// PageWarningsChanged fires multiple times during an audit, which we want to ignore.
|
137
162
|
if (this.isLHAttached) {
|
@@ -148,6 +173,8 @@ export class LighthousePanel extends UI.Panel.Panel {
|
|
148
173
|
return;
|
149
174
|
}
|
150
175
|
|
176
|
+
this.startView.updateStartButton();
|
177
|
+
|
151
178
|
this.unauditableExplanation = evt.data.helpText;
|
152
179
|
this.startView.setUnauditableExplanation(evt.data.helpText);
|
153
180
|
this.startView.setStartButtonEnabled(!evt.data.helpText);
|
@@ -348,11 +375,30 @@ export class LighthousePanel extends UI.Panel.Panel {
|
|
348
375
|
const categoryIDs = this.controller.getCategoryIDs();
|
349
376
|
const flags = this.controller.getFlags();
|
350
377
|
|
378
|
+
this.currentLighthouseRun = {inspectedURL, categoryIDs, flags};
|
379
|
+
|
351
380
|
await this.setupEmulationAndProtocolConnection();
|
352
381
|
|
353
|
-
|
382
|
+
if (flags.mode === 'timespan') {
|
383
|
+
await this.protocolService.startTimespan(this.currentLighthouseRun);
|
384
|
+
}
|
385
|
+
|
386
|
+
} catch (err) {
|
387
|
+
await this.resetEmulationAndProtocolConnection();
|
388
|
+
if (err instanceof Error) {
|
389
|
+
this.statusView.renderBugReport(err);
|
390
|
+
}
|
391
|
+
}
|
392
|
+
}
|
393
|
+
|
394
|
+
private async collectLighthouseResults(): Promise<void> {
|
395
|
+
try {
|
396
|
+
if (!this.currentLighthouseRun) {
|
397
|
+
throw new Error('Lighthouse is not started');
|
398
|
+
}
|
399
|
+
this.renderStatusView(this.currentLighthouseRun.inspectedURL);
|
354
400
|
|
355
|
-
const lighthouseResponse = await this.protocolService.
|
401
|
+
const lighthouseResponse = await this.protocolService.collectLighthouseResults(this.currentLighthouseRun);
|
356
402
|
|
357
403
|
if (lighthouseResponse && lighthouseResponse.fatal) {
|
358
404
|
const error = new Error(lighthouseResponse.message);
|
@@ -375,10 +421,13 @@ export class LighthousePanel extends UI.Panel.Panel {
|
|
375
421
|
if (err instanceof Error) {
|
376
422
|
this.statusView.renderBugReport(err);
|
377
423
|
}
|
424
|
+
} finally {
|
425
|
+
this.currentLighthouseRun = undefined;
|
378
426
|
}
|
379
427
|
}
|
380
428
|
|
381
429
|
private async cancelLighthouse(): Promise<void> {
|
430
|
+
this.currentLighthouseRun = undefined;
|
382
431
|
this.statusView.updateStatus(i18nString(UIStrings.cancelling));
|
383
432
|
await this.resetEmulationAndProtocolConnection();
|
384
433
|
this.renderStartView();
|