chrome-devtools-frontend 1.0.1660788 → 1.0.1661063

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 (132) hide show
  1. package/.agents/skills/evaluate-ai-css-completion/SKILL.md +133 -0
  2. package/.agents/skills/evaluate-ai-css-completion/scripts/evaluate.js +76 -0
  3. package/eslint.config.mjs +7 -0
  4. package/extension-api/ExtensionAPI.d.ts +88 -0
  5. package/front_end/core/host/InspectorFrontendHost.ts +1 -0
  6. package/front_end/core/host/InspectorFrontendHostStub.ts +2 -0
  7. package/front_end/core/platform/StringUtilities.ts +20 -4
  8. package/front_end/core/sdk/CPUThrottlingManager.ts +2 -0
  9. package/front_end/core/sdk/DOMDebuggerModel.ts +2 -0
  10. package/front_end/core/sdk/DOMModel.ts +1 -0
  11. package/front_end/core/sdk/DebuggerModel.ts +4 -4
  12. package/front_end/core/sdk/EventBreakpointsModel.ts +2 -0
  13. package/front_end/core/sdk/FrameManager.ts +1 -0
  14. package/front_end/core/sdk/IsolateManager.ts +1 -0
  15. package/front_end/core/sdk/NetworkManager.ts +2 -0
  16. package/front_end/core/sdk/NetworkRequest.ts +1 -0
  17. package/front_end/core/sdk/PageResourceLoader.ts +2 -0
  18. package/front_end/core/sdk/SourceMap.ts +5 -5
  19. package/front_end/core/sdk/SourceMapManager.ts +3 -2
  20. package/front_end/core/sdk/TargetManager.ts +4 -0
  21. package/front_end/entrypoints/main/MainImpl.ts +2 -1
  22. package/front_end/models/bindings/CompilerScriptMapping.ts +5 -6
  23. package/front_end/models/bindings/ContentProviderBasedProject.ts +4 -4
  24. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +3 -4
  25. package/front_end/models/bindings/DefaultScriptMapping.ts +3 -3
  26. package/front_end/models/bindings/NetworkProject.ts +1 -10
  27. package/front_end/models/bindings/ResourceMapping.ts +3 -4
  28. package/front_end/models/bindings/ResourceScriptMapping.ts +2 -3
  29. package/front_end/models/bindings/SASSSourceMapping.ts +3 -4
  30. package/front_end/models/bindings/StylesSourceMapping.ts +3 -3
  31. package/front_end/models/bindings/TempFile.ts +8 -3
  32. package/front_end/models/extensions/ExtensionAPI.ts +110 -46
  33. package/front_end/models/formatter/ScriptFormatter.ts +8 -11
  34. package/front_end/models/issues_manager/CookieIssue.ts +21 -9
  35. package/front_end/models/issues_manager/Issue.ts +3 -4
  36. package/front_end/models/issues_manager/IssueAggregator.ts +0 -9
  37. package/front_end/models/issues_manager/IssueResolver.ts +2 -2
  38. package/front_end/models/issues_manager/IssuesManager.ts +136 -137
  39. package/front_end/models/issues_manager/issues_manager.ts +0 -2
  40. package/front_end/models/persistence/AutomaticFileSystemWorkspaceBinding.ts +5 -0
  41. package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +13 -10
  42. package/front_end/models/workspace/WorkspaceImpl.ts +10 -1
  43. package/front_end/models/workspace_diff/WorkspaceDiff.ts +10 -4
  44. package/front_end/panels/ai_assistance/components/ChatMessage.ts +2 -1
  45. package/front_end/panels/application/FrameDetailsView.ts +1 -1
  46. package/front_end/panels/application/WebMCPView.ts +38 -43
  47. package/front_end/panels/application/components/AdsView.ts +201 -30
  48. package/front_end/panels/application/components/adsView.css +25 -0
  49. package/front_end/panels/application/preloading/components/RuleSetDetailsView.ts +2 -2
  50. package/front_end/panels/console/ConsoleView.ts +2 -1
  51. package/front_end/panels/console/PromptBuilder.ts +2 -1
  52. package/front_end/panels/emulation/DeviceModeView.ts +52 -70
  53. package/front_end/panels/issues/IssueView.ts +0 -2
  54. package/front_end/panels/issues/IssuesPane.ts +1 -8
  55. package/front_end/panels/js_timeline/js_timeline-meta.ts +3 -2
  56. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +3 -3
  57. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +5 -5
  58. package/front_end/panels/linear_memory_inspector/components/LinearMemoryHighlightChipList.ts +4 -4
  59. package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +2 -2
  60. package/front_end/panels/linear_memory_inspector/components/LinearMemoryNavigator.ts +6 -6
  61. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +3 -3
  62. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterDisplay.ts +8 -9
  63. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterDisplayUtils.ts +2 -2
  64. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterSettings.ts +1 -1
  65. package/front_end/panels/linear_memory_inspector/linear_memory_inspector-meta.ts +2 -2
  66. package/front_end/panels/network/RequestPayloadView.ts +15 -13
  67. package/front_end/panels/network/RequestTimingView.ts +95 -127
  68. package/front_end/panels/profiler/HeapSnapshotView.ts +1 -1
  69. package/front_end/panels/profiler/WritableProfileHeader.ts +2 -2
  70. package/front_end/panels/recorder/{components/ControlButton.ts → ControlButton.ts} +9 -10
  71. package/front_end/panels/recorder/{components/CreateRecordingView.ts → CreateRecordingView.ts} +48 -47
  72. package/front_end/panels/recorder/{components/ExtensionView.ts → ExtensionView.ts} +8 -8
  73. package/front_end/panels/recorder/RecorderController.ts +88 -77
  74. package/front_end/panels/recorder/{components/RecordingListView.ts → RecordingListView.ts} +19 -20
  75. package/front_end/panels/recorder/{components/RecordingView.ts → RecordingView.ts} +88 -88
  76. package/front_end/panels/recorder/{components/ReplaySection.ts → ReplaySection.ts} +11 -11
  77. package/front_end/panels/recorder/{components/SelectorPicker.ts → SelectorPicker.ts} +13 -13
  78. package/front_end/panels/recorder/{components/StepEditor.ts → StepEditor.ts} +15 -15
  79. package/front_end/panels/recorder/{components/StepView.ts → StepView.ts} +10 -10
  80. package/front_end/panels/recorder/{components/TimelineSection.ts → TimelineSection.ts} +2 -2
  81. package/front_end/panels/recorder/recorder.ts +23 -1
  82. package/front_end/panels/recorder/util/util.ts +113 -0
  83. package/front_end/panels/sources/InplaceFormatterEditorAction.ts +2 -2
  84. package/front_end/panels/sources/SourcesNavigator.ts +2 -3
  85. package/front_end/panels/sources/TabbedEditorContainer.ts +1 -1
  86. package/front_end/panels/timeline/IsolateSelector.ts +10 -8
  87. package/front_end/panels/timeline/TimelinePanel.ts +18 -7
  88. package/front_end/panels/timeline/TimelineUIUtils.ts +144 -129
  89. package/front_end/panels/timeline/timeline-meta.ts +3 -2
  90. package/front_end/third_party/chromium/README.chromium +1 -1
  91. package/front_end/ui/legacy/Treeoutline.ts +3 -0
  92. package/front_end/ui/legacy/Widget.ts +14 -15
  93. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +11 -7
  94. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +2 -1
  95. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +10 -1
  96. package/package.json +1 -1
  97. package/front_end/models/issues_manager/AttributionReportingIssue.ts +0 -247
  98. package/front_end/models/issues_manager/descriptions/arInsecureContext.md +0 -7
  99. package/front_end/models/issues_manager/descriptions/arInvalidInfoHeader.md +0 -5
  100. package/front_end/models/issues_manager/descriptions/arInvalidRegisterOsSourceHeader.md +0 -5
  101. package/front_end/models/issues_manager/descriptions/arInvalidRegisterOsTriggerHeader.md +0 -5
  102. package/front_end/models/issues_manager/descriptions/arInvalidRegisterSourceHeader.md +0 -5
  103. package/front_end/models/issues_manager/descriptions/arInvalidRegisterTriggerHeader.md +0 -5
  104. package/front_end/models/issues_manager/descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +0 -5
  105. package/front_end/models/issues_manager/descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +0 -6
  106. package/front_end/models/issues_manager/descriptions/arNoRegisterOsSourceHeader.md +0 -5
  107. package/front_end/models/issues_manager/descriptions/arNoRegisterOsTriggerHeader.md +0 -5
  108. package/front_end/models/issues_manager/descriptions/arNoRegisterSourceHeader.md +0 -5
  109. package/front_end/models/issues_manager/descriptions/arNoRegisterTriggerHeader.md +0 -5
  110. package/front_end/models/issues_manager/descriptions/arNoWebOrOsSupport.md +0 -4
  111. package/front_end/models/issues_manager/descriptions/arOsSourceIgnored.md +0 -18
  112. package/front_end/models/issues_manager/descriptions/arOsTriggerIgnored.md +0 -19
  113. package/front_end/models/issues_manager/descriptions/arPermissionPolicyDisabled.md +0 -8
  114. package/front_end/models/issues_manager/descriptions/arSourceAndTriggerHeaders.md +0 -9
  115. package/front_end/models/issues_manager/descriptions/arSourceIgnored.md +0 -13
  116. package/front_end/models/issues_manager/descriptions/arTriggerIgnored.md +0 -12
  117. package/front_end/models/issues_manager/descriptions/arUntrustworthyReportingOrigin.md +0 -10
  118. package/front_end/models/issues_manager/descriptions/arWebAndOsHeaders.md +0 -11
  119. package/front_end/panels/issues/AttributionReportingIssueDetailsView.ts +0 -182
  120. package/front_end/panels/recorder/components/components.ts +0 -25
  121. package/front_end/panels/recorder/components/util.ts +0 -116
  122. /package/front_end/panels/recorder/{components/controlButton.css → controlButton.css} +0 -0
  123. /package/front_end/panels/recorder/{components/createRecordingView.css → createRecordingView.css} +0 -0
  124. /package/front_end/panels/recorder/{components/extensionView.css → extensionView.css} +0 -0
  125. /package/front_end/panels/recorder/{components/recordingListView.css → recordingListView.css} +0 -0
  126. /package/front_end/panels/recorder/{components/recordingView.css → recordingView.css} +0 -0
  127. /package/front_end/panels/recorder/{components/replaySection.css → replaySection.css} +0 -0
  128. /package/front_end/panels/recorder/{components/selectorPicker.css → selectorPicker.css} +0 -0
  129. /package/front_end/panels/recorder/{components/startView.css → startView.css} +0 -0
  130. /package/front_end/panels/recorder/{components/stepEditor.css → stepEditor.css} +0 -0
  131. /package/front_end/panels/recorder/{components/stepView.css → stepView.css} +0 -0
  132. /package/front_end/panels/recorder/{components/timelineSection.css → timelineSection.css} +0 -0
@@ -252,8 +252,8 @@ export interface ViewInput {
252
252
  onPaste: () => void;
253
253
  }
254
254
 
255
- export function filterToolCalls(
256
- toolCalls: WebMCP.WebMCPModel.Call[], filterState: FilterState): WebMCP.WebMCPModel.Call[] {
255
+ export function filterToolCalls(toolCalls: WebMCP.WebMCPModel.Call[],
256
+ filterState: FilterState): WebMCP.WebMCPModel.Call[] {
257
257
  let filtered = [...toolCalls];
258
258
 
259
259
  const statusTypes = filterState.statusTypes;
@@ -734,35 +734,32 @@ export class WebMCPView extends UI.Widget.VBox {
734
734
 
735
735
  #filterButtons: FilterMenuButtons;
736
736
 
737
- static createFilterButtons(
738
- onToolTypesClick: (contextMenu: UI.ContextMenu.ContextMenu) => void,
739
- onStatusTypesClick: (contextMenu: UI.ContextMenu.ContextMenu) => void): FilterMenuButtons {
740
- const createButton =
741
- (label: string, onContextMenu: (contextMenu: UI.ContextMenu.ContextMenu) => void, jsLogContext: string):
742
- FilterMenuButton => {
743
- const button = new UI.Toolbar.ToolbarMenuButton(
744
- onContextMenu,
745
- /* isIconDropdown=*/ false, /* useSoftMenu=*/ true, jsLogContext,
746
- /* iconName=*/ undefined,
747
- /* keepOpen=*/ true);
748
- button.setText(label);
749
-
750
- /* eslint-disable-next-line @devtools/no-imperative-dom-api */
751
- const adorner = new Adorners.Adorner.Adorner();
752
- adorner.name = 'countWrapper';
753
- const countElement = document.createElement('span');
754
- adorner.append(countElement);
755
- adorner.classList.add('active-filters-count');
756
- adorner.classList.add('hidden');
757
- button.setAdorner(adorner);
758
-
759
- const setCount = (count: number): void => {
760
- countElement.textContent = `${count}`;
761
- count === 0 ? adorner.hide() : adorner.show();
762
- };
763
-
764
- return {button, setCount};
765
- };
737
+ static createFilterButtons(onToolTypesClick: (contextMenu: UI.ContextMenu.ContextMenu) => void,
738
+ onStatusTypesClick: (contextMenu: UI.ContextMenu.ContextMenu) => void): FilterMenuButtons {
739
+ const createButton = (label: string, onContextMenu: (contextMenu: UI.ContextMenu.ContextMenu) => void,
740
+ jsLogContext: string): FilterMenuButton => {
741
+ const button = new UI.Toolbar.ToolbarMenuButton(onContextMenu,
742
+ /* isIconDropdown=*/ false, /* useSoftMenu=*/ true, jsLogContext,
743
+ /* iconName=*/ undefined,
744
+ /* keepOpen=*/ true);
745
+ button.setText(label);
746
+
747
+ /* eslint-disable-next-line @devtools/no-imperative-dom-api */
748
+ const adorner = new Adorners.Adorner.Adorner();
749
+ adorner.name = 'countWrapper';
750
+ const countElement = document.createElement('span');
751
+ adorner.append(countElement);
752
+ adorner.classList.add('active-filters-count');
753
+ adorner.classList.add('hidden');
754
+ button.setAdorner(adorner);
755
+
756
+ const setCount = (count: number): void => {
757
+ countElement.textContent = `${count}`;
758
+ count === 0 ? adorner.hide() : adorner.show();
759
+ };
760
+
761
+ return {button, setCount};
762
+ };
766
763
 
767
764
  return {
768
765
  toolTypes: createButton(i18nString(UIStrings.toolTypes), onToolTypesClick, 'webmcp.tool-types'),
@@ -968,20 +965,18 @@ export const PAYLOAD_DEFAULT_VIEW = (input: PayloadViewInput, output: object, ta
968
965
 
969
966
  const createPayload = (parsedInput: unknown): TemplateResult => {
970
967
  const object = new SDK.RemoteObject.LocalJSONObject(parsedInput);
971
- const section =
972
- new ObjectUI.ObjectPropertiesSection.RootElement(new ObjectUI.ObjectPropertiesSection.ObjectTree(object, {
973
- readOnly: true,
974
- propertiesMode: ObjectUI.ObjectPropertiesSection.ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED,
975
- }));
976
- section.title = document.createTextNode(object.description);
977
- section.listItemElement.classList.add('source-code', 'object-properties-section');
978
- section.childrenListElement.classList.add('source-code', 'object-properties-section');
979
- section.expand();
968
+ const objectTree = new ObjectUI.ObjectPropertiesSection.ObjectTree(object, {
969
+ readOnly: true,
970
+ propertiesMode: ObjectUI.ObjectPropertiesSection.ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED,
971
+ });
980
972
  return html`<devtools-tree .template=${html`
981
973
  <style>${ObjectUI.ObjectPropertiesSection.objectValueStyles}</style>
982
974
  <style>${ObjectUI.ObjectPropertiesSection.objectPropertiesSectionStyles}</style>
983
975
  <ul role="tree">
984
- <devtools-tree-wrapper .treeElement=${section}></devtools-tree-wrapper>
976
+ <li role=treeitem class="object-properties-section-root-element object-properties-section source-code" open>
977
+ ${object.description}
978
+ ${object.hasChildren ? ObjectUI.ObjectPropertiesSection.renderObjectTree(objectTree) : nothing}
979
+ </li>
985
980
  </ul>
986
981
  `}></devtools-tree>`;
987
982
  };
@@ -1351,8 +1346,8 @@ export function parseToolSchema(schema: JSONSchema7): ParsedToolSchema {
1351
1346
  }
1352
1347
  }
1353
1348
 
1354
- function parseProperty(
1355
- name: string, propDef: JSONSchema7Definition, optional: boolean): ProtocolMonitor.JSONEditor.Parameter {
1349
+ function parseProperty(name: string, propDef: JSONSchema7Definition,
1350
+ optional: boolean): ProtocolMonitor.JSONEditor.Parameter {
1356
1351
  if (typeof propDef === 'boolean') {
1357
1352
  return {
1358
1353
  name,
@@ -2,6 +2,8 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
+ import '../../../ui/legacy/components/data_grid/data_grid.js';
6
+
5
7
  import * as i18n from '../../../core/i18n/i18n.js';
6
8
  import * as SDK from '../../../core/sdk/sdk.js';
7
9
  import type * as Protocol from '../../../generated/protocol.js';
@@ -14,6 +16,10 @@ import adsViewStyles from './adsView.css.js';
14
16
  const {html} = Lit;
15
17
 
16
18
  const UIStrings = {
19
+ /**
20
+ * @description Title for the metrics table.
21
+ */
22
+ metrics: 'Metrics',
17
23
  /**
18
24
  * @description Title for a metric showing the percentage of the viewport covered by ads.
19
25
  */
@@ -35,75 +41,135 @@ const UIStrings = {
35
41
  * @example {5.00%} PH1
36
42
  */
37
43
  average: '(Average: {PH1})',
44
+ /**
45
+ * @description Title for the ad iframes table.
46
+ * @example {3} PH1
47
+ */
48
+ adIframesTitle: 'Ad iframes (total {PH1})',
49
+ /**
50
+ * @description Text to display when a value is not available.
51
+ */
52
+ notAvailable: 'N/A',
53
+ /**
54
+ * @description Text to display when a frame has no name/id.
55
+ */
56
+ unnamed: '<unnamed>',
57
+ /**
58
+ * @description Title for the Element Id column in the ad iframes table.
59
+ */
60
+ elementId: 'Element ID',
61
+ /**
62
+ * @description Title for the Initial origin column in the ad iframes table.
63
+ */
64
+ initialOrigin: 'Initial origin',
65
+ /**
66
+ * @description Title for the CPU column in the ad iframes table.
67
+ */
68
+ cpu: 'CPU',
69
+ /**
70
+ * @description Title for the Network column in the ad iframes table.
71
+ */
72
+ network: 'Network',
73
+ /**
74
+ * @description Accessible name for the ad iframes table.
75
+ */
76
+ adIframes: 'Ad iframes',
38
77
  } as const;
39
78
 
40
79
  const str_ = i18n.i18n.registerUIStrings('panels/application/components/AdsView.ts', UIStrings);
41
80
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
42
81
 
82
+ /**
83
+ * @description Data for a single row in the ad iframes table.
84
+ */
85
+ interface AdFrameNodeData {
86
+ elementId: string;
87
+ initialOrigin: string;
88
+ networkBytes: string;
89
+ cpuTime: string;
90
+ }
91
+
43
92
  export interface ViewInput {
44
93
  metrics: Protocol.Ads.AdMetrics;
94
+ adFrames: AdFrameNodeData[];
45
95
  }
46
96
 
47
97
  export type View = (input: ViewInput, output: undefined, target: HTMLElement|DocumentFragment) => void;
48
98
 
99
+ const formatMetric = (val: number|undefined, formatter: (val: number) => string): string => {
100
+ if (val === undefined || val === -1) {
101
+ return i18nString(UIStrings.notAvailable);
102
+ }
103
+ return formatter(val);
104
+ };
105
+
106
+ const formatCpu = (val: number|undefined): string => {
107
+ return formatMetric(val, (v: number): string => i18n.TimeUtilities.millisToString(v));
108
+ };
109
+
110
+ const formatNetwork = (val: number|undefined): string => {
111
+ return formatMetric(val, (v: number): string => i18n.ByteUtilities.bytesToString(v));
112
+ };
113
+
49
114
  const DEFAULT_VIEW: View = (input, output, target) => {
50
115
  const metrics = input.metrics;
51
116
 
52
117
  const formatValue = (val: number, isPercentage: boolean): string => {
53
- if (isPercentage) {
54
- return new Intl
55
- .NumberFormat(i18n.DevToolsLocale.DevToolsLocale.instance().locale, {
56
- style: 'percent',
57
- maximumFractionDigits: 0,
58
- })
59
- .format(val / 100);
60
- }
61
- return new Intl.NumberFormat(i18n.DevToolsLocale.DevToolsLocale.instance().locale).format(val);
118
+ return formatMetric(val, (v: number): string => {
119
+ if (isPercentage) {
120
+ return new Intl
121
+ .NumberFormat(i18n.DevToolsLocale.DevToolsLocale.instance().locale, {
122
+ style: 'percent',
123
+ maximumFractionDigits: 0,
124
+ })
125
+ .format(v / 100);
126
+ }
127
+ return new Intl.NumberFormat(i18n.DevToolsLocale.DevToolsLocale.instance().locale).format(v);
128
+ });
62
129
  };
63
130
 
64
- const formatAverage = (val: number, isPercentage: boolean): string => {
65
- if (isPercentage) {
131
+ const formatAverage = (val: number|undefined, isPercentage: boolean): string => {
132
+ return formatMetric(val, (v: number): string => {
133
+ if (isPercentage) {
134
+ return new Intl
135
+ .NumberFormat(i18n.DevToolsLocale.DevToolsLocale.instance().locale, {
136
+ style: 'percent',
137
+ minimumFractionDigits: 2,
138
+ maximumFractionDigits: 2,
139
+ })
140
+ .format(v / 100);
141
+ }
66
142
  return new Intl
67
143
  .NumberFormat(i18n.DevToolsLocale.DevToolsLocale.instance().locale, {
68
- style: 'percent',
69
144
  minimumFractionDigits: 2,
70
145
  maximumFractionDigits: 2,
71
146
  })
72
- .format(val / 100);
73
- }
74
- return new Intl
75
- .NumberFormat(i18n.DevToolsLocale.DevToolsLocale.instance().locale, {
76
- minimumFractionDigits: 2,
77
- maximumFractionDigits: 2,
78
- })
79
- .format(val);
80
- };
81
-
82
- const formatCpu = (val: number): string => {
83
- return i18n.TimeUtilities.millisToString(val);
84
- };
85
-
86
- const formatNetwork = (val: number): string => {
87
- return i18n.ByteUtilities.bytesToString(val);
147
+ .format(v);
148
+ });
88
149
  };
89
150
 
90
151
  // clang-format off
91
152
  Lit.render(html`
92
153
  <style>${adsViewStyles}</style>
93
154
  <div class="ads-view-container" jslog=${VisualLogging.pane('ads')}>
155
+ <div class="metrics-title">${i18nString(UIStrings.metrics)}</div>
94
156
  <dl class="metrics-container">
95
157
  <div class="metric-box">
96
158
  <dt class="metric-title">${i18nString(UIStrings.viewportAdDensity)}</dt>
97
159
  <dd class="metric-value">
98
160
  <span>${formatValue(metrics.viewportAdDensityByArea, true)}</span>
99
- <span class="metric-average">${i18nString(UIStrings.average, {PH1: formatAverage(metrics.averageViewportAdDensityByArea, true)})}</span>
161
+ <span class="metric-average">${i18nString(UIStrings.average, {
162
+ PH1: formatAverage(metrics.averageViewportAdDensityByArea, true),
163
+ })}</span>
100
164
  </dd>
101
165
  </div>
102
166
  <div class="metric-box">
103
167
  <dt class="metric-title">${i18nString(UIStrings.viewportAdCount)}</dt>
104
168
  <dd class="metric-value">
105
169
  <span>${formatValue(metrics.viewportAdCount, false)}</span>
106
- <span class="metric-average">${i18nString(UIStrings.average, {PH1: formatAverage(metrics.averageViewportAdCount, false)})}</span>
170
+ <span class="metric-average">${i18nString(UIStrings.average, {
171
+ PH1: formatAverage(metrics.averageViewportAdCount, false),
172
+ })}</span>
107
173
  </dd>
108
174
  </div>
109
175
  <div class="metric-box">
@@ -119,6 +185,27 @@ const DEFAULT_VIEW: View = (input, output, target) => {
119
185
  </dd>
120
186
  </div>
121
187
  </dl>
188
+ <div class="ad-frames-title">${i18nString(UIStrings.adIframesTitle, {PH1: input.adFrames.length})}</div>
189
+ <div class="ad-frames-container">
190
+ <devtools-data-grid striped resize="last" class="ad-frames-data-grid" name=${i18nString(UIStrings.adIframes)}>
191
+ <table>
192
+ <tr>
193
+ <th id="elementId" weight="1">${i18nString(UIStrings.elementId)}</th>
194
+ <th id="initialOrigin" weight="2">${i18nString(UIStrings.initialOrigin)}</th>
195
+ <th id="cpuTime" weight="1">${i18nString(UIStrings.cpu)}</th>
196
+ <th id="networkBytes" weight="1">${i18nString(UIStrings.network)}</th>
197
+ </tr>
198
+ ${input.adFrames.map(frame => html`
199
+ <tr>
200
+ <td title=${frame.elementId}>${frame.elementId}</td>
201
+ <td title=${frame.initialOrigin}>${frame.initialOrigin}</td>
202
+ <td title=${frame.cpuTime}>${frame.cpuTime}</td>
203
+ <td title=${frame.networkBytes}>${frame.networkBytes}</td>
204
+ </tr>
205
+ `)}
206
+ </table>
207
+ </devtools-data-grid>
208
+ </div>
122
209
  </div>
123
210
  `, target);
124
211
  // clang-format on
@@ -131,6 +218,10 @@ export class AdsView extends UI.Widget.Widget {
131
218
  #pollSessionId = 0;
132
219
  #view: View;
133
220
 
221
+ readonly #adFrames = new Map<Protocol.Page.FrameId, Protocol.Ads.AdFrameData>();
222
+ readonly #adIframeElementIds = new Map<Protocol.Page.FrameId, string|null>();
223
+ readonly #fetchingElementIds = new Set<Protocol.Page.FrameId>();
224
+
134
225
  constructor(view: View = DEFAULT_VIEW) {
135
226
  super({useShadowDom: true});
136
227
  this.#view = view;
@@ -194,6 +285,7 @@ export class AdsView extends UI.Widget.Widget {
194
285
  }
195
286
  if (!response.getError()) {
196
287
  this.#currentMetrics = response.metrics;
288
+ this.#processAdFrames(response.metrics);
197
289
  this.requestUpdate();
198
290
  }
199
291
  }
@@ -203,6 +295,65 @@ export class AdsView extends UI.Widget.Widget {
203
295
  }
204
296
  }
205
297
 
298
+ #processAdFrames(metrics: Protocol.Ads.AdMetrics): void {
299
+ // Drop removed frames from the local cache.
300
+ for (const frameId of metrics.removeAdFrames || []) {
301
+ this.#adFrames.delete(frameId);
302
+ this.#adIframeElementIds.delete(frameId);
303
+ }
304
+
305
+ // Merge partial updates into the local cache.
306
+ for (const frame of metrics.updateAdFrames || []) {
307
+ const frameId = frame.frameId;
308
+ const existingFrame = this.#adFrames.get(frameId) || {} as Protocol.Ads.AdFrameData;
309
+
310
+ // Object Spread / Protocol Undefined Behavior
311
+ // To reduce the payload size, the C++ backend only sends the 'initialOrigin' field
312
+ // when it changes since the last sent message for the same frame. Because
313
+ // the parsed JSON frame won't have the 'initialOrigin' key if it hasn't changed,
314
+ // spreading it over existingFrame won't overwrite existingFrame.initialOrigin with
315
+ // undefined.
316
+ const newFrame = {...existingFrame, ...frame} as Protocol.Ads.AdFrameData;
317
+ this.#adFrames.set(frameId, newFrame);
318
+ }
319
+
320
+ // Asynchronously fetch Element IDs for newly tracked frames.
321
+ // Duplicate requests are prevented by #fetchingElementIds.
322
+ for (const frameId of this.#adFrames.keys()) {
323
+ if (!this.#adIframeElementIds.has(frameId) && !this.#fetchingElementIds.has(frameId)) {
324
+ this.#fetchingElementIds.add(frameId);
325
+ void this.#fetchIframeElementId(frameId)
326
+ .then(elementId => {
327
+ if (this.#adFrames.has(frameId) && elementId !== undefined) {
328
+ this.#adIframeElementIds.set(frameId, elementId);
329
+ }
330
+ })
331
+ .catch(() => {})
332
+ .finally(() => {
333
+ this.#fetchingElementIds.delete(frameId);
334
+ this.requestUpdate();
335
+ });
336
+ }
337
+ }
338
+ }
339
+
340
+ async #fetchIframeElementId(frameId: Protocol.Page.FrameId): Promise<string|null|undefined> {
341
+ const frame = SDK.FrameManager.FrameManager.instance().getFrame(frameId);
342
+ if (!frame) {
343
+ return undefined;
344
+ }
345
+ const domModel = frame.resourceTreeModel().target().model(SDK.DOMModel.DOMModel);
346
+ if (!domModel) {
347
+ return undefined;
348
+ }
349
+ const deferredNode = await domModel.getOwnerNodeForFrame(frameId);
350
+ if (deferredNode) {
351
+ const node = await deferredNode.resolvePromise();
352
+ return node?.getAttribute('id') || null;
353
+ }
354
+ return null;
355
+ }
356
+
206
357
  #onPrimaryPageChanged(): void {
207
358
  this.#currentMetrics = {
208
359
  viewportAdDensityByArea: 0,
@@ -214,12 +365,32 @@ export class AdsView extends UI.Widget.Widget {
214
365
  updateAdFrames: [],
215
366
  removeAdFrames: [],
216
367
  };
368
+ this.#adFrames.clear();
369
+ this.#adIframeElementIds.clear();
370
+ this.#fetchingElementIds.clear();
217
371
  this.requestUpdate();
218
372
  }
219
373
 
220
374
  override performUpdate(): void {
375
+ const adFramesArray: AdFrameNodeData[] = [];
376
+ for (const [frameId, frame] of this.#adFrames) {
377
+ // The table displays the resolved ID, or an <unnamed> placeholder if the
378
+ // element lacks an ID attribute, or an empty string while pending.
379
+ const elementIdText = this.#adIframeElementIds.has(frameId) ?
380
+ (this.#adIframeElementIds.get(frameId) || i18nString(UIStrings.unnamed)) :
381
+ '';
382
+
383
+ adFramesArray.push({
384
+ elementId: elementIdText,
385
+ initialOrigin: frame.initialOrigin || '',
386
+ cpuTime: formatCpu(frame.cpuTime),
387
+ networkBytes: formatNetwork(frame.networkBytes),
388
+ });
389
+ }
390
+
221
391
  const viewInput: ViewInput = {
222
392
  metrics: this.#currentMetrics,
393
+ adFrames: adFramesArray,
223
394
  };
224
395
  this.#view(viewInput, undefined, this.contentElement);
225
396
  }
@@ -58,3 +58,28 @@
58
58
  font-weight: normal;
59
59
  color: var(--sys-color-on-surface-subtle);
60
60
  }
61
+
62
+ .metrics-title,
63
+ .ad-frames-title {
64
+ color: var(--sys-color-on-surface);
65
+ flex: 0 0 auto;
66
+ font-weight: bold;
67
+ margin-bottom: 8px;
68
+ }
69
+
70
+ .ad-frames-data-grid {
71
+ flex: auto;
72
+ }
73
+
74
+ .ad-frames-container {
75
+ border: 1px solid var(--sys-color-divider);
76
+ display: flex;
77
+ flex: auto;
78
+ flex-direction: column;
79
+ margin-bottom: 24px;
80
+ height: 300px;
81
+ min-height: 150px;
82
+ position: relative;
83
+ resize: vertical;
84
+ overflow: hidden;
85
+ }
@@ -129,8 +129,8 @@ export class RuleSetDetailsView extends UI.Widget.VBox {
129
129
 
130
130
  async #getSourceText(): Promise<string> {
131
131
  if (this.#shouldPrettyPrint && this.#ruleSet?.sourceText !== undefined) {
132
- const formattedResult =
133
- await Formatter.ScriptFormatter.formatScriptContent('application/json', this.#ruleSet.sourceText);
132
+ const formattedResult = await Formatter.ScriptFormatter.formatScriptContent(
133
+ SDK.TargetManager.TargetManager.instance().settings, 'application/json', this.#ruleSet.sourceText);
134
134
  return formattedResult.formattedContent;
135
135
  }
136
136
 
@@ -346,7 +346,8 @@ export class ConsoleView extends UI.Widget.VBox implements
346
346
  private userHasOpenedSidebarAtLeastOnce = false;
347
347
  private issueToolbarThrottle: Common.Throttler.Throttler;
348
348
  private requestResolver = new Logs.RequestResolver.RequestResolver();
349
- private issueResolver = new IssuesManager.IssueResolver.IssueResolver();
349
+ private issueResolver =
350
+ new IssuesManager.IssueResolver.IssueResolver(IssuesManager.IssuesManager.IssuesManager.instance());
350
351
  #isDetached = false;
351
352
  #onIssuesCountUpdateBound = this.#onIssuesCountUpdate.bind(this);
352
353
  #collapseAllButton: UI.Toolbar.ToolbarButton;
@@ -68,8 +68,9 @@ export class PromptBuilder {
68
68
  const firstNewline = text.indexOf('\n');
69
69
  if (text.length > MAX_CODE_SIZE && (firstNewline < 0 || firstNewline > MAX_CODE_SIZE)) {
70
70
  // Use formatter
71
+ const settings = runtimeModel.target().targetManager().settings;
71
72
  const {formattedContent, formattedMapping} = await Formatter.ScriptFormatter.formatScriptContent(
72
- mappedLocation?.uiSourceCode.mimeType() ?? 'text/javascript', text);
73
+ settings, mappedLocation?.uiSourceCode.mimeType() ?? 'text/javascript', text);
73
74
  const [lineNumber, columnNumber] =
74
75
  formattedMapping.originalToFormatted(mappedLocation?.lineNumber ?? 0, mappedLocation?.columnNumber ?? 0);
75
76
  return {text: formattedContent, columnNumber, lineNumber};