chrome-devtools-frontend 1.0.1660788 → 1.0.1662289

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 (177) hide show
  1. package/.agents/skills/evaluate-ai-css-completion/SKILL.md +143 -0
  2. package/.agents/skills/evaluate-ai-css-completion/scripts/evaluate.js +104 -0
  3. package/.agents/skills/migrate-chromium-test/SKILL.md +7 -2
  4. package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +7 -1
  5. package/docs/ui_engineering.md +75 -42
  6. package/eslint.config.mjs +7 -0
  7. package/extension-api/ExtensionAPI.d.ts +88 -0
  8. package/front_end/core/common/SettingRegistration.ts +0 -5
  9. package/front_end/core/host/InspectorFrontendHost.ts +1 -0
  10. package/front_end/core/host/InspectorFrontendHostStub.ts +2 -0
  11. package/front_end/core/platform/ArrayUtilities.ts +10 -0
  12. package/front_end/core/platform/StringUtilities.ts +20 -4
  13. package/front_end/core/sdk/CPUThrottlingManager.ts +2 -0
  14. package/front_end/core/sdk/DOMDebuggerModel.ts +2 -0
  15. package/front_end/core/sdk/DOMModel.ts +1 -0
  16. package/front_end/core/sdk/DebuggerModel.ts +4 -4
  17. package/front_end/core/sdk/EventBreakpointsModel.ts +2 -0
  18. package/front_end/core/sdk/FrameManager.ts +1 -0
  19. package/front_end/core/sdk/IsolateManager.ts +1 -0
  20. package/front_end/core/sdk/NetworkManager.ts +2 -0
  21. package/front_end/core/sdk/NetworkRequest.ts +1 -0
  22. package/front_end/core/sdk/PageResourceLoader.ts +2 -0
  23. package/front_end/core/sdk/SourceMap.ts +5 -5
  24. package/front_end/core/sdk/SourceMapManager.ts +3 -2
  25. package/front_end/core/sdk/TargetManager.ts +4 -0
  26. package/front_end/entrypoints/main/MainImpl.ts +2 -1
  27. package/front_end/foundation/README.md +86 -0
  28. package/front_end/generated/InspectorBackendCommands.ts +4 -5
  29. package/front_end/generated/protocol.ts +20 -38
  30. package/front_end/models/bindings/CompilerScriptMapping.ts +5 -5
  31. package/front_end/models/bindings/ContentProviderBasedProject.ts +2 -3
  32. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +3 -3
  33. package/front_end/models/bindings/DefaultScriptMapping.ts +3 -3
  34. package/front_end/models/bindings/ResourceMapping.ts +3 -3
  35. package/front_end/models/bindings/ResourceScriptMapping.ts +2 -2
  36. package/front_end/models/bindings/SASSSourceMapping.ts +3 -3
  37. package/front_end/models/bindings/TempFile.ts +8 -3
  38. package/front_end/models/extensions/ExtensionAPI.ts +110 -46
  39. package/front_end/models/extensions/RecorderExtensionEndpoint.ts +7 -5
  40. package/front_end/models/formatter/ScriptFormatter.ts +8 -11
  41. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +14 -5
  42. package/front_end/models/issues_manager/CheckFormsIssuesTrigger.ts +8 -9
  43. package/front_end/models/issues_manager/CookieIssue.ts +21 -9
  44. package/front_end/models/issues_manager/Issue.ts +3 -4
  45. package/front_end/models/issues_manager/IssueAggregator.ts +0 -9
  46. package/front_end/models/issues_manager/IssueResolver.ts +2 -2
  47. package/front_end/models/issues_manager/IssuesManager.ts +136 -137
  48. package/front_end/models/issues_manager/RelatedIssue.ts +10 -8
  49. package/front_end/models/issues_manager/issues_manager.ts +0 -2
  50. package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
  51. package/front_end/models/logs/RequestResolver.ts +2 -2
  52. package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +12 -9
  53. package/front_end/models/trace/handlers/FramesHandler.ts +4 -7
  54. package/front_end/models/trace/handlers/ModelHandlers.ts +0 -1
  55. package/front_end/models/trace/handlers/RendererHandler.ts +2 -15
  56. package/front_end/models/trace/handlers/Threads.ts +4 -11
  57. package/front_end/models/trace/insights/DOMSize.ts +1 -1
  58. package/front_end/models/workspace_diff/WorkspaceDiff.ts +10 -4
  59. package/front_end/panels/ai_assistance/components/ChatMessage.ts +2 -1
  60. package/front_end/panels/application/ApplicationPanelSidebar.ts +0 -44
  61. package/front_end/panels/application/CookieItemsView.ts +1 -1
  62. package/front_end/panels/application/ServiceWorkersView.ts +494 -411
  63. package/front_end/panels/application/WebMCPView.ts +38 -43
  64. package/front_end/panels/application/application.ts +0 -6
  65. package/front_end/panels/application/components/AdsView.ts +201 -30
  66. package/front_end/panels/application/components/adsView.css +25 -0
  67. package/front_end/panels/application/components/components.ts +0 -2
  68. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +1 -1
  69. package/front_end/panels/application/preloading/components/RuleSetDetailsView.ts +2 -2
  70. package/front_end/panels/application/serviceWorkersView.css +40 -4
  71. package/front_end/panels/browser_debugger/XHRBreakpointsSidebarPane.ts +147 -123
  72. package/front_end/panels/common/ExtensionServer.ts +3 -3
  73. package/front_end/panels/console/ConsoleView.ts +3 -2
  74. package/front_end/panels/console/PromptBuilder.ts +2 -1
  75. package/front_end/panels/emulation/DeviceModeView.ts +164 -113
  76. package/front_end/panels/issues/AffectedResourcesView.ts +1 -1
  77. package/front_end/panels/issues/IssueView.ts +0 -2
  78. package/front_end/panels/issues/IssuesPane.ts +1 -8
  79. package/front_end/panels/js_timeline/js_timeline-meta.ts +3 -2
  80. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +53 -12
  81. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +3 -3
  82. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +5 -5
  83. package/front_end/panels/linear_memory_inspector/components/LinearMemoryHighlightChipList.ts +4 -4
  84. package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +2 -2
  85. package/front_end/panels/linear_memory_inspector/components/LinearMemoryNavigator.ts +6 -6
  86. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +3 -3
  87. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterDisplay.ts +8 -9
  88. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterDisplayUtils.ts +2 -2
  89. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterSettings.ts +1 -1
  90. package/front_end/panels/linear_memory_inspector/linear_memory_inspector-meta.ts +2 -2
  91. package/front_end/panels/network/RequestPayloadView.ts +92 -52
  92. package/front_end/panels/network/RequestTimingView.ts +95 -127
  93. package/front_end/panels/network/components/ResponseHeaderSection.ts +5 -3
  94. package/front_end/panels/profiler/HeapSnapshotView.ts +3 -3
  95. package/front_end/panels/profiler/WritableProfileHeader.ts +2 -2
  96. package/front_end/panels/recorder/{components/ControlButton.ts → ControlButton.ts} +9 -10
  97. package/front_end/panels/recorder/{components/CreateRecordingView.ts → CreateRecordingView.ts} +48 -47
  98. package/front_end/panels/recorder/{components/ExtensionView.ts → ExtensionView.ts} +8 -8
  99. package/front_end/panels/recorder/RecorderController.ts +302 -127
  100. package/front_end/panels/recorder/RecorderPanel.ts +1 -1
  101. package/front_end/panels/recorder/{components/RecordingListView.ts → RecordingListView.ts} +19 -20
  102. package/front_end/panels/recorder/{components/RecordingView.ts → RecordingView.ts} +88 -88
  103. package/front_end/panels/recorder/{components/ReplaySection.ts → ReplaySection.ts} +11 -11
  104. package/front_end/panels/recorder/{components/SelectorPicker.ts → SelectorPicker.ts} +13 -13
  105. package/front_end/panels/recorder/{components/StepEditor.ts → StepEditor.ts} +15 -15
  106. package/front_end/panels/recorder/{components/StepView.ts → StepView.ts} +10 -10
  107. package/front_end/panels/recorder/{components/TimelineSection.ts → TimelineSection.ts} +2 -2
  108. package/front_end/panels/recorder/recorder.ts +23 -1
  109. package/front_end/panels/recorder/util/util.ts +113 -0
  110. package/front_end/panels/sources/SourcesView.ts +0 -17
  111. package/front_end/panels/sources/TabbedEditorContainer.ts +1 -1
  112. package/front_end/panels/sources/UISourceCodeFrame.ts +42 -0
  113. package/front_end/panels/sources/sources.ts +0 -2
  114. package/front_end/panels/timeline/CompatibilityTracksAppender.ts +0 -17
  115. package/front_end/panels/timeline/IsolateSelector.ts +10 -8
  116. package/front_end/panels/timeline/ThreadAppender.ts +0 -106
  117. package/front_end/panels/timeline/TimelinePanel.ts +18 -7
  118. package/front_end/panels/timeline/TimelineUIUtils.ts +144 -129
  119. package/front_end/panels/timeline/timeline-meta.ts +3 -2
  120. package/front_end/third_party/chromium/README.chromium +1 -1
  121. package/front_end/ui/components/report_view/ReportView.ts +11 -5
  122. package/front_end/ui/components/report_view/report.css +4 -1
  123. package/front_end/ui/legacy/TextPrompt.ts +49 -1
  124. package/front_end/ui/legacy/Treeoutline.ts +3 -0
  125. package/front_end/ui/legacy/UIUtils.ts +11 -1
  126. package/front_end/ui/legacy/Widget.ts +14 -15
  127. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +2 -2
  128. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +11 -7
  129. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +2 -1
  130. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +10 -1
  131. package/front_end/ui/legacy/textPrompt.css +10 -0
  132. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  133. package/package.json +1 -1
  134. package/front_end/models/issues_manager/AttributionReportingIssue.ts +0 -247
  135. package/front_end/models/issues_manager/descriptions/arInsecureContext.md +0 -7
  136. package/front_end/models/issues_manager/descriptions/arInvalidInfoHeader.md +0 -5
  137. package/front_end/models/issues_manager/descriptions/arInvalidRegisterOsSourceHeader.md +0 -5
  138. package/front_end/models/issues_manager/descriptions/arInvalidRegisterOsTriggerHeader.md +0 -5
  139. package/front_end/models/issues_manager/descriptions/arInvalidRegisterSourceHeader.md +0 -5
  140. package/front_end/models/issues_manager/descriptions/arInvalidRegisterTriggerHeader.md +0 -5
  141. package/front_end/models/issues_manager/descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +0 -5
  142. package/front_end/models/issues_manager/descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +0 -6
  143. package/front_end/models/issues_manager/descriptions/arNoRegisterOsSourceHeader.md +0 -5
  144. package/front_end/models/issues_manager/descriptions/arNoRegisterOsTriggerHeader.md +0 -5
  145. package/front_end/models/issues_manager/descriptions/arNoRegisterSourceHeader.md +0 -5
  146. package/front_end/models/issues_manager/descriptions/arNoRegisterTriggerHeader.md +0 -5
  147. package/front_end/models/issues_manager/descriptions/arNoWebOrOsSupport.md +0 -4
  148. package/front_end/models/issues_manager/descriptions/arOsSourceIgnored.md +0 -18
  149. package/front_end/models/issues_manager/descriptions/arOsTriggerIgnored.md +0 -19
  150. package/front_end/models/issues_manager/descriptions/arPermissionPolicyDisabled.md +0 -8
  151. package/front_end/models/issues_manager/descriptions/arSourceAndTriggerHeaders.md +0 -9
  152. package/front_end/models/issues_manager/descriptions/arSourceIgnored.md +0 -13
  153. package/front_end/models/issues_manager/descriptions/arTriggerIgnored.md +0 -12
  154. package/front_end/models/issues_manager/descriptions/arUntrustworthyReportingOrigin.md +0 -10
  155. package/front_end/models/issues_manager/descriptions/arWebAndOsHeaders.md +0 -11
  156. package/front_end/models/trace/handlers/AuctionWorkletsHandler.ts +0 -183
  157. package/front_end/panels/application/InterestGroupStorageModel.ts +0 -81
  158. package/front_end/panels/application/InterestGroupStorageView.ts +0 -151
  159. package/front_end/panels/application/InterestGroupTreeElement.ts +0 -65
  160. package/front_end/panels/application/components/InterestGroupAccessGrid.ts +0 -135
  161. package/front_end/panels/application/components/interestGroupAccessGrid.css +0 -27
  162. package/front_end/panels/application/interestGroupStorageView.css +0 -9
  163. package/front_end/panels/issues/AttributionReportingIssueDetailsView.ts +0 -182
  164. package/front_end/panels/recorder/components/components.ts +0 -25
  165. package/front_end/panels/recorder/components/util.ts +0 -116
  166. package/front_end/panels/sources/InplaceFormatterEditorAction.ts +0 -149
  167. /package/front_end/panels/recorder/{components/controlButton.css → controlButton.css} +0 -0
  168. /package/front_end/panels/recorder/{components/createRecordingView.css → createRecordingView.css} +0 -0
  169. /package/front_end/panels/recorder/{components/extensionView.css → extensionView.css} +0 -0
  170. /package/front_end/panels/recorder/{components/recordingListView.css → recordingListView.css} +0 -0
  171. /package/front_end/panels/recorder/{components/recordingView.css → recordingView.css} +0 -0
  172. /package/front_end/panels/recorder/{components/replaySection.css → replaySection.css} +0 -0
  173. /package/front_end/panels/recorder/{components/selectorPicker.css → selectorPicker.css} +0 -0
  174. /package/front_end/panels/recorder/{components/startView.css → startView.css} +0 -0
  175. /package/front_end/panels/recorder/{components/stepEditor.css → stepEditor.css} +0 -0
  176. /package/front_end/panels/recorder/{components/stepView.css → stepView.css} +0 -0
  177. /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,
@@ -18,9 +18,6 @@ import * as ExtensionStorageModel from './ExtensionStorageModel.js';
18
18
  import * as FrameDetailsView from './FrameDetailsView.js';
19
19
  import * as IndexedDBModel from './IndexedDBModel.js';
20
20
  import * as IndexedDBViews from './IndexedDBViews.js';
21
- import * as InterestGroupStorageModel from './InterestGroupStorageModel.js';
22
- import * as InterestGroupStorageView from './InterestGroupStorageView.js';
23
- import * as InterestGroupTreeElement from './InterestGroupTreeElement.js';
24
21
  import * as KeyValueStorageItemsView from './KeyValueStorageItemsView.js';
25
22
  import * as OpenedWindowDetailsView from './OpenedWindowDetailsView.js';
26
23
  import * as OriginTrialTreeView from './OriginTrialTreeView.js';
@@ -62,9 +59,6 @@ export {
62
59
  FrameDetailsView,
63
60
  IndexedDBModel,
64
61
  IndexedDBViews,
65
- InterestGroupStorageModel,
66
- InterestGroupStorageView,
67
- InterestGroupTreeElement,
68
62
  KeyValueStorageItemsView,
69
63
  OpenedWindowDetailsView,
70
64
  OriginTrialTreeView,
@@ -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
+ }
@@ -7,7 +7,6 @@ import * as BackForwardCacheView from './BackForwardCacheView.js';
7
7
  import * as BounceTrackingMitigationsView from './BounceTrackingMitigationsView.js';
8
8
  import * as CrashReportContextGrid from './CrashReportContextGrid.js';
9
9
  import * as EndpointsGrid from './EndpointsGrid.js';
10
- import * as InterestGroupAccessGrid from './InterestGroupAccessGrid.js';
11
10
  import * as PermissionsPolicySection from './PermissionsPolicySection.js';
12
11
  import * as ProtocolHandlersView from './ProtocolHandlersView.js';
13
12
  import * as ReportsGrid from './ReportsGrid.js';
@@ -23,7 +22,6 @@ export {
23
22
  BounceTrackingMitigationsView,
24
23
  CrashReportContextGrid,
25
24
  EndpointsGrid,
26
- InterestGroupAccessGrid,
27
25
  PermissionsPolicySection,
28
26
  ProtocolHandlersView,
29
27
  ReportsGrid,
@@ -243,7 +243,7 @@ export class PreloadingDetailsReportView extends LegacyWrapper.LegacyWrapper.Wra
243
243
  .data=${
244
244
  {
245
245
  affectedRequest,
246
- requestResolver: this.#data.requestResolver || new Logs.RequestResolver.RequestResolver(),
246
+ requestResolver: this.#data.requestResolver || new Logs.RequestResolver.RequestResolver(Logs.NetworkLog.NetworkLog.instance()),
247
247
  displayURL: true,
248
248
  urlToDisplay: url,
249
249
  }
@@ -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
 
@@ -96,10 +96,6 @@
96
96
  min-width: 80px;
97
97
  }
98
98
 
99
- .report-field-value {
100
- white-space: normal;
101
- }
102
-
103
99
  .report-field-value-filename,
104
100
  .service-worker-client-string {
105
101
  max-width: 400px;
@@ -162,3 +158,43 @@ devtools-icon.error-icon {
162
158
  vertical-align: bottom;
163
159
  width: var(--sys-size-7);
164
160
  }
161
+
162
+ .service-worker-toolbar {
163
+ margin-left: var(--sys-size-4);
164
+ }
165
+
166
+ .report-field {
167
+ display: flex;
168
+ padding: var(--sys-size-3) 0;
169
+ }
170
+
171
+ .report-field-name {
172
+ font: var(--sys-typescale-body5-medium);
173
+ color: var(--sys-color-on-surface-subtle);
174
+ flex: 0 0 128px;
175
+ text-align: left;
176
+ white-space: pre-wrap;
177
+ }
178
+
179
+ .report-field-value {
180
+ font: var(--sys-typescale-body4-regular);
181
+ flex: auto;
182
+ padding: 0 var(--sys-size-6);
183
+ white-space: normal;
184
+ user-select: text;
185
+ }
186
+
187
+ .service-worker-section {
188
+ border-bottom: 1px solid var(--sys-color-divider);
189
+ grid-column: 1 / 3;
190
+ padding: 0 var(--sys-size-9) 11px var(--sys-size-9);
191
+ }
192
+
193
+ .service-worker-section-container {
194
+ display: contents;
195
+ }
196
+
197
+ devtools-widget {
198
+ display: block;
199
+ }
200
+