chrome-devtools-frontend 1.0.1559913 → 1.0.1561080
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/front_end/core/host/InspectorFrontendHostStub.ts +0 -3
- package/front_end/core/platform/ArrayUtilities.ts +13 -0
- package/front_end/core/root/Runtime.ts +0 -5
- package/front_end/core/sdk/DOMModel.ts +8 -0
- package/front_end/core/sdk/NetworkManager.ts +4 -0
- package/front_end/core/sdk/NetworkRequest.ts +9 -0
- package/front_end/core/sdk/OverlayModel.ts +20 -9
- package/front_end/entrypoints/main/MainImpl.ts +2 -1
- package/front_end/generated/InspectorBackendCommands.ts +4 -2
- package/front_end/generated/protocol-mapping.d.ts +7 -0
- package/front_end/generated/protocol-proxy-api.d.ts +5 -0
- package/front_end/generated/protocol.ts +24 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +23 -22
- package/front_end/models/badges/UserBadges.ts +48 -16
- package/front_end/models/greendev/Prototypes.ts +6 -1
- package/front_end/models/trace/extras/TraceTree.ts +1 -1
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +8 -3
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -142
- package/front_end/panels/ai_assistance/PatchWidget.ts +90 -72
- package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +701 -0
- package/front_end/panels/ai_assistance/components/ChatView.ts +71 -1268
- package/front_end/panels/ai_assistance/components/UserActionRow.ts +514 -31
- package/front_end/panels/ai_assistance/components/chatInput.css +387 -0
- package/front_end/panels/ai_assistance/components/chatView.css +38 -599
- package/front_end/panels/ai_assistance/components/userActionRow.css +230 -0
- package/front_end/panels/autofill/AutofillView.ts +2 -2
- package/front_end/panels/changes/ChangesView.ts +15 -1
- package/front_end/panels/changes/changesView.css +6 -0
- package/front_end/panels/common/BadgeNotification.ts +44 -58
- package/front_end/panels/common/CopyChangesToPrompt.ts +233 -0
- package/front_end/panels/common/common.ts +1 -0
- package/front_end/panels/elements/ElementsTreeElement.ts +183 -359
- package/front_end/panels/elements/ElementsTreeOutline.ts +0 -6
- package/front_end/panels/elements/ShortcutTreeElement.ts +57 -50
- package/front_end/panels/elements/StylePropertiesSection.ts +1 -3
- package/front_end/panels/elements/components/AdornerManager.ts +5 -149
- package/front_end/panels/issues/HiddenIssuesRow.ts +1 -2
- package/front_end/panels/issues/IssueKindView.ts +2 -4
- package/front_end/panels/issues/IssueView.ts +2 -4
- package/front_end/panels/network/NetworkDataGridNode.ts +65 -1
- package/front_end/panels/network/NetworkLogView.ts +2 -4
- package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
- package/front_end/panels/screencast/ScreencastApp.ts +1 -0
- package/front_end/panels/settings/SettingsScreen.ts +3 -2
- package/front_end/panels/timeline/CompatibilityTracksAppender.ts +14 -1
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -4
- package/front_end/panels/timeline/TimelineController.ts +185 -3
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +52 -25
- package/front_end/panels/timeline/TimelineFlameChartView.ts +1 -0
- package/front_end/panels/timeline/TimelinePanel.ts +17 -104
- package/front_end/panels/timeline/TimelineTreeView.ts +1 -0
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -2
- package/front_end/panels/timeline/components/insights/Table.ts +3 -3
- package/front_end/panels/whats_new/ReleaseNoteText.ts +15 -9
- package/front_end/panels/whats_new/resources/WNDT.md +6 -6
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/codemirror.next/rebuild.sh +1 -1
- package/front_end/third_party/lit/rebuild.sh +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +2 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js +9 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.js +9 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.js +10 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +8 -4
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js.map +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/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.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/cjs/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +10 -1
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +13 -7
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +2 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js +9 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.js +9 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.js +10 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +8 -4
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/types.d.ts +10 -1
- package/front_end/third_party/puppeteer/package/package.json +3 -3
- package/front_end/third_party/puppeteer/package/src/api/Page.ts +2 -3
- package/front_end/third_party/puppeteer/package/src/bidi/HTTPRequest.ts +13 -0
- package/front_end/third_party/puppeteer/package/src/bidi/HTTPResponse.ts +10 -0
- package/front_end/third_party/puppeteer/package/src/bidi/core/Request.ts +15 -0
- package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +9 -4
- package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/components/adorners/Adorner.ts +8 -68
- package/front_end/ui/legacy/TabbedPane.ts +1 -1
- package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
- package/package.json +2 -1
|
@@ -2,7 +2,9 @@
|
|
|
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 Common from '../../core/common/common.js';
|
|
5
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
7
|
+
import type * as Platform from '../../core/platform/platform.js';
|
|
6
8
|
import * as Root from '../../core/root/root.js';
|
|
7
9
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
8
10
|
import type * as Protocol from '../../generated/protocol.js';
|
|
@@ -15,15 +17,82 @@ import * as Tracing from '../../services/tracing/tracing.js';
|
|
|
15
17
|
import * as RecordingMetadata from './RecordingMetadata.js';
|
|
16
18
|
|
|
17
19
|
const UIStrings = {
|
|
20
|
+
/**
|
|
21
|
+
* @description Text in Timeline Panel of the Performance panel
|
|
22
|
+
*/
|
|
23
|
+
initializingTracing: 'Initializing tracing…',
|
|
18
24
|
/**
|
|
19
25
|
* @description Text in Timeline Controller of the Performance panel indicating that the Performance Panel cannot
|
|
20
26
|
* record a performance trace because the type of target (where possible types are page, service worker and shared
|
|
21
27
|
* worker) doesn't support it.
|
|
22
28
|
*/
|
|
23
29
|
tracingNotSupported: 'Performance trace recording not supported for this type of target',
|
|
30
|
+
/**
|
|
31
|
+
* @description Text in a status dialog shown during a performance trace of a web page. It indicates to the user what the tracing is currently waiting on.
|
|
32
|
+
*/
|
|
33
|
+
waitingForLoadEvent: 'Waiting for load event…',
|
|
34
|
+
/**
|
|
35
|
+
* @description Text in a status dialog shown during a performance trace of a web page. It indicates to the user what the tracing is currently waiting on.
|
|
36
|
+
*/
|
|
37
|
+
waitingForLoadEventPlus5Seconds: 'Waiting for load event (+5s)…',
|
|
24
38
|
} as const;
|
|
25
39
|
const str_ = i18n.i18n.registerUIStrings('panels/timeline/TimelineController.ts', UIStrings);
|
|
26
40
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
41
|
+
|
|
42
|
+
type StatusUpdate = string|null;
|
|
43
|
+
type Listener = (status: StatusUpdate) => void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Accepts promises with a text label, and reports to a listener as promises resolve.
|
|
47
|
+
* Only returns the label of the first incomplete promise. When no more promises
|
|
48
|
+
* remain, the updated status is null.
|
|
49
|
+
*/
|
|
50
|
+
class StatusChecker {
|
|
51
|
+
#checkers: Array<{title: string, complete: boolean}> = [];
|
|
52
|
+
#listener: Listener|null = null;
|
|
53
|
+
#currentStatus: StatusUpdate = null;
|
|
54
|
+
|
|
55
|
+
add(title: string, promise: Promise<unknown>): void {
|
|
56
|
+
const item = {title, complete: false};
|
|
57
|
+
this.#checkers.push(item);
|
|
58
|
+
|
|
59
|
+
void promise.finally(() => {
|
|
60
|
+
item.complete = true;
|
|
61
|
+
this.#evaluate();
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
setListener(listener: Listener): void {
|
|
66
|
+
this.#listener = null;
|
|
67
|
+
this.#evaluate();
|
|
68
|
+
this.#listener = listener;
|
|
69
|
+
listener(this.#currentStatus);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
removeListener(): void {
|
|
73
|
+
this.#listener = null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#evaluate(): void {
|
|
77
|
+
let nextStatus: StatusUpdate = null;
|
|
78
|
+
|
|
79
|
+
// Only report the status of the first incomplete checker.
|
|
80
|
+
for (const checker of this.#checkers) {
|
|
81
|
+
if (!checker.complete) {
|
|
82
|
+
nextStatus = checker.title;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (nextStatus !== this.#currentStatus) {
|
|
88
|
+
this.#currentStatus = nextStatus;
|
|
89
|
+
if (this.#listener) {
|
|
90
|
+
this.#listener(nextStatus);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
27
96
|
export class TimelineController implements Tracing.TracingManager.TracingManagerClient {
|
|
28
97
|
readonly primaryPageTarget: SDK.Target.Target;
|
|
29
98
|
readonly rootTarget: SDK.Target.Target;
|
|
@@ -35,6 +104,10 @@ export class TimelineController implements Tracing.TracingManager.TracingManager
|
|
|
35
104
|
private readonly client: Client;
|
|
36
105
|
private tracingCompletePromise: PromiseWithResolvers<void>|null = null;
|
|
37
106
|
|
|
107
|
+
// These properties are only used for "Reload and record".
|
|
108
|
+
#statusChecker: StatusChecker|null = null;
|
|
109
|
+
#loadEventFiredCb: (() => void)|null = null;
|
|
110
|
+
|
|
38
111
|
/**
|
|
39
112
|
* We always need to profile against the DevTools root target, which is
|
|
40
113
|
* the target that DevTools is attached to.
|
|
@@ -76,11 +149,72 @@ export class TimelineController implements Tracing.TracingManager.TracingManager
|
|
|
76
149
|
}
|
|
77
150
|
}
|
|
78
151
|
|
|
79
|
-
async
|
|
152
|
+
async #navigateToAboutBlank(): Promise<void> {
|
|
153
|
+
const aboutBlankNavigationComplete = new Promise<void>(async (resolve, reject) => {
|
|
154
|
+
const target = this.primaryPageTarget;
|
|
155
|
+
const resourceModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
156
|
+
if (!resourceModel) {
|
|
157
|
+
reject('Could not load resourceModel');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* To clear out the page and any state from prior test runs, we
|
|
163
|
+
* navigate to about:blank before initiating the trace recording.
|
|
164
|
+
* Once we have navigated to about:blank, we start recording and
|
|
165
|
+
* then navigate to the original page URL, to ensure we profile the
|
|
166
|
+
* page load.
|
|
167
|
+
**/
|
|
168
|
+
function waitForAboutBlank(event: Common.EventTarget.EventTargetEvent<SDK.ResourceTreeModel.ResourceTreeFrame>):
|
|
169
|
+
void {
|
|
170
|
+
if (event.data.url === 'about:blank') {
|
|
171
|
+
resolve();
|
|
172
|
+
} else {
|
|
173
|
+
reject(`Unexpected navigation to ${event.data.url}`);
|
|
174
|
+
}
|
|
175
|
+
resourceModel?.removeEventListener(SDK.ResourceTreeModel.Events.FrameNavigated, waitForAboutBlank);
|
|
176
|
+
}
|
|
177
|
+
resourceModel.addEventListener(SDK.ResourceTreeModel.Events.FrameNavigated, waitForAboutBlank);
|
|
178
|
+
await resourceModel.navigate('about:blank' as Platform.DevToolsPath.UrlString);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
await aboutBlankNavigationComplete;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async #navigateWithSDK(url: Platform.DevToolsPath.UrlString): Promise<void> {
|
|
185
|
+
const resourceModel = this.primaryPageTarget.model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
186
|
+
if (!resourceModel) {
|
|
187
|
+
throw new Error('expected to find ResourceTreeModel');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const loadPromiseWithResolvers = Promise.withResolvers<void>();
|
|
191
|
+
this.#loadEventFiredCb = loadPromiseWithResolvers.resolve;
|
|
192
|
+
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
193
|
+
SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this.#onLoadEventFired, this);
|
|
194
|
+
|
|
195
|
+
// We don't need to await this because we are purposefully showing UI
|
|
196
|
+
// progress as the page loads & tracing is underway.
|
|
197
|
+
void resourceModel.navigate(url);
|
|
198
|
+
|
|
199
|
+
await loadPromiseWithResolvers.promise;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async startRecording(options: RecordingOptions): Promise<void> {
|
|
80
203
|
function disabledByDefault(category: string): string {
|
|
81
204
|
return 'disabled-by-default-' + category;
|
|
82
205
|
}
|
|
83
206
|
|
|
207
|
+
this.client.recordingStatus(i18nString(UIStrings.initializingTracing));
|
|
208
|
+
|
|
209
|
+
// If we are doing "Reload & record", we first navigate the page to
|
|
210
|
+
// about:blank. This is to ensure any data on the timeline from any
|
|
211
|
+
// previous performance recording is lost, avoiding the problem where a
|
|
212
|
+
// timeline will show data & screenshots from a previous page load that
|
|
213
|
+
// was not relevant.
|
|
214
|
+
if (options.navigateToUrl) {
|
|
215
|
+
await this.#navigateToAboutBlank();
|
|
216
|
+
}
|
|
217
|
+
|
|
84
218
|
// The following categories are also used in other tools, but this panel
|
|
85
219
|
// offers the possibility of turning them off (see below).
|
|
86
220
|
// 'disabled-by-default-devtools.screenshot'
|
|
@@ -144,11 +278,40 @@ export class TimelineController implements Tracing.TracingManager.TracingManager
|
|
|
144
278
|
this.#navigationUrls = [];
|
|
145
279
|
this.#fieldData = null;
|
|
146
280
|
this.#recordingStartTime = Date.now();
|
|
281
|
+
|
|
147
282
|
const response = await this.startRecordingWithCategories(categoriesArray.join(','));
|
|
148
283
|
if (response.getError()) {
|
|
149
284
|
await SDK.TargetManager.TargetManager.instance().resumeAllTargets();
|
|
285
|
+
throw new Error(response.getError());
|
|
150
286
|
}
|
|
151
|
-
|
|
287
|
+
|
|
288
|
+
if (!options.navigateToUrl) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// If the user hit "Reload & record", by this point we have:
|
|
293
|
+
// 1. Navigated to about:blank
|
|
294
|
+
// 2. Initiated tracing.
|
|
295
|
+
// We therefore now should navigate back to the original URL that the user wants to profile.
|
|
296
|
+
|
|
297
|
+
// Setup a status checker so we can wait long enough for the page to settle,
|
|
298
|
+
// and to let users know what is going on.
|
|
299
|
+
this.#statusChecker?.removeListener();
|
|
300
|
+
this.#statusChecker = new StatusChecker();
|
|
301
|
+
|
|
302
|
+
const loadEvent = this.#navigateWithSDK(options.navigateToUrl);
|
|
303
|
+
this.#statusChecker.add(i18nString(UIStrings.waitingForLoadEvent), loadEvent);
|
|
304
|
+
this.#statusChecker.add(
|
|
305
|
+
i18nString(UIStrings.waitingForLoadEventPlus5Seconds),
|
|
306
|
+
loadEvent.then(() => new Promise(resolve => setTimeout(resolve, 5000))));
|
|
307
|
+
|
|
308
|
+
this.#statusChecker.setListener(status => {
|
|
309
|
+
if (status === null) {
|
|
310
|
+
void this.stopRecording();
|
|
311
|
+
} else {
|
|
312
|
+
this.client.recordingStatus(status);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
152
315
|
}
|
|
153
316
|
|
|
154
317
|
async #onFrameNavigated(event: {data: SDK.ResourceTreeModel.ResourceTreeFrame}): Promise<void> {
|
|
@@ -159,7 +322,22 @@ export class TimelineController implements Tracing.TracingManager.TracingManager
|
|
|
159
322
|
this.#navigationUrls.push(event.data.url);
|
|
160
323
|
}
|
|
161
324
|
|
|
325
|
+
async #onLoadEventFired(
|
|
326
|
+
event: Common.EventTarget
|
|
327
|
+
.EventTargetEvent<{resourceTreeModel: SDK.ResourceTreeModel.ResourceTreeModel, loadTime: number}>):
|
|
328
|
+
Promise<void> {
|
|
329
|
+
if (!event.data.resourceTreeModel.mainFrame?.isPrimaryFrame()) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
this.#loadEventFiredCb?.();
|
|
334
|
+
}
|
|
335
|
+
|
|
162
336
|
async stopRecording(): Promise<void> {
|
|
337
|
+
this.#statusChecker?.removeListener();
|
|
338
|
+
this.#statusChecker = null;
|
|
339
|
+
this.#loadEventFiredCb = null;
|
|
340
|
+
|
|
163
341
|
if (this.tracingManager) {
|
|
164
342
|
this.tracingManager.stop();
|
|
165
343
|
}
|
|
@@ -167,6 +345,8 @@ export class TimelineController implements Tracing.TracingManager.TracingManager
|
|
|
167
345
|
SDK.TargetManager.TargetManager.instance().removeModelListener(
|
|
168
346
|
SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.FrameNavigated, this.#onFrameNavigated,
|
|
169
347
|
this);
|
|
348
|
+
SDK.TargetManager.TargetManager.instance().removeModelListener(
|
|
349
|
+
SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this.#onLoadEventFired, this);
|
|
170
350
|
|
|
171
351
|
// When throttling is applied to the main renderer, it can slow down the
|
|
172
352
|
// collection of trace events once tracing has completed. Therefore we
|
|
@@ -286,7 +466,8 @@ export class TimelineController implements Tracing.TracingManager.TracingManager
|
|
|
286
466
|
}
|
|
287
467
|
|
|
288
468
|
export interface Client {
|
|
289
|
-
recordingProgress(
|
|
469
|
+
recordingProgress(bufferUsage: number): void;
|
|
470
|
+
recordingStatus(status: string): void;
|
|
290
471
|
loadingStarted(): void;
|
|
291
472
|
processingStarted(): void;
|
|
292
473
|
loadingProgress(progress?: number): void;
|
|
@@ -300,4 +481,5 @@ export interface RecordingOptions {
|
|
|
300
481
|
capturePictures?: boolean;
|
|
301
482
|
captureFilmStrip?: boolean;
|
|
302
483
|
captureSelectorStats?: boolean;
|
|
484
|
+
navigateToUrl?: Platform.DevToolsPath.UrlString;
|
|
303
485
|
}
|
|
@@ -453,6 +453,20 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
|
453
453
|
return this.compatibilityTracksAppender;
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
+
#insertEventToEntryData(event: Trace.Types.Events.Event): number {
|
|
457
|
+
// TODO(crbug.com/457866795): We don't actually need to keep this sorted yet, because we sort
|
|
458
|
+
// in CompatibilityTracksAppender.eventsInTrack. But if we ever wanted to remove that sort,
|
|
459
|
+
// the following code will be needed.
|
|
460
|
+
|
|
461
|
+
// const index = Platform.ArrayUtilities.lowerBound(this.entryData, event, (a, b) => a.ts - b.ts);
|
|
462
|
+
// this.entryData.splice(index, 0, event);
|
|
463
|
+
// return index;
|
|
464
|
+
|
|
465
|
+
// For now, just keep it simple and slightly faster.
|
|
466
|
+
this.entryData.push(event);
|
|
467
|
+
return this.entryData.length - 1;
|
|
468
|
+
}
|
|
469
|
+
|
|
456
470
|
/**
|
|
457
471
|
* Returns the instance of the timeline flame chart data, without
|
|
458
472
|
* adding data to it. In case the timeline data hasn't been instanced
|
|
@@ -546,7 +560,7 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
|
546
560
|
this.entryData = [];
|
|
547
561
|
this.entryTypeByLevel = [];
|
|
548
562
|
this.entryIndexToTitle = [];
|
|
549
|
-
this.#eventIndexByEvent = new
|
|
563
|
+
this.#eventIndexByEvent = new WeakMap();
|
|
550
564
|
|
|
551
565
|
if (this.#timelineData) {
|
|
552
566
|
this.compatibilityTracksAppender?.setFlameChartDataAndEntryData(
|
|
@@ -568,7 +582,7 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
|
568
582
|
this.entryData = [];
|
|
569
583
|
this.entryTypeByLevel = [];
|
|
570
584
|
this.entryIndexToTitle = [];
|
|
571
|
-
this.#eventIndexByEvent = new
|
|
585
|
+
this.#eventIndexByEvent = new WeakMap();
|
|
572
586
|
this.#minimumBoundary = 0;
|
|
573
587
|
this.timeSpan = 0;
|
|
574
588
|
|
|
@@ -750,9 +764,14 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
|
750
764
|
* because then when it comes to drawing we can decorate them differently.
|
|
751
765
|
**/
|
|
752
766
|
#appendFramesAndScreenshotsTrack(): void {
|
|
767
|
+
if (this.entryData.length) {
|
|
768
|
+
throw new Error('expected this.entryData to be empty');
|
|
769
|
+
}
|
|
770
|
+
|
|
753
771
|
if (!this.parsedTrace) {
|
|
754
772
|
return;
|
|
755
773
|
}
|
|
774
|
+
|
|
756
775
|
const filmStrip = Trace.Extras.FilmStrip.fromHandlerData(this.parsedTrace.data);
|
|
757
776
|
const hasScreenshots = filmStrip.frames.length > 0;
|
|
758
777
|
const hasFrames = this.parsedTrace.data.Frames.frames.length > 0;
|
|
@@ -782,27 +801,27 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
|
782
801
|
if (!this.#timelineData || !this.parsedTrace) {
|
|
783
802
|
return;
|
|
784
803
|
}
|
|
804
|
+
|
|
785
805
|
this.appendHeader('', this.screenshotsGroupStyle, false /* selectable */);
|
|
786
806
|
this.entryTypeByLevel[this.currentLevel] = EntryType.SCREENSHOT;
|
|
787
|
-
let prevTimestamp: Trace.Types.Timing.Milli|undefined = undefined;
|
|
788
|
-
|
|
789
|
-
for (const filmStripFrame of filmStrip.frames) {
|
|
790
|
-
const screenshotTimeInMilliSeconds = Trace.Helpers.Timing.microToMilli(filmStripFrame.screenshotEvent.ts);
|
|
791
|
-
this.entryData.push(filmStripFrame.screenshotEvent);
|
|
792
|
-
(this.#timelineData.entryLevels as number[]).push(this.currentLevel);
|
|
793
|
-
(this.#timelineData.entryStartTimes as number[]).push(screenshotTimeInMilliSeconds);
|
|
794
|
-
if (prevTimestamp) {
|
|
795
|
-
(this.#timelineData.entryTotalTimes as number[]).push(screenshotTimeInMilliSeconds - prevTimestamp);
|
|
796
|
-
}
|
|
797
|
-
prevTimestamp = screenshotTimeInMilliSeconds;
|
|
798
|
-
}
|
|
799
|
-
if (filmStrip.frames.length && prevTimestamp !== undefined) {
|
|
800
|
-
const maxRecordTimeMillis =
|
|
801
|
-
Trace.Helpers.Timing.traceWindowMilliSeconds(this.parsedTrace.data.Meta.traceBounds).max;
|
|
802
807
|
|
|
803
|
-
|
|
804
|
-
|
|
808
|
+
const traceEnd = Trace.Helpers.Timing.traceWindowMilliSeconds(this.parsedTrace.data.Meta.traceBounds).max;
|
|
809
|
+
|
|
810
|
+
for (let i = 0; i < filmStrip.frames.length; ++i) {
|
|
811
|
+
const currentFrame = filmStrip.frames[i];
|
|
812
|
+
const nextFrame = filmStrip.frames[i + 1];
|
|
813
|
+
const startTimeMillis = Trace.Helpers.Timing.microToMilli(currentFrame.screenshotEvent.ts);
|
|
814
|
+
// If there is no next frame, use the end of the trace.
|
|
815
|
+
const endTimeMillis = nextFrame ? Trace.Helpers.Timing.microToMilli(nextFrame.screenshotEvent.ts) : traceEnd;
|
|
816
|
+
const durationMillis = endTimeMillis - startTimeMillis;
|
|
817
|
+
|
|
818
|
+
const index = this.#insertEventToEntryData(currentFrame.screenshotEvent);
|
|
819
|
+
(this.#timelineData.entryLevels as number[]).splice(index, 0, this.currentLevel);
|
|
820
|
+
(this.#timelineData.entryStartTimes as number[]).splice(index, 0, startTimeMillis);
|
|
821
|
+
(this.#timelineData.entryTotalTimes as number[]).splice(index, 0, durationMillis);
|
|
822
|
+
this.entryIndexToTitle.splice(index, 0, '');
|
|
805
823
|
}
|
|
824
|
+
|
|
806
825
|
++this.currentLevel;
|
|
807
826
|
}
|
|
808
827
|
|
|
@@ -1175,16 +1194,24 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
|
1175
1194
|
}
|
|
1176
1195
|
|
|
1177
1196
|
#appendFrame(frame: Trace.Types.Events.LegacyTimelineFrame): void {
|
|
1178
|
-
const index = this
|
|
1179
|
-
this.entryData.push(frame);
|
|
1197
|
+
const index = this.#insertEventToEntryData(frame);
|
|
1180
1198
|
const durationMilliseconds = Trace.Helpers.Timing.microToMilli(frame.duration);
|
|
1181
|
-
this.entryIndexToTitle
|
|
1199
|
+
this.entryIndexToTitle.splice(index, 0, i18n.TimeUtilities.millisToString(durationMilliseconds, true));
|
|
1200
|
+
|
|
1182
1201
|
if (!this.#timelineData) {
|
|
1183
1202
|
return;
|
|
1184
1203
|
}
|
|
1185
|
-
|
|
1186
|
-
this.#timelineData.entryTotalTimes
|
|
1187
|
-
|
|
1204
|
+
|
|
1205
|
+
if (Array.isArray(this.#timelineData.entryLevels) && Array.isArray(this.#timelineData.entryTotalTimes) &&
|
|
1206
|
+
Array.isArray(this.#timelineData.entryStartTimes)) {
|
|
1207
|
+
this.#timelineData.entryLevels.splice(index, 0, this.currentLevel);
|
|
1208
|
+
this.#timelineData.entryTotalTimes.splice(index, 0, durationMilliseconds);
|
|
1209
|
+
this.#timelineData.entryStartTimes.splice(index, 0, Trace.Helpers.Timing.microToMilli(frame.startTime));
|
|
1210
|
+
} else {
|
|
1211
|
+
this.#timelineData.entryLevels[index] = this.currentLevel;
|
|
1212
|
+
this.#timelineData.entryTotalTimes[index] = durationMilliseconds;
|
|
1213
|
+
this.#timelineData.entryStartTimes[index] = Trace.Helpers.Timing.microToMilli(frame.startTime);
|
|
1214
|
+
}
|
|
1188
1215
|
}
|
|
1189
1216
|
|
|
1190
1217
|
createSelection(entryIndex: number): TimelineSelection|null {
|
|
@@ -125,6 +125,7 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
|
|
|
125
125
|
private readonly onMainEntrySelected: (event: Common.EventTarget.EventTargetEvent<number>) => void;
|
|
126
126
|
private readonly onNetworkEntrySelected: (event: Common.EventTarget.EventTargetEvent<number>) => void;
|
|
127
127
|
readonly #boundRefreshAfterIgnoreList: () => void;
|
|
128
|
+
/** This is sorted by ts. */
|
|
128
129
|
#selectedEvents: Trace.Types.Events.Event[]|null;
|
|
129
130
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
|
130
131
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -228,10 +228,6 @@ const UIStrings = {
|
|
|
228
228
|
* @description Text in Timeline Panel of the Performance panel
|
|
229
229
|
*/
|
|
230
230
|
processingTrace: 'Processing trace…',
|
|
231
|
-
/**
|
|
232
|
-
* @description Text in Timeline Panel of the Performance panel
|
|
233
|
-
*/
|
|
234
|
-
initializingTracing: 'Initializing tracing…',
|
|
235
231
|
/**
|
|
236
232
|
* @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
|
|
237
233
|
*/
|
|
@@ -345,7 +341,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
345
341
|
private readonly recordingOptionUIControls: UI.Toolbar.ToolbarItem[];
|
|
346
342
|
private state: State;
|
|
347
343
|
private recordingPageReload: boolean;
|
|
348
|
-
private readonly millisecondsToRecordAfterLoadEvent: number;
|
|
349
344
|
private readonly toggleRecordAction: UI.ActionRegistration.Action;
|
|
350
345
|
private readonly recordReloadAction: UI.ActionRegistration.Action;
|
|
351
346
|
readonly #historyManager: TimelineHistoryManager;
|
|
@@ -459,10 +454,8 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
459
454
|
">💫</div>`;
|
|
460
455
|
const adorner = new Adorners.Adorner.Adorner();
|
|
461
456
|
adorner.classList.add('fix-perf-icon');
|
|
462
|
-
adorner.
|
|
463
|
-
|
|
464
|
-
content: adornerContent,
|
|
465
|
-
};
|
|
457
|
+
adorner.name = i18nString(UIStrings.fixMe);
|
|
458
|
+
adorner.append(adornerContent);
|
|
466
459
|
this.#traceEngineModel = traceModel || this.#instantiateNewModel();
|
|
467
460
|
|
|
468
461
|
this.element.addEventListener('contextmenu', this.contextMenu.bind(this), false);
|
|
@@ -473,7 +466,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
473
466
|
this.recordingOptionUIControls = [];
|
|
474
467
|
this.state = State.IDLE;
|
|
475
468
|
this.recordingPageReload = false;
|
|
476
|
-
this.millisecondsToRecordAfterLoadEvent = 5000;
|
|
477
469
|
this.toggleRecordAction = UI.ActionRegistry.ActionRegistry.instance().getAction('timeline.toggle-recording');
|
|
478
470
|
this.recordReloadAction = UI.ActionRegistry.ActionRegistry.instance().getAction('timeline.record-reload');
|
|
479
471
|
|
|
@@ -538,9 +530,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
538
530
|
|
|
539
531
|
this.createFileSelector();
|
|
540
532
|
|
|
541
|
-
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
542
|
-
SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this.loadEventFired, this);
|
|
543
|
-
|
|
544
533
|
this.flameChart = new TimelineFlameChartView(this);
|
|
545
534
|
this.element.addEventListener(
|
|
546
535
|
'toggle-popover', event => this.flameChart.togglePopover((event as CustomEvent).detail));
|
|
@@ -1858,41 +1847,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1858
1847
|
return navigationEntry.url as Platform.DevToolsPath.UrlString;
|
|
1859
1848
|
}
|
|
1860
1849
|
|
|
1861
|
-
async #navigateToAboutBlank(): Promise<void> {
|
|
1862
|
-
const aboutBlankNavigationComplete = new Promise<void>(async (resolve, reject) => {
|
|
1863
|
-
if (!this.controller) {
|
|
1864
|
-
reject('Could not find TimelineController');
|
|
1865
|
-
return;
|
|
1866
|
-
}
|
|
1867
|
-
const target = this.controller.primaryPageTarget;
|
|
1868
|
-
const resourceModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
1869
|
-
if (!resourceModel) {
|
|
1870
|
-
reject('Could not load resourceModel');
|
|
1871
|
-
return;
|
|
1872
|
-
}
|
|
1873
|
-
|
|
1874
|
-
/**
|
|
1875
|
-
* To clear out the page and any state from prior test runs, we
|
|
1876
|
-
* navigate to about:blank before initiating the trace recording.
|
|
1877
|
-
* Once we have navigated to about:blank, we start recording and
|
|
1878
|
-
* then navigate to the original page URL, to ensure we profile the
|
|
1879
|
-
* page load.
|
|
1880
|
-
**/
|
|
1881
|
-
function waitForAboutBlank(event: Common.EventTarget.EventTargetEvent<SDK.ResourceTreeModel.ResourceTreeFrame>):
|
|
1882
|
-
void {
|
|
1883
|
-
if (event.data.url === 'about:blank') {
|
|
1884
|
-
resolve();
|
|
1885
|
-
} else {
|
|
1886
|
-
reject(`Unexpected navigation to ${event.data.url}`);
|
|
1887
|
-
}
|
|
1888
|
-
resourceModel?.removeEventListener(SDK.ResourceTreeModel.Events.FrameNavigated, waitForAboutBlank);
|
|
1889
|
-
}
|
|
1890
|
-
resourceModel.addEventListener(SDK.ResourceTreeModel.Events.FrameNavigated, waitForAboutBlank);
|
|
1891
|
-
await resourceModel.navigate('about:blank' as Platform.DevToolsPath.UrlString);
|
|
1892
|
-
});
|
|
1893
|
-
await aboutBlankNavigationComplete;
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
1850
|
async #startCPUProfilingRecording(): Promise<void> {
|
|
1897
1851
|
try {
|
|
1898
1852
|
this.cpuProfiler = UI.Context.Context.instance().flavor(SDK.CPUProfilerModel.CPUProfilerModel);
|
|
@@ -1953,30 +1907,18 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1953
1907
|
}
|
|
1954
1908
|
|
|
1955
1909
|
const urlToTrace = await this.#evaluateInspectedURL();
|
|
1956
|
-
|
|
1957
|
-
//
|
|
1958
|
-
|
|
1959
|
-
// timeline will show data & screenshots from a previous page load that
|
|
1960
|
-
// was not relevant.
|
|
1961
|
-
if (this.recordingPageReload) {
|
|
1962
|
-
await this.#navigateToAboutBlank();
|
|
1963
|
-
}
|
|
1964
|
-
const recordingOptions = {
|
|
1910
|
+
|
|
1911
|
+
// Order is important here: we tell the controller to start recording, which enables tracing.
|
|
1912
|
+
await this.controller.startRecording({
|
|
1965
1913
|
enableJSSampling: !this.disableCaptureJSProfileSetting.get(),
|
|
1966
1914
|
capturePictures: this.captureLayersAndPicturesSetting.get(),
|
|
1967
1915
|
captureFilmStrip: this.showScreenshotsSetting.get(),
|
|
1968
1916
|
captureSelectorStats: this.captureSelectorStatsSetting.get(),
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
if (response.getError()) {
|
|
1973
|
-
throw new Error(response.getError());
|
|
1974
|
-
}
|
|
1917
|
+
navigateToUrl: this.recordingPageReload ? urlToTrace : undefined,
|
|
1918
|
+
});
|
|
1919
|
+
|
|
1975
1920
|
// Once we get here, we know tracing is active.
|
|
1976
|
-
|
|
1977
|
-
// If the user has just hit "record", we don't do any navigating.
|
|
1978
|
-
const recordingConfig = this.recordingPageReload ? {navigateToUrl: urlToTrace} : undefined;
|
|
1979
|
-
this.recordingStarted(recordingConfig);
|
|
1921
|
+
this.recordingStarted();
|
|
1980
1922
|
} catch (e) {
|
|
1981
1923
|
await this.recordingFailed(e.message);
|
|
1982
1924
|
}
|
|
@@ -2428,28 +2370,11 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2428
2370
|
return ThemeSupport.ThemeSupport.instance().getComputedValue('--app-color-system');
|
|
2429
2371
|
}
|
|
2430
2372
|
|
|
2431
|
-
private recordingStarted(
|
|
2432
|
-
if (config && this.recordingPageReload && this.controller) {
|
|
2433
|
-
// If the user hit "Reload & record", by this point we have:
|
|
2434
|
-
// 1. Navigated to about:blank
|
|
2435
|
-
// 2. Initiated tracing.
|
|
2436
|
-
// We therefore now should navigate back to the original URL that the user wants to profile.
|
|
2437
|
-
const resourceModel = this.controller?.primaryPageTarget.model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
2438
|
-
if (!resourceModel) {
|
|
2439
|
-
void this.recordingFailed('Could not navigate to original URL');
|
|
2440
|
-
return;
|
|
2441
|
-
}
|
|
2442
|
-
// We don't need to await this because we are purposefully showing UI
|
|
2443
|
-
// progress as the page loads & tracing is underway.
|
|
2444
|
-
void resourceModel.navigate(config.navigateToUrl);
|
|
2445
|
-
}
|
|
2446
|
-
|
|
2373
|
+
private recordingStarted(): void {
|
|
2447
2374
|
this.#changeView({mode: 'STATUS_PANE_OVERLAY'});
|
|
2448
2375
|
this.setState(State.RECORDING);
|
|
2449
|
-
this.showRecordingStarted();
|
|
2450
2376
|
if (this.statusDialog) {
|
|
2451
2377
|
this.statusDialog.enableAndFocusButton();
|
|
2452
|
-
this.statusDialog.updateStatus(i18nString(UIStrings.tracing));
|
|
2453
2378
|
this.statusDialog.updateProgressBar(i18nString(UIStrings.bufferUsage), 0);
|
|
2454
2379
|
this.statusDialog.startTimer();
|
|
2455
2380
|
}
|
|
@@ -2461,6 +2386,12 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2461
2386
|
}
|
|
2462
2387
|
}
|
|
2463
2388
|
|
|
2389
|
+
recordingStatus(status: string): void {
|
|
2390
|
+
if (this.statusDialog) {
|
|
2391
|
+
this.statusDialog.updateStatus(status);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2464
2395
|
/**
|
|
2465
2396
|
* Hide the sidebar, but persist the user's state, because when they import a
|
|
2466
2397
|
* trace we want to revert the sidebar back to what it was.
|
|
@@ -2902,7 +2833,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2902
2833
|
},
|
|
2903
2834
|
() => this.stopRecording());
|
|
2904
2835
|
this.statusDialog.showPane(this.statusPaneContainer);
|
|
2905
|
-
this.statusDialog.updateStatus(i18nString(UIStrings.
|
|
2836
|
+
this.statusDialog.updateStatus(i18nString(UIStrings.tracing));
|
|
2906
2837
|
this.statusDialog.updateProgressBar(i18nString(UIStrings.bufferUsage), 0);
|
|
2907
2838
|
}
|
|
2908
2839
|
|
|
@@ -2912,24 +2843,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2912
2843
|
}
|
|
2913
2844
|
}
|
|
2914
2845
|
|
|
2915
|
-
private async loadEventFired(
|
|
2916
|
-
event: Common.EventTarget
|
|
2917
|
-
.EventTargetEvent<{resourceTreeModel: SDK.ResourceTreeModel.ResourceTreeModel, loadTime: number}>):
|
|
2918
|
-
Promise<void> {
|
|
2919
|
-
if (this.state !== State.RECORDING || !this.recordingPageReload ||
|
|
2920
|
-
this.controller?.primaryPageTarget !== event.data.resourceTreeModel.target()) {
|
|
2921
|
-
return;
|
|
2922
|
-
}
|
|
2923
|
-
const controller = this.controller;
|
|
2924
|
-
await new Promise(r => window.setTimeout(r, this.millisecondsToRecordAfterLoadEvent));
|
|
2925
|
-
|
|
2926
|
-
// Check if we're still in the same recording session.
|
|
2927
|
-
if (controller !== this.controller || this.state !== State.RECORDING) {
|
|
2928
|
-
return;
|
|
2929
|
-
}
|
|
2930
|
-
void this.stopRecording();
|
|
2931
|
-
}
|
|
2932
|
-
|
|
2933
2846
|
private frameForSelection(selection: TimelineSelection): Trace.Types.Events.LegacyTimelineFrame|null {
|
|
2934
2847
|
if (this.#viewMode.mode !== 'VIEWING_TRACE') {
|
|
2935
2848
|
return null;
|
|
@@ -171,6 +171,7 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
|
171
171
|
export class TimelineTreeView extends
|
|
172
172
|
Common.ObjectWrapper.eventMixin<TimelineTreeView.EventTypes, typeof UI.Widget.VBox>(UI.Widget.VBox)
|
|
173
173
|
implements UI.SearchableView.Searchable {
|
|
174
|
+
/** This is sorted by ts. */
|
|
174
175
|
#selectedEvents: Trace.Types.Events.Event[]|null;
|
|
175
176
|
private searchResults: Trace.Extras.TraceTree.Node[];
|
|
176
177
|
linkifier!: Components.Linkifier.Linkifier;
|
|
@@ -75,7 +75,7 @@ interface ViewInput {
|
|
|
75
75
|
estimatedSavingsAriaLabel: string|null;
|
|
76
76
|
renderContent: () => Lit.LitTemplate;
|
|
77
77
|
dispatchInsightToggle: () => void;
|
|
78
|
-
onHeaderKeyDown: () => void;
|
|
78
|
+
onHeaderKeyDown: (event: KeyboardEvent) => void;
|
|
79
79
|
onAskAIButtonClick: () => void;
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -412,7 +412,7 @@ export abstract class BaseInsightComponent<T extends InsightModel> extends UI.Wi
|
|
|
412
412
|
showAskAI: this.#canShowAskAI(),
|
|
413
413
|
dispatchInsightToggle: () => this.#dispatchInsightToggle(),
|
|
414
414
|
renderContent: () => this.renderContent(),
|
|
415
|
-
onHeaderKeyDown:
|
|
415
|
+
onHeaderKeyDown: this.#onHeaderKeyDown.bind(this),
|
|
416
416
|
onAskAIButtonClick: () => this.#onAskAIButtonClick(),
|
|
417
417
|
};
|
|
418
418
|
this.#view(input, undefined, this.contentElement);
|
|
@@ -239,11 +239,11 @@ export class Table extends UI.Widget.Widget {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
#onHoverRow(row: TableDataRow, rowEl: HTMLElement): void {
|
|
242
|
-
if (row === this.#currentHoverRow) {
|
|
242
|
+
if (row === this.#currentHoverRow || !this.element.shadowRoot) {
|
|
243
243
|
return;
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
-
for (const el of this.element.querySelectorAll('.hover')) {
|
|
246
|
+
for (const el of this.element.shadowRoot.querySelectorAll('.hover')) {
|
|
247
247
|
el.classList.remove('hover');
|
|
248
248
|
}
|
|
249
249
|
|
|
@@ -251,7 +251,7 @@ export class Table extends UI.Widget.Widget {
|
|
|
251
251
|
let curRow: TableDataRow|undefined = this.#rowToParentRow.get(row);
|
|
252
252
|
while (curRow) {
|
|
253
253
|
rowEl.classList.add('hover');
|
|
254
|
-
curRow = this.#rowToParentRow.get(
|
|
254
|
+
curRow = this.#rowToParentRow.get(curRow);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
this.#currentHoverRow = row;
|