chrome-devtools-frontend 1.0.1672557 → 1.0.1674545

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 (141) hide show
  1. package/front_end/core/common/SettingRegistration.ts +1 -26
  2. package/front_end/core/common/Settings.ts +4 -53
  3. package/front_end/core/host/UserMetrics.ts +127 -117
  4. package/front_end/core/protocol_client/PuppeteerDevToolsConnection.ts +42 -9
  5. package/front_end/core/root/Runtime.ts +10 -0
  6. package/front_end/core/sdk/NetworkManager.ts +0 -35
  7. package/front_end/core/sdk/SourceMap.ts +1 -19
  8. package/front_end/core/sdk/SourceMapManager.ts +75 -48
  9. package/front_end/core/sdk/SourceMapScopesInfo.ts +0 -62
  10. package/front_end/devtools_compatibility.js +1 -1
  11. package/front_end/generated/InspectorBackendCommands.ts +4 -3
  12. package/front_end/generated/SupportedCSSProperties.ts +16 -1
  13. package/front_end/generated/protocol-mapping.d.ts +8 -0
  14. package/front_end/generated/protocol-proxy-api.d.ts +6 -0
  15. package/front_end/generated/protocol.ts +16 -2
  16. package/front_end/models/ai_assistance/AiSetting.ts +66 -3
  17. package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
  18. package/front_end/models/emulation/DeviceModeModel.ts +25 -34
  19. package/front_end/models/javascript_metadata/NativeFunctions.js +4 -4
  20. package/front_end/models/trace/ModelImpl.ts +5 -0
  21. package/front_end/models/trace/Processor.ts +5 -0
  22. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +7 -1
  23. package/front_end/models/trace/handlers/MetaHandler.ts +8 -4
  24. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +11 -0
  25. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -10
  26. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +3 -45
  27. package/front_end/panels/application/BackgroundServiceView.ts +42 -40
  28. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  29. package/front_end/panels/common/ExtensionServer.ts +7 -1
  30. package/front_end/panels/common/common.ts +0 -1
  31. package/front_end/panels/console/ConsoleInsightTeaser.ts +7 -6
  32. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  33. package/front_end/panels/elements/ClassesPaneWidget.ts +2 -2
  34. package/front_end/panels/elements/ElementsTreeElement.ts +56 -4
  35. package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
  36. package/front_end/panels/elements/components/AdornerManager.ts +1 -0
  37. package/front_end/panels/emulation/AdvancedApp.ts +3 -3
  38. package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -11
  39. package/front_end/panels/emulation/DeviceModeView.ts +234 -75
  40. package/front_end/panels/emulation/InspectedPagePlaceholder.ts +1 -1
  41. package/front_end/panels/emulation/deviceModeView.css +4 -21
  42. package/front_end/panels/emulation/emulation-meta.ts +4 -30
  43. package/front_end/panels/emulation/emulation.ts +0 -3
  44. package/front_end/panels/explain/components/ConsoleInsight.ts +11 -7
  45. package/front_end/panels/layers/LayersPanel.ts +2 -2
  46. package/front_end/panels/layers/layers-meta.ts +2 -2
  47. package/front_end/panels/lighthouse/LighthouseController.ts +3 -7
  48. package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +313 -0
  49. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +0 -10
  50. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +21 -10
  51. package/front_end/panels/mobile_throttling/mobile_throttling.ts +3 -0
  52. package/front_end/panels/network/NetworkConfigView.ts +1 -71
  53. package/front_end/panels/network/networkConfigView.css +1 -2
  54. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +3 -3
  55. package/front_end/panels/profiler/HeapDetachedElementsView.ts +5 -5
  56. package/front_end/panels/profiler/HeapProfileView.ts +32 -32
  57. package/front_end/panels/profiler/HeapProfilerPanel.ts +2 -2
  58. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +33 -37
  59. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +26 -27
  60. package/front_end/panels/profiler/HeapSnapshotView.ts +48 -48
  61. package/front_end/panels/profiler/IsolateSelector.ts +10 -10
  62. package/front_end/panels/profiler/ModuleUIStrings.ts +25 -25
  63. package/front_end/panels/profiler/ProfileLauncherView.ts +6 -6
  64. package/front_end/panels/profiler/ProfilesPanel.ts +6 -6
  65. package/front_end/panels/profiler/WritableProfileHeader.ts +6 -6
  66. package/front_end/panels/profiler/profiler-meta.ts +7 -7
  67. package/front_end/panels/recorder/RecorderPanel.ts +1 -1
  68. package/front_end/panels/settings/AISettingsTab.ts +27 -23
  69. package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +12 -17
  70. package/front_end/panels/timeline/TimelinePanel.ts +20 -35
  71. package/front_end/panels/timeline/components/LiveMetricsView.ts +27 -6
  72. package/front_end/panels/timeline/components/NetworkTrackWidget.ts +1 -1
  73. package/front_end/panels/timeline/components/components.ts +0 -4
  74. package/front_end/panels/timeline/components/liveMetricsView.css +7 -0
  75. package/front_end/third_party/chromium/README.chromium +1 -1
  76. package/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +0 -0
  77. package/front_end/third_party/source-map-scopes-codec/package/LICENSE +0 -0
  78. package/front_end/third_party/source-map-scopes-codec/package/README.md +0 -0
  79. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +0 -0
  80. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
  81. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +0 -0
  82. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +0 -0
  83. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +0 -0
  84. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +0 -0
  85. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +0 -0
  86. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +0 -0
  87. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +0 -0
  88. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +0 -0
  89. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +0 -0
  90. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +0 -0
  91. package/front_end/third_party/source-map-scopes-codec/package/deno.json +1 -1
  92. package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
  93. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +2 -0
  94. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -1
  95. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +2 -0
  96. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +0 -0
  97. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +0 -0
  98. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +0 -0
  99. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +0 -0
  100. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +0 -0
  101. package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +0 -0
  102. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +0 -0
  103. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +0 -0
  104. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +0 -0
  105. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +0 -0
  106. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +0 -0
  107. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +0 -0
  108. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +0 -0
  109. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +0 -0
  110. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +0 -0
  111. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js +0 -0
  112. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js.map +0 -0
  113. package/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +0 -0
  114. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +0 -0
  115. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js.map +0 -0
  116. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.ts +0 -0
  117. package/front_end/third_party/source-map-scopes-codec/package/src/util.js +0 -0
  118. package/front_end/third_party/source-map-scopes-codec/package/src/util.js.map +0 -0
  119. package/front_end/third_party/source-map-scopes-codec/package/src/util.ts +0 -0
  120. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +0 -0
  121. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +0 -0
  122. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +0 -0
  123. package/front_end/ui/components/dialogs/ShortcutDialog.ts +2 -0
  124. package/front_end/ui/components/settings/SettingCheckbox.ts +4 -12
  125. package/front_end/ui/components/settings/settingCheckbox.css +0 -7
  126. package/front_end/ui/legacy/Treeoutline.ts +14 -14
  127. package/front_end/ui/legacy/UIUtils.ts +2 -47
  128. package/front_end/ui/legacy/Widget.ts +10 -2
  129. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
  130. package/front_end/ui/lit/Directives.ts +80 -0
  131. package/front_end/ui/lit/lit.ts +1 -0
  132. package/front_end/ui/lit/render.ts +8 -0
  133. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  134. package/mcp/mcp.ts +1 -0
  135. package/package.json +1 -1
  136. package/front_end/panels/common/ThrottlingUtils.ts +0 -51
  137. package/front_end/panels/emulation/DeviceModeWrapper.ts +0 -248
  138. package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +0 -235
  139. package/front_end/panels/timeline/components/NetworkThrottlingSelector.ts +0 -245
  140. package/front_end/panels/timeline/components/cpuThrottlingSelector.css +0 -30
  141. package/front_end/panels/timeline/components/networkThrottlingSelector.css +0 -24
@@ -156,7 +156,8 @@ export class BackgroundServiceView extends UI.Widget.VBox {
156
156
  private readonly splitWidget: UI.SplitWidget.SplitWidget;
157
157
  private readonly dataGrid: DataGrid.DataGrid.DataGridImpl<EventData>;
158
158
  private readonly previewPanel: UI.Widget.VBox;
159
- private selectedEventNode: EventDataNode|null;
159
+ #isRecording = false;
160
+ #selectedEventNode: EventDataNode|null = null;
160
161
  private preview: UI.Widget.Widget|null;
161
162
 
162
163
  static getUIString(serviceName: string): string {
@@ -214,7 +215,7 @@ export class BackgroundServiceView extends UI.Widget.VBox {
214
215
 
215
216
  this.toolbar = this.contentElement.createChild('devtools-toolbar', 'background-service-toolbar');
216
217
  this.toolbar.setAttribute('jslog', `${VisualLogging.toolbar()}`);
217
- void this.setupToolbar();
218
+ this.setupToolbar();
218
219
 
219
220
  /**
220
221
  * This will contain the DataGrid for displaying events, and a panel at the bottom for showing
@@ -228,15 +229,13 @@ export class BackgroundServiceView extends UI.Widget.VBox {
228
229
  this.previewPanel = new UI.Widget.VBox();
229
230
  this.previewPanel.element.setAttribute('jslog', `${VisualLogging.pane('preview').track({resize: true})}`);
230
231
 
231
- this.selectedEventNode = null;
232
-
233
232
  this.preview = null;
234
233
 
235
234
  this.splitWidget.setMainWidget(this.dataGrid.asWidget());
236
235
  this.splitWidget.setSidebarWidget(this.previewPanel);
237
236
  this.splitWidget.hideMain();
238
237
 
239
- this.showPreview(null);
238
+ this.performUpdate();
240
239
  }
241
240
 
242
241
  getDataGrid(): DataGrid.DataGrid.DataGridImpl<EventData> {
@@ -246,7 +245,7 @@ export class BackgroundServiceView extends UI.Widget.VBox {
246
245
  /**
247
246
  * Creates the toolbar UI element.
248
247
  */
249
- private async setupToolbar(): Promise<void> {
248
+ private setupToolbar(): void {
250
249
  this.toolbar.wrappable = true;
251
250
  this.recordButton = (UI.Toolbar.Toolbar.createActionButton(this.recordAction) as UI.Toolbar.ToolbarToggle);
252
251
  this.recordButton.toggleOnClick(false);
@@ -264,7 +263,6 @@ export class BackgroundServiceView extends UI.Widget.VBox {
264
263
  this.saveButton.addEventListener(UI.Toolbar.ToolbarButton.Events.CLICK, _event => {
265
264
  void this.saveToFile();
266
265
  });
267
- this.saveButton.setEnabled(false);
268
266
  this.toolbar.appendToolbarItem(this.saveButton);
269
267
 
270
268
  this.toolbar.appendSeparator();
@@ -295,18 +293,17 @@ export class BackgroundServiceView extends UI.Widget.VBox {
295
293
  * Clears the grid and panel.
296
294
  */
297
295
  private clearView(): void {
298
- this.selectedEventNode = null;
296
+ this.#selectedEventNode = null;
299
297
  this.dataGrid.rootNode().removeChildren();
300
298
  this.splitWidget.hideMain();
301
- this.saveButton.setEnabled(false);
302
- this.showPreview(null);
299
+ this.performUpdate();
303
300
  }
304
301
 
305
302
  /**
306
303
  * Called when the `Toggle Record` button is clicked.
307
304
  */
308
305
  toggleRecording(): void {
309
- const isRecording = !this.recordButton.isToggled();
306
+ const isRecording = !this.#isRecording;
310
307
  this.model.setRecording(isRecording, this.serviceName);
311
308
  const featureName = BackgroundServiceView.getUIString(this.serviceName).toLowerCase();
312
309
 
@@ -331,19 +328,12 @@ export class BackgroundServiceView extends UI.Widget.VBox {
331
328
  return;
332
329
  }
333
330
 
334
- if (state.isRecording === this.recordButton.isToggled()) {
331
+ if (state.isRecording === this.#isRecording) {
335
332
  return;
336
333
  }
337
334
 
338
- this.recordButton.setToggled(state.isRecording);
339
- this.updateRecordButtonTooltip();
340
- this.showPreview(this.selectedEventNode);
341
- }
342
-
343
- private updateRecordButtonTooltip(): void {
344
- const buttonTooltip = this.recordButton.isToggled() ? i18nString(UIStrings.stopRecordingEvents) :
345
- i18nString(UIStrings.startRecordingEvents);
346
- this.recordButton.setTitle(buttonTooltip, 'background-service.toggle-recording');
335
+ this.#isRecording = state.isRecording;
336
+ this.performUpdate();
347
337
  }
348
338
 
349
339
  private onEventReceived({
@@ -380,8 +370,7 @@ export class BackgroundServiceView extends UI.Widget.VBox {
380
370
  }
381
371
 
382
372
  if (this.dataGrid.rootNode().children.length === 1) {
383
- this.saveButton.setEnabled(true);
384
- this.showPreview(this.selectedEventNode);
373
+ this.performUpdate();
385
374
  }
386
375
  }
387
376
 
@@ -401,12 +390,31 @@ export class BackgroundServiceView extends UI.Widget.VBox {
401
390
  });
402
391
  dataGrid.setStriped(true);
403
392
 
404
- dataGrid.addEventListener(
405
- DataGrid.DataGrid.Events.SELECTED_NODE, event => this.showPreview((event.data as EventDataNode)));
393
+ dataGrid.addEventListener(DataGrid.DataGrid.Events.SELECTED_NODE, event => {
394
+ this.#selectedEventNode = event.data as EventDataNode;
395
+ this.performUpdate();
396
+ });
406
397
 
407
398
  return dataGrid;
408
399
  }
409
400
 
401
+ override performUpdate(): void {
402
+ this.#updateToolbar();
403
+ this.#updatePreview();
404
+ }
405
+
406
+ #updateToolbar(): void {
407
+ if (this.recordButton) {
408
+ this.recordButton.setToggled(this.#isRecording);
409
+ const buttonTooltip =
410
+ this.#isRecording ? i18nString(UIStrings.stopRecordingEvents) : i18nString(UIStrings.startRecordingEvents);
411
+ this.recordButton.setTitle(buttonTooltip, 'background-service.toggle-recording');
412
+ }
413
+ if (this.saveButton) {
414
+ this.saveButton.setEnabled(this.dataGrid.rootNode().children.length > 0);
415
+ }
416
+ }
417
+
410
418
  /**
411
419
  * Creates the data object to pass to the DataGrid Node.
412
420
  */
@@ -475,19 +483,13 @@ export class BackgroundServiceView extends UI.Widget.VBox {
475
483
  return url as Platform.DevToolsPath.UrlString;
476
484
  }
477
485
 
478
- private showPreview(dataNode: EventDataNode|null): void {
479
- if (this.selectedEventNode && this.selectedEventNode === dataNode) {
480
- return;
481
- }
482
-
483
- this.selectedEventNode = dataNode;
484
-
486
+ #updatePreview(): void {
485
487
  if (this.preview) {
486
488
  this.preview.detach();
487
489
  }
488
490
 
489
- if (this.selectedEventNode) {
490
- this.preview = this.selectedEventNode.createPreview();
491
+ if (this.#selectedEventNode) {
492
+ this.preview = this.#selectedEventNode.createPreview();
491
493
  this.preview.show(this.previewPanel.contentElement);
492
494
  return;
493
495
  }
@@ -496,7 +498,7 @@ export class BackgroundServiceView extends UI.Widget.VBox {
496
498
  if (this.dataGrid.rootNode().children.length) {
497
499
  emptyWidget = new UI.EmptyWidget.EmptyWidget(
498
500
  i18nString(UIStrings.noEventSelected), i18nString(UIStrings.selectAnEventToViewMetadata));
499
- } else if (this.recordButton.isToggled()) {
501
+ } else if (this.#isRecording) {
500
502
  // Inform users that we are recording/waiting for events.
501
503
  const featureName = BackgroundServiceView.getUIString(this.serviceName).toLowerCase();
502
504
  emptyWidget = new UI.EmptyWidget.EmptyWidget(
@@ -505,11 +507,11 @@ export class BackgroundServiceView extends UI.Widget.VBox {
505
507
  } else {
506
508
  const recordShortcuts =
507
509
  UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutsForAction('background-service.toggle-recording')[0];
508
- emptyWidget = new UI.EmptyWidget.EmptyWidget(
509
- i18nString(UIStrings.noRecording), i18nString(UIStrings.startRecordingToDebug, {
510
- PH1: i18nString(UIStrings.startRecordingEvents),
511
- PH2: recordShortcuts.title(),
512
- }));
510
+ emptyWidget = new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.noRecording),
511
+ i18nString(UIStrings.startRecordingToDebug, {
512
+ PH1: i18nString(UIStrings.startRecordingEvents),
513
+ PH2: recordShortcuts ? recordShortcuts.title() : '',
514
+ }));
513
515
  emptyWidget.link = this.createLearnMoreLink();
514
516
 
515
517
  const button = UI.UIUtils.createTextButton(
@@ -280,6 +280,7 @@ export abstract class KeyValueStorageItemsView extends UI.Widget.VBox {
280
280
  },
281
281
  };
282
282
  this.#view(viewInput, viewOutput, this.contentElement);
283
+ this.doResize();
283
284
  }
284
285
 
285
286
  protected isAiButtonEnabled(): boolean {
@@ -951,7 +951,7 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
951
951
  /**
952
952
  * Slightly more permissive as {@link extensionAllowedOnURL}: This method also permits
953
953
  * UISourceCodes that originate from a {@link SDK.Script.Script} with a sourceURL magic comment as
954
- * long as the corresponding target is permitted.
954
+ * long as the corresponding target and the embedder name (if it is a URL) are permitted.
955
955
  */
956
956
  private extensionAllowedOnContentProvider(
957
957
  contentProvider: TextUtils.ContentProvider.ContentProvider, port: MessagePort): boolean {
@@ -968,6 +968,12 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
968
968
  }
969
969
  return scripts.every(script => {
970
970
  if (script.hasSourceURL) {
971
+ // TODO(542925220): embedderName is a terrible proxy, but currently V8 stores the original URL only in there.
972
+ // We'll add a proper field in the future and will replace it then.
973
+ const embedderName = script.embedderName();
974
+ if (embedderName && URL.canParse(embedderName) && !this.extensionAllowedOnURL(embedderName, port)) {
975
+ return false;
976
+ }
971
977
  return this.extensionAllowedOnTarget(script.target(), port);
972
978
  }
973
979
  return this.extensionAllowedOnURL(script.contentURL(), port) &&
@@ -109,5 +109,4 @@ export * as ExtensionServer from './ExtensionServer.js';
109
109
  export * as ExtensionView from './ExtensionView.js';
110
110
  export * as PersistenceUtils from './PersistenceUtils.js';
111
111
  export * as DOMLinkifier from './DOMLinkifier.js';
112
- export * as ThrottlingUtils from './ThrottlingUtils.js';
113
112
  export * as ExtensionIframe from './ExtensionView.js';
@@ -437,10 +437,12 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
437
437
  this.requestUpdate();
438
438
  }
439
439
 
440
- #getConsoleInsightsEnabledSetting(): Common.Settings.Setting<boolean>|undefined {
441
- const result = Common.Settings.Settings.instance().maybeResolve(
442
- AiAssistanceModel.AiUtils.consoleInsightsEnabledSettingDescriptor);
443
- return 'setting' in result ? (result.setting as Common.Settings.Setting<boolean>) : undefined;
440
+ #getConsoleInsightsEnabledSetting(): AiAssistanceModel.AiSetting.AiSetting<boolean> {
441
+ return new AiAssistanceModel.AiSetting.AiSetting(
442
+ AiAssistanceModel.AiUtils.consoleInsightsEnabledSettingDescriptor,
443
+ Host.AidaClient.HostConfigTracker.instance(),
444
+ Common.Settings.Settings.instance(),
445
+ );
444
446
  }
445
447
 
446
448
  #getOnboardingCompletedSetting(): Common.Settings.Setting<boolean> {
@@ -466,8 +468,7 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
466
468
 
467
469
  #onTellMeMoreClick(event: Event): void {
468
470
  event.stopPropagation();
469
- if (this.#getConsoleInsightsEnabledSetting()?.getIfNotDisabled() &&
470
- this.#getOnboardingCompletedSetting()?.getIfNotDisabled()) {
471
+ if (this.#getConsoleInsightsEnabledSetting()?.getIfNotDisabled() && this.#getOnboardingCompletedSetting()?.get()) {
471
472
  this.#executeConsoleInsightAction();
472
473
  return;
473
474
  }
@@ -1539,7 +1539,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1539
1539
  if (!this.shouldShowInsights()) {
1540
1540
  return false;
1541
1541
  }
1542
- if (!Common.Settings.Settings.instance().moduleSetting('console-insight-teasers-enabled').getIfNotDisabled() ||
1542
+ if (!Common.Settings.Settings.instance().moduleSetting('console-insight-teasers-enabled').get() ||
1543
1543
  !AiAssistanceModel.BuiltInAi.BuiltInAi.instance().isEventuallyAvailable()) {
1544
1544
  return false;
1545
1545
  }
@@ -342,8 +342,8 @@ export class ClassNamePrompt extends UI.TextPrompt.TextPrompt {
342
342
  return [...completions];
343
343
  }
344
344
 
345
- private async buildClassNameCompletions(expression: string, prefix: string, force?: boolean):
346
- Promise<UI.SuggestBox.Suggestions> {
345
+ private async buildClassNameCompletions(expression: string, prefix: string,
346
+ force?: boolean): Promise<UI.SuggestBox.Suggestions> {
347
347
  if (!prefix || force) {
348
348
  this.classNamesPromise = null;
349
349
  }
@@ -40,6 +40,7 @@ import * as Common from '../../core/common/common.js';
40
40
  import * as Host from '../../core/host/host.js';
41
41
  import * as i18n from '../../core/i18n/i18n.js';
42
42
  import * as Platform from '../../core/platform/platform.js';
43
+ import * as Root from '../../core/root/root.js';
43
44
  import * as SDK from '../../core/sdk/sdk.js';
44
45
  import * as TextUtils from '../../core/text_utils/text_utils.js';
45
46
  import * as Protocol from '../../generated/protocol.js';
@@ -244,6 +245,14 @@ const UIStrings = {
244
245
  * @description ARIA label for an elements tree adorner
245
246
  */
246
247
  stopForceOpenPopover: 'Stop keeping this popover open',
248
+ /**
249
+ * @description ARIA label for an elements tree adorner
250
+ */
251
+ forceShowInterest: 'Trigger interest on this element',
252
+ /**
253
+ * @description ARIA label for an elements tree adorner
254
+ */
255
+ stopForceShowInterest: 'Cancel interest on this element',
247
256
  /**
248
257
  * @description Label of the adorner for flex elements in the Elements panel
249
258
  */
@@ -426,6 +435,7 @@ export interface ViewInput {
426
435
  flexAdornerActive: boolean;
427
436
  gridAdornerActive: boolean;
428
437
  popoverAdornerActive: boolean;
438
+ interestAdornerActive: boolean;
429
439
 
430
440
  adProvenance?: Protocol.Network.AdProvenance;
431
441
  target?: SDK.Target.Target;
@@ -438,6 +448,7 @@ export interface ViewInput {
438
448
  showGridLanesAdorner: boolean;
439
449
  showMediaAdorner: boolean;
440
450
  showPopoverAdorner: boolean;
451
+ showInterestAdorner: boolean;
441
452
  showTopLayerAdorner: boolean;
442
453
  isSubgrid: boolean;
443
454
 
@@ -453,6 +464,7 @@ export interface ViewInput {
453
464
  onGridAdornerClick: (e: Event) => void;
454
465
  onMediaAdornerClick: (e: Event) => void;
455
466
  onPopoverAdornerClick: (e: Event) => void;
467
+ onInterestAdornerClick: (e: Event) => void;
456
468
  onScrollSnapAdornerClick: (e: Event) => void;
457
469
  onTopLayerAdornerClick: (e: Event) => void;
458
470
  onViewSourceAdornerClick: () => void;
@@ -977,9 +989,9 @@ function maybeRenderAdAdorner(input: ViewInput): Lit.TemplateResult|typeof nothi
977
989
  export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement): void => {
978
990
  const hasAdorners = !!input.adProvenance || input.showContainerAdorner || input.showFlexAdorner ||
979
991
  input.showGridAdorner || input.showGridLanesAdorner || input.showMediaAdorner || input.showPopoverAdorner ||
980
- input.showTopLayerAdorner || input.showViewSourceAdorner || input.showScrollAdorner ||
981
- input.showScrollSnapAdorner || input.showSlotAdorner || input.showStartingStyleAdorner ||
982
- input.showCustomElementAdorner;
992
+ input.showInterestAdorner || input.showTopLayerAdorner || input.showViewSourceAdorner ||
993
+ input.showScrollAdorner || input.showScrollSnapAdorner || input.showSlotAdorner ||
994
+ input.showStartingStyleAdorner || input.showCustomElementAdorner;
983
995
  const gutterContainerClasses = {
984
996
  'has-decorations': input.decorations.length || input.descendantDecorations.length,
985
997
  'gutter-container': true,
@@ -1121,6 +1133,20 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
1121
1133
  ${adornerRef()}>
1122
1134
  <span>${ElementsComponents.AdornerManager.RegisteredAdorners.POPOVER}</span>
1123
1135
  </devtools-adorner>`: nothing}
1136
+ ${input.showInterestAdorner ? html`<devtools-adorner
1137
+ class=clickable
1138
+ role=button
1139
+ toggleable=true
1140
+ tabindex=0
1141
+ .name=${ElementsComponents.AdornerManager.RegisteredAdorners.INTEREST}
1142
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.INTEREST).track({ click: true })}
1143
+ active=${input.interestAdornerActive}
1144
+ aria-label=${input.interestAdornerActive ? i18nString(UIStrings.stopForceShowInterest) : i18nString(UIStrings.forceShowInterest)}
1145
+ @click=${input.onInterestAdornerClick}
1146
+ @keydown=${handleAdornerKeydown(input.onInterestAdornerClick)}
1147
+ ${adornerRef()}>
1148
+ <span>${ElementsComponents.AdornerManager.RegisteredAdorners.INTEREST}</span>
1149
+ </devtools-adorner>`: nothing}
1124
1150
  ${input.showTopLayerAdorner ? html`<devtools-adorner
1125
1151
  class=clickable
1126
1152
  role=button
@@ -1238,6 +1264,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1238
1264
  #flexAdornerActive = false;
1239
1265
  #gridAdornerActive = false;
1240
1266
  #popoverAdornerActive = false;
1267
+ #interestAdornerActive = false;
1241
1268
 
1242
1269
  #scrollSnapAdornerActive = false;
1243
1270
  #startingStyleAdornerActive = false;
@@ -1389,9 +1416,14 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1389
1416
  showMediaAdorner: this.node().isMediaNode() && !this.isClosingTag(),
1390
1417
  showPopoverAdorner:
1391
1418
  Boolean(this.node().attributes().find(attr => attr.name === 'popover')) && !this.isClosingTag(),
1419
+ showInterestAdorner: Boolean(Root.Runtime.hostConfig.devToolsAllowInterestForcing?.enabled) &&
1420
+ Boolean(this.node().attributes().find(attr =>
1421
+ attr.name === 'interesttarget' || attr.name === 'interestfor')) &&
1422
+ !this.isClosingTag(),
1392
1423
  showTopLayerAdorner: this.node().topLayerIndex() !== -1 && !this.isClosingTag(),
1393
1424
  gridAdornerActive: this.#gridAdornerActive,
1394
1425
  popoverAdornerActive: this.#popoverAdornerActive,
1426
+ interestAdornerActive: this.#interestAdornerActive,
1395
1427
  isSubgrid: Boolean(this.#layout?.isSubgrid),
1396
1428
  showViewSourceAdorner: this.nodeInternal.isRootNode() && isOpeningTag(this.tagTypeContext),
1397
1429
  showScrollAdorner: ((this.node().nodeName() === 'HTML' && this.node().ownerDocument?.isScrollable()) ||
@@ -1431,6 +1463,8 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1431
1463
  (event: Event) => this.#onMediaAdornerClick(event),
1432
1464
  onPopoverAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1433
1465
  (event: Event) => this.#onPopoverAdornerClick(event),
1466
+ onInterestAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1467
+ (event: Event) => this.#onInterestAdornerClick(event),
1434
1468
  onScrollSnapAdornerClick:
1435
1469
  this.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onScrollSnapAdornerClick(event),
1436
1470
  onTopLayerAdornerClick: this.treeOutline?.disableEdits ? () => {} :
@@ -1792,9 +1826,11 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1792
1826
  showGridLanesAdorner: false,
1793
1827
  showMediaAdorner: false,
1794
1828
  showPopoverAdorner: false,
1829
+ showInterestAdorner: false,
1795
1830
  showTopLayerAdorner: false,
1796
1831
  gridAdornerActive: false,
1797
1832
  popoverAdornerActive: false,
1833
+ interestAdornerActive: false,
1798
1834
  isSubgrid: false,
1799
1835
  showViewSourceAdorner: false,
1800
1836
  showScrollAdorner: false,
@@ -1815,6 +1851,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1815
1851
  onGridAdornerClick: () => {},
1816
1852
  onMediaAdornerClick: () => {},
1817
1853
  onPopoverAdornerClick: () => {},
1854
+ onInterestAdornerClick: () => {},
1818
1855
  onScrollSnapAdornerClick: () => {},
1819
1856
  onTopLayerAdornerClick: () => {},
1820
1857
  isHovered: false,
@@ -2369,7 +2406,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2369
2406
  contextMenu.viewSection().appendItem(i18nString(UIStrings.switchToAccessibilityTree),
2370
2407
  () => ElementsPanel.instance().toggleAccessibilityTree(),
2371
2408
  {jslogContext: 'switch-to-accessibility-tree'});
2372
- const deviceModeWrapperAction = new Emulation.DeviceModeWrapper.ActionDelegate();
2409
+ const deviceModeWrapperAction = new Emulation.DeviceModeView.ActionDelegate();
2373
2410
  contextMenu.viewSection().appendItem(
2374
2411
  i18nString(UIStrings.captureNodeScreenshot),
2375
2412
  deviceModeWrapperAction.handleAction.bind(
@@ -3275,6 +3312,21 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3275
3312
  this.performUpdate();
3276
3313
  }
3277
3314
 
3315
+ async #onInterestAdornerClick(event: Event): Promise<void> {
3316
+ event.stopPropagation();
3317
+ const node = this.node();
3318
+ const nodeId = node.id;
3319
+ if (!nodeId) {
3320
+ return;
3321
+ }
3322
+ await node.domModel().agent.invoke_forceShowInterest({nodeId, enable: !this.#interestAdornerActive});
3323
+ this.#interestAdornerActive = !this.#interestAdornerActive;
3324
+ if (this.#interestAdornerActive) {
3325
+ Badges.UserBadges.instance().recordAction(Badges.BadgeAction.MODERN_DOM_BADGE_CLICKED);
3326
+ }
3327
+ this.performUpdate();
3328
+ }
3329
+
3278
3330
  #onStartingStyleAdornerClick(event: Event): void {
3279
3331
  event.stopPropagation();
3280
3332
  const node = this.node();
@@ -1668,7 +1668,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
1668
1668
  this.#elementsForSyncViewportCheck = [];
1669
1669
  return;
1670
1670
  }
1671
- const scrollContainer = this.contentElement.parentElement;
1671
+ const scrollContainer = this.element.parentElement;
1672
1672
  if (!scrollContainer) {
1673
1673
  this.#elementsForSyncViewportCheck = [];
1674
1674
  return;
@@ -16,6 +16,7 @@ export enum RegisteredAdorners {
16
16
  FLEX = 'flex',
17
17
  GRID = 'grid',
18
18
  GRID_LANES = 'grid-lanes',
19
+ INTEREST = 'interest',
19
20
  MEDIA = 'media',
20
21
  POPOVER = 'popover',
21
22
  REVEAL = 'reveal',
@@ -9,14 +9,14 @@ import type * as Foundation from '../../foundation/foundation.js';
9
9
  import * as UI from '../../ui/legacy/legacy.js';
10
10
  import * as ThemeSupport from '../../ui/legacy/theme_support/theme_support.js';
11
11
 
12
- import {DeviceModeWrapper} from './DeviceModeWrapper.js';
12
+ import {DeviceModeView} from './DeviceModeView.js';
13
13
  import {type Bounds, Events, InspectedPagePlaceholder} from './InspectedPagePlaceholder.js';
14
14
 
15
15
  let appInstance: AdvancedApp|null = null;
16
16
 
17
17
  export class AdvancedApp implements UI.App.App {
18
18
  private rootSplitWidget!: UI.SplitWidget.SplitWidget;
19
- private deviceModeView!: DeviceModeWrapper;
19
+ private deviceModeView!: DeviceModeView;
20
20
  private inspectedPagePlaceholder!: InspectedPagePlaceholder;
21
21
  private toolboxWindow?: Window|null;
22
22
  private toolboxRootView?: UI.RootView.RootView;
@@ -58,7 +58,7 @@ export class AdvancedApp implements UI.App.App {
58
58
 
59
59
  this.inspectedPagePlaceholder = InspectedPagePlaceholder.instance();
60
60
  this.inspectedPagePlaceholder.addEventListener(Events.UPDATE, this.onSetInspectedPageBounds.bind(this), this);
61
- this.deviceModeView = new DeviceModeWrapper();
61
+ this.deviceModeView = new DeviceModeView();
62
62
 
63
63
  UI.DockController.DockController.instance().addEventListener(
64
64
  UI.DockController.Events.BEFORE_DOCK_SIDE_CHANGED, this.onBeforeDockSideChange, this);
@@ -117,14 +117,7 @@ const UIStrings = {
117
117
  * @example {4.3} PH1
118
118
  */
119
119
  defaultF: '{PH1} (default)',
120
- /**
121
- * @description Command to hide the frame around the mobile device screen.
122
- */
123
- hideDeviceFrame: 'Hide device frame',
124
- /**
125
- * @description Command to show the frame around the mobile device screen.
126
- */
127
- showDeviceFrame: 'Show device frame',
120
+
128
121
  /**
129
122
  * @description Command to hide a display in the device mode toolbar that shows the different media
130
123
  * queries for the device, above the device screen.
@@ -801,8 +794,7 @@ export class DeviceModeToolbar extends UI.Widget.Widget {
801
794
  return;
802
795
  }
803
796
  const model = this.model;
804
- appendToggleItem(contextMenu.headerSection(), model.deviceOutlineSetting(), i18nString(UIStrings.hideDeviceFrame),
805
- i18nString(UIStrings.showDeviceFrame), !model.canShowDeviceFrame(), 'device-frame');
797
+
806
798
  appendToggleItem(
807
799
  contextMenu.headerSection(), this.showMediaInspectorSetting, i18nString(UIStrings.hideMediaQueries),
808
800
  i18nString(UIStrings.showMediaQueries), undefined, 'media-queries');
@@ -839,7 +831,6 @@ export class DeviceModeToolbar extends UI.Widget.Widget {
839
831
  }
840
832
 
841
833
  private reset(): void {
842
- this.model?.deviceOutlineSetting().set(false);
843
834
  this.showDeviceScaleFactorSetting.set(false);
844
835
  this.showUserAgentTypeSetting.set(false);
845
836
  this.showMediaInspectorSetting.set(false);