chrome-devtools-frontend 1.0.1721762 → 1.0.1724140

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 (195) hide show
  1. package/docs/cookbook/dependencies.md +55 -11
  2. package/docs/get_the_code.md +15 -0
  3. package/front_end/core/i18n/collect-ui-strings.js +58 -12
  4. package/front_end/core/sdk/WebAuthnModel.ts +17 -10
  5. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  6. package/front_end/generated/protocol.ts +16 -0
  7. package/front_end/models/comment_manager/CD4ABridge.ts +4 -0
  8. package/front_end/models/comment_manager/CommentThread.ts +16 -0
  9. package/front_end/models/trace/handlers/NetworkRequestsHandler.ts +13 -6
  10. package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +92 -0
  11. package/front_end/panels/accessibility/accessibilityAnnouncementRecordingListView.css +3 -1
  12. package/front_end/panels/accessibility/accessibilityAnnouncementRecordingView.css +12 -1
  13. package/front_end/panels/application/StorageView.ts +250 -178
  14. package/front_end/panels/application/SubAppsView.ts +159 -0
  15. package/front_end/panels/application/application.ts +2 -0
  16. package/front_end/panels/application/preloading/components/PreloadingDisabledInfobar.ts +1 -1
  17. package/front_end/panels/application/subAppsView.css +21 -0
  18. package/front_end/panels/elements/ClassesPaneWidget.ts +3 -1
  19. package/front_end/panels/elements/DOMTreeElementWidget.ts +3 -1
  20. package/front_end/panels/elements/DOMTreeWidget.ts +12 -0
  21. package/front_end/panels/elements/StyleEditorWidget.ts +29 -0
  22. package/front_end/panels/elements/StylesSidebarPane.ts +1 -0
  23. package/front_end/panels/layer_viewer/Layers3DView.ts +21 -37
  24. package/front_end/panels/network/NetworkConfigView.ts +12 -10
  25. package/front_end/panels/network/networkConfigView.css +8 -8
  26. package/front_end/panels/screencast/ScreencastView.ts +3 -6
  27. package/front_end/panels/security/SecurityPanelSidebar.ts +0 -31
  28. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +9 -16
  29. package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +358 -345
  30. package/front_end/panels/settings/emulation/components/userAgentClientHintsForm.css +136 -121
  31. package/front_end/panels/sources/SourcesPanel.ts +3 -1
  32. package/front_end/panels/sources/TabbedEditorContainer.ts +41 -18
  33. package/front_end/panels/sources/UISourceCodeFrame.ts +1 -1
  34. package/front_end/panels/timeline/TimelineCommentContext.ts +171 -0
  35. package/front_end/panels/timeline/TimelineCommentController.ts +36 -0
  36. package/front_end/panels/timeline/timeline.ts +2 -0
  37. package/front_end/panels/webauthn/WebauthnPane.ts +15 -13
  38. package/front_end/third_party/chromium/README.chromium +1 -1
  39. package/front_end/third_party/puppeteer/README.chromium +2 -2
  40. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +113 -3
  41. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +21311 -20981
  42. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.d.ts +36 -0
  43. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.d.ts.map +1 -1
  44. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.js +22 -0
  45. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.js.map +1 -1
  46. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.d.ts.map +1 -1
  47. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.js +20 -18
  48. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.js.map +1 -1
  49. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPRequest.d.ts +20 -1
  50. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPRequest.d.ts.map +1 -1
  51. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPRequest.js +2 -2
  52. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPRequest.js.map +1 -1
  53. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts +40 -1
  54. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts.map +1 -1
  55. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js +3 -1
  56. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js.map +1 -1
  57. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/locators/locators.d.ts +2 -0
  58. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/locators/locators.d.ts.map +1 -1
  59. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/locators/locators.js +41 -5
  60. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/locators/locators.js.map +1 -1
  61. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPRequest.d.ts +2 -1
  62. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPRequest.js +23 -2
  64. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPRequest.js.map +1 -1
  65. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Input.js +1 -1
  66. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Page.d.ts +3 -2
  67. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Page.d.ts.map +1 -1
  68. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Page.js +13 -1
  69. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Page.js.map +1 -1
  70. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/core/Request.d.ts +1 -0
  71. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/core/Request.d.ts.map +1 -1
  72. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/core/Request.js +18 -11
  73. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/core/Request.js.map +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.d.ts +2 -1
  75. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.d.ts.map +1 -1
  76. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.js +8 -1
  77. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.js.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts +2 -1
  79. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js +24 -12
  81. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/EmulationManager.d.ts +1 -1
  83. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/EmulationManager.d.ts.map +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/EmulationManager.js +13 -7
  85. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/EmulationManager.js.map +1 -1
  86. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Frame.d.ts.map +1 -1
  87. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Frame.js +5 -1
  88. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Frame.js.map +1 -1
  89. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPRequest.d.ts +22 -1
  90. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPRequest.d.ts.map +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPRequest.js +75 -9
  92. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPRequest.js.map +1 -1
  93. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkEventManager.d.ts +18 -4
  94. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkEventManager.d.ts.map +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkEventManager.js +8 -4
  96. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkEventManager.js.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.js +65 -26
  99. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.js.map +1 -1
  100. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Page.d.ts +3 -2
  101. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Page.d.ts.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Page.js +19 -0
  103. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Page.js.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.d.ts.map +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.js +4 -3
  106. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.js.map +1 -1
  107. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Target.d.ts +1 -0
  108. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Target.d.ts.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Target.js +4 -0
  110. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Target.js.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.d.ts +2 -0
  112. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.d.ts.map +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js +95 -8
  114. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js.map +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserConnector.d.ts +0 -8
  116. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserConnector.d.ts.map +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserConnector.js +8 -24
  118. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserConnector.js.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserWebSocketTransport.d.ts +1 -0
  120. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserWebSocketTransport.d.ts.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserWebSocketTransport.js +5 -4
  122. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserWebSocketTransport.js.map +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/ConnectOptions.d.ts +9 -0
  124. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/ConnectOptions.d.ts.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/WaitTask.d.ts.map +1 -1
  126. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/WaitTask.js +10 -0
  127. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/WaitTask.js.map +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.d.ts +10 -0
  129. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.d.ts.map +1 -1
  130. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.js +30 -5
  131. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.js.map +1 -1
  132. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts +1 -1
  133. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts.map +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js.map +1 -1
  136. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/Poller.d.ts +2 -0
  137. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/Poller.d.ts.map +1 -1
  138. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/Poller.js +33 -3
  139. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/Poller.js.map +1 -1
  140. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
  141. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js +1 -2
  142. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js.map +1 -1
  143. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/NodeWebSocketTransport.d.ts +4 -0
  144. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/NodeWebSocketTransport.d.ts.map +1 -1
  145. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/NodeWebSocketTransport.js +1 -0
  146. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/NodeWebSocketTransport.js.map +1 -1
  147. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  148. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  149. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js.map +1 -1
  150. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/encoding.d.ts +2 -2
  151. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/encoding.d.ts.map +1 -1
  152. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  153. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  154. package/front_end/third_party/puppeteer/package/lib/types.d.ts +113 -3
  155. package/front_end/third_party/puppeteer/package/package.json +4 -4
  156. package/front_end/third_party/puppeteer/package/src/api/Browser.ts +42 -0
  157. package/front_end/third_party/puppeteer/package/src/api/BrowserContext.ts +25 -22
  158. package/front_end/third_party/puppeteer/package/src/api/HTTPRequest.ts +22 -2
  159. package/front_end/third_party/puppeteer/package/src/api/Page.ts +45 -2
  160. package/front_end/third_party/puppeteer/package/src/api/locators/locators.ts +79 -32
  161. package/front_end/third_party/puppeteer/package/src/bidi/HTTPRequest.ts +32 -12
  162. package/front_end/third_party/puppeteer/package/src/bidi/Input.ts +1 -1
  163. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +18 -2
  164. package/front_end/third_party/puppeteer/package/src/bidi/core/Request.ts +21 -13
  165. package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +12 -2
  166. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +37 -16
  167. package/front_end/third_party/puppeteer/package/src/cdp/EmulationManager.ts +14 -11
  168. package/front_end/third_party/puppeteer/package/src/cdp/Frame.ts +7 -1
  169. package/front_end/third_party/puppeteer/package/src/cdp/HTTPRequest.ts +101 -14
  170. package/front_end/third_party/puppeteer/package/src/cdp/NetworkEventManager.ts +26 -6
  171. package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +111 -29
  172. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +37 -1
  173. package/front_end/third_party/puppeteer/package/src/cdp/ScreenRecording.ts +5 -4
  174. package/front_end/third_party/puppeteer/package/src/cdp/Target.ts +5 -0
  175. package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +122 -7
  176. package/front_end/third_party/puppeteer/package/src/common/BrowserConnector.ts +13 -33
  177. package/front_end/third_party/puppeteer/package/src/common/BrowserWebSocketTransport.ts +10 -5
  178. package/front_end/third_party/puppeteer/package/src/common/ConnectOptions.ts +10 -0
  179. package/front_end/third_party/puppeteer/package/src/common/WaitTask.ts +12 -0
  180. package/front_end/third_party/puppeteer/package/src/common/util.ts +39 -5
  181. package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
  182. package/front_end/third_party/puppeteer/package/src/injected/Poller.ts +35 -3
  183. package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +4 -2
  184. package/front_end/third_party/puppeteer/package/src/node/NodeWebSocketTransport.ts +5 -0
  185. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  186. package/front_end/third_party/puppeteer/package/src/util/encoding.ts +2 -2
  187. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  188. package/front_end/ui/helpers/OpenInNewTab.ts +8 -0
  189. package/front_end/ui/legacy/LinkContextMenuProvider.ts +1 -1
  190. package/front_end/ui/legacy/ListWidget.ts +14 -18
  191. package/front_end/ui/legacy/TabbedPane.ts +46 -3
  192. package/front_end/ui/legacy/Treeoutline.ts +3 -1
  193. package/front_end/ui/legacy/UIUtils.ts +1 -1
  194. package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
  195. package/package.json +1 -1
@@ -4,155 +4,170 @@
4
4
  * found in the LICENSE file.
5
5
  */
6
6
 
7
- .root {
8
- color: var(--sys-color-on-surface);
9
- width: 100%;
10
- }
7
+ @scope to (devtools-widget > *) {
8
+ /* Host styles can now reach the elements of this form. For example,
9
+ * the inspector common styles set "box-sizing: border-box" on all
10
+ * elements, and ListWidget editors set margins on all inputs. Restore
11
+ * the default box sizing and input margins of the browser. */
12
+ :scope * {
13
+ box-sizing: revert;
14
+ }
11
15
 
12
- .tree-title {
13
- font-weight: 700;
14
- display: flex;
15
- align-items: center;
16
+ :scope input {
17
+ margin: revert;
18
+ }
16
19
 
17
- & > [aria-controls="form-container"] {
18
- margin-left: var(--sys-size-2);
19
- padding-right: var(--sys-size-3);
20
+ .root {
21
+ color: var(--sys-color-on-surface);
22
+ width: 100%;
23
+ }
20
24
 
21
- & > [name="triangle-right"],
22
- & > [name="triangle-down"] {
23
- vertical-align: bottom;
24
- }
25
+ .tree-title {
26
+ font-weight: 700;
27
+ display: flex;
28
+ align-items: center;
25
29
 
26
- &[aria-expanded="true"] > [name="triangle-right"] {
27
- display: none;
28
- }
30
+ & > [aria-controls="form-container"] {
31
+ margin-left: var(--sys-size-2);
32
+ padding-right: var(--sys-size-3);
33
+
34
+ & > [name="triangle-right"],
35
+ & > [name="triangle-down"] {
36
+ vertical-align: bottom;
37
+ }
29
38
 
30
- &[aria-expanded="false"] > [name="triangle-down"] {
31
- display: none;
39
+ &[aria-expanded="true"] > [name="triangle-right"] {
40
+ display: none;
41
+ }
42
+
43
+ &[aria-expanded="false"] > [name="triangle-down"] {
44
+ display: none;
45
+ }
32
46
  }
33
47
  }
34
- }
35
-
36
- .form-container {
37
- display: grid;
38
- grid-template-columns: 1fr 1fr 1fr auto;
39
- align-items: center;
40
- gap: var(--sys-size-5) 10px;
41
- padding: 0 10px;
42
- }
43
48
 
44
- .full-row {
45
- grid-column: 1 / 5;
46
- }
49
+ .form-container {
50
+ display: grid;
51
+ grid-template-columns: 1fr 1fr 1fr auto;
52
+ align-items: center;
53
+ gap: var(--sys-size-5) 10px;
54
+ padding: 0 10px;
55
+ }
47
56
 
48
- .form-factors-checkbox-group {
49
- display: grid;
50
- grid-template-columns: repeat(2, 1fr);
51
- gap: var(--sys-size-4) 10px;
52
- }
57
+ .full-row {
58
+ grid-column: 1 / 5;
59
+ }
53
60
 
54
- .form-factor-checkbox-label {
55
- display: flex;
56
- align-items: center;
57
- gap: var(--sys-size-4);
58
- white-space: nowrap;
59
- }
61
+ .form-factors-checkbox-group {
62
+ display: grid;
63
+ grid-template-columns: repeat(2, 1fr);
64
+ gap: var(--sys-size-4) 10px;
65
+ }
60
66
 
61
- hr.section-separator {
62
- grid-column: 1 / 5; /* Ensures the separator spans all columns */
63
- border: none;
64
- margin-top: var(--sys-size-1);
65
- }
67
+ .form-factor-checkbox-label {
68
+ display: flex;
69
+ align-items: center;
70
+ gap: var(--sys-size-4);
71
+ white-space: nowrap;
72
+ }
66
73
 
67
- .half-row {
68
- grid-column: span 2;
69
- }
74
+ hr.section-separator {
75
+ grid-column: 1 / 5; /* Ensures the separator spans all columns */
76
+ border: none;
77
+ margin-top: var(--sys-size-1);
78
+ }
70
79
 
71
- .mobile-checkbox-container {
72
- display: flex;
73
- }
80
+ .half-row {
81
+ grid-column: span 2;
82
+ }
74
83
 
75
- .device-model-input {
76
- grid-column: 1 / 4;
77
- }
84
+ .mobile-checkbox-container {
85
+ display: flex;
86
+ }
78
87
 
79
- .input-field {
80
- color: var(--sys-color-on-surface);
81
- padding: 3px var(--sys-size-4);
82
- border-radius: var(--sys-size-2);
83
- border: var(--sys-size-1) solid var(--sys-color-neutral-outline);
84
- background-color: var(--sys-color-cdt-base-container);
85
- font-size: inherit;
86
- height: 18px;
87
- }
88
+ .device-model-input {
89
+ grid-column: 1 / 4;
90
+ }
88
91
 
89
- .input-field::placeholder {
90
- color: var(--sys-color-on-surface-subtle);
91
- }
92
+ .input-field {
93
+ color: var(--sys-color-on-surface);
94
+ padding: 3px var(--sys-size-4);
95
+ border-radius: var(--sys-size-2);
96
+ border: var(--sys-size-1) solid var(--sys-color-neutral-outline);
97
+ background-color: var(--sys-color-cdt-base-container);
98
+ font-family: inherit;
99
+ font-size: inherit;
100
+ height: 18px;
101
+ }
92
102
 
93
- .input-field:focus {
94
- border: var(--sys-size-1) solid var(--sys-color-state-focus-ring);
95
- outline-style: none;
96
- }
103
+ .input-field::placeholder {
104
+ color: var(--sys-color-on-surface-subtle);
105
+ }
97
106
 
98
- .add-container {
99
- cursor: pointer;
100
- display: flex;
101
- align-items: center;
102
- gap: var(--sys-size-4);
103
- }
107
+ .input-field:focus {
108
+ border: var(--sys-size-1) solid var(--sys-color-state-focus-ring);
109
+ outline-style: none;
110
+ }
104
111
 
105
- .add-icon {
106
- margin-right: 5px;
107
- }
112
+ .add-container {
113
+ cursor: pointer;
114
+ display: flex;
115
+ align-items: center;
116
+ gap: var(--sys-size-4);
117
+ }
108
118
 
109
- .brand-row {
110
- display: flex;
111
- align-items: center;
112
- gap: 10px;
113
- justify-content: space-between;
114
- }
119
+ .add-icon {
120
+ margin-right: 5px;
121
+ }
115
122
 
116
- .brand-row > input {
117
- width: 100%;
118
- }
123
+ .brand-row {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 10px;
127
+ justify-content: space-between;
128
+ }
119
129
 
120
- .info-icon {
121
- margin-left: 5px;
122
- margin-right: var(--sys-size-1);
123
- height: var(--sys-size-8);
124
- width: var(--sys-size-8);
125
- }
130
+ .brand-row > input {
131
+ width: 100%;
132
+ }
126
133
 
127
- .link,
128
- .devtools-link {
129
- color: var(--sys-color-primary);
130
- text-decoration: underline;
131
- cursor: pointer;
132
- outline-offset: var(--sys-size-2);
133
- font-weight: 400;
134
- }
134
+ .info-icon {
135
+ margin-left: 5px;
136
+ margin-right: var(--sys-size-1);
137
+ height: var(--sys-size-8);
138
+ width: var(--sys-size-8);
139
+ }
135
140
 
136
- devtools-icon + .link {
137
- margin-inline-start: var(--sys-size-2);
138
- }
141
+ .link,
142
+ .devtools-link {
143
+ color: var(--sys-color-primary);
144
+ text-decoration: underline;
145
+ cursor: pointer;
146
+ outline-offset: var(--sys-size-2);
147
+ font-weight: 400;
148
+ }
139
149
 
140
- .hide-container {
141
- display: none;
142
- }
150
+ devtools-icon + .link {
151
+ margin-inline-start: var(--sys-size-2);
152
+ }
143
153
 
144
- .input-field-label-container {
145
- display: flex;
146
- flex-direction: column;
147
- gap: 10px;
148
- }
154
+ .hide-container {
155
+ display: none;
156
+ }
149
157
 
150
- @media (forced-colors: active) {
151
- .input-field {
152
- border: var(--sys-size-1) solid;
158
+ .input-field-label-container {
159
+ display: flex;
160
+ flex-direction: column;
161
+ gap: 10px;
153
162
  }
154
163
 
155
- .tree-title[aria-disabled="true"] {
156
- color: GrayText;
164
+ @media (forced-colors: active) {
165
+ .input-field {
166
+ border: var(--sys-size-1) solid;
167
+ }
168
+
169
+ .tree-title[aria-disabled="true"] {
170
+ color: GrayText;
171
+ }
157
172
  }
158
173
  }
@@ -916,7 +916,9 @@ export class SourcesPanel extends UI.Panel.Panel implements
916
916
 
917
917
  #editorClosed({data: {uiSourceCode}}: Common.EventTarget.EventTargetEvent<EditorClosedEvent>): void {
918
918
  const context = UI.Context.Context.instance();
919
- if (context.flavor(Workspace.UISourceCode.UISourceCode) === uiSourceCode) {
919
+ const currentFlavor = context.flavor(Workspace.UISourceCode.UISourceCode);
920
+ const flavorScriptId = currentFlavor?.canonicalScriptId();
921
+ if (currentFlavor === uiSourceCode || (flavorScriptId && flavorScriptId === uiSourceCode.canonicalScriptId())) {
920
922
  context.setFlavor(Workspace.UISourceCode.UISourceCode, null);
921
923
  }
922
924
  }
@@ -346,6 +346,7 @@ export class TabbedEditorContainer extends TabbedEditorContainerBase {
346
346
  const icon = !hasLoadError ?
347
347
  (PanelCommon.PersistenceUtils.PersistenceUtils.iconForUISourceCode(uiSourceCode) ?? undefined) :
348
348
  undefined;
349
+ const viewSourceCode = this.#tabViewSourceCodes.get(tabId) ?? uiSourceCode;
349
350
  return {
350
351
  tabId,
351
352
  title: titleForFile(uiSourceCode),
@@ -357,8 +358,8 @@ export class TabbedEditorContainer extends TabbedEditorContainerBase {
357
358
  disconnectedAutomaticFileSystemRoot,
358
359
  icon,
359
360
  widget: (this.#currentFile?.canonicalScriptId() === uiSourceCode.canonicalScriptId()) ?
360
- this.#getOrCreateSourceView(this.#currentFile) :
361
- this.getCreatedSourceView(uiSourceCode),
361
+ this.#getOrCreateSourceView(viewSourceCode) :
362
+ this.getCreatedSourceView(viewSourceCode),
362
363
  };
363
364
  }),
364
365
  activeTabId: this.#currentFile ? this.#tabIdForUISourceCode(this.#currentFile) : undefined,
@@ -457,6 +458,12 @@ export class TabbedEditorContainer extends TabbedEditorContainerBase {
457
458
  readonly #tabDelegate: EditorContainerTabDelegate;
458
459
  #tabIds: Map<Workspace.UISourceCode.UISourceCode, string>;
459
460
  #files: Map<string, Workspace.UISourceCode.UISourceCode>;
461
+ /**
462
+ * Maps a tab id to the UISourceCode whose view is currently bound to that
463
+ * tab. This can differ from the canonical UISourceCode in `#files` when the
464
+ * tab's view was recycled to show a duplicate script with the same URL.
465
+ */
466
+ readonly #tabViewSourceCodes = new Map<string, Workspace.UISourceCode.UISourceCode>();
460
467
  readonly #loadErrorFiles = new Set<Workspace.UISourceCode.UISourceCode>();
461
468
  #previouslyViewedFilesSetting: Common.Settings.Setting<SerializedHistoryItem[]>;
462
469
  #history: History;
@@ -602,7 +609,9 @@ export class TabbedEditorContainer extends TabbedEditorContainerBase {
602
609
  }
603
610
 
604
611
  fileViews(): UI.Widget.Widget[] {
605
- return Array.from(this.#files.values()).map(getViewByUISourceCode).filter(Boolean) as UI.Widget.Widget[];
612
+ return Array.from(this.#files.entries())
613
+ .map(([tabId, file]) => getViewByUISourceCode(this.#tabViewSourceCodes.get(tabId) ?? file))
614
+ .filter(Boolean) as UI.Widget.Widget[];
606
615
  }
607
616
 
608
617
  showSourceLocation(uiSourceCode: Workspace.UISourceCode.UISourceCode,
@@ -785,13 +794,30 @@ export class TabbedEditorContainer extends TabbedEditorContainerBase {
785
794
  this.#removeViewListeners();
786
795
  this.#currentFile = uiSourceCode;
787
796
 
797
+ let tabId: string;
788
798
  try {
789
799
  // Selecting the tab may cause showFile to be called again, but with the canonical source code,
790
800
  // which is not what we want, so we prevent reentrant calls.
791
801
  this.#reentrantShow = true;
792
- const tabId = this.#tabIds.get(canonicalSourceCode) || this.#appendFileTab(canonicalSourceCode);
802
+ tabId = this.#tabIds.get(canonicalSourceCode) || this.#appendFileTab(canonicalSourceCode);
793
803
  this.#appendHistory(tabId);
794
804
 
805
+ const tabViewSourceCode = this.#tabViewSourceCodes.get(tabId) ?? canonicalSourceCode;
806
+ const tabView = this.#getOrCreateSourceView(tabViewSourceCode);
807
+ if (tabView instanceof UISourceCodeFrame && tabViewSourceCode !== uiSourceCode) {
808
+ // We are showing a different UISourceCode in the same tab (because it has the same URL). This
809
+ // commonly happens when switching between workers or iframes containing the same code, and while the
810
+ // contents are usually identical they may not be and it is important to show users when they aren't.
811
+ this.#recycleUISourceCodeFrame(tabView, uiSourceCode);
812
+ if (uiSourceCode.project().type() !== Workspace.Workspace.projectTypes.FileSystem) {
813
+ // Disable editing, because it may confuse users that only one of the copies of this code changes.
814
+ uiSourceCode.disableEdit();
815
+ }
816
+ } else {
817
+ this.#getOrCreateSourceView(uiSourceCode);
818
+ }
819
+ this.#tabViewSourceCodes.set(tabId, uiSourceCode);
820
+
795
821
  this.#scheduleUpdate();
796
822
  } finally {
797
823
  this.#reentrantShow = false;
@@ -802,23 +828,9 @@ export class TabbedEditorContainer extends TabbedEditorContainerBase {
802
828
  }
803
829
 
804
830
  const previousView = this.#currentView;
805
- if (uiSourceCode) {
806
- this.#getOrCreateSourceView(uiSourceCode);
807
- }
808
831
  this.#currentView = this.visibleView;
809
832
  this.#addViewListeners();
810
833
 
811
- if (this.#currentView instanceof UISourceCodeFrame && this.#currentView.uiSourceCode() !== uiSourceCode) {
812
- // We are showing a different UISourceCode in the same tab (because it has the same URL). This
813
- // commonly happens when switching between workers or iframes containing the same code, and while the
814
- // contents are usually identical they may not be and it is important to show users when they aren't.
815
- this.#recycleUISourceCodeFrame(this.#currentView, uiSourceCode);
816
- if (uiSourceCode.project().type() !== Workspace.Workspace.projectTypes.FileSystem) {
817
- // Disable editing, because it may confuse users that only one of the copies of this code changes.
818
- uiSourceCode.disableEdit();
819
- }
820
- }
821
-
822
834
  const eventData = {
823
835
  currentFile: this.#currentFile,
824
836
  currentView: this.#currentView,
@@ -954,6 +966,11 @@ export class TabbedEditorContainer extends TabbedEditorContainerBase {
954
966
  tabIds.push(tabId);
955
967
  } else {
956
968
  this.#removeSourceFrame(uiSourceCode);
969
+ for (const [k, v] of this.#tabViewSourceCodes) {
970
+ if (v === uiSourceCode) {
971
+ this.#tabViewSourceCodes.delete(k);
972
+ }
973
+ }
957
974
  }
958
975
  for (const [k, v] of this.#uriToUISourceCode) {
959
976
  if (v === uiSourceCode) {
@@ -999,6 +1016,7 @@ export class TabbedEditorContainer extends TabbedEditorContainerBase {
999
1016
  #appendFileTab(uiSourceCode: Workspace.UISourceCode.UISourceCode, index?: number, ignoreHistory?: boolean): string {
1000
1017
  const tabId = this.#generateTabId();
1001
1018
  this.#tabIds.set(uiSourceCode, tabId);
1019
+ this.#tabViewSourceCodes.set(tabId, uiSourceCode);
1002
1020
 
1003
1021
  if (index !== undefined) {
1004
1022
  const entries = Array.from(this.#files.entries());
@@ -1065,6 +1083,11 @@ export class TabbedEditorContainer extends TabbedEditorContainerBase {
1065
1083
  this.#currentView = null;
1066
1084
  this.#currentFile = null;
1067
1085
  }
1086
+ const viewSourceCode = this.#tabViewSourceCodes.get(tabId);
1087
+ if (viewSourceCode) {
1088
+ this.#removeSourceFrame(viewSourceCode);
1089
+ this.#tabViewSourceCodes.delete(tabId);
1090
+ }
1068
1091
  if (uiSourceCode) {
1069
1092
  this.#tabIds.delete(uiSourceCode);
1070
1093
  this.#loadErrorFiles.delete(uiSourceCode);
@@ -337,7 +337,7 @@ export class UISourceCodeFrame extends UISourceCodeFrameBase {
337
337
  private reloadPlugins(): void {
338
338
  this.disposePlugins();
339
339
  this.loadPlugins();
340
- if (!this.loaded) {
340
+ if (!pluginCompartment.get(this.textEditor.state)) {
341
341
  // Until the content is loaded the editor still holds the placeholder
342
342
  // state, which doesn't contain `pluginCompartment` at all. Reconfiguring
343
343
  // a compartment that isn't part of the state is a no-op, so the plugins
@@ -0,0 +1,171 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as Platform from '../../core/platform/platform.js';
6
+ import * as AIAssistance from '../../models/ai_assistance/ai_assistance.js';
7
+ import * as Trace from '../../models/trace/trace.js';
8
+ import * as SourceMapsResolver from '../../models/trace_source_maps_resolver/trace_source_maps_resolver.js';
9
+
10
+ /**
11
+ * A long call path keeps this many outermost entries, which usually say why
12
+ * the code ran, such as `Task > Event: click > Function call`.
13
+ */
14
+ const CALL_PATH_OUTER_ENTRIES = 3;
15
+ /**
16
+ * A long call path keeps this many innermost entries, ending with the
17
+ * commented entry itself.
18
+ */
19
+ const CALL_PATH_INNER_ENTRIES = 15;
20
+
21
+ /**
22
+ * Returns the English label of a trace warning. These lines are read by the
23
+ * AI agent, not shown in the UI, so they are not localized.
24
+ */
25
+ function labelForWarning(warning: Trace.Handlers.ModelHandlers.Warnings.Warning): string {
26
+ switch (warning) {
27
+ case 'LONG_TASK':
28
+ return 'Long task';
29
+ case 'IDLE_CALLBACK_OVER_TIME':
30
+ return 'Idle callback over time';
31
+ case 'FORCED_REFLOW':
32
+ return 'Forced reflow';
33
+ case 'LONG_INTERACTION':
34
+ return 'Long interaction';
35
+ default:
36
+ Platform.assertNever(warning, `Unknown warning: ${warning}`);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Returns the location of the entry's code as `url:line:column`, with
42
+ * 1-based line and column numbers as editors show them, or null if the entry
43
+ * has no code location. The location is in the authored source if a source
44
+ * map resolved it.
45
+ *
46
+ * This follows SourceMapsResolver.codeLocationForEntry() but skips its
47
+ * Workspace lookup, which only maps a bare URL to a workspace URL, so that
48
+ * the controller does not need a Workspace.
49
+ *
50
+ * Network requests are skipped: their URL is the request, not code, and a
51
+ * cross-origin request's final URL must be redacted.
52
+ */
53
+ function sourceLocationForEntry(event: Trace.Types.Events.Event, parsedTrace: Trace.TraceModel.ParsedTrace): string|
54
+ null {
55
+ if (Trace.Types.Events.isSyntheticNetworkRequest(event)) {
56
+ return null;
57
+ }
58
+ let url: string|null = null;
59
+ let line: number|undefined;
60
+ let column: number|undefined;
61
+ const uiLocation = SourceMapsResolver.SourceMapsResolver.resolvedCodeLocationForEntry(event)?.devtoolsLocation;
62
+ const rawCallFrame = uiLocation ? null : Trace.Helpers.Trace.rawCallFrameForEntry(event);
63
+ if (uiLocation) {
64
+ url = uiLocation.uiSourceCode.url();
65
+ line = uiLocation.lineNumber;
66
+ column = uiLocation.columnNumber;
67
+ } else if (rawCallFrame) {
68
+ url = rawCallFrame.url;
69
+ line = rawCallFrame.lineNumber >= 0 ? rawCallFrame.lineNumber : undefined;
70
+ column = rawCallFrame.columnNumber >= 0 ? rawCallFrame.columnNumber : undefined;
71
+ } else {
72
+ url = Trace.Handlers.Helpers.getNonResolvedURL(event, parsedTrace.data);
73
+ }
74
+ if (!url) {
75
+ return null;
76
+ }
77
+ if (line === undefined) {
78
+ return url;
79
+ }
80
+ return column === undefined ? `${url}:${line + 1}` : `${url}:${line + 1}:${column + 1}`;
81
+ }
82
+
83
+ /**
84
+ * Returns the names of the entry's ancestors and the entry itself, outermost
85
+ * first, for example `Task > Timer fired > Function call > handleClick`, or
86
+ * null if the entry has no ancestors.
87
+ *
88
+ * JS call stacks can be hundreds of entries deep, so a long call path keeps
89
+ * only its outermost and innermost entries and says how many it skipped, for
90
+ * example `Task > Event: click > Function call > … (240 more) > render > …`.
91
+ */
92
+ function callPathForEntry(event: Trace.Types.Events.Event, parsedTrace: Trace.TraceModel.ParsedTrace): string|null {
93
+ const node = parsedTrace.data.Renderer.entryToNode.get(event) ?? parsedTrace.data.Samples.entryToNode.get(event);
94
+ if (!node?.parent) {
95
+ return null;
96
+ }
97
+ const names: string[] = [];
98
+ for (let current: Trace.Helpers.TreeHelpers.TraceEntryNode|null = node; current; current = current.parent) {
99
+ names.push(Trace.Name.forEntry(current.entry, parsedTrace));
100
+ }
101
+ // The walk goes from the entry up to the root, so reverse it to put the
102
+ // outermost entry first.
103
+ names.reverse();
104
+ const skippedCount = names.length - CALL_PATH_OUTER_ENTRIES - CALL_PATH_INNER_ENTRIES;
105
+ // Replacing a single entry with a placeholder would not shorten the path.
106
+ if (skippedCount > 1) {
107
+ names.splice(CALL_PATH_OUTER_ENTRIES, skippedCount, `… (${skippedCount} more)`);
108
+ }
109
+ return names.join(' > ');
110
+ }
111
+
112
+ /**
113
+ * Describes a flame chart entry for the AI agent that receives comments on
114
+ * it. The entry title is already sent as the anchor's text signature, so the
115
+ * lines add what identifies the entry in the trace and where its code is: the
116
+ * trace event name, the entry's timing, its track, its source location, its
117
+ * call path, its warnings and the page that was traced.
118
+ *
119
+ * Times are relative to the start of the trace, which is where the
120
+ * Performance panel's time ruler starts.
121
+ *
122
+ * Lines without a value are omitted.
123
+ */
124
+ export function agentContextForEntry(
125
+ event: Trace.Types.Events.Event,
126
+ trackName: string|null,
127
+ parsedTrace: Trace.TraceModel.ParsedTrace,
128
+ ): string[] {
129
+ const {micros} = AIAssistance.UnitFormatters;
130
+ const lines: string[] = [];
131
+
132
+ lines.push(`Trace event: ${event.name}`);
133
+
134
+ const timing = [`starts at ${micros(event.ts - parsedTrace.data.Meta.traceBounds.min)}`];
135
+ if (event.dur) {
136
+ timing.push(`duration ${micros(event.dur)}`);
137
+ }
138
+ const selfTime = parsedTrace.data.Renderer.entryToNode.get(event)?.selfTime;
139
+ if (selfTime !== undefined) {
140
+ timing.push(`self time ${micros(selfTime)}`);
141
+ }
142
+ lines.push(`Timing: ${timing.join(', ')}`);
143
+
144
+ if (trackName) {
145
+ lines.push(`Track: ${trackName}`);
146
+ }
147
+
148
+ const sourceLocation = sourceLocationForEntry(event, parsedTrace);
149
+ if (sourceLocation) {
150
+ lines.push(`Source: ${sourceLocation}`);
151
+ }
152
+
153
+ const callPath = callPathForEntry(event, parsedTrace);
154
+ if (callPath) {
155
+ lines.push(`Call path: ${callPath}`);
156
+ }
157
+
158
+ const warnings = parsedTrace.data.Warnings.perEvent.get(event);
159
+ if (warnings?.length) {
160
+ lines.push(`Warnings: ${warnings.map(labelForWarning).join(', ')}`);
161
+ }
162
+
163
+ // The main frame URL is same-origin with the trace by definition, so it
164
+ // does not need redaction.
165
+ const mainFrameURL = parsedTrace.data.Meta.mainFrameURL;
166
+ if (mainFrameURL) {
167
+ lines.push(`Traced page: ${mainFrameURL}`);
168
+ }
169
+
170
+ return lines;
171
+ }
@@ -9,6 +9,7 @@ import type * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
9
9
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
10
10
 
11
11
  import * as Overlays from './overlays/overlays.js';
12
+ import {agentContextForEntry} from './TimelineCommentContext.js';
12
13
  import type {TimelineFlameChartDataProvider} from './TimelineFlameChartDataProvider.js';
13
14
  import type {TimelineFlameChartNetworkDataProvider} from './TimelineFlameChartNetworkDataProvider.js';
14
15
 
@@ -338,9 +339,44 @@ export class TimelineCommentController {
338
339
  durationMicro,
339
340
  chartLocation,
340
341
  },
342
+ agentContext: this.#agentContextFor(entry),
341
343
  },
342
344
  anchorElement: canvas,
343
345
  highlightRect,
344
346
  };
345
347
  }
348
+
349
+ /**
350
+ * Returns the lines that describe the entry to the AI agent, or undefined
351
+ * if no trace is active.
352
+ */
353
+ #agentContextFor(entry: ResolvedEntry): string[]|undefined {
354
+ if (!this.#parsedTrace) {
355
+ return undefined;
356
+ }
357
+ return agentContextForEntry(entry.event, this.#trackNameFor(entry), this.#parsedTrace);
358
+ }
359
+
360
+ /**
361
+ * Returns the name of the track that contains the entry. Groups are stored
362
+ * in level order and nested groups follow their parent, so the entry's
363
+ * track is the last group that starts at or above the entry's level. The
364
+ * data provider's groupForEvent() is not used because it only knows tracks
365
+ * built by track appenders, and not, for example, the Frames track.
366
+ */
367
+ #trackNameFor(entry: ResolvedEntry): string|null {
368
+ const timelineData = entry.flameChart.timelineData();
369
+ if (!timelineData) {
370
+ return null;
371
+ }
372
+ const level = timelineData.entryLevels[entry.entryIndex];
373
+ let trackName: string|null = null;
374
+ for (const group of timelineData.groups) {
375
+ if (group.startLevel > level) {
376
+ break;
377
+ }
378
+ trackName = group.name;
379
+ }
380
+ return trackName;
381
+ }
346
382
  }
@@ -23,6 +23,7 @@ import * as StatusDialog from './StatusDialog.js';
23
23
  import * as TargetForEvent from './TargetForEvent.js';
24
24
  import * as ThirdPartyTreeView from './ThirdPartyTreeView.js';
25
25
  import * as ThreadAppender from './ThreadAppender.js';
26
+ import * as TimelineCommentContext from './TimelineCommentContext.js';
26
27
  import * as TimelineCommentController from './TimelineCommentController.js';
27
28
  import * as TimelineController from './TimelineController.js';
28
29
  import * as TimelineDetailsView from './TimelineDetailsView.js';
@@ -69,6 +70,7 @@ export {
69
70
  TargetForEvent,
70
71
  ThirdPartyTreeView,
71
72
  ThreadAppender,
73
+ TimelineCommentContext,
72
74
  TimelineCommentController,
73
75
  TimelineController,
74
76
  TimelineDetailsView,