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.
Files changed (78) hide show
  1. package/front_end/Images/src/dots-circle.svg +10 -0
  2. package/front_end/core/host/UserMetrics.ts +0 -1
  3. package/front_end/core/platform/api/HostRuntime.ts +9 -6
  4. package/front_end/core/platform/browser/HostRuntime.ts +2 -2
  5. package/front_end/core/platform/node/HostRuntime.ts +7 -7
  6. package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
  7. package/front_end/core/root/ExperimentNames.ts +0 -1
  8. package/front_end/core/sdk/CrashReportContextModel.ts +28 -0
  9. package/front_end/core/sdk/sdk.ts +2 -2
  10. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +3 -3
  11. package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker-entrypoint.ts +5 -4
  12. package/front_end/entrypoints/main/MainImpl.ts +0 -101
  13. package/front_end/models/ai_assistance/ChangeManager.ts +6 -6
  14. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +112 -5
  15. package/front_end/models/ai_assistance/agents/AiAgent.ts +9 -25
  16. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +2 -2
  17. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +6 -3
  18. package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +10 -9
  19. package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +313 -0
  20. package/front_end/models/ai_assistance/agents/FileAgent.ts +15 -1
  21. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +15 -1
  22. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +19 -8
  23. package/front_end/models/ai_assistance/agents/StylingAgent.ts +35 -278
  24. package/front_end/models/ai_assistance/ai_assistance.ts +0 -2
  25. package/front_end/models/javascript_metadata/NativeFunctions.js +1 -5
  26. package/front_end/models/web_mcp/WebMCPModel.ts +187 -0
  27. package/front_end/models/web_mcp/web_mcp.ts +9 -0
  28. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -1
  29. package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
  30. package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +88 -0
  31. package/front_end/panels/ai_assistance/components/ChatMessage.ts +149 -49
  32. package/front_end/panels/ai_assistance/components/ChatView.ts +11 -15
  33. package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +13 -4
  34. package/front_end/panels/ai_assistance/components/chatMessage.css +53 -1
  35. package/front_end/panels/ai_assistance/components/chatView.css +0 -10
  36. package/front_end/panels/ai_assistance/components/exportForAgentsDialog.css +13 -0
  37. package/front_end/panels/application/WebMCPView.ts +471 -25
  38. package/front_end/panels/application/webMCPView.css +53 -2
  39. package/front_end/panels/elements/ElementsTreeElement.ts +1 -1
  40. package/front_end/panels/elements/ElementsTreeOutline.ts +87 -0
  41. package/front_end/panels/elements/StylePropertiesSection.ts +0 -4
  42. package/front_end/panels/elements/elements.ts +3 -0
  43. package/front_end/panels/elements/elementsTreeOutline.css +21 -0
  44. package/front_end/panels/elements/stylePropertiesTreeOutline.css +7 -0
  45. package/front_end/panels/lighthouse/LighthousePanel.ts +7 -1
  46. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +25 -2
  47. package/front_end/panels/profiler/HeapDetachedElementsView.ts +0 -4
  48. package/front_end/panels/profiler/HeapProfileView.ts +0 -4
  49. package/front_end/panels/profiler/HeapProfilerPanel.ts +4 -13
  50. package/front_end/panels/profiler/HeapSnapshotProxy.ts +2 -6
  51. package/front_end/panels/profiler/HeapSnapshotView.ts +19 -32
  52. package/front_end/panels/profiler/ProfileHeader.ts +1 -15
  53. package/front_end/panels/profiler/ProfileTypeRegistry.ts +4 -12
  54. package/front_end/panels/profiler/ProfileView.ts +1 -6
  55. package/front_end/panels/profiler/ProfilesPanel.ts +60 -7
  56. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +27 -22
  57. package/front_end/panels/timeline/EventsTimelineTreeView.ts +1 -1
  58. package/front_end/panels/timeline/ThirdPartyTreeView.ts +2 -2
  59. package/front_end/panels/timeline/TimelinePanel.ts +11 -153
  60. package/front_end/panels/timeline/TimelineTreeView.ts +147 -48
  61. package/front_end/panels/timeline/TimelineUIUtils.ts +2 -1
  62. package/front_end/panels/timeline/components/CWVMetrics.ts +18 -2
  63. package/front_end/panels/timeline/timeline-meta.ts +11 -0
  64. package/front_end/panels/timeline/utils/Helpers.ts +5 -0
  65. package/front_end/third_party/chromium/README.chromium +1 -1
  66. package/front_end/ui/components/markdown_view/CodeBlock.ts +47 -1
  67. package/front_end/ui/components/markdown_view/codeBlock.css +8 -0
  68. package/front_end/ui/legacy/FilterBar.ts +2 -0
  69. package/front_end/ui/legacy/SplitWidget.ts +33 -27
  70. package/front_end/ui/legacy/TabbedPane.ts +123 -3
  71. package/front_end/ui/legacy/Widget.ts +95 -48
  72. package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -1
  73. package/front_end/ui/legacy/components/utils/jsUtils.css +2 -0
  74. package/front_end/ui/legacy/infobar.css +1 -0
  75. package/front_end/ui/visual_logging/KnownContextValues.ts +6 -1
  76. package/package.json +1 -1
  77. package/front_end/core/sdk/WebMCPModel.ts +0 -104
  78. 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 {ProfileSidebarTreeElement} from './ProfileSidebarTreeElement.js';
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(dataDisplayDelegate: DataDisplayDelegate, profile: HeapProfileHeader) {
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.searchResults = [];
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 = instance.trackingHeapSnapshotProfileType.recordAllocationStacksSetting().get();
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() !== instance.trackingHeapSnapshotProfileType) {
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() !== instance.trackingHeapSnapshotProfileType) {
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 = (event.data as HeapSnapshotGridNode);
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 showOptionToExposeInternalsInHeapSnapshot ? exposeInternalsInHeapSnapshotCheckbox : null;
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 = (await this.tempFile.copyToOutputStream(fileOutputStream, this.onChunkTransferred.bind(this)) as {
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
- if (!success) {
1849
- const error = (reader.error() as {
1850
- message: string,
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 : reader.error();
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
- function isFinished(this: ProfileType, profile: ProfileHeader): boolean {
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 class ProfileTypeRegistry {
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 {type DataDisplayDelegate, ProfileHeader, type ProfileType} from './ProfileHeader.js';
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
- constructor(name: string, profileTypes: ProfileType[], recordingActionId: string) {
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 = profile.createView(this);
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: (ProfileGroupSidebarTreeElement|null)|this = this;
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(widget(UI.TabbedPane.TabbedPane, {
679
- tabs: [
680
- {
681
- id: 'request',
682
- title: i18nString(UIStrings.request),
683
- view: input.type === undefined ?
684
- new UI.EmptyWidget.EmptyWidget(
685
- i18nString(UIStrings.noMessageSelected), i18nString(UIStrings.selectAMessageToView)) :
686
- SourceFrame.JSONView.JSONView.createViewSync(input.request || null),
687
- enabled: input.type === 'sent',
688
- selected: input.selectedTab === 'request',
689
- },
690
- {
691
- id: 'response',
692
- title: i18nString(UIStrings.response),
693
- view: input.type === undefined ?
694
- new UI.EmptyWidget.EmptyWidget(
695
- i18nString(UIStrings.noMessageSelected), i18nString(UIStrings.selectAMessageToView)) :
696
- SourceFrame.JSONView.JSONView.createViewSync(input.response || null),
697
- selected: input.selectedTab === 'response',
698
- }
699
- ]}), target);
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);