chrome-devtools-frontend 1.0.1558690 → 1.0.1561080

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/front_end/Images/src/container.svg +4 -0
  2. package/front_end/core/common/Gzip.ts +15 -0
  3. package/front_end/core/host/InspectorFrontendHostStub.ts +0 -3
  4. package/front_end/core/platform/ArrayUtilities.ts +13 -0
  5. package/front_end/core/root/Runtime.ts +0 -5
  6. package/front_end/core/sdk/CSSMetadata.ts +6 -6
  7. package/front_end/core/sdk/CSSModel.ts +2 -2
  8. package/front_end/core/sdk/DOMModel.ts +15 -3
  9. package/front_end/core/sdk/NetworkManager.ts +4 -0
  10. package/front_end/core/sdk/NetworkRequest.ts +9 -0
  11. package/front_end/core/sdk/OverlayModel.ts +20 -9
  12. package/front_end/entrypoints/main/MainImpl.ts +2 -1
  13. package/front_end/generated/InspectorBackendCommands.ts +6 -3
  14. package/front_end/generated/SupportedCSSProperties.js +64 -32
  15. package/front_end/generated/protocol-mapping.d.ts +16 -0
  16. package/front_end/generated/protocol-proxy-api.d.ts +12 -0
  17. package/front_end/generated/protocol.ts +38 -1
  18. package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
  19. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +11 -7
  20. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +23 -22
  21. package/front_end/models/badges/UserBadges.ts +48 -16
  22. package/front_end/models/greendev/Prototypes.ts +6 -1
  23. package/front_end/models/trace/LanternComputationData.ts +4 -3
  24. package/front_end/models/trace/Processor.ts +6 -5
  25. package/front_end/models/trace/Styles.ts +10 -1
  26. package/front_end/models/trace/extras/TraceTree.ts +1 -1
  27. package/front_end/models/trace/handlers/LargestImagePaintHandler.ts +2 -2
  28. package/front_end/models/trace/handlers/MetaHandler.ts +14 -0
  29. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +59 -34
  30. package/front_end/models/trace/helpers/Timing.ts +8 -1
  31. package/front_end/models/trace/insights/Common.ts +1 -1
  32. package/front_end/models/trace/insights/LCPBreakdown.ts +4 -4
  33. package/front_end/models/trace/insights/LCPDiscovery.ts +3 -3
  34. package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
  35. package/front_end/models/trace/insights/types.ts +1 -1
  36. package/front_end/models/trace/types/TraceEvents.ts +62 -10
  37. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -142
  38. package/front_end/panels/ai_assistance/PatchWidget.ts +90 -72
  39. package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
  40. package/front_end/panels/ai_assistance/components/ChatInput.ts +701 -0
  41. package/front_end/panels/ai_assistance/components/ChatView.ts +71 -1268
  42. package/front_end/panels/ai_assistance/components/UserActionRow.ts +514 -31
  43. package/front_end/panels/ai_assistance/components/chatInput.css +387 -0
  44. package/front_end/panels/ai_assistance/components/chatView.css +38 -599
  45. package/front_end/panels/ai_assistance/components/userActionRow.css +230 -0
  46. package/front_end/panels/autofill/AutofillView.ts +2 -2
  47. package/front_end/panels/changes/ChangesView.ts +15 -1
  48. package/front_end/panels/changes/changesView.css +6 -0
  49. package/front_end/panels/common/AiCodeGenerationTeaser.ts +48 -12
  50. package/front_end/panels/common/BadgeNotification.ts +44 -58
  51. package/front_end/panels/common/CopyChangesToPrompt.ts +233 -0
  52. package/front_end/panels/common/aiCodeGenerationTeaser.css +14 -0
  53. package/front_end/panels/common/common.ts +2 -1
  54. package/front_end/panels/console/consoleView.css +1 -1
  55. package/front_end/panels/elements/CSSRuleValidator.ts +38 -0
  56. package/front_end/panels/elements/ElementsTreeElement.ts +222 -377
  57. package/front_end/panels/elements/ElementsTreeOutline.ts +0 -23
  58. package/front_end/panels/elements/ShortcutTreeElement.ts +57 -50
  59. package/front_end/panels/elements/StylePropertiesSection.ts +1 -3
  60. package/front_end/panels/elements/StylesSidebarPane.ts +15 -4
  61. package/front_end/panels/elements/components/AdornerManager.ts +5 -149
  62. package/front_end/panels/issues/HiddenIssuesRow.ts +1 -2
  63. package/front_end/panels/issues/IssueKindView.ts +2 -4
  64. package/front_end/panels/issues/IssueView.ts +2 -4
  65. package/front_end/panels/network/NetworkDataGridNode.ts +65 -1
  66. package/front_end/panels/network/NetworkLogView.ts +2 -4
  67. package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
  68. package/front_end/panels/screencast/ScreencastApp.ts +1 -0
  69. package/front_end/panels/settings/SettingsScreen.ts +3 -2
  70. package/front_end/panels/timeline/CompatibilityTracksAppender.ts +14 -1
  71. package/front_end/panels/timeline/StatusDialog.ts +4 -3
  72. package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -4
  73. package/front_end/panels/timeline/TimelineController.ts +185 -3
  74. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +52 -25
  75. package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +3 -16
  76. package/front_end/panels/timeline/TimelineFlameChartView.ts +65 -21
  77. package/front_end/panels/timeline/TimelinePanel.ts +86 -126
  78. package/front_end/panels/timeline/TimelineTreeView.ts +1 -0
  79. package/front_end/panels/timeline/TimelineUIUtils.ts +28 -2
  80. package/front_end/panels/timeline/TimingsTrackAppender.ts +3 -1
  81. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
  82. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -2
  83. package/front_end/panels/timeline/components/insights/RenderBlocking.ts +6 -4
  84. package/front_end/panels/timeline/components/insights/Table.ts +3 -3
  85. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +4 -0
  86. package/front_end/panels/timeline/timelinePanel.css +8 -1
  87. package/front_end/panels/timeline/utils/EntryNodes.ts +2 -1
  88. package/front_end/panels/whats_new/ReleaseNoteText.ts +15 -9
  89. package/front_end/panels/whats_new/resources/WNDT.md +6 -6
  90. package/front_end/third_party/chromium/README.chromium +1 -1
  91. package/front_end/third_party/codemirror.next/rebuild.sh +1 -1
  92. package/front_end/third_party/lit/rebuild.sh +1 -1
  93. package/front_end/third_party/puppeteer/README.chromium +2 -2
  94. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +2 -3
  95. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js +9 -0
  99. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js.map +1 -1
  100. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.d.ts +3 -0
  101. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.js +9 -0
  103. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.js.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.d.ts +3 -0
  105. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.d.ts.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.js +10 -0
  107. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.js.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +8 -4
  110. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts.map +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js.map +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  116. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  117. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  118. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  120. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +10 -1
  123. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +13 -7
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +2 -3
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js +9 -0
  129. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js.map +1 -1
  130. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.d.ts +3 -0
  131. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
  132. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.js +9 -0
  133. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.js.map +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.d.ts +3 -0
  135. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.d.ts.map +1 -1
  136. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.js +10 -0
  137. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.js.map +1 -1
  138. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
  139. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +8 -4
  140. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
  141. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts +1 -1
  142. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts.map +1 -1
  143. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js +1 -1
  144. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js.map +1 -1
  145. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  146. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  147. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  148. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  149. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  150. package/front_end/third_party/puppeteer/package/lib/types.d.ts +10 -1
  151. package/front_end/third_party/puppeteer/package/package.json +3 -3
  152. package/front_end/third_party/puppeteer/package/src/api/Page.ts +2 -3
  153. package/front_end/third_party/puppeteer/package/src/bidi/HTTPRequest.ts +13 -0
  154. package/front_end/third_party/puppeteer/package/src/bidi/HTTPResponse.ts +10 -0
  155. package/front_end/third_party/puppeteer/package/src/bidi/core/Request.ts +15 -0
  156. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +9 -4
  157. package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
  158. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  159. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  160. package/front_end/ui/components/adorners/Adorner.ts +8 -68
  161. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +70 -28
  162. package/front_end/ui/legacy/SearchableView.ts +11 -5
  163. package/front_end/ui/legacy/SplitWidget.ts +1 -1
  164. package/front_end/ui/legacy/TabbedPane.ts +1 -1
  165. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +43 -9
  166. package/front_end/ui/visual_logging/KnownContextValues.ts +16 -0
  167. package/package.json +2 -1
@@ -229,9 +229,17 @@ const UIStrings = {
229
229
  */
230
230
  processingTrace: 'Processing trace…',
231
231
  /**
232
- * @description Text in Timeline Panel of the Performance panel
232
+ * @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
233
+ */
234
+ preparingTraceForDownload: 'Preparing…',
235
+ /**
236
+ * @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
233
237
  */
234
- initializingTracing: 'Initializing tracing…',
238
+ compressingTraceForDownload: 'Compressing…',
239
+ /**
240
+ * @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
241
+ */
242
+ encodingTraceForDownload: 'Encoding…',
235
243
  /**
236
244
  * @description Tooltip description for a checkbox that toggles the visibility of data added by extensions of this panel (Performance).
237
245
  */
@@ -333,7 +341,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
333
341
  private readonly recordingOptionUIControls: UI.Toolbar.ToolbarItem[];
334
342
  private state: State;
335
343
  private recordingPageReload: boolean;
336
- private readonly millisecondsToRecordAfterLoadEvent: number;
337
344
  private readonly toggleRecordAction: UI.ActionRegistration.Action;
338
345
  private readonly recordReloadAction: UI.ActionRegistration.Action;
339
346
  readonly #historyManager: TimelineHistoryManager;
@@ -447,12 +454,9 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
447
454
  ">💫</div>`;
448
455
  const adorner = new Adorners.Adorner.Adorner();
449
456
  adorner.classList.add('fix-perf-icon');
450
- adorner.data = {
451
- name: i18nString(UIStrings.fixMe),
452
- content: adornerContent,
453
- };
457
+ adorner.name = i18nString(UIStrings.fixMe);
458
+ adorner.append(adornerContent);
454
459
  this.#traceEngineModel = traceModel || this.#instantiateNewModel();
455
- this.#listenForProcessingProgress();
456
460
 
457
461
  this.element.addEventListener('contextmenu', this.contextMenu.bind(this), false);
458
462
  this.dropTarget = new UI.DropTarget.DropTarget(
@@ -462,7 +466,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
462
466
  this.recordingOptionUIControls = [];
463
467
  this.state = State.IDLE;
464
468
  this.recordingPageReload = false;
465
- this.millisecondsToRecordAfterLoadEvent = 5000;
466
469
  this.toggleRecordAction = UI.ActionRegistry.ActionRegistry.instance().getAction('timeline.toggle-recording');
467
470
  this.recordReloadAction = UI.ActionRegistry.ActionRegistry.instance().getAction('timeline.record-reload');
468
471
 
@@ -527,9 +530,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
527
530
 
528
531
  this.createFileSelector();
529
532
 
530
- SDK.TargetManager.TargetManager.instance().addModelListener(
531
- SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this.loadEventFired, this);
532
-
533
533
  this.flameChart = new TimelineFlameChartView(this);
534
534
  this.element.addEventListener(
535
535
  'toggle-popover', event => this.flameChart.togglePopover((event as CustomEvent).detail));
@@ -675,7 +675,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
675
675
  #setActiveInsight(insight: TimelineComponents.Sidebar.ActiveInsight|null, opts: {
676
676
  highlightInsight: boolean,
677
677
  } = {highlightInsight: false}): void {
678
- if (insight) {
678
+ if (insight && this.#splitWidget.showMode() !== UI.SplitWidget.ShowMode.BOTH) {
679
679
  this.#splitWidget.showBoth();
680
680
  }
681
681
  this.#sideBar.setActiveInsight(insight, {highlight: opts.highlightInsight});
@@ -732,7 +732,25 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
732
732
  config.includeRuntimeCallStats = Root.Runtime.experiments.isEnabled('timeline-v8-runtime-call-stats');
733
733
  config.debugMode = Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.TIMELINE_DEBUG_MODE);
734
734
 
735
- return Trace.TraceModel.Model.createWithAllHandlers(config);
735
+ const traceEngineModel = Trace.TraceModel.Model.createWithAllHandlers(config);
736
+
737
+ traceEngineModel.addEventListener(Trace.TraceModel.ModelUpdateEvent.eventName, e => {
738
+ const updateEvent = e as Trace.TraceModel.ModelUpdateEvent;
739
+ const str = i18nString(UIStrings.processed);
740
+
741
+ // Trace Engine will report progress from [0...1] but we still have more work to do. So, scale them down a bit.
742
+ const traceParseMaxProgress = 0.7;
743
+
744
+ if (updateEvent.data.type === Trace.TraceModel.ModelUpdateType.COMPLETE) {
745
+ this.statusDialog?.updateProgressBar(str, 100 * traceParseMaxProgress);
746
+ } else if (updateEvent.data.type === Trace.TraceModel.ModelUpdateType.PROGRESS_UPDATE) {
747
+ const data = updateEvent.data.data;
748
+ this.statusDialog?.updateProgressBar(str, data.percent * 100 * traceParseMaxProgress);
749
+ }
750
+ });
751
+
752
+ this.#traceEngineModel = traceEngineModel;
753
+ return this.#traceEngineModel;
736
754
  }
737
755
 
738
756
  static extensionDataVisibilitySetting(): Common.Settings.Setting<boolean> {
@@ -1455,6 +1473,9 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1455
1473
  }
1456
1474
 
1457
1475
  this.#showExportTraceErrorDialog(error);
1476
+ } finally {
1477
+ this.statusDialog?.remove();
1478
+ this.statusDialog = null;
1458
1479
  }
1459
1480
  }
1460
1481
 
@@ -1464,6 +1485,24 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1464
1485
  addModifications: boolean,
1465
1486
  shouldCompress: boolean,
1466
1487
  }): Promise<void> {
1488
+ this.statusDialog = new StatusDialog(
1489
+ {
1490
+ hideStopButton: true,
1491
+ showProgress: true,
1492
+ },
1493
+ async () => {
1494
+ this.statusDialog?.remove();
1495
+ this.statusDialog = null;
1496
+ });
1497
+ this.statusDialog.showPane(this.statusPaneContainer, 'tinted');
1498
+ this.statusDialog.updateStatus(i18nString(UIStrings.preparingTraceForDownload));
1499
+ this.statusDialog.updateProgressBar(i18nString(UIStrings.preparingTraceForDownload), 0);
1500
+ this.statusDialog.requestUpdate();
1501
+ await this.statusDialog.updateComplete;
1502
+ // Not sure why the above isn't sufficient.
1503
+ await new Promise(resolve => requestAnimationFrame(resolve));
1504
+ await new Promise(resolve => requestAnimationFrame(resolve));
1505
+
1467
1506
  // Base the filename on the trace's time of recording
1468
1507
  const isoDate =
1469
1508
  Platform.DateUtilities.toISO8601Compact(metadata.startTime ? new Date(metadata.startTime) : new Date());
@@ -1499,8 +1538,16 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1499
1538
  let blob = new Blob(blobParts, {type: 'application/json'});
1500
1539
 
1501
1540
  if (config.shouldCompress) {
1541
+ this.statusDialog.updateStatus(i18nString(UIStrings.compressingTraceForDownload));
1542
+ this.statusDialog.updateProgressBar(i18nString(UIStrings.compressingTraceForDownload), 0);
1543
+
1502
1544
  fileName = `${fileName}.gz` as Platform.DevToolsPath.RawPathString;
1503
- const gzStream = Common.Gzip.compressStream(blob.stream());
1545
+ const inputSize = blob.size;
1546
+ const monitoredStream = Common.Gzip.createMonitoredStream(blob.stream(), bytesRead => {
1547
+ this.statusDialog?.updateProgressBar(
1548
+ i18nString(UIStrings.compressingTraceForDownload), bytesRead / inputSize * 100);
1549
+ });
1550
+ const gzStream = Common.Gzip.compressStream(monitoredStream);
1504
1551
  blob = await new Response(gzStream, {
1505
1552
  headers: {'Content-Type': 'application/gzip'},
1506
1553
  }).blob();
@@ -1515,9 +1562,12 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1515
1562
  try {
1516
1563
  // The maximum string length in v8 is `2 ** 29 - 23`, aka 538 MB.
1517
1564
  // If the gzipped&base64-encoded trace is larger than that, this'll throw a RangeError.
1565
+ this.statusDialog.updateStatus(i18nString(UIStrings.encodingTraceForDownload));
1566
+ this.statusDialog.updateProgressBar(i18nString(UIStrings.encodingTraceForDownload), 100);
1518
1567
  bytesAsB64 = await Common.Base64.encode(blob);
1519
1568
  } catch {
1520
1569
  }
1570
+
1521
1571
  if (bytesAsB64?.length) {
1522
1572
  const contentData = new TextUtils.ContentData.ContentData(bytesAsB64, /* isBase64=*/ true, blob.type);
1523
1573
  await Workspace.FileManager.FileManager.instance().save(fileName, contentData, /* forceSaveAs=*/ true);
@@ -1531,6 +1581,9 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1531
1581
  a.click();
1532
1582
  URL.revokeObjectURL(url);
1533
1583
  }
1584
+
1585
+ this.statusDialog.remove();
1586
+ this.statusDialog = null;
1534
1587
  }
1535
1588
 
1536
1589
  async handleSaveToFileAction(): Promise<void> {
@@ -1794,41 +1847,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1794
1847
  return navigationEntry.url as Platform.DevToolsPath.UrlString;
1795
1848
  }
1796
1849
 
1797
- async #navigateToAboutBlank(): Promise<void> {
1798
- const aboutBlankNavigationComplete = new Promise<void>(async (resolve, reject) => {
1799
- if (!this.controller) {
1800
- reject('Could not find TimelineController');
1801
- return;
1802
- }
1803
- const target = this.controller.primaryPageTarget;
1804
- const resourceModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel);
1805
- if (!resourceModel) {
1806
- reject('Could not load resourceModel');
1807
- return;
1808
- }
1809
-
1810
- /**
1811
- * To clear out the page and any state from prior test runs, we
1812
- * navigate to about:blank before initiating the trace recording.
1813
- * Once we have navigated to about:blank, we start recording and
1814
- * then navigate to the original page URL, to ensure we profile the
1815
- * page load.
1816
- **/
1817
- function waitForAboutBlank(event: Common.EventTarget.EventTargetEvent<SDK.ResourceTreeModel.ResourceTreeFrame>):
1818
- void {
1819
- if (event.data.url === 'about:blank') {
1820
- resolve();
1821
- } else {
1822
- reject(`Unexpected navigation to ${event.data.url}`);
1823
- }
1824
- resourceModel?.removeEventListener(SDK.ResourceTreeModel.Events.FrameNavigated, waitForAboutBlank);
1825
- }
1826
- resourceModel.addEventListener(SDK.ResourceTreeModel.Events.FrameNavigated, waitForAboutBlank);
1827
- await resourceModel.navigate('about:blank' as Platform.DevToolsPath.UrlString);
1828
- });
1829
- await aboutBlankNavigationComplete;
1830
- }
1831
-
1832
1850
  async #startCPUProfilingRecording(): Promise<void> {
1833
1851
  try {
1834
1852
  this.cpuProfiler = UI.Context.Context.instance().flavor(SDK.CPUProfilerModel.CPUProfilerModel);
@@ -1889,30 +1907,18 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1889
1907
  }
1890
1908
 
1891
1909
  const urlToTrace = await this.#evaluateInspectedURL();
1892
- // If we are doing "Reload & record", we first navigate the page to
1893
- // about:blank. This is to ensure any data on the timeline from any
1894
- // previous performance recording is lost, avoiding the problem where a
1895
- // timeline will show data & screenshots from a previous page load that
1896
- // was not relevant.
1897
- if (this.recordingPageReload) {
1898
- await this.#navigateToAboutBlank();
1899
- }
1900
- const recordingOptions = {
1910
+
1911
+ // Order is important here: we tell the controller to start recording, which enables tracing.
1912
+ await this.controller.startRecording({
1901
1913
  enableJSSampling: !this.disableCaptureJSProfileSetting.get(),
1902
1914
  capturePictures: this.captureLayersAndPicturesSetting.get(),
1903
1915
  captureFilmStrip: this.showScreenshotsSetting.get(),
1904
1916
  captureSelectorStats: this.captureSelectorStatsSetting.get(),
1905
- };
1906
- // Order is important here: we tell the controller to start recording, which enables tracing.
1907
- const response = await this.controller.startRecording(recordingOptions);
1908
- if (response.getError()) {
1909
- throw new Error(response.getError());
1910
- }
1917
+ navigateToUrl: this.recordingPageReload ? urlToTrace : undefined,
1918
+ });
1919
+
1911
1920
  // Once we get here, we know tracing is active.
1912
- // This is when, if the user has hit "Reload & Record" that we now need to navigate to the original URL.
1913
- // If the user has just hit "record", we don't do any navigating.
1914
- const recordingConfig = this.recordingPageReload ? {navigateToUrl: urlToTrace} : undefined;
1915
- this.recordingStarted(recordingConfig);
1921
+ this.recordingStarted();
1916
1922
  } catch (e) {
1917
1923
  await this.recordingFailed(e.message);
1918
1924
  }
@@ -1965,7 +1971,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1965
1971
  {
1966
1972
  description: error,
1967
1973
  buttonText: i18nString(UIStrings.close),
1968
- hideStopButton: true,
1974
+ hideStopButton: false,
1969
1975
  showProgress: undefined,
1970
1976
  showTimer: undefined,
1971
1977
  },
@@ -2055,7 +2061,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2055
2061
 
2056
2062
  private onClearButton(): void {
2057
2063
  this.#historyManager.clear();
2058
- this.#traceEngineModel = this.#instantiateNewModel();
2064
+ this.#instantiateNewModel();
2059
2065
  ModificationsManager.reset();
2060
2066
  this.#uninstallSourceMapsResolver();
2061
2067
  this.flameChart.getMainDataProvider().reset();
@@ -2364,28 +2370,11 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2364
2370
  return ThemeSupport.ThemeSupport.instance().getComputedValue('--app-color-system');
2365
2371
  }
2366
2372
 
2367
- private recordingStarted(config?: {navigateToUrl: Platform.DevToolsPath.UrlString}): void {
2368
- if (config && this.recordingPageReload && this.controller) {
2369
- // If the user hit "Reload & record", by this point we have:
2370
- // 1. Navigated to about:blank
2371
- // 2. Initiated tracing.
2372
- // We therefore now should navigate back to the original URL that the user wants to profile.
2373
- const resourceModel = this.controller?.primaryPageTarget.model(SDK.ResourceTreeModel.ResourceTreeModel);
2374
- if (!resourceModel) {
2375
- void this.recordingFailed('Could not navigate to original URL');
2376
- return;
2377
- }
2378
- // We don't need to await this because we are purposefully showing UI
2379
- // progress as the page loads & tracing is underway.
2380
- void resourceModel.navigate(config.navigateToUrl);
2381
- }
2382
-
2373
+ private recordingStarted(): void {
2383
2374
  this.#changeView({mode: 'STATUS_PANE_OVERLAY'});
2384
2375
  this.setState(State.RECORDING);
2385
- this.showRecordingStarted();
2386
2376
  if (this.statusDialog) {
2387
2377
  this.statusDialog.enableAndFocusButton();
2388
- this.statusDialog.updateStatus(i18nString(UIStrings.tracing));
2389
2378
  this.statusDialog.updateProgressBar(i18nString(UIStrings.bufferUsage), 0);
2390
2379
  this.statusDialog.startTimer();
2391
2380
  }
@@ -2397,6 +2386,12 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2397
2386
  }
2398
2387
  }
2399
2388
 
2389
+ recordingStatus(status: string): void {
2390
+ if (this.statusDialog) {
2391
+ this.statusDialog.updateStatus(status);
2392
+ }
2393
+ }
2394
+
2400
2395
  /**
2401
2396
  * Hide the sidebar, but persist the user's state, because when they import a
2402
2397
  * trace we want to revert the sidebar back to what it was.
@@ -2467,23 +2462,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2467
2462
  this.statusDialog?.updateStatus(i18nString(UIStrings.processingTrace));
2468
2463
  }
2469
2464
 
2470
- #listenForProcessingProgress(): void {
2471
- this.#traceEngineModel.addEventListener(Trace.TraceModel.ModelUpdateEvent.eventName, e => {
2472
- const updateEvent = e as Trace.TraceModel.ModelUpdateEvent;
2473
- const str = i18nString(UIStrings.processed);
2474
-
2475
- // Trace Engine will report progress from [0...1] but we still have more work to do. So, scale them down a bit.
2476
- const traceParseMaxProgress = 0.7;
2477
-
2478
- if (updateEvent.data.type === Trace.TraceModel.ModelUpdateType.COMPLETE) {
2479
- this.statusDialog?.updateProgressBar(str, 100 * traceParseMaxProgress);
2480
- } else if (updateEvent.data.type === Trace.TraceModel.ModelUpdateType.PROGRESS_UPDATE) {
2481
- const data = updateEvent.data.data;
2482
- this.statusDialog?.updateProgressBar(str, data.percent * 100 * traceParseMaxProgress);
2483
- }
2484
- });
2485
- }
2486
-
2487
2465
  #onSourceMapsNodeNamesResolved(): void {
2488
2466
  // Source maps can change the way calls hierarchies should look in
2489
2467
  // the flame chart (f.e. if some calls are ignore listed after
@@ -2855,7 +2833,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2855
2833
  },
2856
2834
  () => this.stopRecording());
2857
2835
  this.statusDialog.showPane(this.statusPaneContainer);
2858
- this.statusDialog.updateStatus(i18nString(UIStrings.initializingTracing));
2836
+ this.statusDialog.updateStatus(i18nString(UIStrings.tracing));
2859
2837
  this.statusDialog.updateProgressBar(i18nString(UIStrings.bufferUsage), 0);
2860
2838
  }
2861
2839
 
@@ -2865,24 +2843,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2865
2843
  }
2866
2844
  }
2867
2845
 
2868
- private async loadEventFired(
2869
- event: Common.EventTarget
2870
- .EventTargetEvent<{resourceTreeModel: SDK.ResourceTreeModel.ResourceTreeModel, loadTime: number}>):
2871
- Promise<void> {
2872
- if (this.state !== State.RECORDING || !this.recordingPageReload ||
2873
- this.controller?.primaryPageTarget !== event.data.resourceTreeModel.target()) {
2874
- return;
2875
- }
2876
- const controller = this.controller;
2877
- await new Promise(r => window.setTimeout(r, this.millisecondsToRecordAfterLoadEvent));
2878
-
2879
- // Check if we're still in the same recording session.
2880
- if (controller !== this.controller || this.state !== State.RECORDING) {
2881
- return;
2882
- }
2883
- void this.stopRecording();
2884
- }
2885
-
2886
2846
  private frameForSelection(selection: TimelineSelection): Trace.Types.Events.LegacyTimelineFrame|null {
2887
2847
  if (this.#viewMode.mode !== 'VIEWING_TRACE') {
2888
2848
  return null;
@@ -3061,7 +3021,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
3061
3021
  * 3. Flash the Insight with the highlight colour we use in other panels.
3062
3022
  */
3063
3023
  revealInsight(insightModel: Trace.Insights.Types.InsightModel): void {
3064
- const insightSetKey = insightModel.navigationId ?? Trace.Types.Events.NO_NAVIGATION;
3024
+ const insightSetKey = insightModel.navigation?.args.data?.navigationId ?? Trace.Types.Events.NO_NAVIGATION;
3065
3025
  this.#setActiveInsight({model: insightModel, insightSetKey}, {highlightInsight: true});
3066
3026
  }
3067
3027
 
@@ -171,6 +171,7 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
171
171
  export class TimelineTreeView extends
172
172
  Common.ObjectWrapper.eventMixin<TimelineTreeView.EventTypes, typeof UI.Widget.VBox>(UI.Widget.VBox)
173
173
  implements UI.SearchableView.Searchable {
174
+ /** This is sorted by ts. */
174
175
  #selectedEvents: Trace.Types.Events.Event[]|null;
175
176
  private searchResults: Trace.Extras.TraceTree.Node[];
176
177
  linkifier!: Components.Linkifier.Linkifier;
@@ -824,6 +824,10 @@ export class TimelineUIUtils {
824
824
  link = 'https://web.dev/lcp/';
825
825
  name = 'largest contentful paint';
826
826
  break;
827
+ case Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION:
828
+ link = 'https://developer.chrome.com/docs/web-platform/soft-navigations-experiment';
829
+ name = 'largest contentful paint (soft navigation)';
830
+ break;
827
831
  case Trace.Types.Events.Name.MARK_FCP:
828
832
  link = 'https://web.dev/first-contentful-paint/';
829
833
  name = 'first contentful paint';
@@ -1001,6 +1005,20 @@ export class TimelineUIUtils {
1001
1005
  return contentHelper.fragment;
1002
1006
  }
1003
1007
 
1008
+ if (Trace.Types.Events.isNavigationStart(event)) {
1009
+ url = (event.args.data?.documentLoaderURL ?? event.args.data?.url) as Platform.DevToolsPath.UrlString;
1010
+ if (url) {
1011
+ contentHelper.appendElementRow(i18nString(UIStrings.url), LegacyComponents.Linkifier.Linkifier.linkifyURL(url));
1012
+ }
1013
+ }
1014
+
1015
+ if (Trace.Types.Events.isSoftNavigationStart(event)) {
1016
+ url = event.args.context.URL as Platform.DevToolsPath.UrlString;
1017
+ if (url) {
1018
+ contentHelper.appendElementRow(i18nString(UIStrings.url), LegacyComponents.Linkifier.Linkifier.linkifyURL(url));
1019
+ }
1020
+ }
1021
+
1004
1022
  if (Trace.Types.Events.isV8Compile(event)) {
1005
1023
  url = event.args.data?.url as Platform.DevToolsPath.UrlString;
1006
1024
  if (url) {
@@ -1428,6 +1446,7 @@ export class TimelineUIUtils {
1428
1446
  break;
1429
1447
  }
1430
1448
 
1449
+ case Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION:
1431
1450
  // @ts-expect-error Fall-through intended.
1432
1451
  case Trace.Types.Events.Name.MARK_LCP_CANDIDATE: {
1433
1452
  contentHelper.appendTextRow(i18nString(UIStrings.type), String(unsafeEventData['type']));
@@ -2244,6 +2263,10 @@ export class TimelineUIUtils {
2244
2263
  color = 'var(--color-text-primary)';
2245
2264
  tall = true;
2246
2265
  break;
2266
+ case Trace.Types.Events.Name.SOFT_NAVIGATION_START:
2267
+ color = 'var(--sys-color-blue)';
2268
+ tall = true;
2269
+ break;
2247
2270
  case Trace.Types.Events.Name.FRAME_STARTED_LOADING:
2248
2271
  color = 'green';
2249
2272
  tall = true;
@@ -2264,6 +2287,7 @@ export class TimelineUIUtils {
2264
2287
  color = 'var(--sys-color-green-bright)';
2265
2288
  tall = true;
2266
2289
  break;
2290
+ case Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION:
2267
2291
  case Trace.Types.Events.Name.MARK_LCP_CANDIDATE:
2268
2292
  color = 'var(--sys-color-green)';
2269
2293
  tall = true;
@@ -2509,6 +2533,7 @@ export function timeStampForEventAdjustedForClosestNavigationIfPossible(
2509
2533
  event,
2510
2534
  parsedTrace.data.Meta.traceBounds,
2511
2535
  parsedTrace.data.Meta.navigationsByNavigationId,
2536
+ parsedTrace.data.Meta.softNavigationsById,
2512
2537
  parsedTrace.data.Meta.navigationsByFrameId,
2513
2538
  );
2514
2539
  return Trace.Helpers.Timing.microToMilli(time);
@@ -2523,7 +2548,8 @@ export function timeStampForEventAdjustedForClosestNavigationIfPossible(
2523
2548
  export function isMarkerEvent(parsedTrace: Trace.TraceModel.ParsedTrace, event: Trace.Types.Events.Event): boolean {
2524
2549
  const {Name} = Trace.Types.Events;
2525
2550
 
2526
- if (event.name === Name.TIME_STAMP || event.name === Name.NAVIGATION_START) {
2551
+ if (event.name === Name.TIME_STAMP || event.name === Name.NAVIGATION_START ||
2552
+ event.name === Name.SOFT_NAVIGATION_START) {
2527
2553
  return true;
2528
2554
  }
2529
2555
 
@@ -2532,7 +2558,7 @@ export function isMarkerEvent(parsedTrace: Trace.TraceModel.ParsedTrace, event:
2532
2558
  }
2533
2559
 
2534
2560
  if (Trace.Types.Events.isMarkDOMContent(event) || Trace.Types.Events.isMarkLoad(event) ||
2535
- Trace.Types.Events.isLargestContentfulPaintCandidate(event)) {
2561
+ Trace.Types.Events.isAnyLargestContentfulPaintCandidate(event)) {
2536
2562
  // isOutermostMainFrame was added in 2022, so we fallback to isMainFrame
2537
2563
  // for older traces.
2538
2564
  if (!event.args.data) {
@@ -42,6 +42,7 @@ export const SORT_ORDER_PAGE_LOAD_MARKERS: Readonly<Record<string, number>> = {
42
42
  [Trace.Types.Events.Name.MARK_FIRST_PAINT]: 2,
43
43
  [Trace.Types.Events.Name.MARK_DOM_CONTENT]: 3,
44
44
  [Trace.Types.Events.Name.MARK_LCP_CANDIDATE]: 4,
45
+ [Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: 5,
45
46
  };
46
47
 
47
48
  export class TimingsTrackAppender implements TrackAppender {
@@ -182,7 +183,7 @@ export class TimingsTrackAppender implements TrackAppender {
182
183
  color = '#1A6937';
183
184
  title = Trace.Handlers.ModelHandlers.PageLoadMetrics.MetricName.FCP;
184
185
  }
185
- if (Trace.Types.Events.isLargestContentfulPaintCandidate(markerEvent)) {
186
+ if (Trace.Types.Events.isAnyLargestContentfulPaintCandidate(markerEvent)) {
186
187
  color = '#1A3422';
187
188
  title = Trace.Handlers.ModelHandlers.PageLoadMetrics.MetricName.LCP;
188
189
  }
@@ -282,6 +283,7 @@ export class TimingsTrackAppender implements TrackAppender {
282
283
  event,
283
284
  this.#parsedTrace.data.Meta.traceBounds,
284
285
  this.#parsedTrace.data.Meta.navigationsByNavigationId,
286
+ this.#parsedTrace.data.Meta.softNavigationsById,
285
287
  this.#parsedTrace.data.Meta.navigationsByFrameId,
286
288
  );
287
289
  info.formattedTime = getDurationString(timeOfEvent);
@@ -84,7 +84,7 @@ interface InsightData {
84
84
  }
85
85
 
86
86
  interface LocalMetrics {
87
- lcp: {value: Trace.Types.Timing.Micro, event: Trace.Types.Events.LargestContentfulPaintCandidate}|null;
87
+ lcp: {value: Trace.Types.Timing.Micro, event: Trace.Types.Events.AnyLargestContentfulPaintCandidate}|null;
88
88
  cls: {value: number, worstClusterEvent: Trace.Types.Events.Event|null};
89
89
  inp: {value: Trace.Types.Timing.Micro, event: Trace.Types.Events.SyntheticInteractionPair}|null;
90
90
  }
@@ -75,7 +75,7 @@ interface ViewInput {
75
75
  estimatedSavingsAriaLabel: string|null;
76
76
  renderContent: () => Lit.LitTemplate;
77
77
  dispatchInsightToggle: () => void;
78
- onHeaderKeyDown: () => void;
78
+ onHeaderKeyDown: (event: KeyboardEvent) => void;
79
79
  onAskAIButtonClick: () => void;
80
80
  }
81
81
 
@@ -412,7 +412,7 @@ export abstract class BaseInsightComponent<T extends InsightModel> extends UI.Wi
412
412
  showAskAI: this.#canShowAskAI(),
413
413
  dispatchInsightToggle: () => this.#dispatchInsightToggle(),
414
414
  renderContent: () => this.renderContent(),
415
- onHeaderKeyDown: () => this.#onHeaderKeyDown,
415
+ onHeaderKeyDown: this.#onHeaderKeyDown.bind(this),
416
416
  onAskAIButtonClick: () => this.#onAskAIButtonClick(),
417
417
  };
418
418
  this.#view(input, undefined, this.contentElement);
@@ -5,15 +5,17 @@
5
5
  import * as i18n from '../../../../core/i18n/i18n.js';
6
6
  import type {RenderBlockingInsightModel} from '../../../../models/trace/insights/RenderBlocking.js';
7
7
  import * as Trace from '../../../../models/trace/trace.js';
8
+ import * as UI from '../../../../ui/legacy/legacy.js';
8
9
  import * as Lit from '../../../../ui/lit/lit.js';
9
10
 
10
11
  import {BaseInsightComponent} from './BaseInsightComponent.js';
11
12
  import {eventRef} from './EventRef.js';
12
- import {createLimitedRows, renderOthersLabel, type TableDataRow} from './Table.js';
13
+ import {createLimitedRows, renderOthersLabel, Table, type TableDataRow} from './Table.js';
13
14
 
14
15
  const {UIStrings, i18nString, createOverlayForRequest} = Trace.Insights.Models.RenderBlocking;
15
16
 
16
17
  const {html} = Lit;
18
+ const {widgetConfig} = UI.Widget;
17
19
 
18
20
  export class RenderBlocking extends BaseInsightComponent<RenderBlockingInsightModel> {
19
21
  override internalName = 'render-blocking-requests';
@@ -58,12 +60,12 @@ export class RenderBlocking extends BaseInsightComponent<RenderBlockingInsightMo
58
60
  // clang-format off
59
61
  return html`
60
62
  <div class="insight-section">
61
- <devtools-widget
62
- .data=${{
63
+ <devtools-widget .widgetConfig=${widgetConfig(Table, {
64
+ data: {
63
65
  insight: this,
64
66
  headers: [i18nString(UIStrings.renderBlockingRequest), i18nString(UIStrings.duration)],
65
67
  rows,
66
- }}>
68
+ }})}>
67
69
  </devtools-widget>
68
70
  </div>
69
71
  `;
@@ -239,11 +239,11 @@ export class Table extends UI.Widget.Widget {
239
239
  }
240
240
 
241
241
  #onHoverRow(row: TableDataRow, rowEl: HTMLElement): void {
242
- if (row === this.#currentHoverRow) {
242
+ if (row === this.#currentHoverRow || !this.element.shadowRoot) {
243
243
  return;
244
244
  }
245
245
 
246
- for (const el of this.element.querySelectorAll('.hover')) {
246
+ for (const el of this.element.shadowRoot.querySelectorAll('.hover')) {
247
247
  el.classList.remove('hover');
248
248
  }
249
249
 
@@ -251,7 +251,7 @@ export class Table extends UI.Widget.Widget {
251
251
  let curRow: TableDataRow|undefined = this.#rowToParentRow.get(row);
252
252
  while (curRow) {
253
253
  rowEl.classList.add('hover');
254
- curRow = this.#rowToParentRow.get(row);
254
+ curRow = this.#rowToParentRow.get(curRow);
255
255
  }
256
256
 
257
257
  this.#currentHoverRow = row;
@@ -1616,6 +1616,10 @@ export class Overlays extends EventTarget {
1616
1616
  #mouseMoveOverlay(
1617
1617
  e: MouseEvent, event: Trace.Types.Events.PageLoadEvent, name: string, overlay: Trace.Types.Overlays.TimingsMarker,
1618
1618
  markers: HTMLElement, marker: HTMLElement): void {
1619
+ if (Trace.Types.Events.isSoftNavigationStart(event)) {
1620
+ name = 'Soft Nav';
1621
+ }
1622
+
1619
1623
  const fieldResult = overlay.entryToFieldResult.get(event);
1620
1624
  const popoverElement = this.#createOverlayPopover(overlay.adjustedTimestamp, name, fieldResult);
1621
1625
  this.#lastMouseOffsetX = e.offsetX + (markers.offsetLeft || 0) + (marker.offsetLeft || 0);
@@ -90,11 +90,18 @@
90
90
  pointer-events: none;
91
91
  }
92
92
 
93
- .timeline.panel .status-pane-container.tinted {
93
+ .timeline.panel .status-pane-container.opaque {
94
94
  background-color: var(--sys-color-cdt-base-container);
95
95
  pointer-events: auto;
96
96
  }
97
97
 
98
+ .timeline.panel .status-pane-container.tinted {
99
+ /* stylelint-disable-next-line plugin/use_theme_colors */
100
+ background-color: #0005;
101
+ background-blend-mode: multiply;
102
+ pointer-events: auto;
103
+ }
104
+
98
105
  .timeline-landing-page.legacy > div > p {
99
106
  flex: none;
100
107
  white-space: pre-line;
@@ -29,7 +29,8 @@ export function nodeIdsForEvent(
29
29
  } else if (Trace.Types.Events.isSyntheticLayoutShift(event) && event.args.data?.impacted_nodes) {
30
30
  event.args.data.impacted_nodes.forEach(node => foundIds.add(node.node_id));
31
31
  } else if (
32
- Trace.Types.Events.isLargestContentfulPaintCandidate(event) && typeof event.args.data?.nodeId !== 'undefined') {
32
+ Trace.Types.Events.isAnyLargestContentfulPaintCandidate(event) &&
33
+ typeof event.args.data?.nodeId !== 'undefined') {
33
34
  foundIds.add(event.args.data.nodeId);
34
35
  } else if (Trace.Types.Events.isPaint(event) && typeof event.args.data.nodeId !== 'undefined') {
35
36
  foundIds.add(event.args.data.nodeId);
@@ -40,22 +40,28 @@ export function getReleaseNote(): ReleaseNote {
40
40
  }
41
41
 
42
42
  let releaseNote: ReleaseNote = {
43
- version: 143,
44
- header: 'What\'s new in DevTools 143',
43
+ version: 144,
44
+ header: 'What\'s new in DevTools 144',
45
45
  markdownLinks: [
46
+ {
47
+ key: 'request-conditions',
48
+ link: 'https://developer.chrome.com/blog/new-in-devtools-144/#request-conditions',
49
+ },
46
50
  {
47
51
  key: 'mcp-server',
48
- link: 'https://developer.chrome.com/blog/new-in-devtools-143/#mcp-server',
52
+ link: 'https://developer.chrome.com/blog/new-in-devtools-144/#mcp-server',
49
53
  },
50
54
  {
51
- key: 'trace-sharing',
52
- link: 'https://developer.chrome.com/blog/new-in-devtools-143/#trace-sharing',
55
+ key: 'adopted-stylesheets',
56
+ link: 'https://developer.chrome.com/blog/new-in-devtools-144/#adopted-stylesheets',
53
57
  },
58
+ ],
59
+ videoLinks: [
54
60
  {
55
- key: 'starting-style',
56
- link: 'https://developer.chrome.com/blog/new-in-devtools-143/#starting-style',
61
+ description: 'See past highlights from Chrome 144',
62
+ link: 'https://developer.chrome.com/blog/new-in-devtools-144' as Platform.DevToolsPath.UrlString,
63
+ type: VideoType.WHATS_NEW,
57
64
  },
58
65
  ],
59
- videoLinks: [],
60
- link: 'https://developer.chrome.com/blog/new-in-devtools-143/',
66
+ link: 'https://developer.chrome.com/blog/new-in-devtools-144/',
61
67
  };