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
@@ -178,8 +178,8 @@ export class TimelineTreeView extends
178
178
  private lastHoveredProfileNode!: Trace.Extras.TraceTree.Node|null;
179
179
  private textFilterInternal!: TimelineRegExp;
180
180
  private taskFilter!: Trace.Extras.TraceFilter.ExclusiveNameFilter;
181
- protected startTime!: Trace.Types.Timing.Milli;
182
- protected endTime!: Trace.Types.Timing.Milli;
181
+ protected startTimeInternal!: Trace.Types.Timing.Milli;
182
+ protected endTimeInternal!: Trace.Types.Timing.Milli;
183
183
  splitWidget!: UI.SplitWidget.SplitWidget;
184
184
  detailsView!: UI.Widget.Widget;
185
185
  private searchableView!: UI.SearchableView.SearchableView;
@@ -197,6 +197,10 @@ export class TimelineTreeView extends
197
197
  #entityMapper: Trace.EntityMapper.EntityMapper|null = null;
198
198
  #lastHighlightedEvent: HTMLElement|null = null;
199
199
  eventToTreeNode = new WeakMap<Trace.Types.Events.Event, Trace.Extras.TraceTree.Node>();
200
+ // Compact mode is used to render the tree view in a more compact UI,
201
+ // suitable for AI assistance widgets. It removes sidebars and toolbars.
202
+ #compactMode = false;
203
+ #maxLinkLength: number|undefined = undefined;
200
204
 
201
205
  /**
202
206
  * Determines if the first child in the data grid will be selected
@@ -213,12 +217,85 @@ export class TimelineTreeView extends
213
217
  this.searchResults = [];
214
218
  }
215
219
 
220
+ get selectedEvents(): Trace.Types.Events.Event[] {
221
+ return this.#selectedEvents || [];
222
+ }
223
+
224
+ set selectedEvents(selectedEvents: Trace.Types.Events.Event[]|null) {
225
+ this.#selectedEvents = selectedEvents;
226
+ this.refreshTree();
227
+ }
228
+
229
+ set parsedTrace(parsedTrace: Trace.TraceModel.ParsedTrace|null) {
230
+ this.#parsedTrace = parsedTrace;
231
+ this.refreshTree();
232
+ }
233
+
234
+ get parsedTrace(): Trace.TraceModel.ParsedTrace|null {
235
+ return this.#parsedTrace;
236
+ }
237
+
238
+ set startTime(startTime: Trace.Types.Timing.Milli) {
239
+ if (this.startTimeInternal === startTime) {
240
+ return;
241
+ }
242
+ this.startTimeInternal = startTime;
243
+ this.refreshTree();
244
+ }
245
+
246
+ get startTime(): Trace.Types.Timing.Milli {
247
+ return this.startTimeInternal;
248
+ }
249
+
250
+ set endTime(endTime: Trace.Types.Timing.Milli) {
251
+ if (this.endTimeInternal === endTime) {
252
+ return;
253
+ }
254
+ this.endTimeInternal = endTime;
255
+ this.refreshTree();
256
+ }
257
+
258
+ get endTime(): Trace.Types.Timing.Milli {
259
+ return this.endTimeInternal;
260
+ }
261
+
262
+ get compactMode(): boolean {
263
+ return this.#compactMode;
264
+ }
265
+
266
+ set compactMode(v: boolean) {
267
+ if (this.#compactMode === v) {
268
+ return;
269
+ }
270
+ this.#compactMode = v;
271
+ if (this.dataGrid) {
272
+ this.#applyCompactMode();
273
+ }
274
+ }
275
+
276
+ get maxLinkLength(): number|undefined {
277
+ return this.#maxLinkLength;
278
+ }
279
+
280
+ set maxLinkLength(maxLinkLength: number|undefined) {
281
+ this.#maxLinkLength = maxLinkLength;
282
+ }
283
+
284
+ #applyCompactMode(): void {
285
+ if (this.#compactMode && this.dataGrid) {
286
+ this.splitWidget?.detach();
287
+ this.dataGrid.asWidget().detach();
288
+ this.dataGrid.asWidget().show(this.element);
289
+ this.dataGrid.renderInline();
290
+ }
291
+ }
292
+
216
293
  #eventNameForSorting(event: Trace.Types.Events.Event): string {
217
294
  const name = TimelineUIUtils.eventTitle(event) || event.name;
218
- if (!this.#parsedTrace) {
295
+ if (!this.parsedTrace) {
219
296
  return name;
220
297
  }
221
- return name + ':@' + Trace.Handlers.Helpers.getNonResolvedURL(event, this.#parsedTrace.data);
298
+ return name + ':@' + Trace.Handlers.Helpers.getNonResolvedURL(event, this.parsedTrace.data);
222
299
  }
223
300
 
224
301
  setSearchableView(searchableView: UI.SearchableView.SearchableView): void {
@@ -239,9 +316,6 @@ export class TimelineTreeView extends
239
316
  entityMapper(): Trace.EntityMapper.EntityMapper|null {
240
317
  return this.#entityMapper;
241
318
  }
242
- parsedTrace(): Trace.TraceModel.ParsedTrace|null {
243
- return this.#parsedTrace;
244
- }
245
319
 
246
320
  isThirdPartyTreeView(): boolean {
247
321
  return false;
@@ -269,13 +343,6 @@ export class TimelineTreeView extends
269
343
  const columns: DataGrid.DataGrid.ColumnDescriptor[] = [];
270
344
  this.populateColumns(columns);
271
345
 
272
- this.splitWidget = new UI.SplitWidget.SplitWidget(true, true, 'timeline-tree-view-details-split-widget');
273
- const mainView = new UI.Widget.VBox();
274
- const toolbar = mainView.element.createChild('devtools-toolbar');
275
- toolbar.setAttribute('jslog', `${VisualLogging.toolbar()}`);
276
- toolbar.wrappable = true;
277
- this.populateToolbar(toolbar);
278
-
279
346
  this.dataGrid = new DataGrid.SortableDataGrid.SortableDataGrid({
280
347
  displayName: i18nString(UIStrings.performance),
281
348
  columns,
@@ -287,9 +354,22 @@ export class TimelineTreeView extends
287
354
  this.dataGrid.addEventListener(DataGrid.DataGrid.Events.OPENED_NODE, this.onGridNodeOpened, this);
288
355
  this.dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.LAST);
289
356
  this.dataGrid.setRowContextMenuCallback(this.onContextMenu.bind(this));
290
- this.dataGrid.asWidget().show(mainView.element);
291
357
  this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SELECTED_NODE, this.updateDetailsForSelection, this);
292
358
 
359
+ if (this.#compactMode) {
360
+ this.#applyCompactMode();
361
+ return;
362
+ }
363
+
364
+ this.splitWidget = new UI.SplitWidget.SplitWidget(true, true, 'timeline-tree-view-details-split-widget');
365
+ const mainView = new UI.Widget.VBox();
366
+ const toolbar = mainView.element.createChild('devtools-toolbar');
367
+ toolbar.setAttribute('jslog', `${VisualLogging.toolbar()}`);
368
+ toolbar.wrappable = true;
369
+ this.populateToolbar(toolbar);
370
+
371
+ this.dataGrid.asWidget().show(mainView.element);
372
+
293
373
  this.detailsView = new UI.Widget.VBox();
294
374
  this.detailsView.element.classList.add('timeline-details-view', 'timeline-details-view-body');
295
375
  this.splitWidget.setMainWidget(mainView);
@@ -299,6 +379,13 @@ export class TimelineTreeView extends
299
379
  this.splitWidget.addEventListener(UI.SplitWidget.Events.SHOW_MODE_CHANGED, this.onShowModeChanged, this);
300
380
  }
301
381
 
382
+ override wasShown(): void {
383
+ super.wasShown();
384
+ this.refreshTree();
385
+ this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SELECTED_NODE, this.#onDataGridSelectionChange, this);
386
+ this.dataGrid.addEventListener(DataGrid.DataGrid.Events.DESELECTED_NODE, this.#onDataGridDeselection, this);
387
+ }
388
+
302
389
  lastSelectedNode(): Trace.Extras.TraceTree.Node|null|undefined {
303
390
  return this.lastSelectedNodeInternal;
304
391
  }
@@ -375,11 +462,6 @@ export class TimelineTreeView extends
375
462
  toolbar.appendToolbarItem(textFilterUI);
376
463
  }
377
464
 
378
- selectedEvents(): Trace.Types.Events.Event[] {
379
- // TODO: can we make this type readonly?
380
- return this.#selectedEvents || [];
381
- }
382
-
383
465
  appendContextMenuItems(_contextMenu: UI.ContextMenu.ContextMenu, _node: Trace.Extras.TraceTree.Node): void {
384
466
  }
385
467
 
@@ -459,7 +541,7 @@ export class TimelineTreeView extends
459
541
 
460
542
  buildTopDownTree(doNotAggregate: boolean, eventGroupIdCallback: ((arg0: Trace.Types.Events.Event) => string)|null):
461
543
  Trace.Extras.TraceTree.Node {
462
- return new Trace.Extras.TraceTree.TopDownRootNode(this.selectedEvents(), {
544
+ return new Trace.Extras.TraceTree.TopDownRootNode(this.selectedEvents, {
463
545
  filters: this.filters(),
464
546
  startTime: this.startTime,
465
547
  endTime: this.endTime,
@@ -469,10 +551,24 @@ export class TimelineTreeView extends
469
551
  }
470
552
 
471
553
  populateColumns(columns: DataGrid.DataGrid.ColumnDescriptor[]): void {
472
- columns.push({id: 'self', title: i18nString(UIStrings.selfTime), width: '120px', fixedWidth: true, sortable: true});
554
+ if (this.compactMode) {
555
+ columns.push(
556
+ ({id: 'self', title: i18nString(UIStrings.selfTime), width: '15%', sortable: true} as
557
+ DataGrid.DataGrid.ColumnDescriptor));
558
+ columns.push(
559
+ ({id: 'total', title: i18nString(UIStrings.totalTime), width: '15%', sortable: true} as
560
+ DataGrid.DataGrid.ColumnDescriptor));
561
+ } else {
562
+ columns.push(
563
+ ({id: 'self', title: i18nString(UIStrings.selfTime), width: '120px', fixedWidth: true, sortable: true} as
564
+ DataGrid.DataGrid.ColumnDescriptor));
565
+ columns.push(
566
+ ({id: 'total', title: i18nString(UIStrings.totalTime), width: '120px', fixedWidth: true, sortable: true} as
567
+ DataGrid.DataGrid.ColumnDescriptor));
568
+ }
473
569
  columns.push(
474
- {id: 'total', title: i18nString(UIStrings.totalTime), width: '120px', fixedWidth: true, sortable: true});
475
- columns.push({id: 'activity', title: i18nString(UIStrings.activity), disclosure: true, sortable: true});
570
+ ({id: 'activity', title: i18nString(UIStrings.activity), disclosure: true, sortable: true} as
571
+ DataGrid.DataGrid.ColumnDescriptor));
476
572
  }
477
573
 
478
574
  sortingChanged(): void {
@@ -564,6 +660,9 @@ export class TimelineTreeView extends
564
660
  }
565
661
 
566
662
  private onShowModeChanged(): void {
663
+ if (this.#compactMode || !this.splitWidget) {
664
+ return;
665
+ }
567
666
  if (this.splitWidget.showMode() === UI.SplitWidget.ShowMode.ONLY_MAIN) {
568
667
  return;
569
668
  }
@@ -572,6 +671,9 @@ export class TimelineTreeView extends
572
671
  }
573
672
 
574
673
  protected updateDetailsForSelection(): void {
674
+ if (this.#compactMode || !this.splitWidget || !this.detailsView) {
675
+ return;
676
+ }
575
677
  const selectedNode = this.dataGrid.selectedNode ? (this.dataGrid.selectedNode as TreeGridNode).profileNode : null;
576
678
  if (selectedNode === this.lastSelectedNodeInternal) {
577
679
  return;
@@ -612,12 +714,6 @@ export class TimelineTreeView extends
612
714
  this.dispatchEventToListeners(TimelineTreeView.Events.TREE_ROW_CLICKED, {node});
613
715
  }
614
716
 
615
- override wasShown(): void {
616
- super.wasShown();
617
- this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SELECTED_NODE, this.#onDataGridSelectionChange, this);
618
- this.dataGrid.addEventListener(DataGrid.DataGrid.Events.DESELECTED_NODE, this.#onDataGridDeselection, this);
619
- }
620
-
621
717
  override childWasDetached(_widget: UI.Widget.Widget): void {
622
718
  this.dataGrid.removeEventListener(DataGrid.DataGrid.Events.SELECTED_NODE, this.#onDataGridSelectionChange);
623
719
  this.dataGrid.removeEventListener(DataGrid.DataGrid.Events.DESELECTED_NODE, this.#onDataGridDeselection);
@@ -808,12 +904,13 @@ export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode<Gri
808
904
  }
809
905
  } else if (event) {
810
906
  name.textContent = TimelineUIUtils.eventTitle(event);
811
- const parsedTrace = this.treeView.parsedTrace();
907
+ const parsedTrace = this.treeView.parsedTrace;
812
908
  const target = parsedTrace ? targetForEvent(parsedTrace, event) : null;
813
909
  const linkifier = this.treeView.linkifier;
814
910
  const isFreshOrEnhanced =
815
911
  Boolean(parsedTrace && Tracing.FreshRecording.Tracker.instance().recordingIsFreshOrEnhanced(parsedTrace));
816
- this.linkElement = TimelineUIUtils.linkifyTopCallFrame(event, target, linkifier, isFreshOrEnhanced);
912
+ const maxLength = this.treeView.maxLinkLength;
913
+ this.linkElement = TimelineUIUtils.linkifyTopCallFrame(event, target, linkifier, isFreshOrEnhanced, maxLength);
817
914
  if (this.linkElement) {
818
915
  container.createChild('div', 'activity-link').appendChild(this.linkElement);
819
916
  }
@@ -841,7 +938,7 @@ export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode<Gri
841
938
  switch (columnId) {
842
939
  case 'start-time': {
843
940
  event = this.profileNode.event;
844
- const parsedTrace = this.treeView.parsedTrace();
941
+ const parsedTrace = this.treeView.parsedTrace;
845
942
  if (!parsedTrace) {
846
943
  throw new Error('Unable to load trace data for tree view');
847
944
  }
@@ -957,8 +1054,8 @@ export class AggregatedTimelineTreeView extends TimelineTreeView {
957
1054
  protected readonly groupBySetting: Common.Settings.Setting<AggregatedTimelineTreeView.GroupBy>;
958
1055
  readonly stackView: TimelineStackView;
959
1056
 
960
- constructor() {
961
- super();
1057
+ constructor(element?: HTMLElement) {
1058
+ super(element);
962
1059
  this.groupBySetting = Common.Settings.Settings.instance().createSetting(
963
1060
  'timeline-tree-group-by', AggregatedTimelineTreeView.GroupBy.None);
964
1061
  this.groupBySetting.addChangeListener(() => this.refreshTree());
@@ -1038,7 +1135,7 @@ export class AggregatedTimelineTreeView extends TimelineTreeView {
1038
1135
  break;
1039
1136
 
1040
1137
  case AggregatedTimelineTreeView.GroupBy.Frame: {
1041
- const frame = id ? this.parsedTrace()?.data.PageFrames.frames.get(id) : undefined;
1138
+ const frame = id ? this.parsedTrace?.data.PageFrames.frames.get(id) : undefined;
1042
1139
  const frameName = frame ? TimelineUIUtils.displayNameForFrame(frame) : i18nString(UIStrings.page);
1043
1140
  return {name: frameName, color};
1044
1141
  }
@@ -1067,10 +1164,12 @@ export class AggregatedTimelineTreeView extends TimelineTreeView {
1067
1164
  ];
1068
1165
  toolbar.appendToolbarItem(
1069
1166
  new UI.Toolbar.ToolbarSettingComboBox(options, this.groupBySetting, i18nString(UIStrings.groupBy)));
1070
- toolbar.appendSpacer();
1071
- toolbar.appendToolbarItem(this.splitWidget.createShowHideSidebarButton(
1072
- i18nString(UIStrings.showHeaviestStack), i18nString(UIStrings.hideHeaviestStack),
1073
- i18nString(UIStrings.heaviestStackShown), i18nString(UIStrings.heaviestStackHidden)));
1167
+ if (!this.compactMode && this.splitWidget) {
1168
+ toolbar.appendSpacer();
1169
+ toolbar.appendToolbarItem(this.splitWidget.createShowHideSidebarButton(
1170
+ i18nString(UIStrings.showHeaviestStack), i18nString(UIStrings.hideHeaviestStack),
1171
+ i18nString(UIStrings.heaviestStackShown), i18nString(UIStrings.heaviestStackHidden)));
1172
+ }
1074
1173
  }
1075
1174
 
1076
1175
  private buildHeaviestStack(treeNode: Trace.Extras.TraceTree.Node): Trace.Extras.TraceTree.Node[] {
@@ -1123,13 +1222,13 @@ export class AggregatedTimelineTreeView extends TimelineTreeView {
1123
1222
  return this.domainByEvent.bind(this, groupBy);
1124
1223
  case GroupBy.URL:
1125
1224
  return (event: Trace.Types.Events.Event) => {
1126
- const parsedTrace = this.parsedTrace();
1225
+ const parsedTrace = this.parsedTrace;
1127
1226
  return parsedTrace ? Trace.Handlers.Helpers.getNonResolvedURL(event, parsedTrace.data) ?? '' : '';
1128
1227
  };
1129
1228
  case GroupBy.Frame:
1130
1229
  return (event: Trace.Types.Events.Event) => {
1131
1230
  const frameId = Trace.Helpers.Trace.frameIDForEvent(event);
1132
- return frameId || this.parsedTrace()?.data.Meta.mainFrameId || '';
1231
+ return frameId || this.parsedTrace?.data.Meta.mainFrameId || '';
1133
1232
  };
1134
1233
  default:
1135
1234
  console.assert(false, `Unexpected aggregation setting: ${groupBy}`);
@@ -1141,7 +1240,7 @@ export class AggregatedTimelineTreeView extends TimelineTreeView {
1141
1240
  // The eventid == the identity of a node that we expect in a bottomUp tree (either without grouping or with the groupBy grouping)
1142
1241
  // A "top node" (in `ungroupedTopNodes`) is aggregated by this. (But so are all the other nodes, except the `GroupNode`s)
1143
1242
  private domainByEvent(groupBy: AggregatedTimelineTreeView.GroupBy, event: Trace.Types.Events.Event): string {
1144
- const parsedTrace = this.parsedTrace();
1243
+ const parsedTrace = this.parsedTrace;
1145
1244
  if (!parsedTrace) {
1146
1245
  return '';
1147
1246
  }
@@ -1254,8 +1353,8 @@ export namespace AggregatedTimelineTreeView {
1254
1353
  }
1255
1354
 
1256
1355
  export class CallTreeTimelineTreeView extends AggregatedTimelineTreeView {
1257
- constructor() {
1258
- super();
1356
+ constructor(element?: HTMLElement) {
1357
+ super(element);
1259
1358
  this.element.setAttribute('jslog', `${VisualLogging.pane('call-tree').track({resize: true})}`);
1260
1359
  this.dataGrid.markColumnAsSortedBy('total', DataGrid.DataGrid.Order.Descending);
1261
1360
  }
@@ -1267,14 +1366,14 @@ export class CallTreeTimelineTreeView extends AggregatedTimelineTreeView {
1267
1366
  }
1268
1367
 
1269
1368
  export class BottomUpTimelineTreeView extends AggregatedTimelineTreeView {
1270
- constructor() {
1271
- super();
1369
+ constructor(element?: HTMLElement) {
1370
+ super(element);
1272
1371
  this.element.setAttribute('jslog', `${VisualLogging.pane('bottom-up').track({resize: true})}`);
1273
1372
  this.dataGrid.markColumnAsSortedBy('self', DataGrid.DataGrid.Order.Descending);
1274
1373
  }
1275
1374
 
1276
1375
  override buildTree(): Trace.Extras.TraceTree.Node {
1277
- return new Trace.Extras.TraceTree.BottomUpRootNode(this.selectedEvents(), {
1376
+ return new Trace.Extras.TraceTree.BottomUpRootNode(this.selectedEvents, {
1278
1377
  textFilter: this.textFilter(),
1279
1378
  filters: this.filtersWithoutTextFilter(),
1280
1379
  startTime: this.startTime,
@@ -785,7 +785,7 @@ export class TimelineUIUtils {
785
785
 
786
786
  static linkifyTopCallFrame(
787
787
  event: Trace.Types.Events.Event, target: SDK.Target.Target|null, linkifier: LegacyComponents.Linkifier.Linkifier,
788
- isFreshOrEnhanced = false): Element|null {
788
+ isFreshOrEnhanced = false, maxLength?: number): Element|null {
789
789
  let frame = Trace.Helpers.Trace.getZeroIndexedStackTraceInEventPayload(event)?.[0];
790
790
  if (Trace.Types.Events.isProfileCall(event)) {
791
791
  frame = event.callFrame;
@@ -800,6 +800,7 @@ export class TimelineUIUtils {
800
800
  showColumnNumber: true,
801
801
  columnNumber: frame.columnNumber,
802
802
  lineNumber: frame.lineNumber,
803
+ maxLength,
803
804
  };
804
805
  if (isFreshOrEnhanced) {
805
806
  return linkifier.maybeLinkifyConsoleCallFrame(target, frame, {showColumnNumber: true, inlineFrameIndex: 0});
@@ -121,6 +121,7 @@ interface MetricsViewInput {
121
121
  didDismissFieldMismatchNotice: boolean;
122
122
  onDismisFieldMismatchNotice: () => void;
123
123
  onClickMetric: (traceEvent: Trace.Types.Events.Event) => void;
124
+ skipBottomBorder: boolean;
124
125
  }
125
126
 
126
127
  type MetricsView = (input: MetricsViewInput, output: undefined, target: HTMLElement) => void;
@@ -210,7 +211,7 @@ const CWV_METRICS_VIEW: MetricsView = (input, _output, target) => {
210
211
  <span>${clsEl}</span>
211
212
  <span class="row-label">Local</span>
212
213
  </div>
213
- <span class="row-border"></span>
214
+ ${!field && input.skipBottomBorder ? Lit.nothing : html`<span class="row-border"></span>`}
214
215
  `;
215
216
 
216
217
  let fieldMetricsTemplateResult;
@@ -234,7 +235,7 @@ const CWV_METRICS_VIEW: MetricsView = (input, _output, target) => {
234
235
  <span>${clsEl}</span>
235
236
  <span class="row-label">${i18nString(UIStrings.fieldScoreLabel, {PH1: scope})}</span>
236
237
  </div>
237
- <span class="row-border"></span>
238
+ ${input.skipBottomBorder ? Lit.nothing : html`<span class="row-border"></span>`}
238
239
  `;
239
240
  // clang-format on
240
241
  }
@@ -293,6 +294,8 @@ export class CWVMetrics extends UI.Widget.Widget {
293
294
 
294
295
  #didDismissFieldMismatchNotice = false;
295
296
 
297
+ #skipBottomBorder = false;
298
+
296
299
  constructor(element?: HTMLElement, view: MetricsView = CWV_METRICS_VIEW) {
297
300
  super(element, {useShadowDom: true});
298
301
  this.#view = view;
@@ -303,6 +306,18 @@ export class CWVMetrics extends UI.Widget.Widget {
303
306
  this.requestUpdate();
304
307
  }
305
308
 
309
+ get skipBottomBorder(): boolean {
310
+ return this.#skipBottomBorder;
311
+ }
312
+
313
+ set skipBottomBorder(x: boolean) {
314
+ if (x === this.#skipBottomBorder) {
315
+ return;
316
+ }
317
+ this.#skipBottomBorder = x;
318
+ this.requestUpdate();
319
+ }
320
+
306
321
  #onClickMetric(traceEvent: Trace.Types.Events.Event): void {
307
322
  this.element.dispatchEvent(new Insights.EventRef.EventReferenceClick(traceEvent));
308
323
  }
@@ -333,6 +348,7 @@ export class CWVMetrics extends UI.Widget.Widget {
333
348
  didDismissFieldMismatchNotice: this.#didDismissFieldMismatchNotice,
334
349
  onDismisFieldMismatchNotice: this.#onDismisFieldMismatchNotice.bind(this),
335
350
  onClickMetric: this.#onClickMetric.bind(this),
351
+ skipBottomBorder: this.#skipBottomBorder,
336
352
  };
337
353
  this.#view(input, undefined, this.contentElement);
338
354
  }
@@ -401,3 +401,14 @@ Common.Revealer.registerRevealer({
401
401
  return new Timeline.TimelinePanel.TimeRangeRevealer();
402
402
  },
403
403
  });
404
+
405
+ Common.Revealer.registerRevealer({
406
+ contextTypes() {
407
+ return maybeRetrieveContextTypes(Timeline => [Timeline.Utils.Helpers.RevealableBottomUpProfile]);
408
+ },
409
+ destination: Common.Revealer.RevealerDestination.TIMELINE_PANEL,
410
+ async loadRevealer() {
411
+ const Timeline = await loadTimelineModule();
412
+ return new Timeline.TimelinePanel.BottomUpProfileRevealer();
413
+ },
414
+ });
@@ -136,3 +136,8 @@ export class RevealableTimeRange {
136
136
  constructor(public bounds: Trace.Types.Timing.TraceWindowMicro) {
137
137
  }
138
138
  }
139
+
140
+ export class RevealableBottomUpProfile {
141
+ constructor(public bounds: Trace.Types.Timing.TraceWindowMicro) {
142
+ }
143
+ }
@@ -1,7 +1,7 @@
1
1
  Name: Dependencies sourced from the upstream `chromium` repository
2
2
  URL: Internal
3
3
  Version: N/A
4
- Revision: c9e49d7cdbbc11a6a70bb2573f5a18cb23c1789b
4
+ Revision: ed66cb5e93e6205f5231c1dcfac9b91b2aa4ffd6
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE
@@ -34,6 +34,11 @@ const UIStrings = {
34
34
  * @description Disclaimer shown in the code blocks.
35
35
  */
36
36
  disclaimer: 'Use code snippets with caution',
37
+ /**
38
+ * @description The title of the button to show all lines of a code block.
39
+ * @example {5} PH1
40
+ */
41
+ showAllLines: 'Show all lines ({PH1} more)',
37
42
  } as const;
38
43
  const str_ = i18n.i18n.registerUIStrings('ui/components/markdown_view/CodeBlock.ts', UIStrings);
39
44
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -130,6 +135,7 @@ export class CodeBlock extends HTMLElement {
130
135
  #copied = false;
131
136
  #editorState?: CodeMirror.EditorState;
132
137
  #languageConf = new CodeMirror.Compartment();
138
+ #truncationConf = new CodeMirror.Compartment();
133
139
  /**
134
140
  * Whether to display a notice "​​Use code snippets with caution" in code
135
141
  * blocks.
@@ -138,6 +144,7 @@ export class CodeBlock extends HTMLElement {
138
144
  #header?: string;
139
145
  #showCopyButton = true;
140
146
  #citations: Citation[] = [];
147
+ #displayLimit = Number.MAX_VALUE;
141
148
 
142
149
  connectedCallback(): void {
143
150
  void this.#render();
@@ -152,6 +159,7 @@ export class CodeBlock extends HTMLElement {
152
159
  CodeMirror.EditorState.readOnly.of(true),
153
160
  CodeMirror.EditorView.lineWrapping,
154
161
  this.#languageConf.of(CodeMirror.javascript.javascript()),
162
+ this.#truncationConf.of([]),
155
163
  ],
156
164
  });
157
165
  void this.#render();
@@ -190,6 +198,15 @@ export class CodeBlock extends HTMLElement {
190
198
  this.#citations = citations;
191
199
  }
192
200
 
201
+ set displayLimit(value: number) {
202
+ this.#displayLimit = value;
203
+ void this.#render();
204
+ }
205
+
206
+ get displayLimit(): number {
207
+ return this.#displayLimit;
208
+ }
209
+
193
210
  #onCopy(): void {
194
211
  UI.UIUtils.copyTextToClipboard(this.#code, i18nString(UIStrings.copied));
195
212
  this.#copied = true;
@@ -256,6 +273,9 @@ export class CodeBlock extends HTMLElement {
256
273
  throw new Error('Unexpected: trying to render the text editor without editorState');
257
274
  }
258
275
 
276
+ const linesCount = this.#editorState.doc.lines;
277
+ const isTruncated = linesCount > this.#displayLimit;
278
+
259
279
  // clang-format off
260
280
  Lit.render(
261
281
  html`<div class='codeblock' jslog=${VisualLogging.section('code')}>
@@ -271,6 +291,19 @@ export class CodeBlock extends HTMLElement {
271
291
  <div class="code">
272
292
  <devtools-text-editor .state=${this.#editorState}></devtools-text-editor>
273
293
  </div>
294
+ ${isTruncated ? html`
295
+ <div class="show-all-container">
296
+ <devtools-button
297
+ .variant=${Buttons.Button.Variant.OUTLINED}
298
+ .size=${Buttons.Button.Size.SMALL}
299
+ .jslogContext=${'show-all'}
300
+ .title=${i18nString(UIStrings.showAllLines, { PH1: linesCount - this.#displayLimit })}
301
+ @click=${() => {
302
+ this.displayLimit = Number.MAX_VALUE;
303
+ }}
304
+ >${i18nString(UIStrings.showAllLines, { PH1: linesCount - this.#displayLimit })}</devtools-button>
305
+ </div>
306
+ ` : Lit.nothing}
274
307
  </div>
275
308
  ${this.#displayNotice ? this.#renderNotice() : Lit.nothing}
276
309
  </div>`,
@@ -288,8 +321,21 @@ export class CodeBlock extends HTMLElement {
288
321
  }
289
322
 
290
323
  const language = await languageFromToken(this.#codeLang);
324
+ let truncationExtension: CodeMirror.Extension = [];
325
+ if (isTruncated) {
326
+ truncationExtension = CodeMirror.EditorView.decorations.of(CodeMirror.Decoration.set(
327
+ CodeMirror.Decoration.replace({}).range(
328
+ this.#editorState.doc.line(this.#displayLimit).to,
329
+ this.#editorState.doc.length,
330
+ ),
331
+ ));
332
+ }
333
+
291
334
  editor.dispatch({
292
- effects: this.#languageConf.reconfigure(language),
335
+ effects: [
336
+ this.#languageConf.reconfigure(language),
337
+ this.#truncationConf.reconfigure(truncationExtension),
338
+ ],
293
339
  });
294
340
  }
295
341
  }
@@ -108,3 +108,11 @@
108
108
  text-decoration-line: underline;
109
109
  }
110
110
  }
111
+
112
+ .show-all-container {
113
+ display: flex;
114
+ justify-content: center;
115
+ align-items: center;
116
+ padding: var(--sys-size-4) 0;
117
+ background-color: var(--code-block-background-color); /* stylelint-disable-line plugin/use_theme_colors */
118
+ }
@@ -21,6 +21,8 @@ import {Tooltip} from './Tooltip.js';
21
21
  import {bindCheckbox, CheckboxLabel, createTextChild} from './UIUtils.js';
22
22
  import {HBox} from './Widget.js';
23
23
 
24
+ export {filterStyles};
25
+
24
26
  const UIStrings = {
25
27
  /**
26
28
  * @description Text to filter result items