chrome-devtools-frontend 1.0.1605219 → 1.0.1606789
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/Images/src/dots-circle.svg +10 -0
- package/front_end/core/host/UserMetrics.ts +0 -1
- package/front_end/core/platform/api/HostRuntime.ts +9 -6
- package/front_end/core/platform/browser/HostRuntime.ts +2 -2
- package/front_end/core/platform/node/HostRuntime.ts +7 -7
- package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
- package/front_end/core/root/ExperimentNames.ts +0 -1
- package/front_end/core/sdk/CrashReportContextModel.ts +28 -0
- package/front_end/core/sdk/sdk.ts +2 -2
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +3 -3
- package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker-entrypoint.ts +5 -4
- package/front_end/entrypoints/main/MainImpl.ts +0 -101
- package/front_end/models/ai_assistance/ChangeManager.ts +6 -6
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +112 -5
- package/front_end/models/ai_assistance/agents/AiAgent.ts +9 -25
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +2 -2
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +6 -3
- package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +10 -9
- package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +313 -0
- package/front_end/models/ai_assistance/agents/FileAgent.ts +15 -1
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +15 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +19 -8
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +35 -278
- package/front_end/models/ai_assistance/ai_assistance.ts +0 -2
- package/front_end/models/javascript_metadata/NativeFunctions.js +1 -5
- package/front_end/models/web_mcp/WebMCPModel.ts +187 -0
- package/front_end/models/web_mcp/web_mcp.ts +9 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -1
- package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
- package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +88 -0
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +149 -49
- package/front_end/panels/ai_assistance/components/ChatView.ts +11 -15
- package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +13 -4
- package/front_end/panels/ai_assistance/components/chatMessage.css +53 -1
- package/front_end/panels/ai_assistance/components/chatView.css +0 -10
- package/front_end/panels/ai_assistance/components/exportForAgentsDialog.css +13 -0
- package/front_end/panels/application/WebMCPView.ts +471 -25
- package/front_end/panels/application/webMCPView.css +53 -2
- package/front_end/panels/elements/ElementsTreeElement.ts +1 -1
- package/front_end/panels/elements/ElementsTreeOutline.ts +87 -0
- package/front_end/panels/elements/StylePropertiesSection.ts +0 -4
- package/front_end/panels/elements/elements.ts +3 -0
- package/front_end/panels/elements/elementsTreeOutline.css +21 -0
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +7 -0
- package/front_end/panels/lighthouse/LighthousePanel.ts +7 -1
- package/front_end/panels/lighthouse/LighthouseProtocolService.ts +25 -2
- package/front_end/panels/profiler/HeapDetachedElementsView.ts +0 -4
- package/front_end/panels/profiler/HeapProfileView.ts +0 -4
- package/front_end/panels/profiler/HeapProfilerPanel.ts +4 -13
- package/front_end/panels/profiler/HeapSnapshotProxy.ts +2 -6
- package/front_end/panels/profiler/HeapSnapshotView.ts +19 -32
- package/front_end/panels/profiler/ProfileHeader.ts +1 -15
- package/front_end/panels/profiler/ProfileTypeRegistry.ts +4 -12
- package/front_end/panels/profiler/ProfileView.ts +1 -6
- package/front_end/panels/profiler/ProfilesPanel.ts +60 -7
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +27 -22
- package/front_end/panels/timeline/EventsTimelineTreeView.ts +1 -1
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +2 -2
- package/front_end/panels/timeline/TimelinePanel.ts +11 -153
- package/front_end/panels/timeline/TimelineTreeView.ts +147 -48
- package/front_end/panels/timeline/TimelineUIUtils.ts +2 -1
- package/front_end/panels/timeline/components/CWVMetrics.ts +18 -2
- package/front_end/panels/timeline/timeline-meta.ts +11 -0
- package/front_end/panels/timeline/utils/Helpers.ts +5 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/markdown_view/CodeBlock.ts +47 -1
- package/front_end/ui/components/markdown_view/codeBlock.css +8 -0
- package/front_end/ui/legacy/FilterBar.ts +2 -0
- package/front_end/ui/legacy/SplitWidget.ts +33 -27
- package/front_end/ui/legacy/TabbedPane.ts +123 -3
- package/front_end/ui/legacy/Widget.ts +95 -48
- package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -1
- package/front_end/ui/legacy/components/utils/jsUtils.css +2 -0
- package/front_end/ui/legacy/infobar.css +1 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +6 -1
- package/package.json +1 -1
- package/front_end/core/sdk/WebMCPModel.ts +0 -104
- package/front_end/models/ai_assistance/ConversationHandler.ts +0 -325
|
@@ -8,7 +8,6 @@ import * as Common from '../../core/common/common.js';
|
|
|
8
8
|
import * as Host from '../../core/host/host.js';
|
|
9
9
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
10
10
|
import * as Platform from '../../core/platform/platform.js';
|
|
11
|
-
import * as Root from '../../core/root/root.js';
|
|
12
11
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
13
12
|
import type * as Protocol from '../../generated/protocol.js';
|
|
14
13
|
import * as Bindings from '../../models/bindings/bindings.js';
|
|
@@ -45,8 +44,7 @@ import {
|
|
|
45
44
|
ProfileHeader,
|
|
46
45
|
ProfileType,
|
|
47
46
|
} from './ProfileHeader.js';
|
|
48
|
-
import {
|
|
49
|
-
import {instance} from './ProfileTypeRegistry.js';
|
|
47
|
+
import type {ProfileTypeRegistry} from './ProfileTypeRegistry.js';
|
|
50
48
|
|
|
51
49
|
const UIStrings = {
|
|
52
50
|
/**
|
|
@@ -271,7 +269,7 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
|
271
269
|
const moduleUIstr_ = i18n.i18n.registerUIStrings('panels/profiler/ModuleUIStrings.ts', ModuleUIStrings.UIStrings);
|
|
272
270
|
const moduleI18nString = i18n.i18n.getLocalizedString.bind(undefined, moduleUIstr_);
|
|
273
271
|
export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayDelegate, UI.SearchableView.Searchable {
|
|
274
|
-
searchResults: number[];
|
|
272
|
+
searchResults: number[] = [];
|
|
275
273
|
profile: HeapProfileHeader;
|
|
276
274
|
readonly linkifier: Components.Linkifier.Linkifier;
|
|
277
275
|
readonly parentDataDisplayDelegate: DataDisplayDelegate;
|
|
@@ -310,6 +308,7 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
|
310
308
|
trackingOverviewGrid?: HeapTimelineOverview;
|
|
311
309
|
currentSearchResultIndex = -1;
|
|
312
310
|
currentSearch?: HeapSnapshotModel.HeapSnapshotModel.SearchConfig;
|
|
311
|
+
#registry: ProfileTypeRegistry;
|
|
313
312
|
|
|
314
313
|
get currentQuery(): string|undefined {
|
|
315
314
|
return this.currentSearch?.query;
|
|
@@ -320,13 +319,17 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
|
320
319
|
}
|
|
321
320
|
}
|
|
322
321
|
|
|
323
|
-
constructor(
|
|
322
|
+
constructor(
|
|
323
|
+
dataDisplayDelegate: DataDisplayDelegate,
|
|
324
|
+
profile: HeapProfileHeader,
|
|
325
|
+
registry: ProfileTypeRegistry,
|
|
326
|
+
) {
|
|
324
327
|
super({
|
|
325
328
|
title: i18nString(UIStrings.heapSnapshot),
|
|
326
329
|
viewId: 'heap-snapshot',
|
|
327
330
|
});
|
|
328
331
|
|
|
329
|
-
this
|
|
332
|
+
this.#registry = registry;
|
|
330
333
|
|
|
331
334
|
this.element.classList.add('heap-snapshot-view');
|
|
332
335
|
this.profile = profile;
|
|
@@ -340,7 +343,7 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
|
340
343
|
if (isHeapTimeline) {
|
|
341
344
|
this.createOverview();
|
|
342
345
|
}
|
|
343
|
-
const hasAllocationStacks =
|
|
346
|
+
const hasAllocationStacks = registry.trackingHeapSnapshotProfileType.recordAllocationStacksSetting().get();
|
|
344
347
|
|
|
345
348
|
this.parentDataDisplayDelegate = dataDisplayDelegate;
|
|
346
349
|
|
|
@@ -425,7 +428,7 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
|
425
428
|
this.perspectives = [];
|
|
426
429
|
this.comparisonPerspective = new ComparisonPerspective();
|
|
427
430
|
this.perspectives.push(new SummaryPerspective());
|
|
428
|
-
if (profile.profileType() !==
|
|
431
|
+
if (profile.profileType() !== this.#registry.trackingHeapSnapshotProfileType) {
|
|
429
432
|
this.perspectives.push(this.comparisonPerspective);
|
|
430
433
|
}
|
|
431
434
|
this.perspectives.push(new ContainmentPerspective());
|
|
@@ -621,7 +624,7 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
|
621
624
|
|
|
622
625
|
override async toolbarItems(): Promise<UI.Toolbar.ToolbarItem[]> {
|
|
623
626
|
const result: UI.Toolbar.ToolbarItem[] = [this.perspectiveSelect, this.classNameFilter];
|
|
624
|
-
if (this.profile.profileType() !==
|
|
627
|
+
if (this.profile.profileType() !== this.#registry.trackingHeapSnapshotProfileType) {
|
|
625
628
|
result.push(this.baseSelect, this.filterSelect);
|
|
626
629
|
}
|
|
627
630
|
result.push(this.selectedSizeText);
|
|
@@ -828,7 +831,7 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
|
828
831
|
|
|
829
832
|
inspectedObjectChanged(
|
|
830
833
|
event: Common.EventTarget.EventTargetEvent<DataGrid.DataGrid.DataGridNode<HeapSnapshotGridNode>>): void {
|
|
831
|
-
const selectedNode =
|
|
834
|
+
const selectedNode = event.data;
|
|
832
835
|
const heapProfilerModel = this.profile.heapProfilerModel();
|
|
833
836
|
if (heapProfilerModel && selectedNode instanceof HeapSnapshotGenericObjectNode) {
|
|
834
837
|
void heapProfilerModel.addInspectedHeapObject(
|
|
@@ -1335,12 +1338,10 @@ export class HeapSnapshotProfileType extends
|
|
|
1335
1338
|
}
|
|
1336
1339
|
|
|
1337
1340
|
override customContent(): Element|null {
|
|
1338
|
-
const showOptionToExposeInternalsInHeapSnapshot = Root.Runtime.experiments.isEnabled(
|
|
1339
|
-
Root.ExperimentNames.ExperimentName.SHOW_OPTION_TO_EXPOSE_INTERNALS_IN_HEAP_SNAPSHOT);
|
|
1340
1341
|
const exposeInternalsInHeapSnapshotCheckbox =
|
|
1341
1342
|
SettingsUI.SettingsUI.createSettingCheckbox(i18nString(UIStrings.exposeInternals), this.exposeInternals);
|
|
1342
1343
|
this.customContentInternal = exposeInternalsInHeapSnapshotCheckbox;
|
|
1343
|
-
return
|
|
1344
|
+
return exposeInternalsInHeapSnapshotCheckbox;
|
|
1344
1345
|
}
|
|
1345
1346
|
|
|
1346
1347
|
override setCustomContentEnabled(enable: boolean): void {
|
|
@@ -1680,14 +1681,6 @@ export class HeapProfileHeader extends ProfileHeader {
|
|
|
1680
1681
|
return await this.snapshotProxy.getLocation(nodeIndex);
|
|
1681
1682
|
}
|
|
1682
1683
|
|
|
1683
|
-
override createSidebarTreeElement(dataDisplayDelegate: DataDisplayDelegate): ProfileSidebarTreeElement {
|
|
1684
|
-
return new ProfileSidebarTreeElement(dataDisplayDelegate, this, 'heap-snapshot-sidebar-tree-item');
|
|
1685
|
-
}
|
|
1686
|
-
|
|
1687
|
-
override createView(dataDisplayDelegate: DataDisplayDelegate): HeapSnapshotView {
|
|
1688
|
-
return new HeapSnapshotView(dataDisplayDelegate, this);
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
1684
|
prepareToLoad(): void {
|
|
1692
1685
|
console.assert(!this.receiver, 'Already loading');
|
|
1693
1686
|
this.setupWorker();
|
|
@@ -1813,9 +1806,7 @@ export class HeapProfileHeader extends ProfileHeader {
|
|
|
1813
1806
|
return;
|
|
1814
1807
|
}
|
|
1815
1808
|
if (this.tempFile) {
|
|
1816
|
-
const error =
|
|
1817
|
-
message: string,
|
|
1818
|
-
} | null);
|
|
1809
|
+
const error = await this.tempFile.copyToOutputStream(fileOutputStream, this.onChunkTransferred.bind(this));
|
|
1819
1810
|
if (error) {
|
|
1820
1811
|
Common.Console.Console.instance().error('Failed to read heap snapshot from temp file: ' + error.message);
|
|
1821
1812
|
}
|
|
@@ -1845,15 +1836,11 @@ export class HeapProfileHeader extends ProfileHeader {
|
|
|
1845
1836
|
this.setupWorker();
|
|
1846
1837
|
const reader = new Bindings.FileUtils.ChunkedFileReader(file, 10000000);
|
|
1847
1838
|
const success = await reader.read((this.receiver as Common.StringOutputStream.OutputStream));
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
} | null);
|
|
1852
|
-
if (error) {
|
|
1853
|
-
this.updateStatus(error.message);
|
|
1854
|
-
}
|
|
1839
|
+
const error = reader.error();
|
|
1840
|
+
if (!success && error) {
|
|
1841
|
+
this.updateStatus(error.message);
|
|
1855
1842
|
}
|
|
1856
|
-
return success ? null :
|
|
1843
|
+
return success ? null : error;
|
|
1857
1844
|
}
|
|
1858
1845
|
|
|
1859
1846
|
override profileType(): HeapSnapshotProfileType {
|
|
@@ -34,17 +34,6 @@ export class ProfileHeader extends Common.ObjectWrapper.ObjectWrapper<EventTypes
|
|
|
34
34
|
this.dispatchEventToListeners(Events.UPDATE_STATUS, new StatusUpdate(subtitle, wait));
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
/**
|
|
38
|
-
* Must be implemented by subclasses.
|
|
39
|
-
*/
|
|
40
|
-
createSidebarTreeElement(_dataDisplayDelegate: DataDisplayDelegate): UI.TreeOutline.TreeElement {
|
|
41
|
-
throw new Error('Not implemented.');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
createView(_dataDisplayDelegate: DataDisplayDelegate): UI.Widget.Widget {
|
|
45
|
-
throw new Error('Not implemented.');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
37
|
removeTempFile(): void {
|
|
49
38
|
if (this.tempFile) {
|
|
50
39
|
this.tempFile.remove();
|
|
@@ -167,10 +156,7 @@ export class ProfileType extends Common.ObjectWrapper.ObjectWrapper<ProfileEvent
|
|
|
167
156
|
}
|
|
168
157
|
|
|
169
158
|
getProfiles(): ProfileHeader[] {
|
|
170
|
-
|
|
171
|
-
return this.#profileBeingRecorded !== profile;
|
|
172
|
-
}
|
|
173
|
-
return this.profiles.filter(isFinished.bind(this));
|
|
159
|
+
return this.profiles.filter(profile => this.#profileBeingRecorded !== profile);
|
|
174
160
|
}
|
|
175
161
|
|
|
176
162
|
customContent(): Element|null {
|
|
@@ -2,21 +2,13 @@
|
|
|
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 {DetachedElementsProfileType} from './HeapDetachedElementsView.js';
|
|
6
|
-
import {SamplingHeapProfileType} from './HeapProfileView.js';
|
|
7
|
-
import {HeapSnapshotProfileType, TrackingHeapSnapshotProfileType} from './HeapSnapshotView.js';
|
|
5
|
+
import type {DetachedElementsProfileType} from './HeapDetachedElementsView.js';
|
|
6
|
+
import type {SamplingHeapProfileType} from './HeapProfileView.js';
|
|
7
|
+
import type {HeapSnapshotProfileType, TrackingHeapSnapshotProfileType} from './HeapSnapshotView.js';
|
|
8
8
|
|
|
9
|
-
export
|
|
9
|
+
export interface ProfileTypeRegistry {
|
|
10
10
|
heapSnapshotProfileType: HeapSnapshotProfileType;
|
|
11
11
|
samplingHeapProfileType: SamplingHeapProfileType;
|
|
12
12
|
trackingHeapSnapshotProfileType: TrackingHeapSnapshotProfileType;
|
|
13
13
|
detachedElementProfileType: DetachedElementsProfileType;
|
|
14
|
-
constructor() {
|
|
15
|
-
this.heapSnapshotProfileType = new HeapSnapshotProfileType();
|
|
16
|
-
this.samplingHeapProfileType = new SamplingHeapProfileType();
|
|
17
|
-
this.trackingHeapSnapshotProfileType = new TrackingHeapSnapshotProfileType();
|
|
18
|
-
this.detachedElementProfileType = new DetachedElementsProfileType();
|
|
19
|
-
}
|
|
20
14
|
}
|
|
21
|
-
|
|
22
|
-
export const instance = new ProfileTypeRegistry();
|
|
@@ -19,8 +19,7 @@ import * as UI from '../../ui/legacy/legacy.js';
|
|
|
19
19
|
import {BottomUpProfileDataGridTree} from './BottomUpProfileDataGrid.js';
|
|
20
20
|
import {type Formatter, type ProfileDataGridNode, ProfileDataGridTree} from './ProfileDataGrid.js';
|
|
21
21
|
import {ProfileFlameChart, type ProfileFlameChartDataProvider} from './ProfileFlameChartDataProvider.js';
|
|
22
|
-
import {
|
|
23
|
-
import {ProfileSidebarTreeElement} from './ProfileSidebarTreeElement.js';
|
|
22
|
+
import {ProfileHeader, type ProfileType} from './ProfileHeader.js';
|
|
24
23
|
import {TopDownProfileDataGridTree} from './TopDownProfileDataGrid.js';
|
|
25
24
|
|
|
26
25
|
const UIStrings = {
|
|
@@ -547,10 +546,6 @@ export class WritableProfileHeader extends ProfileHeader implements Common.Strin
|
|
|
547
546
|
this.removeTempFile();
|
|
548
547
|
}
|
|
549
548
|
|
|
550
|
-
override createSidebarTreeElement(panel: DataDisplayDelegate): ProfileSidebarTreeElement {
|
|
551
|
-
return new ProfileSidebarTreeElement(panel, this, 'profile-sidebar-tree-item');
|
|
552
|
-
}
|
|
553
|
-
|
|
554
549
|
override canSaveToFile(): boolean {
|
|
555
550
|
return !this.fromFile();
|
|
556
551
|
}
|
|
@@ -39,7 +39,19 @@ import objectValueStyles from '../../ui/legacy/components/object_ui/objectValue.
|
|
|
39
39
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
40
40
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
41
41
|
|
|
42
|
+
import {
|
|
43
|
+
DetachedElementsProfileHeader,
|
|
44
|
+
DetachedElementsProfileType,
|
|
45
|
+
DetachedElementsProfileView
|
|
46
|
+
} from './HeapDetachedElementsView.js';
|
|
42
47
|
import heapProfilerStyles from './heapProfiler.css.js';
|
|
48
|
+
import {HeapProfileView, SamplingHeapProfileHeader, SamplingHeapProfileType} from './HeapProfileView.js';
|
|
49
|
+
import {
|
|
50
|
+
HeapProfileHeader,
|
|
51
|
+
HeapSnapshotProfileType,
|
|
52
|
+
HeapSnapshotView,
|
|
53
|
+
TrackingHeapSnapshotProfileType
|
|
54
|
+
} from './HeapSnapshotView.js';
|
|
43
55
|
import {
|
|
44
56
|
type DataDisplayDelegate,
|
|
45
57
|
ProfileEvents as ProfileTypeEvents,
|
|
@@ -50,6 +62,8 @@ import {Events as ProfileLauncherEvents, ProfileLauncherView} from './ProfileLau
|
|
|
50
62
|
import {ProfileSidebarTreeElement} from './ProfileSidebarTreeElement.js';
|
|
51
63
|
import profilesPanelStyles from './profilesPanel.css.js';
|
|
52
64
|
import profilesSidebarTreeStyles from './profilesSidebarTree.css.js';
|
|
65
|
+
import type {ProfileTypeRegistry} from './ProfileTypeRegistry.js';
|
|
66
|
+
import {WritableProfileHeader} from './ProfileView.js';
|
|
53
67
|
|
|
54
68
|
const UIStrings = {
|
|
55
69
|
/**
|
|
@@ -82,8 +96,35 @@ const UIStrings = {
|
|
|
82
96
|
} as const;
|
|
83
97
|
const str_ = i18n.i18n.registerUIStrings('panels/profiler/ProfilesPanel.ts', UIStrings);
|
|
84
98
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
99
|
+
|
|
100
|
+
function createSidebarTreeElement(
|
|
101
|
+
profiler: ProfileHeader, dataDisplayDelegate: DataDisplayDelegate): ProfileSidebarTreeElement {
|
|
102
|
+
if (profiler instanceof HeapProfileHeader) {
|
|
103
|
+
return new ProfileSidebarTreeElement(dataDisplayDelegate, profiler, 'heap-snapshot-sidebar-tree-item');
|
|
104
|
+
}
|
|
105
|
+
if (profiler instanceof WritableProfileHeader) {
|
|
106
|
+
return new ProfileSidebarTreeElement(dataDisplayDelegate, profiler, 'profile-sidebar-tree-item');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
throw new Error('Not implemented.');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function createView(profiler: ProfileHeader, dataDisplayDelegate: DataDisplayDelegate, registry: ProfileTypeRegistry):
|
|
113
|
+
UI.View.SimpleView {
|
|
114
|
+
if (profiler instanceof HeapProfileHeader) {
|
|
115
|
+
return new HeapSnapshotView(dataDisplayDelegate, profiler, registry);
|
|
116
|
+
}
|
|
117
|
+
if (profiler instanceof SamplingHeapProfileHeader) {
|
|
118
|
+
return new HeapProfileView(profiler);
|
|
119
|
+
}
|
|
120
|
+
if (profiler instanceof DetachedElementsProfileHeader) {
|
|
121
|
+
return new DetachedElementsProfileView(dataDisplayDelegate, profiler);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
throw new Error('Not implemented.');
|
|
125
|
+
}
|
|
126
|
+
|
|
85
127
|
export class ProfilesPanel extends UI.Panel.PanelWithSidebar implements DataDisplayDelegate {
|
|
86
|
-
readonly profileTypes: ProfileType[];
|
|
87
128
|
profilesItemTreeElement: ProfilesSidebarTreeElement;
|
|
88
129
|
sidebarTree: UI.TreeOutline.TreeOutlineInShadow;
|
|
89
130
|
profileViews: HTMLDivElement;
|
|
@@ -102,9 +143,18 @@ export class ProfilesPanel extends UI.Panel.PanelWithSidebar implements DataDisp
|
|
|
102
143
|
typeIdToSidebarSection: Record<string, ProfileTypeSidebarSection>;
|
|
103
144
|
fileSelectorElement!: HTMLInputElement;
|
|
104
145
|
selectedProfileType?: ProfileType;
|
|
105
|
-
|
|
146
|
+
static registry: ProfileTypeRegistry = {
|
|
147
|
+
heapSnapshotProfileType: new HeapSnapshotProfileType(),
|
|
148
|
+
samplingHeapProfileType: new SamplingHeapProfileType(),
|
|
149
|
+
trackingHeapSnapshotProfileType: new TrackingHeapSnapshotProfileType(),
|
|
150
|
+
detachedElementProfileType: new DetachedElementsProfileType(),
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
constructor(
|
|
154
|
+
name: string,
|
|
155
|
+
recordingActionId: string,
|
|
156
|
+
) {
|
|
106
157
|
super(name);
|
|
107
|
-
this.profileTypes = profileTypes;
|
|
108
158
|
this.registerRequiredCSS(objectValueStyles, profilesPanelStyles, heapProfilerStyles);
|
|
109
159
|
|
|
110
160
|
const mainContainer = new UI.Widget.VBox();
|
|
@@ -179,6 +229,10 @@ export class ProfilesPanel extends UI.Panel.PanelWithSidebar implements DataDisp
|
|
|
179
229
|
SDK.HeapProfilerModel.HeapProfilerModel, this.updateProfileTypeSpecificUI, this);
|
|
180
230
|
}
|
|
181
231
|
|
|
232
|
+
get profileTypes(): ProfileType[] {
|
|
233
|
+
return Object.values(ProfilesPanel.registry);
|
|
234
|
+
}
|
|
235
|
+
|
|
182
236
|
onKeyDown(event: KeyboardEvent): void {
|
|
183
237
|
let handled = false;
|
|
184
238
|
if (event.key === 'ArrowDown' && !event.altKey) {
|
|
@@ -437,7 +491,7 @@ export class ProfilesPanel extends UI.Panel.PanelWithSidebar implements DataDisp
|
|
|
437
491
|
if (index !== -1) {
|
|
438
492
|
return this.profileToView[index].view;
|
|
439
493
|
}
|
|
440
|
-
const view =
|
|
494
|
+
const view = createView(profile, this, ProfilesPanel.registry);
|
|
441
495
|
view.element.classList.add('profile-view');
|
|
442
496
|
this.profileToView.push({profile, view});
|
|
443
497
|
return view;
|
|
@@ -490,9 +544,8 @@ export class ProfileTypeSidebarSection extends UI.TreeOutline.TreeElement {
|
|
|
490
544
|
addProfileHeader(profile: ProfileHeader): void {
|
|
491
545
|
this.hidden = false;
|
|
492
546
|
const profileType = profile.profileType();
|
|
493
|
-
let sidebarParent:
|
|
494
|
-
const profileTreeElement =
|
|
495
|
-
(profile.createSidebarTreeElement(this.dataDisplayDelegate) as ProfileSidebarTreeElement);
|
|
547
|
+
let sidebarParent: ProfileGroupSidebarTreeElement|null|this = this;
|
|
548
|
+
const profileTreeElement = createSidebarTreeElement(profile, this.dataDisplayDelegate);
|
|
496
549
|
this.profileTreeElements.push(profileTreeElement);
|
|
497
550
|
|
|
498
551
|
if (!profile.fromFile() && profileType.profileBeingRecorded() !== profile) {
|
|
@@ -675,28 +675,33 @@ type InfoWidgetView = (input: InfoWidgetViewInput, output: undefined, target: HT
|
|
|
675
675
|
|
|
676
676
|
const INFO_WIDGET_VIEW: InfoWidgetView = (input, _output, target) => {
|
|
677
677
|
// clang-format off
|
|
678
|
-
render(
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
678
|
+
render(html`
|
|
679
|
+
<devtools-tabbed-pane>${input.type === undefined ? html`
|
|
680
|
+
<devtools-widget
|
|
681
|
+
id="request" title=${i18nString(UIStrings.request)}
|
|
682
|
+
?selected=${input.selectedTab === 'request'} disabled
|
|
683
|
+
${widget(UI.EmptyWidget.EmptyWidget, {
|
|
684
|
+
header: i18nString(UIStrings.noMessageSelected),
|
|
685
|
+
text: i18nString(UIStrings.selectAMessageToView)})}>
|
|
686
|
+
</devtools-widget>
|
|
687
|
+
<devtools-widget
|
|
688
|
+
id="response" title=${i18nString(UIStrings.response)}
|
|
689
|
+
?selected=${input.selectedTab === 'response'}
|
|
690
|
+
${widget(UI.EmptyWidget.EmptyWidget, {
|
|
691
|
+
header: i18nString(UIStrings.noMessageSelected),
|
|
692
|
+
text: i18nString(UIStrings.selectAMessageToView)})}>
|
|
693
|
+
</devtools-widget>`: html`
|
|
694
|
+
<devtools-widget
|
|
695
|
+
id="request" title=${i18nString(UIStrings.request)}
|
|
696
|
+
?selected=${input.selectedTab === 'request'} ?disabled=${input.type !== 'sent'}
|
|
697
|
+
${widget(SourceFrame.JSONView.SearchableJsonView, {jsonObject: input.request})}>
|
|
698
|
+
</devtools-widget>
|
|
699
|
+
<devtools-widget
|
|
700
|
+
id="response" title=${i18nString(UIStrings.response)}
|
|
701
|
+
?selected=${input.selectedTab === 'response'}
|
|
702
|
+
${widget(SourceFrame.JSONView.SearchableJsonView, {jsonObject: input.response})}>
|
|
703
|
+
</devtools-widget>`}
|
|
704
|
+
</devtools-tabbed-pane>`, target);
|
|
700
705
|
// clang-format on
|
|
701
706
|
};
|
|
702
707
|
|
|
@@ -106,7 +106,7 @@ export class EventsTimelineTreeView extends TimelineTreeView {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
override showDetailsForNode(node: Trace.Extras.TraceTree.Node): boolean {
|
|
109
|
-
const parsedTrace = this.parsedTrace
|
|
109
|
+
const parsedTrace = this.parsedTrace;
|
|
110
110
|
if (!parsedTrace) {
|
|
111
111
|
return false;
|
|
112
112
|
}
|
|
@@ -76,7 +76,7 @@ export class ThirdPartyTreeViewWidget extends TimelineTreeView.TimelineTreeView
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
override buildTree(): Trace.Extras.TraceTree.Node {
|
|
79
|
-
const parsedTrace = this.parsedTrace
|
|
79
|
+
const parsedTrace = this.parsedTrace;
|
|
80
80
|
const entityMapper = this.entityMapper();
|
|
81
81
|
|
|
82
82
|
if (!parsedTrace || !entityMapper) {
|
|
@@ -96,7 +96,7 @@ export class ThirdPartyTreeViewWidget extends TimelineTreeView.TimelineTreeView
|
|
|
96
96
|
const filter = new Trace.Extras.TraceFilter.VisibleEventsFilter(
|
|
97
97
|
Trace.Styles.visibleTypes().concat([Trace.Types.Events.Name.SYNTHETIC_NETWORK_REQUEST]));
|
|
98
98
|
|
|
99
|
-
const node = new Trace.Extras.TraceTree.BottomUpRootNode(this.selectedEvents
|
|
99
|
+
const node = new Trace.Extras.TraceTree.BottomUpRootNode(this.selectedEvents, {
|
|
100
100
|
textFilter: this.textFilter(),
|
|
101
101
|
filters: [filter],
|
|
102
102
|
startTime: this.startTime,
|
|
@@ -54,7 +54,6 @@ import * as TraceBounds from '../../services/trace_bounds/trace_bounds.js';
|
|
|
54
54
|
import * as Tracing from '../../services/tracing/tracing.js';
|
|
55
55
|
import * as Adorners from '../../ui/components/adorners/adorners.js';
|
|
56
56
|
import * as Dialogs from '../../ui/components/dialogs/dialogs.js';
|
|
57
|
-
import * as Snackbars from '../../ui/components/snackbars/snackbars.js';
|
|
58
57
|
import {Link} from '../../ui/kit/kit.js';
|
|
59
58
|
import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
|
|
60
59
|
import * as SettingsUI from '../../ui/legacy/components/settings_ui/settings_ui.js';
|
|
@@ -311,10 +310,6 @@ const UIStrings = {
|
|
|
311
310
|
* @description Title of the shortcuts dialog shown to the user that lists keyboard shortcuts.
|
|
312
311
|
*/
|
|
313
312
|
shortcutsDialogTitle: 'Keyboard shortcuts for flamechart',
|
|
314
|
-
/**
|
|
315
|
-
* @description Notification shown to the user whenever DevTools receives an external request.
|
|
316
|
-
*/
|
|
317
|
-
externalRequestReceived: '`DevTools` received an external request',
|
|
318
313
|
} as const;
|
|
319
314
|
const str_ = i18n.i18n.registerUIStrings('panels/timeline/TimelinePanel.ts', UIStrings);
|
|
320
315
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
@@ -407,7 +402,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
407
402
|
private traceLoadStart!: Trace.Types.Timing.Milli|null;
|
|
408
403
|
|
|
409
404
|
#traceEngineModel: Trace.TraceModel.Model;
|
|
410
|
-
#externalAIConversationData: AiAssistanceModel.ConversationHandler.ExternalPerformanceAIConversationData|null = null;
|
|
411
405
|
#sourceMapsResolver: SourceMapsResolver.SourceMapsResolver|null = null;
|
|
412
406
|
#entityMapper: Trace.EntityMapper.EntityMapper|null = null;
|
|
413
407
|
#onSourceMapsNodeNamesResolvedBound = this.#onSourceMapsNodeNamesResolved.bind(this);
|
|
@@ -976,39 +970,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
976
970
|
return this.#traceEngineModel;
|
|
977
971
|
}
|
|
978
972
|
|
|
979
|
-
getOrCreateExternalAIConversationData(): AiAssistanceModel.ConversationHandler.ExternalPerformanceAIConversationData {
|
|
980
|
-
if (!this.#externalAIConversationData) {
|
|
981
|
-
const conversationHandler = AiAssistanceModel.ConversationHandler.ConversationHandler.instance();
|
|
982
|
-
const focus = AiAssistanceModel.AIContext.getPerformanceAgentFocusFromModel(this.model);
|
|
983
|
-
if (!focus) {
|
|
984
|
-
throw new Error('could not create performance agent focus');
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
const conversation = new AiAssistanceModel.AiConversation.AiConversation({
|
|
988
|
-
type: AiAssistanceModel.AiHistoryStorage.ConversationType.PERFORMANCE,
|
|
989
|
-
data: [],
|
|
990
|
-
isReadOnly: true,
|
|
991
|
-
aidaClient: conversationHandler.aidaClient,
|
|
992
|
-
isExternal: true,
|
|
993
|
-
});
|
|
994
|
-
|
|
995
|
-
const selected = new AiAssistanceModel.PerformanceAgent.PerformanceTraceContext(focus);
|
|
996
|
-
selected.external = true;
|
|
997
|
-
|
|
998
|
-
this.#externalAIConversationData = {
|
|
999
|
-
conversationHandler,
|
|
1000
|
-
conversation,
|
|
1001
|
-
selected,
|
|
1002
|
-
};
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
return this.#externalAIConversationData;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
invalidateExternalAIConversationData(): void {
|
|
1009
|
-
this.#externalAIConversationData = null;
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
973
|
/**
|
|
1013
974
|
* NOTE: this method only exists to enable some layout tests to be migrated to the new engine.
|
|
1014
975
|
* DO NOT use this method within DevTools. It is marked as deprecated so
|
|
@@ -3102,120 +3063,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
3102
3063
|
return trace;
|
|
3103
3064
|
}
|
|
3104
3065
|
|
|
3105
|
-
static async *
|
|
3106
|
-
handleExternalRecordRequest(): AsyncGenerator<
|
|
3107
|
-
AiAssistanceModel.AiAgent.ExternalRequestResponse, AiAssistanceModel.AiAgent.ExternalRequestResponse> {
|
|
3108
|
-
yield {
|
|
3109
|
-
type: AiAssistanceModel.AiAgent.ExternalRequestResponseType.NOTIFICATION,
|
|
3110
|
-
message: 'Recording performance trace',
|
|
3111
|
-
};
|
|
3112
|
-
TimelinePanel.instance().invalidateExternalAIConversationData();
|
|
3113
|
-
void VisualLogging.logFunctionCall('timeline.record-reload', 'external');
|
|
3114
|
-
Snackbars.Snackbar.Snackbar.show({message: i18nString(UIStrings.externalRequestReceived)});
|
|
3115
|
-
|
|
3116
|
-
const panelInstance = TimelinePanel.instance();
|
|
3117
|
-
// Given how the current UX works, it's nice to show the user the Perf
|
|
3118
|
-
// Panel so they see what's happening
|
|
3119
|
-
await UI.ViewManager.ViewManager.instance().showView('timeline');
|
|
3120
|
-
|
|
3121
|
-
function onRecordingCompleted(eventData: EventTypes[Events.RECORDING_COMPLETED]):
|
|
3122
|
-
AiAssistanceModel.AiAgent.ExternalRequestResponse {
|
|
3123
|
-
if ('errorText' in eventData) {
|
|
3124
|
-
return {
|
|
3125
|
-
type: AiAssistanceModel.AiAgent.ExternalRequestResponseType.ERROR,
|
|
3126
|
-
message: `Error running the trace: ${eventData.errorText}`,
|
|
3127
|
-
};
|
|
3128
|
-
}
|
|
3129
|
-
|
|
3130
|
-
const parsedTrace = panelInstance.model.parsedTrace(eventData.traceIndex);
|
|
3131
|
-
if (!parsedTrace || !parsedTrace.insights || parsedTrace.insights.size === 0) {
|
|
3132
|
-
return {
|
|
3133
|
-
type: AiAssistanceModel.AiAgent.ExternalRequestResponseType.ERROR,
|
|
3134
|
-
message: 'The trace was loaded successfully but no Insights were detected.',
|
|
3135
|
-
};
|
|
3136
|
-
}
|
|
3137
|
-
|
|
3138
|
-
const insightSetId = Array.from(parsedTrace.insights.keys()).find(k => k !== 'NO_NAVIGATION');
|
|
3139
|
-
if (!insightSetId) {
|
|
3140
|
-
return {
|
|
3141
|
-
type: AiAssistanceModel.AiAgent.ExternalRequestResponseType.ERROR,
|
|
3142
|
-
message: 'The trace was loaded successfully but no navigation was detected.',
|
|
3143
|
-
};
|
|
3144
|
-
}
|
|
3145
|
-
|
|
3146
|
-
const insightsForNav = parsedTrace.insights.get(insightSetId);
|
|
3147
|
-
if (!insightsForNav) {
|
|
3148
|
-
return {
|
|
3149
|
-
type: AiAssistanceModel.AiAgent.ExternalRequestResponseType.ERROR,
|
|
3150
|
-
message: 'The trace was loaded successfully but no Insights were detected.',
|
|
3151
|
-
};
|
|
3152
|
-
}
|
|
3153
|
-
|
|
3154
|
-
let responseTextForNonPassedInsights = '';
|
|
3155
|
-
// We still return info on the passed insights, but we put it at the
|
|
3156
|
-
// bottom of the response under a heading.
|
|
3157
|
-
let responseTextForPassedInsights = '';
|
|
3158
|
-
|
|
3159
|
-
// TODO(b/442392194): use PerformanceTraceFormatter summary instead.
|
|
3160
|
-
for (const insight of Object.values(insightsForNav.model)) {
|
|
3161
|
-
const focus = AiAssistanceModel.AIContext.AgentFocus.fromParsedTrace(parsedTrace);
|
|
3162
|
-
const formatter = new AiAssistanceModel.PerformanceInsightFormatter.PerformanceInsightFormatter(focus, insight);
|
|
3163
|
-
if (!formatter.insightIsSupported()) {
|
|
3164
|
-
// Not all Insights are integrated with "Ask AI" yet, let's avoid
|
|
3165
|
-
// filling up the response with those ones because there will be no
|
|
3166
|
-
// useful information.
|
|
3167
|
-
continue;
|
|
3168
|
-
}
|
|
3169
|
-
|
|
3170
|
-
const formatted = formatter.formatInsight({headingLevel: 3});
|
|
3171
|
-
|
|
3172
|
-
if (insight.state === 'pass') {
|
|
3173
|
-
responseTextForPassedInsights += `${formatted}\n\n`;
|
|
3174
|
-
continue;
|
|
3175
|
-
} else {
|
|
3176
|
-
responseTextForNonPassedInsights += `${formatted}\n\n`;
|
|
3177
|
-
}
|
|
3178
|
-
}
|
|
3179
|
-
|
|
3180
|
-
const finalText = `# Trace recording results
|
|
3181
|
-
|
|
3182
|
-
## Non-passing insights:
|
|
3183
|
-
|
|
3184
|
-
These insights highlight potential problems and opportunities to improve performance.
|
|
3185
|
-
${responseTextForNonPassedInsights}
|
|
3186
|
-
|
|
3187
|
-
## Passing insights:
|
|
3188
|
-
|
|
3189
|
-
These insights are passing, which means they are not considered to highlight considerable performance problems.
|
|
3190
|
-
${responseTextForPassedInsights}`;
|
|
3191
|
-
|
|
3192
|
-
return {
|
|
3193
|
-
type: AiAssistanceModel.AiAgent.ExternalRequestResponseType.ANSWER,
|
|
3194
|
-
message: finalText,
|
|
3195
|
-
devToolsLogs: [],
|
|
3196
|
-
};
|
|
3197
|
-
}
|
|
3198
|
-
|
|
3199
|
-
return await new Promise(resolve => {
|
|
3200
|
-
function listener(e: Common.EventTarget.EventTargetEvent<EventTypes[Events.RECORDING_COMPLETED]>): void {
|
|
3201
|
-
resolve(onRecordingCompleted(e.data));
|
|
3202
|
-
panelInstance.removeEventListener(Events.RECORDING_COMPLETED, listener);
|
|
3203
|
-
}
|
|
3204
|
-
panelInstance.addEventListener(Events.RECORDING_COMPLETED, listener);
|
|
3205
|
-
|
|
3206
|
-
panelInstance.recordReload();
|
|
3207
|
-
});
|
|
3208
|
-
}
|
|
3209
|
-
|
|
3210
|
-
static async handleExternalAnalyzeRequest(prompt: string): Promise<AsyncGenerator<
|
|
3211
|
-
AiAssistanceModel.AiAgent.ExternalRequestResponse, AiAssistanceModel.AiAgent.ExternalRequestResponse>> {
|
|
3212
|
-
const data = TimelinePanel.instance().getOrCreateExternalAIConversationData();
|
|
3213
|
-
return await data.conversationHandler.handleExternalRequest({
|
|
3214
|
-
conversationType: AiAssistanceModel.AiHistoryStorage.ConversationType.PERFORMANCE,
|
|
3215
|
-
prompt,
|
|
3216
|
-
data,
|
|
3217
|
-
});
|
|
3218
|
-
}
|
|
3219
3066
|
}
|
|
3220
3067
|
|
|
3221
3068
|
export const enum State {
|
|
@@ -3291,6 +3138,17 @@ export class TimeRangeRevealer implements Common.Revealer.Revealer<Utils.Helpers
|
|
|
3291
3138
|
}
|
|
3292
3139
|
}
|
|
3293
3140
|
|
|
3141
|
+
export class BottomUpProfileRevealer implements Common.Revealer.Revealer<Utils.Helpers.RevealableBottomUpProfile> {
|
|
3142
|
+
async reveal(revealable: Utils.Helpers.RevealableBottomUpProfile): Promise<void> {
|
|
3143
|
+
await UI.ViewManager.ViewManager.instance().showView('timeline');
|
|
3144
|
+
const panel = TimelinePanel.instance();
|
|
3145
|
+
TraceBounds.TraceBounds.BoundsManager.instance().setTimelineVisibleWindow(
|
|
3146
|
+
revealable.bounds, {ignoreMiniMapBounds: true, shouldAnimate: true});
|
|
3147
|
+
panel.select(null);
|
|
3148
|
+
panel.getFlameChart().selectDetailsViewTab(Tab.BottomUp, null);
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
|
|
3294
3152
|
export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
|
|
3295
3153
|
handleAction(context: UI.Context.Context, actionId: string): boolean {
|
|
3296
3154
|
const panel = context.flavor(TimelinePanel);
|