chrome-devtools-frontend 1.0.1535712 → 1.0.1537268

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 (231) hide show
  1. package/docs/contributing/images/issues-nearestslo.png +0 -0
  2. package/docs/contributing/issues.md +17 -21
  3. package/front_end/core/common/Console.ts +1 -8
  4. package/front_end/core/common/ParsedURL.ts +10 -20
  5. package/front_end/core/common/SegmentedRange.ts +1 -2
  6. package/front_end/core/common/StringOutputStream.ts +1 -4
  7. package/front_end/core/host/AidaClient.ts +64 -5
  8. package/front_end/core/host/DispatchHttpRequestClient.ts +62 -0
  9. package/front_end/core/host/GdpClient.ts +8 -57
  10. package/front_end/core/host/host.ts +2 -0
  11. package/front_end/core/i18n/i18nImpl.ts +0 -24
  12. package/front_end/core/protocol_client/CDPConnection.ts +10 -8
  13. package/front_end/core/protocol_client/InspectorBackend.ts +36 -42
  14. package/front_end/core/sdk/AnimationModel.ts +1 -2
  15. package/front_end/core/sdk/CSSMatchedStyles.ts +2 -2
  16. package/front_end/core/sdk/CSSModel.ts +1 -1
  17. package/front_end/core/sdk/CSSProperty.ts +3 -6
  18. package/front_end/core/sdk/CSSStyleDeclaration.ts +4 -4
  19. package/front_end/core/sdk/DebuggerModel.ts +1 -2
  20. package/front_end/core/sdk/EnhancedTracesParser.ts +24 -5
  21. package/front_end/core/sdk/RehydratingConnection.ts +112 -4
  22. package/front_end/core/sdk/RehydratingObject.ts +8 -0
  23. package/front_end/core/sdk/SourceMap.ts +2 -3
  24. package/front_end/core/sdk/TraceObject.ts +5 -1
  25. package/front_end/entrypoints/node_app/NodeConnectionsPanel.ts +2 -1
  26. package/front_end/generated/InspectorBackendCommands.js +1 -2
  27. package/front_end/generated/SupportedCSSProperties.js +19 -0
  28. package/front_end/generated/protocol.ts +0 -27
  29. package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
  30. package/front_end/models/trace/types/File.ts +9 -0
  31. package/front_end/panels/accessibility/AccessibilityNodeView.ts +18 -17
  32. package/front_end/panels/accessibility/AccessibilitySidebarView.ts +9 -12
  33. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +5 -9
  34. package/front_end/panels/ai_assistance/components/ChatView.ts +63 -74
  35. package/front_end/panels/application/AppManifestView.ts +7 -6
  36. package/front_end/panels/application/ApplicationPanelSidebar.ts +4 -4
  37. package/front_end/panels/application/BackForwardCacheTreeElement.ts +2 -6
  38. package/front_end/panels/application/OpenedWindowDetailsView.ts +6 -6
  39. package/front_end/panels/application/StorageView.ts +9 -8
  40. package/front_end/panels/application/components/BackForwardCacheView.ts +366 -342
  41. package/front_end/panels/application/components/FrameDetailsView.ts +8 -11
  42. package/front_end/panels/application/components/OriginTrialTreeView.ts +65 -69
  43. package/front_end/panels/application/components/ProtocolHandlersView.ts +3 -2
  44. package/front_end/panels/application/components/backForwardCacheView.css +4 -0
  45. package/front_end/panels/application/components/badge.css +1 -1
  46. package/front_end/panels/application/preloading/components/PreloadingDisabledInfobar.ts +2 -1
  47. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +44 -53
  48. package/front_end/panels/browser_debugger/ObjectEventListenersSidebarPane.ts +8 -8
  49. package/front_end/panels/common/BadgeNotification.ts +2 -1
  50. package/front_end/panels/common/GdpSignUpDialog.ts +2 -1
  51. package/front_end/panels/console/ConsoleInsightTeaser.ts +8 -2
  52. package/front_end/panels/console/ConsolePinPane.ts +12 -7
  53. package/front_end/panels/developer_resources/DeveloperResourcesView.ts +9 -9
  54. package/front_end/panels/elements/ComputedStyleWidget.ts +7 -7
  55. package/front_end/panels/elements/EventListenersWidget.ts +9 -9
  56. package/front_end/panels/elements/NodeStackTraceWidget.ts +6 -6
  57. package/front_end/panels/elements/PlatformFontsWidget.ts +5 -5
  58. package/front_end/panels/elements/PropertiesWidget.ts +8 -8
  59. package/front_end/panels/layer_viewer/Layers3DView.ts +2 -1
  60. package/front_end/panels/layer_viewer/PaintProfilerView.ts +3 -3
  61. package/front_end/panels/network/RequestCookiesView.ts +2 -1
  62. package/front_end/panels/network/RequestTimingView.ts +2 -1
  63. package/front_end/panels/recorder/RecorderController.ts +33 -23
  64. package/front_end/panels/recorder/components/CreateRecordingView.ts +259 -226
  65. package/front_end/panels/security/CookieControlsView.ts +2 -1
  66. package/front_end/panels/security/CookieReportView.ts +3 -2
  67. package/front_end/panels/settings/AISettingsTab.ts +164 -172
  68. package/front_end/panels/settings/KeybindsSettingsTab.ts +6 -0
  69. package/front_end/panels/settings/SettingsScreen.ts +3 -7
  70. package/front_end/panels/settings/aiSettingsTab.css +151 -148
  71. package/front_end/panels/settings/components/SyncSection.ts +2 -1
  72. package/front_end/panels/settings/settings-meta.ts +1 -2
  73. package/front_end/panels/sources/AddSourceMapURLDialog.ts +23 -26
  74. package/front_end/panels/sources/DebuggerPausedMessage.ts +4 -3
  75. package/front_end/panels/sources/ResourceOriginPlugin.ts +3 -2
  76. package/front_end/panels/sources/SourcesNavigator.ts +2 -1
  77. package/front_end/panels/sources/TabbedEditorContainer.ts +3 -2
  78. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +9 -9
  79. package/front_end/panels/timeline/TimelinePanel.ts +60 -11
  80. package/front_end/panels/timeline/TimelineUIUtils.ts +3 -2
  81. package/front_end/panels/timeline/components/DetailsView.ts +5 -4
  82. package/front_end/panels/timeline/components/ExportTraceOptions.ts +33 -34
  83. package/front_end/panels/timeline/components/FieldSettingsDialog.ts +2 -1
  84. package/front_end/panels/timeline/components/LiveMetricsView.ts +5 -4
  85. package/front_end/panels/timeline/components/MetricCompareStrings.ts +25 -24
  86. package/front_end/panels/timeline/components/insights/LCPDiscovery.ts +2 -1
  87. package/front_end/third_party/chromium/README.chromium +2 -2
  88. package/front_end/third_party/puppeteer/README.chromium +2 -2
  89. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts +9 -1
  90. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts.map +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.js.map +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/BrowserContext.d.ts +2 -2
  93. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/BrowserContext.d.ts.map +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/BrowserContext.js.map +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +13 -1
  96. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.d.ts +2 -2
  99. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.d.ts.map +1 -1
  100. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.js +5 -2
  101. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.js.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts +2 -2
  103. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js +3 -1
  105. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +1 -12
  107. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.d.ts +6 -0
  109. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.d.ts.map +1 -1
  110. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js +1 -0
  111. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js.map +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts +2 -2
  113. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +6 -1
  115. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
  116. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.d.ts +2 -1
  117. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.d.ts.map +1 -1
  118. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.js +2 -2
  119. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.js.map +1 -1
  120. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts +2 -2
  121. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +3 -1
  123. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  124. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  126. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  127. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  129. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/disposable.d.ts +2 -2
  130. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/disposable.d.ts.map +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/disposable.js +3 -1
  132. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/disposable.js.map +1 -1
  133. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/util.d.ts +1 -0
  134. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/util.d.ts.map +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/util.js +1 -0
  136. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/util.js.map +1 -1
  137. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  138. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  139. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +28 -3
  140. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +21 -10
  141. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts +9 -1
  142. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts.map +1 -1
  143. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.js.map +1 -1
  144. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/BrowserContext.d.ts +2 -2
  145. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/BrowserContext.d.ts.map +1 -1
  146. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/BrowserContext.js.map +1 -1
  147. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Input.d.ts +1 -1
  148. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Input.d.ts.map +1 -1
  149. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +13 -1
  150. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  151. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  152. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.d.ts +2 -2
  153. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.d.ts.map +1 -1
  154. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.js +5 -2
  155. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.js.map +1 -1
  156. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts +2 -2
  157. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts.map +1 -1
  158. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js +3 -1
  159. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js.map +1 -1
  160. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Realm.d.ts +1 -12
  161. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Realm.d.ts.map +1 -1
  162. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.d.ts +6 -0
  163. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.d.ts.map +1 -1
  164. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js +1 -0
  165. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js.map +1 -1
  166. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts +2 -2
  167. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
  168. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +6 -1
  169. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
  170. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.d.ts +2 -1
  171. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.d.ts.map +1 -1
  172. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.js +2 -2
  173. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.js.map +1 -1
  174. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts +2 -2
  175. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
  176. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +3 -1
  177. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  178. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  179. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  180. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  181. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/disposable.d.ts +2 -2
  182. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/disposable.d.ts.map +1 -1
  183. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/disposable.js +2 -2
  184. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/disposable.js.map +1 -1
  185. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/util.d.ts +1 -0
  186. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/util.d.ts.map +1 -1
  187. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/util.js +1 -0
  188. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/util.js.map +1 -1
  189. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  190. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  191. package/front_end/third_party/puppeteer/package/lib/types.d.ts +28 -3
  192. package/front_end/third_party/puppeteer/package/package.json +2 -2
  193. package/front_end/third_party/puppeteer/package/src/api/Browser.ts +13 -1
  194. package/front_end/third_party/puppeteer/package/src/api/BrowserContext.ts +7 -2
  195. package/front_end/third_party/puppeteer/package/src/api/Page.ts +14 -1
  196. package/front_end/third_party/puppeteer/package/src/bidi/BrowserContext.ts +8 -5
  197. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +5 -2
  198. package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +8 -0
  199. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +11 -2
  200. package/front_end/third_party/puppeteer/package/src/cdp/BrowserContext.ts +3 -2
  201. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +5 -5
  202. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  203. package/front_end/third_party/puppeteer/package/src/util/disposable.ts +2 -2
  204. package/front_end/third_party/puppeteer/package/src/util/util.ts +1 -0
  205. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  206. package/front_end/ui/components/docs/tooltip/basic.ts +1 -1
  207. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +280 -0
  208. package/front_end/ui/components/text_editor/text_editor.ts +1 -0
  209. package/front_end/ui/components/tooltips/Tooltip.ts +33 -18
  210. package/front_end/ui/i18n/i18n.ts +31 -0
  211. package/front_end/ui/legacy/Dialog.ts +0 -1
  212. package/front_end/ui/legacy/SettingsUI.ts +0 -14
  213. package/front_end/ui/legacy/SoftDropDown.ts +1 -12
  214. package/front_end/ui/legacy/ViewManager.ts +2 -4
  215. package/front_end/ui/legacy/Widget.ts +33 -17
  216. package/front_end/ui/legacy/XLink.ts +0 -3
  217. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +9 -0
  218. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +2 -1
  219. package/front_end/ui/legacy/components/utils/Linkifier.ts +9 -3
  220. package/front_end/ui/legacy/legacy.ts +0 -2
  221. package/front_end/ui/visual_logging/KnownContextValues.ts +4 -1
  222. package/mcp/mcp.ts +6 -0
  223. package/package.json +1 -1
  224. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatterBounds.snapshot.txt +0 -4
  225. package/front_end/ui/components/docs/breadcrumbs_perf/initial-breadcrumb-perf.html +0 -20
  226. package/front_end/ui/components/docs/breadcrumbs_perf/initial-breadcrumb-perf.ts +0 -25
  227. package/front_end/ui/components/docs/breadcrumbs_perf/nested-breadcrumbs-perf.html +0 -20
  228. package/front_end/ui/components/docs/breadcrumbs_perf/nested-breadcrumbs-perf.ts +0 -36
  229. package/front_end/ui/components/docs/recorder_create_recording_view/basic.html +0 -20
  230. package/front_end/ui/components/docs/recorder_create_recording_view/basic.ts +0 -27
  231. package/front_end/ui/legacy/ThrottledWidget.ts +0 -48
@@ -1,7 +1,6 @@
1
1
  // Copyright 2021 The Chromium Authors
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
- /* eslint-disable @devtools/no-lit-render-outside-of-view */
5
4
 
6
5
  import '../../../ui/components/chrome_link/chrome_link.js';
7
6
  import '../../../ui/components/expandable_list/expandable_list.js';
@@ -15,19 +14,16 @@ import * as SDK from '../../../core/sdk/sdk.js';
15
14
  import * as Protocol from '../../../generated/protocol.js';
16
15
  import * as Buttons from '../../../ui/components/buttons/buttons.js';
17
16
  import type * as ExpandableList from '../../../ui/components/expandable_list/expandable_list.js';
18
- import * as LegacyWrapper from '../../../ui/components/legacy_wrapper/legacy_wrapper.js';
19
- import * as RenderCoordinator from '../../../ui/components/render_coordinator/render_coordinator.js';
20
17
  import type * as ReportView from '../../../ui/components/report_view/report_view.js';
21
18
  import type * as TreeOutline from '../../../ui/components/tree_outline/tree_outline.js';
22
19
  import * as Components from '../../../ui/legacy/components/utils/utils.js';
23
- import * as Lit from '../../../ui/lit/lit.js';
20
+ import * as UI from '../../../ui/legacy/legacy.js';
21
+ import {html, type LitTemplate, nothing, render, type TemplateResult} from '../../../ui/lit/lit.js';
24
22
  import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
25
23
 
26
24
  import {NotRestoredReasonDescription} from './BackForwardCacheStrings.js';
27
25
  import backForwardCacheViewStyles from './backForwardCacheView.css.js';
28
26
 
29
- const {html} = Lit;
30
-
31
27
  const UIStrings = {
32
28
  /**
33
29
  * @description Title text in back/forward cache view of the Application panel
@@ -66,6 +62,10 @@ const UIStrings = {
66
62
  * page eligible for back/forward cache.
67
63
  */
68
64
  pageSupportNeeded: 'Actionable',
65
+ /**
66
+ * @description Label for the completion of the back/forward cache test
67
+ */
68
+ testCompleted: 'Back/forward cache test completed.',
69
69
  /**
70
70
  * @description Explanation for actionable items which prevent the page from being eligible
71
71
  * for back/forward cache.
@@ -154,18 +154,336 @@ const enum ScreenStatusType {
154
154
  RESULT = 'Result',
155
155
  }
156
156
 
157
- export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableComponent {
158
- readonly #shadow = this.attachShadow({mode: 'open'});
157
+ function renderMainFrameInformation(
158
+ frame: SDK.ResourceTreeModel.ResourceTreeFrame|null,
159
+ frameTreeData: {node: FrameTreeNodeData, frameCount: number, issueCount: number}|undefined,
160
+ reasonToFramesMap: Map<Protocol.Page.BackForwardCacheNotRestoredReason, string[]>, screenStatus: ScreenStatusType,
161
+ navigateAwayAndBack: () => Promise<void>): TemplateResult {
162
+ if (!frame) {
163
+ // clang-format of
164
+ return html`
165
+ <devtools-report-key>
166
+ ${i18nString(UIStrings.mainFrame)}
167
+ </devtools-report-key>
168
+ <devtools-report-value>
169
+ ${i18nString(UIStrings.unavailable)}
170
+ </devtools-report-value>`;
171
+ // clang-format on
172
+ }
173
+ const isTestRunning = (screenStatus === ScreenStatusType.RUNNING);
174
+ // Prevent running BFCache test on the DevTools window itself via DevTools on DevTools
175
+ const isTestingForbidden = Common.ParsedURL.schemeIs(frame.url, 'devtools:');
176
+ // clang-format off
177
+ return html`
178
+ ${renderBackForwardCacheStatus(frame.backForwardCacheDetails.restoredFromCache)}
179
+ <devtools-report-key>${i18nString(UIStrings.url)}</devtools-report-key>
180
+ <devtools-report-value>${frame.url}</devtools-report-value>
181
+ ${maybeRenderFrameTree(frameTreeData)}
182
+ <devtools-report-section>
183
+ <devtools-button
184
+ aria-label=${i18nString(UIStrings.runTest)}
185
+ .disabled=${isTestRunning || isTestingForbidden}
186
+ .spinner=${isTestRunning}
187
+ .variant=${Buttons.Button.Variant.PRIMARY}
188
+ @click=${navigateAwayAndBack}
189
+ jslog=${VisualLogging.action('back-forward-cache.run-test').track({click: true})}>
190
+ ${isTestRunning ? html`
191
+ ${i18nString(UIStrings.runningTest)}`:`
192
+ ${i18nString(UIStrings.runTest)}
193
+ `}
194
+ </devtools-button>
195
+ </devtools-report-section>
196
+ <devtools-report-divider>
197
+ </devtools-report-divider>
198
+ ${maybeRenderExplanations(frame.backForwardCacheDetails.explanations,
199
+ frame.backForwardCacheDetails.explanationsTree,
200
+ reasonToFramesMap)}
201
+ <devtools-report-section>
202
+ <x-link href="https://web.dev/bfcache/" class="link"
203
+ jslog=${VisualLogging.action('learn-more.eligibility').track({click: true})}>
204
+ ${i18nString(UIStrings.learnMore)}
205
+ </x-link>
206
+ </devtools-report-section>`;
207
+ // clang-format on
208
+ }
209
+
210
+ function maybeRenderFrameTree(
211
+ frameTreeData: {node: FrameTreeNodeData, frameCount: number, issueCount: number}|undefined): LitTemplate {
212
+ if (!frameTreeData || (frameTreeData.frameCount === 0 && frameTreeData.issueCount === 0)) {
213
+ return nothing;
214
+ }
215
+
216
+ function treeNodeRenderer(node: TreeOutline.TreeOutlineUtils.TreeNode<FrameTreeNodeData>): TemplateResult {
217
+ // clang-format off
218
+ return html`
219
+ <div class="text-ellipsis">
220
+ ${node.treeNodeData.iconName ? html`
221
+ <devtools-icon class="inline-icon extra-large" .name=${node.treeNodeData.iconName} style="margin-bottom: -3px;">
222
+ </devtools-icon>
223
+ ` : nothing}
224
+ ${node.treeNodeData.text}
225
+ </div>`;
226
+ // clang-format on
227
+ }
228
+
229
+ const frameTreeNode = buildFrameTree(frameTreeData.node);
230
+ // Override the icon for the outermost frame.
231
+ frameTreeNode.treeNodeData.iconName = 'frame';
232
+ let title = '';
233
+ // The translation pipeline does not support nested plurals. We avoid this
234
+ // here by pulling out the logic for one of the plurals into code instead.
235
+ if (frameTreeData.frameCount === 1) {
236
+ title = i18nString(UIStrings.issuesInSingleFrame, {n: frameTreeData.issueCount});
237
+ } else {
238
+ title = i18nString(UIStrings.issuesInMultipleFrames, {n: frameTreeData.issueCount, m: frameTreeData.frameCount});
239
+ }
240
+ const root: TreeOutline.TreeOutlineUtils.TreeNode<FrameTreeNodeData> = {
241
+ treeNodeData: {
242
+ text: title,
243
+ },
244
+ id: 'root',
245
+ children: () => Promise.resolve([frameTreeNode]),
246
+ };
247
+
248
+ // clang-format off
249
+ return html`
250
+ <devtools-report-key jslog=${VisualLogging.section('frames')}>${i18nString(UIStrings.framesTitle)}</devtools-report-key>
251
+ <devtools-report-value>
252
+ <devtools-tree-outline .data=${{
253
+ tree: [root],
254
+ defaultRenderer: treeNodeRenderer,
255
+ compact: true,
256
+ } as TreeOutline.TreeOutline.TreeOutlineData<FrameTreeNodeData>}>
257
+ </devtools-tree-outline>
258
+ </devtools-report-value>`;
259
+ // clang-format on
260
+ }
261
+
262
+ let nextNodeId = 0;
263
+
264
+ function buildFrameTree(data: FrameTreeNodeData): TreeOutline.TreeOutlineUtils.TreeNode<FrameTreeNodeData> {
265
+ const children = data.children;
266
+ const node = {
267
+ treeNodeData: {
268
+ text: data.text,
269
+ ...(data.iconName ? {iconName: data.iconName} : {}),
270
+ },
271
+ ...(children?.length ? {children: () => Promise.resolve(children.map(child => buildFrameTree(child)))} : {}),
272
+ id: String(nextNodeId++),
273
+ };
274
+ return node;
275
+ }
276
+
277
+ function renderBackForwardCacheStatus(status: boolean|undefined): TemplateResult {
278
+ switch (status) {
279
+ case true:
280
+ // clang-format off
281
+ return html`
282
+ <devtools-report-section class="cache-status-section" tabindex="-1">
283
+ <div class="status extra-large">
284
+ <devtools-icon class="inline-icon extra-large" name="check-circle" style="color: var(--icon-checkmark-green);">
285
+ </devtools-icon>
286
+ </div>
287
+ ${i18nString(UIStrings.restoredFromBFCache)}
288
+ </devtools-report-section>`;
289
+ // clang-format on
290
+ case false:
291
+ // clang-format off
292
+ return html`
293
+ <devtools-report-section class="cache-status-section" tabindex="-1">
294
+ <div class="status">
295
+ <devtools-icon class="inline-icon extra-large" name="clear">
296
+ </devtools-icon>
297
+ </div>
298
+ ${i18nString(UIStrings.normalNavigation)}
299
+ </devtools-report-section>`;
300
+ // clang-format on
301
+ }
302
+ // clang-format off
303
+ return html`
304
+ <devtools-report-section class="cache-status-section" tabindex="-1">
305
+ ${i18nString(UIStrings.unknown)}
306
+ </devtools-report-section>`;
307
+ // clang-format on
308
+ }
309
+
310
+ function maybeRenderExplanations(
311
+ explanations: Protocol.Page.BackForwardCacheNotRestoredExplanation[],
312
+ explanationTree: Protocol.Page.BackForwardCacheNotRestoredExplanationTree|undefined,
313
+ reasonToFramesMap: Map<Protocol.Page.BackForwardCacheNotRestoredReason, string[]>): LitTemplate {
314
+ if (explanations.length === 0) {
315
+ return nothing;
316
+ }
317
+
318
+ const pageSupportNeeded = explanations.filter(
319
+ explanation => explanation.type === Protocol.Page.BackForwardCacheNotRestoredReasonType.PageSupportNeeded);
320
+ const supportPending = explanations.filter(
321
+ explanation => explanation.type === Protocol.Page.BackForwardCacheNotRestoredReasonType.SupportPending);
322
+ const circumstantial = explanations.filter(
323
+ explanation => explanation.type === Protocol.Page.BackForwardCacheNotRestoredReasonType.Circumstantial);
324
+
325
+ // Disabled until https://crbug.com/1079231 is fixed.
326
+ // clang-format off
327
+ return html`
328
+ ${renderExplanations(i18nString(UIStrings.pageSupportNeeded), i18nString(UIStrings.pageSupportNeededExplanation), pageSupportNeeded, reasonToFramesMap)}
329
+ ${renderExplanations(i18nString(UIStrings.supportPending), i18nString(UIStrings.supportPendingExplanation), supportPending, reasonToFramesMap)}
330
+ ${renderExplanations(i18nString(UIStrings.circumstantial), i18nString(UIStrings.circumstantialExplanation), circumstantial, reasonToFramesMap)}`;
331
+ // clang-format on
332
+ }
333
+
334
+ function renderExplanations(
335
+ category: Platform.UIString.LocalizedString, explainerText: Platform.UIString.LocalizedString,
336
+ explanations: Protocol.Page.BackForwardCacheNotRestoredExplanation[],
337
+ reasonToFramesMap: Map<Protocol.Page.BackForwardCacheNotRestoredReason, string[]>): TemplateResult {
338
+ // Disabled until https://crbug.com/1079231 is fixed.
339
+ // clang-format off
340
+ return html`
341
+ ${explanations.length > 0 ? html`
342
+ <devtools-report-section-header>
343
+ ${category}
344
+ <div class="help-outline-icon">
345
+ <devtools-icon class="inline-icon medium" name="help" title=${explainerText}>
346
+ </devtools-icon>
347
+ </div>
348
+ </devtools-report-section-header>
349
+ ${explanations.map(explanation => renderReason(explanation, reasonToFramesMap.get(explanation.reason)))}
350
+ ` : nothing}`;
351
+ // clang-format on
352
+ }
353
+
354
+ function maybeRenderReasonContext(explanation: Protocol.Page.BackForwardCacheNotRestoredExplanation): LitTemplate {
355
+ if (explanation.reason ===
356
+ Protocol.Page.BackForwardCacheNotRestoredReason.EmbedderExtensionSentMessageToCachedFrame &&
357
+ explanation.context) {
358
+ const link = 'chrome://extensions/?id=' + explanation.context as Platform.DevToolsPath.UrlString;
359
+ // clang-format off
360
+ return html`${i18nString(UIStrings.blockingExtensionId)}
361
+ <devtools-chrome-link .href=${link}>${explanation.context}</devtools-chrome-link>`;
362
+ // clang-format on
363
+ }
364
+ return nothing;
365
+ }
366
+
367
+ function renderFramesPerReason(frames: string[]|undefined): LitTemplate {
368
+ if (frames === undefined || frames.length === 0) {
369
+ return nothing;
370
+ }
371
+ const rows = [html`<div>${i18nString(UIStrings.framesPerIssue, {n: frames.length})}</div>`];
372
+ rows.push(...frames.map(url => html`<div class="text-ellipsis" title=${url}
373
+ jslog=${VisualLogging.treeItem()}>${url}</div>`));
374
+ return html`
375
+ <div class="details-list"
376
+ jslog=${VisualLogging.tree('frames-per-issue')}>
377
+ <devtools-expandable-list .data=${{
378
+ rows,
379
+ title: i18nString(UIStrings.framesPerIssue, {n: frames.length}),
380
+ } as ExpandableList.ExpandableList.ExpandableListData}
381
+ jslog=${VisualLogging.treeItem()}></devtools-expandable-list>
382
+ </div>
383
+ `;
384
+ }
385
+
386
+ function maybeRenderDeepLinkToUnload(explanation: Protocol.Page.BackForwardCacheNotRestoredExplanation): LitTemplate {
387
+ if (explanation.reason === Protocol.Page.BackForwardCacheNotRestoredReason.UnloadHandlerExistsInMainFrame ||
388
+ explanation.reason === Protocol.Page.BackForwardCacheNotRestoredReason.UnloadHandlerExistsInSubFrame) {
389
+ return html`
390
+ <x-link href="https://web.dev/bfcache/#never-use-the-unload-event" class="link"
391
+ jslog=${VisualLogging.action('learn-more.never-use-unload').track({
392
+ click: true,
393
+ })}>
394
+ ${i18nString(UIStrings.neverUseUnload)}
395
+ </x-link>`;
396
+ }
397
+ return nothing;
398
+ }
399
+
400
+ function maybeRenderJavaScriptDetails(details: Protocol.Page.BackForwardCacheBlockingDetails[]|undefined): LitTemplate {
401
+ if (details === undefined || details.length === 0) {
402
+ return nothing;
403
+ }
404
+ const maxLengthForDisplayedURLs = 50;
405
+ const linkifier = new Components.Linkifier.Linkifier(maxLengthForDisplayedURLs);
406
+ const rows = [html`<div>${i18nString(UIStrings.filesPerIssue, {n: details.length})}</div>`];
407
+ rows.push(...details.map(
408
+ detail => html`${
409
+ linkifier.linkifyScriptLocation(
410
+ null, null, detail.url as Platform.DevToolsPath.UrlString, detail.lineNumber, {
411
+ columnNumber: detail.columnNumber,
412
+ showColumnNumber: true,
413
+ inlineFrameIndex: 0,
414
+ })}`));
415
+ return html`
416
+ <div class="details-list">
417
+ <devtools-expandable-list .data=${
418
+ {rows} as ExpandableList.ExpandableList.ExpandableListData}></devtools-expandable-list>
419
+ </div>
420
+ `;
421
+ }
422
+
423
+ function renderReason(
424
+ explanation: Protocol.Page.BackForwardCacheNotRestoredExplanation, frames: string[]|undefined): TemplateResult {
425
+ // clang-format off
426
+ return html`
427
+ <devtools-report-section>
428
+ ${(explanation.reason in NotRestoredReasonDescription) ?
429
+ html`
430
+ <div class="circled-exclamation-icon">
431
+ <devtools-icon class="inline-icon medium" style="color: var(--icon-warning)" name="warning">
432
+ </devtools-icon>
433
+ </div>
434
+ <div>
435
+ ${NotRestoredReasonDescription[explanation.reason].name()}
436
+ ${maybeRenderDeepLinkToUnload(explanation)}
437
+ ${maybeRenderReasonContext(explanation)}
438
+ </div>` :
439
+ nothing}
440
+ </devtools-report-section>
441
+ <div class="gray-text">
442
+ ${explanation.reason}
443
+ </div>
444
+ ${maybeRenderJavaScriptDetails(explanation.details)}
445
+ ${renderFramesPerReason(frames)}`;
446
+ // clang-format on
447
+ }
448
+
449
+ interface ViewInput {
450
+ frame: SDK.ResourceTreeModel.ResourceTreeFrame|null;
451
+ frameTreeData: {node: FrameTreeNodeData, frameCount: number, issueCount: number}|undefined;
452
+ reasonToFramesMap: Map<Protocol.Page.BackForwardCacheNotRestoredReason, string[]>;
453
+ screenStatus: ScreenStatusType;
454
+ navigateAwayAndBack: () => Promise<void>;
455
+ }
456
+
457
+ type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
458
+
459
+ const DEFAULT_VIEW: View = (input, output, target) => {
460
+ // Disabled until https://crbug.com/1079231 is fixed.
461
+ // clang-format off
462
+ render(html`
463
+ <style>${backForwardCacheViewStyles}</style>
464
+ <devtools-report .data=${
465
+ {reportTitle: i18nString(UIStrings.backForwardCacheTitle)} as ReportView.ReportView.ReportData
466
+ } jslog=${VisualLogging.pane('back-forward-cache')}>
467
+
468
+ ${renderMainFrameInformation(input.frame, input.frameTreeData, input.reasonToFramesMap, input.screenStatus, input.navigateAwayAndBack)}
469
+ </devtools-report>
470
+ `, target);
471
+ // clang-format on
472
+ };
473
+
474
+ export class BackForwardCacheView extends UI.Widget.Widget {
159
475
  #screenStatus = ScreenStatusType.RESULT;
160
- #nextNodeId = 0;
161
476
  #historyIndex = 0;
477
+ #view: View;
162
478
 
163
- constructor() {
164
- super();
479
+ constructor(view = DEFAULT_VIEW) {
480
+ super({useShadowDom: true});
481
+ this.#view = view;
165
482
  this.#getMainResourceTreeModel()?.addEventListener(
166
- SDK.ResourceTreeModel.Events.PrimaryPageChanged, this.render, this);
483
+ SDK.ResourceTreeModel.Events.PrimaryPageChanged, this.requestUpdate, this);
167
484
  this.#getMainResourceTreeModel()?.addEventListener(
168
- SDK.ResourceTreeModel.Events.BackForwardCacheDetailsUpdated, this.render, this);
485
+ SDK.ResourceTreeModel.Events.BackForwardCacheDetailsUpdated, this.requestUpdate, this);
486
+ this.requestUpdate();
169
487
  }
170
488
 
171
489
  #getMainResourceTreeModel(): SDK.ResourceTreeModel.ResourceTreeModel|null {
@@ -176,25 +494,21 @@ export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableC
176
494
  #getMainFrame(): SDK.ResourceTreeModel.ResourceTreeFrame|null {
177
495
  return this.#getMainResourceTreeModel()?.mainFrame || null;
178
496
  }
179
- connectedCallback(): void {
180
- this.parentElement?.classList.add('overflow-auto');
181
- }
182
497
 
183
- override async render(): Promise<void> {
184
- await RenderCoordinator.write('BackForwardCacheView render', () => {
185
- // Disabled until https://crbug.com/1079231 is fixed.
186
- // clang-format off
187
- Lit.render(html`
188
- <style>${backForwardCacheViewStyles}</style>
189
- <devtools-report .data=${
190
- {reportTitle: i18nString(UIStrings.backForwardCacheTitle)} as ReportView.ReportView.ReportData
191
- } jslog=${VisualLogging.pane('back-forward-cache')}>
192
-
193
- ${this.#renderMainFrameInformation()}
194
- </devtools-report>
195
- `, this.#shadow, {host: this});
196
- // clang-format on
197
- });
498
+ override async performUpdate(): Promise<void> {
499
+ const reasonToFramesMap = new Map<Protocol.Page.BackForwardCacheNotRestoredReason, string[]>();
500
+ const explanationTree = this.#getMainFrame()?.backForwardCacheDetails?.explanationsTree;
501
+ if (explanationTree) {
502
+ this.#buildReasonToFramesMap(explanationTree, {blankCount: 1}, reasonToFramesMap);
503
+ }
504
+ const viewInput: ViewInput = {
505
+ frame: this.#getMainFrame(),
506
+ frameTreeData: this.#buildFrameTreeDataRecursive(explanationTree, {blankCount: 1}),
507
+ reasonToFramesMap,
508
+ screenStatus: this.#screenStatus,
509
+ navigateAwayAndBack: this.#navigateAwayAndBack.bind(this),
510
+ };
511
+ this.#view(viewInput, undefined, this.contentElement);
198
512
  }
199
513
 
200
514
  #renderBackForwardCacheTestResult(): void {
@@ -202,7 +516,14 @@ export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableC
202
516
  SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.FrameNavigated,
203
517
  this.#renderBackForwardCacheTestResult, this);
204
518
  this.#screenStatus = ScreenStatusType.RESULT;
205
- void this.render();
519
+ this.requestUpdate();
520
+ void this.updateComplete.then(() => {
521
+ UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.testCompleted));
522
+ const resultsSection = this.contentElement?.querySelector('.cache-status-section') as HTMLElement;
523
+ if (resultsSection) {
524
+ resultsSection.focus();
525
+ }
526
+ });
206
527
  }
207
528
 
208
529
  async #onNavigatedAway(): Promise<void> {
@@ -244,7 +565,7 @@ export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableC
244
565
  }
245
566
  this.#historyIndex = historyResults.currentIndex;
246
567
  this.#screenStatus = ScreenStatusType.RUNNING;
247
- void this.render();
568
+ this.requestUpdate();
248
569
 
249
570
  // This event listener is removed inside of onNavigatedAway().
250
571
  SDK.TargetManager.TargetManager.instance().addModelListener(
@@ -258,120 +579,17 @@ export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableC
258
579
  void resourceTreeModel.navigate('chrome://terms' as Platform.DevToolsPath.UrlString);
259
580
  }
260
581
 
261
- #renderMainFrameInformation(): Lit.TemplateResult {
262
- const frame = this.#getMainFrame();
263
- if (!frame) {
264
- // clang-format off
265
- return html`
266
- <devtools-report-key>
267
- ${i18nString(UIStrings.mainFrame)}
268
- </devtools-report-key>
269
- <devtools-report-value>
270
- ${i18nString(UIStrings.unavailable)}
271
- </devtools-report-value>
272
- `;
273
- // clang-format on
274
- }
275
- const isTestRunning = (this.#screenStatus === ScreenStatusType.RUNNING);
276
- // Prevent running BFCache test on the DevTools window itself via DevTools on DevTools
277
- const isTestingForbidden = Common.ParsedURL.schemeIs(frame.url, 'devtools:');
278
- // clang-format off
279
- return html`
280
- ${this.#renderBackForwardCacheStatus(frame.backForwardCacheDetails.restoredFromCache)}
281
- <devtools-report-key>${i18nString(UIStrings.url)}</devtools-report-key>
282
- <devtools-report-value>${frame.url}</devtools-report-value>
283
- ${this.#maybeRenderFrameTree(frame.backForwardCacheDetails.explanationsTree)}
284
- <devtools-report-section>
285
- <devtools-button
286
- aria-label=${i18nString(UIStrings.runTest)}
287
- .disabled=${isTestRunning || isTestingForbidden}
288
- .spinner=${isTestRunning}
289
- .variant=${Buttons.Button.Variant.PRIMARY}
290
- @click=${this.#navigateAwayAndBack}
291
- jslog=${VisualLogging.action('back-forward-cache.run-test').track({click: true})}>
292
- ${isTestRunning ? html`
293
- ${i18nString(UIStrings.runningTest)}`:`
294
- ${i18nString(UIStrings.runTest)}
295
- `}
296
- </devtools-button>
297
- </devtools-report-section>
298
- <devtools-report-divider>
299
- </devtools-report-divider>
300
- ${this.#maybeRenderExplanations(frame.backForwardCacheDetails.explanations,
301
- frame.backForwardCacheDetails.explanationsTree)}
302
- <devtools-report-section>
303
- <x-link href="https://web.dev/bfcache/" class="link"
304
- jslog=${VisualLogging.action('learn-more.eligibility').track({click: true})}>
305
- ${i18nString(UIStrings.learnMore)}
306
- </x-link>
307
- </devtools-report-section>
308
- `;
309
- // clang-format on
310
- }
311
-
312
- #maybeRenderFrameTree(explanationTree: Protocol.Page.BackForwardCacheNotRestoredExplanationTree|undefined):
313
- Lit.LitTemplate {
314
- if (!explanationTree || (explanationTree.explanations.length === 0 && explanationTree.children.length === 0)) {
315
- return Lit.nothing;
316
- }
317
-
318
- function treeNodeRenderer(node: TreeOutline.TreeOutlineUtils.TreeNode<FrameTreeNodeData>): Lit.TemplateResult {
319
- // clang-format off
320
- return html`
321
- <div class="text-ellipsis">
322
- ${node.treeNodeData.iconName ? html`
323
- <devtools-icon class="inline-icon extra-large" .name=${node.treeNodeData.iconName} style="margin-bottom: -3px;">
324
- </devtools-icon>
325
- ` : Lit.nothing}
326
- ${node.treeNodeData.text}
327
- </div>
328
- `;
329
- // clang-format on
330
- }
331
-
332
- const frameTreeData = this.#buildFrameTreeDataRecursive(explanationTree, {blankCount: 1});
333
- // Override the icon for the outermost frame.
334
- frameTreeData.node.treeNodeData.iconName = 'frame';
335
- let title = '';
336
- // The translation pipeline does not support nested plurals. We avoid this
337
- // here by pulling out the logic for one of the plurals into code instead.
338
- if (frameTreeData.frameCount === 1) {
339
- title = i18nString(UIStrings.issuesInSingleFrame, {n: frameTreeData.issueCount});
340
- } else {
341
- title = i18nString(UIStrings.issuesInMultipleFrames, {n: frameTreeData.issueCount, m: frameTreeData.frameCount});
342
- }
343
- const root: TreeOutline.TreeOutlineUtils.TreeNode<FrameTreeNodeData> = {
344
- treeNodeData: {
345
- text: title,
346
- },
347
- id: 'root',
348
- children: () => Promise.resolve([frameTreeData.node]),
349
- };
350
-
351
- // clang-format off
352
- return html`
353
- <devtools-report-key jslog=${VisualLogging.section('frames')}>${i18nString(UIStrings.framesTitle)}</devtools-report-key>
354
- <devtools-report-value>
355
- <devtools-tree-outline .data=${{
356
- tree: [root],
357
- defaultRenderer: treeNodeRenderer,
358
- compact: true,
359
- } as TreeOutline.TreeOutline.TreeOutlineData<FrameTreeNodeData>}>
360
- </devtools-tree-outline>
361
- </devtools-report-value>
362
- `;
363
- // clang-format on
364
- }
365
-
366
582
  // Builds a subtree of the frame tree, conaining only frames with BFCache issues and their ancestors.
367
583
  // Returns the root node, the number of frames in the subtree, and the number of issues in the subtree.
368
584
  #buildFrameTreeDataRecursive(
369
- explanationTree: Protocol.Page.BackForwardCacheNotRestoredExplanationTree,
370
- nextBlankURLCount: {blankCount: number}):
371
- {node: TreeOutline.TreeOutlineUtils.TreeNode<FrameTreeNodeData>, frameCount: number, issueCount: number} {
585
+ explanationTree: Protocol.Page.BackForwardCacheNotRestoredExplanationTree|undefined,
586
+ nextBlankURLCount: {blankCount: number}): {node: FrameTreeNodeData, frameCount: number, issueCount: number} {
587
+ if (!explanationTree) {
588
+ return {node: {text: ''}, frameCount: 0, issueCount: 0};
589
+ }
372
590
  let frameCount = 1;
373
591
  let issueCount = 0;
374
- const children: Array<TreeOutline.TreeOutlineUtils.TreeNode<FrameTreeNodeData>> = [];
592
+ const children: FrameTreeNodeData[] = [];
375
593
 
376
594
  let nodeUrlText = '';
377
595
  if (explanationTree.url.length) {
@@ -382,7 +600,7 @@ export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableC
382
600
  }
383
601
 
384
602
  for (const explanation of explanationTree.explanations) {
385
- const child = {treeNodeData: {text: explanation.reason}, id: String(this.#nextNodeId++)};
603
+ const child = {text: explanation.reason};
386
604
  issueCount += 1;
387
605
  children.push(child);
388
606
  }
@@ -395,18 +613,12 @@ export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableC
395
613
  }
396
614
  }
397
615
 
398
- let node: TreeOutline.TreeOutlineUtils.TreeNode<FrameTreeNodeData> = {
399
- treeNodeData: {
400
- text: `(${issueCount}) ${nodeUrlText}`,
401
- },
402
- id: String(this.#nextNodeId++),
616
+ let node: FrameTreeNodeData = {
617
+ text: `(${issueCount}) ${nodeUrlText}`,
403
618
  };
404
619
  if (children.length) {
405
- node = {
406
- ...node,
407
- children: () => Promise.resolve(children),
408
- };
409
- node.treeNodeData.iconName = 'iframe';
620
+ node = {...node, children};
621
+ node.iconName = 'iframe';
410
622
  } else if (!explanationTree.url.length) {
411
623
  // If the current node increased the blank count, but it has no children and
412
624
  // is therefore not shown, decrement the blank count again.
@@ -415,42 +627,6 @@ export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableC
415
627
  return {node, frameCount, issueCount};
416
628
  }
417
629
 
418
- #renderBackForwardCacheStatus(status: boolean|undefined): Lit.TemplateResult {
419
- switch (status) {
420
- case true:
421
- // clang-format off
422
- return html`
423
- <devtools-report-section>
424
- <div class="status extra-large">
425
- <devtools-icon class="inline-icon extra-large" name="check-circle" style="color: var(--icon-checkmark-green);">
426
- </devtools-icon>
427
- </div>
428
- ${i18nString(UIStrings.restoredFromBFCache)}
429
- </devtools-report-section>
430
- `;
431
- // clang-format on
432
- case false:
433
- // clang-format off
434
- return html`
435
- <devtools-report-section>
436
- <div class="status">
437
- <devtools-icon class="inline-icon extra-large" name="clear">
438
- </devtools-icon>
439
- </div>
440
- ${i18nString(UIStrings.normalNavigation)}
441
- </devtools-report-section>
442
- `;
443
- // clang-format on
444
- }
445
- // clang-format off
446
- return html`
447
- <devtools-report-section>
448
- ${i18nString(UIStrings.unknown)}
449
- </devtools-report-section>
450
- `;
451
- // clang-format on
452
- }
453
-
454
630
  #buildReasonToFramesMap(
455
631
  explanationTree: Protocol.Page.BackForwardCacheNotRestoredExplanationTree,
456
632
  nextBlankURLCount: {blankCount: number},
@@ -473,162 +649,10 @@ export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableC
473
649
  this.#buildReasonToFramesMap(child, nextBlankURLCount, outputMap);
474
650
  });
475
651
  }
476
-
477
- #maybeRenderExplanations(
478
- explanations: Protocol.Page.BackForwardCacheNotRestoredExplanation[],
479
- explanationTree: Protocol.Page.BackForwardCacheNotRestoredExplanationTree|undefined): Lit.LitTemplate {
480
- if (explanations.length === 0) {
481
- return Lit.nothing;
482
- }
483
-
484
- const pageSupportNeeded = explanations.filter(
485
- explanation => explanation.type === Protocol.Page.BackForwardCacheNotRestoredReasonType.PageSupportNeeded);
486
- const supportPending = explanations.filter(
487
- explanation => explanation.type === Protocol.Page.BackForwardCacheNotRestoredReasonType.SupportPending);
488
- const circumstantial = explanations.filter(
489
- explanation => explanation.type === Protocol.Page.BackForwardCacheNotRestoredReasonType.Circumstantial);
490
-
491
- const reasonToFramesMap = new Map<Protocol.Page.BackForwardCacheNotRestoredReason, string[]>();
492
- if (explanationTree) {
493
- this.#buildReasonToFramesMap(explanationTree, {blankCount: 1}, reasonToFramesMap);
494
- }
495
- // Disabled until https://crbug.com/1079231 is fixed.
496
- // clang-format off
497
- return html`
498
- ${this.#renderExplanations(i18nString(UIStrings.pageSupportNeeded), i18nString(UIStrings.pageSupportNeededExplanation), pageSupportNeeded, reasonToFramesMap)}
499
- ${this.#renderExplanations(i18nString(UIStrings.supportPending), i18nString(UIStrings.supportPendingExplanation), supportPending, reasonToFramesMap)}
500
- ${this.#renderExplanations(i18nString(UIStrings.circumstantial), i18nString(UIStrings.circumstantialExplanation), circumstantial, reasonToFramesMap)}
501
- `;
502
- // clang-format on
503
- }
504
-
505
- #renderExplanations(
506
- category: Platform.UIString.LocalizedString, explainerText: Platform.UIString.LocalizedString,
507
- explanations: Protocol.Page.BackForwardCacheNotRestoredExplanation[],
508
- reasonToFramesMap: Map<Protocol.Page.BackForwardCacheNotRestoredReason, string[]>): Lit.TemplateResult {
509
- // Disabled until https://crbug.com/1079231 is fixed.
510
- // clang-format off
511
- return html`
512
- ${explanations.length > 0 ? html`
513
- <devtools-report-section-header>
514
- ${category}
515
- <div class="help-outline-icon">
516
- <devtools-icon class="inline-icon medium" name="help" title=${explainerText}>
517
- </devtools-icon>
518
- </div>
519
- </devtools-report-section-header>
520
- ${explanations.map(explanation => this.#renderReason(explanation, reasonToFramesMap.get(explanation.reason)))}
521
- ` : Lit.nothing}
522
- `;
523
- // clang-format on
524
- }
525
-
526
- #maybeRenderReasonContext(explanation: Protocol.Page.BackForwardCacheNotRestoredExplanation): Lit.LitTemplate {
527
- if (explanation.reason ===
528
- Protocol.Page.BackForwardCacheNotRestoredReason.EmbedderExtensionSentMessageToCachedFrame &&
529
- explanation.context) {
530
- const link = 'chrome://extensions/?id=' + explanation.context as Platform.DevToolsPath.UrlString;
531
- // clang-format off
532
- return html`${i18nString(UIStrings.blockingExtensionId)}
533
- <devtools-chrome-link .href=${link}>${explanation.context}</devtools-chrome-link>`;
534
- // clang-format on
535
- }
536
- return Lit.nothing;
537
- }
538
-
539
- #renderFramesPerReason(frames: string[]|undefined): Lit.LitTemplate {
540
- if (frames === undefined || frames.length === 0) {
541
- return Lit.nothing;
542
- }
543
- const rows = [html`<div>${i18nString(UIStrings.framesPerIssue, {n: frames.length})}</div>`];
544
- rows.push(...frames.map(url => html`<div class="text-ellipsis" title=${url}
545
- jslog=${VisualLogging.treeItem()}>${url}</div>`));
546
- return html`
547
- <div class="details-list"
548
- jslog=${VisualLogging.tree('frames-per-issue')}>
549
- <devtools-expandable-list .data=${{
550
- rows,
551
- title: i18nString(UIStrings.framesPerIssue, {n: frames.length}),
552
- } as ExpandableList.ExpandableList.ExpandableListData}
553
- jslog=${VisualLogging.treeItem()}></devtools-expandable-list>
554
- </div>
555
- `;
556
- }
557
-
558
- #maybeRenderDeepLinkToUnload(explanation: Protocol.Page.BackForwardCacheNotRestoredExplanation): Lit.LitTemplate {
559
- if (explanation.reason === Protocol.Page.BackForwardCacheNotRestoredReason.UnloadHandlerExistsInMainFrame ||
560
- explanation.reason === Protocol.Page.BackForwardCacheNotRestoredReason.UnloadHandlerExistsInSubFrame) {
561
- return html`
562
- <x-link href="https://web.dev/bfcache/#never-use-the-unload-event" class="link"
563
- jslog=${VisualLogging.action('learn-more.never-use-unload').track({
564
- click: true,
565
- })}>
566
- ${i18nString(UIStrings.neverUseUnload)}
567
- </x-link>`;
568
- }
569
- return Lit.nothing;
570
- }
571
-
572
- #maybeRenderJavaScriptDetails(details: Protocol.Page.BackForwardCacheBlockingDetails[]|undefined): Lit.LitTemplate {
573
- if (details === undefined || details.length === 0) {
574
- return Lit.nothing;
575
- }
576
- const maxLengthForDisplayedURLs = 50;
577
- const linkifier = new Components.Linkifier.Linkifier(maxLengthForDisplayedURLs);
578
- const rows = [html`<div>${i18nString(UIStrings.filesPerIssue, {n: details.length})}</div>`];
579
- rows.push(...details.map(
580
- detail => html`${
581
- linkifier.linkifyScriptLocation(
582
- null, null, detail.url as Platform.DevToolsPath.UrlString, detail.lineNumber, {
583
- columnNumber: detail.columnNumber,
584
- showColumnNumber: true,
585
- inlineFrameIndex: 0,
586
- })}`));
587
- return html`
588
- <div class="details-list">
589
- <devtools-expandable-list .data=${
590
- {rows} as ExpandableList.ExpandableList.ExpandableListData}></devtools-expandable-list>
591
- </div>
592
- `;
593
- }
594
-
595
- #renderReason(explanation: Protocol.Page.BackForwardCacheNotRestoredExplanation, frames: string[]|undefined):
596
- Lit.TemplateResult {
597
- // clang-format off
598
- return html`
599
- <devtools-report-section>
600
- ${(explanation.reason in NotRestoredReasonDescription) ?
601
- html`
602
- <div class="circled-exclamation-icon">
603
- <devtools-icon class="inline-icon medium" style="color: var(--icon-warning)" name="warning">
604
- </devtools-icon>
605
- </div>
606
- <div>
607
- ${NotRestoredReasonDescription[explanation.reason].name()}
608
- ${this.#maybeRenderDeepLinkToUnload(explanation)}
609
- ${this.#maybeRenderReasonContext(explanation)}
610
- </div>` :
611
- Lit.nothing}
612
- </devtools-report-section>
613
- <div class="gray-text">
614
- ${explanation.reason}
615
- </div>
616
- ${this.#maybeRenderJavaScriptDetails(explanation.details)}
617
- ${this.#renderFramesPerReason(frames)}
618
- `;
619
- // clang-format on
620
- }
621
652
  }
622
653
 
623
654
  interface FrameTreeNodeData {
624
655
  text: string;
625
656
  iconName?: string;
626
- }
627
-
628
- customElements.define('devtools-resources-back-forward-cache-view', BackForwardCacheView);
629
-
630
- declare global {
631
- interface HTMLElementTagNameMap {
632
- 'devtools-resources-back-forward-cache-view': BackForwardCacheView;
633
- }
657
+ children?: FrameTreeNodeData[];
634
658
  }