chrome-devtools-frontend 1.0.1566234 → 1.0.1567721

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 (188) hide show
  1. package/docs/contributing/performance.md +24 -0
  2. package/front_end/core/common/Base64.ts +21 -2
  3. package/front_end/core/common/ResourceType.ts +7 -0
  4. package/front_end/core/host/InspectorFrontendHostStub.ts +3 -0
  5. package/front_end/core/host/UserMetrics.ts +20 -0
  6. package/front_end/core/sdk/NetworkManager.ts +3 -3
  7. package/front_end/entrypoints/main/MainImpl.ts +1 -7
  8. package/front_end/generated/Deprecation.ts +0 -8
  9. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  10. package/front_end/generated/SupportedCSSProperties.js +39 -49
  11. package/front_end/generated/protocol.ts +4 -0
  12. package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
  13. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +98 -105
  14. package/front_end/models/emulation/DeviceModeModel.ts +1 -1
  15. package/front_end/models/formatter/FormatterWorkerPool.ts +8 -6
  16. package/front_end/models/javascript_metadata/NativeFunctions.js +4 -9
  17. package/front_end/models/persistence/PersistenceImpl.ts +8 -0
  18. package/front_end/models/text_utils/TextUtils.snapshot.txt +83 -0
  19. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +0 -1
  20. package/front_end/panels/ai_assistance/components/ArtifactsViewer.ts +28 -4
  21. package/front_end/panels/ai_assistance/components/ChatView.ts +52 -169
  22. package/front_end/panels/ai_assistance/components/CollapsibleAssistanceContentWidget.ts +27 -8
  23. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +19 -4
  24. package/front_end/panels/application/ApplicationPanelSidebar.ts +1 -0
  25. package/front_end/panels/application/DeviceBoundSessionsModel.ts +42 -0
  26. package/front_end/panels/application/DeviceBoundSessionsTreeElement.ts +60 -11
  27. package/front_end/panels/application/DeviceBoundSessionsView.ts +947 -103
  28. package/front_end/panels/application/ResourcesPanel.ts +7 -0
  29. package/front_end/panels/application/deviceBoundSessionsView.css +10 -1
  30. package/front_end/panels/common/AiCodeGenerationUpgradeDialog.ts +115 -0
  31. package/front_end/panels/common/aiCodeGenerationUpgradeDialog.css +79 -0
  32. package/front_end/panels/common/common.ts +1 -0
  33. package/front_end/panels/console/ConsoleInsightTeaser.ts +17 -3
  34. package/front_end/panels/issues/AffectedSourcesView.ts +0 -1
  35. package/front_end/panels/issues/IssuesPane.ts +0 -4
  36. package/front_end/panels/network/RequestTimingView.ts +5 -20
  37. package/front_end/panels/network/networkTimingTable.css +5 -5
  38. package/front_end/panels/recorder/components/StepEditor.ts +15 -8
  39. package/front_end/panels/settings/AISettingsTab.ts +31 -2
  40. package/front_end/panels/sources/InplaceFormatterEditorAction.ts +8 -6
  41. package/front_end/panels/sources/UISourceCodeFrame.ts +9 -3
  42. package/front_end/panels/timeline/TimelinePanel.ts +12 -4
  43. package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +1 -1
  44. package/front_end/third_party/chromium/README.chromium +1 -1
  45. package/front_end/third_party/puppeteer/README.chromium +2 -2
  46. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts +9 -2
  47. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts.map +1 -1
  48. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.js.map +1 -1
  49. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +8 -0
  50. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  51. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js +8 -0
  52. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  53. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.d.ts +2 -1
  54. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.d.ts.map +1 -1
  55. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.js +2 -2
  56. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.js.map +1 -1
  57. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.d.ts.map +1 -1
  58. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.js +3 -1
  59. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.js.map +1 -1
  60. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Frame.d.ts.map +1 -1
  61. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Frame.js +1 -1
  62. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Frame.js.map +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  64. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js +3 -3
  65. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  66. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/UserContext.d.ts +1 -0
  67. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/UserContext.d.ts.map +1 -1
  68. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/UserContext.js +1 -0
  69. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/UserContext.js.map +1 -1
  70. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
  71. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +1 -0
  72. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
  73. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +33 -31
  75. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  76. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/WebWorker.d.ts +2 -2
  77. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/WebWorker.d.ts.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/WebWorker.js +1 -4
  79. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/WebWorker.js.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConsoleMessage.d.ts +7 -1
  81. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConsoleMessage.d.ts.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConsoleMessage.js +11 -1
  83. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConsoleMessage.js.map +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Cookie.d.ts +2 -2
  85. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  86. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +2 -2
  87. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +2 -2
  88. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  89. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  90. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +13 -4
  92. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +62 -42
  93. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts +9 -2
  94. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts.map +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.js.map +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +8 -0
  97. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js +8 -0
  99. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  100. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.d.ts +2 -1
  101. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.d.ts.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.js +2 -2
  103. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.js.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.d.ts.map +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.js +3 -1
  106. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.js.map +1 -1
  107. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Frame.d.ts.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Frame.js +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Frame.js.map +1 -1
  110. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js +3 -3
  112. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/UserContext.d.ts +1 -0
  114. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/UserContext.d.ts.map +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/UserContext.js +1 -0
  116. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/UserContext.js.map +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
  118. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +1 -0
  119. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
  120. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +33 -31
  122. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/WebWorker.d.ts +2 -2
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/WebWorker.d.ts.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/WebWorker.js +1 -4
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/WebWorker.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConsoleMessage.d.ts +7 -1
  128. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConsoleMessage.d.ts.map +1 -1
  129. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConsoleMessage.js +11 -1
  130. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConsoleMessage.js.map +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Cookie.d.ts +2 -2
  132. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +2 -2
  133. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +2 -2
  134. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  136. package/front_end/third_party/puppeteer/package/lib/types.d.ts +13 -4
  137. package/front_end/third_party/puppeteer/package/package.json +3 -3
  138. package/front_end/third_party/puppeteer/package/src/api/Browser.ts +11 -3
  139. package/front_end/third_party/puppeteer/package/src/api/Page.ts +9 -0
  140. package/front_end/third_party/puppeteer/package/src/bidi/Browser.ts +3 -3
  141. package/front_end/third_party/puppeteer/package/src/bidi/BrowserContext.ts +3 -1
  142. package/front_end/third_party/puppeteer/package/src/bidi/Frame.ts +1 -0
  143. package/front_end/third_party/puppeteer/package/src/bidi/core/BrowsingContext.ts +3 -5
  144. package/front_end/third_party/puppeteer/package/src/bidi/core/UserContext.ts +2 -0
  145. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +1 -0
  146. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +43 -45
  147. package/front_end/third_party/puppeteer/package/src/cdp/WebWorker.ts +3 -11
  148. package/front_end/third_party/puppeteer/package/src/common/ConsoleMessage.ts +12 -0
  149. package/front_end/third_party/puppeteer/package/src/common/Cookie.ts +2 -2
  150. package/front_end/third_party/puppeteer/package/src/revisions.ts +2 -2
  151. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  152. package/front_end/third_party/source-map-scopes-codec/README.chromium +2 -5
  153. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +1 -1
  154. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
  155. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +1 -1
  156. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +1 -1
  157. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +1 -1
  158. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +1 -1
  159. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +1 -1
  160. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +1 -1
  161. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +1 -1
  162. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +1 -1
  163. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +130 -0
  164. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +1 -0
  165. package/front_end/third_party/source-map-scopes-codec/package/deno.json +1 -1
  166. package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
  167. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +1 -1
  168. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +1 -1
  169. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +4 -0
  170. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +1 -1
  171. package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +4 -0
  172. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +30 -13
  173. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +1 -1
  174. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +35 -17
  175. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +1 -1
  176. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +1 -1
  177. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +1 -1
  178. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +2 -2
  179. package/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +1 -1
  180. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +7 -0
  181. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js.map +1 -0
  182. package/front_end/third_party/source-map-scopes-codec/package/src/util.ts +1 -1
  183. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +4 -0
  184. package/front_end/ui/visual_logging/KnownContextValues.ts +11 -0
  185. package/mcp/mcp.ts +1 -0
  186. package/package.json +1 -2
  187. package/front_end/third_party/source-map-scopes-codec/package/src/scopes-tsconfig.json +0 -8
  188. /package/front_end/third_party/source-map-scopes-codec/package/src/{scopes.d.ts → scopes.ts} +0 -0
@@ -218,6 +218,13 @@ export class ResourcesPanel extends UI.Panel.PanelWithSidebar {
218
218
  this.deviceBoundSessionsView.showSession(model, site, sessionId);
219
219
  this.showView(this.deviceBoundSessionsView);
220
220
  }
221
+ showDeviceBoundSessionDefault(model: DeviceBoundSessionsModel, title: string, description: string): void {
222
+ if (!this.deviceBoundSessionsView) {
223
+ this.deviceBoundSessionsView = new DeviceBoundSessionsView();
224
+ }
225
+ this.deviceBoundSessionsView.showDefault(model, title, description);
226
+ this.showView(this.deviceBoundSessionsView);
227
+ }
221
228
  }
222
229
 
223
230
  export class ResourceRevealer implements Common.Revealer.Revealer<SDK.Resource.Resource> {
@@ -11,8 +11,17 @@
11
11
  display: block;
12
12
  }
13
13
 
14
- .device-bound-session-view-wrapper {
14
+ .device-bound-session-view-wrapper, .device-bound-session-sidebar {
15
15
  overflow-y: auto;
16
16
  scroll-behavior: smooth;
17
17
  padding-bottom: 20px;
18
18
  }
19
+
20
+ .device-bound-session-no-events-wrapper, .device-bound-session-no-event-details {
21
+ padding: 0 20px;
22
+ }
23
+
24
+ .device-bound-sessions-toolbar {
25
+ background-color: var(--sys-color-cdt-base-container);
26
+ border-bottom: var(--sys-size-1) solid var(--sys-color-divider);
27
+ }
@@ -0,0 +1,115 @@
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
+ /* eslint-disable @devtools/no-lit-render-outside-of-view */
5
+
6
+ import * as Host from '../../core/host/host.js';
7
+ import * as i18n from '../../core/i18n/i18n.js';
8
+ import * as Buttons from '../../ui/components/buttons/buttons.js';
9
+ import * as UI from '../../ui/legacy/legacy.js';
10
+ import * as Lit from '../../ui/lit/lit.js';
11
+
12
+ import styles from './aiCodeGenerationUpgradeDialog.css.js';
13
+
14
+ const {html} = Lit;
15
+
16
+ const UIStringsNotTranslate = {
17
+ /**
18
+ * @description Header text for the upgrade notice dialog.
19
+ */
20
+ codeCompletionJustGotBetter: 'Code completion just got better',
21
+ /**
22
+ * @description First item in the description
23
+ */
24
+ asYouType: 'As you type, DevTools generates code suggestions to help you code faster.',
25
+ /**
26
+ * @description Second item in the description
27
+ */
28
+ describeCodeInComment:
29
+ 'In Console and Sources, you can now describe the code you need in a comment, then press Ctrl+I to generate it.',
30
+ /**
31
+ * @description Second item in the description
32
+ */
33
+ describeCodeInCommentForMacOs:
34
+ 'In Console and Sources, you can now describe the code you need in a comment, then press Cmd+I to generate it.',
35
+ /**
36
+ * @description Text for the manage in settings button in the upgrade notice dialog.
37
+ */
38
+ manageInSettings: 'Manage in settings',
39
+ /**
40
+ * @description Text for the got it button in the upgrade notice dialog.
41
+ */
42
+ gotIt: 'Got it',
43
+ } as const;
44
+
45
+ const lockedString = i18n.i18n.lockedString;
46
+
47
+ export class AiCodeGenerationUpgradeDialog {
48
+ static show(): void {
49
+ const dialog = new UI.Dialog.Dialog();
50
+ dialog.setAriaLabel(lockedString(UIStringsNotTranslate.codeCompletionJustGotBetter));
51
+ // clang-format off
52
+ Lit.render(html`
53
+ <div class="ai-code-generation-upgrade-dialog">
54
+ <style>
55
+ ${styles}
56
+ </style>
57
+ <header>
58
+ <div class="header-icon-container">
59
+ <devtools-icon name="pen-spark"></devtools-icon>
60
+ </div>
61
+ <h2 tabindex="-1">
62
+ ${lockedString(UIStringsNotTranslate.codeCompletionJustGotBetter)}
63
+ </h2>
64
+ </header>
65
+ <main class="reminder-container">
66
+ <div class="reminder-item">
67
+ <devtools-icon class="reminder-icon" name="code"></devtools-icon>
68
+ <span>${lockedString(UIStringsNotTranslate.asYouType)}</span>
69
+ </div>
70
+ <div class="reminder-item">
71
+ <devtools-icon class="reminder-icon" name="text-analysis"></devtools-icon>
72
+ <span>
73
+ ${Host.Platform.isMac() ?
74
+ lockedString(UIStringsNotTranslate.describeCodeInCommentForMacOs) :
75
+ lockedString(UIStringsNotTranslate.describeCodeInComment)}
76
+ </span>
77
+ </div>
78
+ </main>
79
+ <footer>
80
+ <div class="right-buttons">
81
+ <devtools-button
82
+ @click=${() => {
83
+ void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
84
+ }}
85
+ .jslogContext=${'ai-code-generation-upgrade-dialog.manage-in-settings'}
86
+ .variant=${Buttons.Button.Variant.OUTLINED}
87
+ aria-label=${lockedString(UIStringsNotTranslate.manageInSettings)}>
88
+ ${lockedString(UIStringsNotTranslate.manageInSettings)}
89
+ </devtools-button>
90
+ <devtools-button
91
+ @click=${() => {
92
+ dialog.hide();
93
+ }}
94
+ .jslogContext=${'ai-code-generation-upgrade-dialog.continue'}
95
+ .variant=${Buttons.Button.Variant.PRIMARY}>
96
+ ${lockedString(UIStringsNotTranslate.gotIt)}
97
+ </devtools-button>
98
+ </div>
99
+ </footer>
100
+ </div>`, dialog.contentElement);
101
+ // clang-format on
102
+
103
+ dialog.setOutsideClickCallback(ev => {
104
+ ev.consume(true); // true = preventDefault()
105
+ dialog.hide();
106
+ });
107
+
108
+ dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.MEASURE_CONTENT);
109
+ dialog.setDimmed(true);
110
+ dialog.show();
111
+ }
112
+
113
+ private constructor() {
114
+ }
115
+ }
@@ -0,0 +1,79 @@
1
+ /*
2
+ * Copyright 2026 The Chromium Authors
3
+ * Use of this source code is governed by a BSD-style license that can be
4
+ * found in the LICENSE file.
5
+ */
6
+
7
+
8
+ .ai-code-generation-upgrade-dialog {
9
+ width: var(--sys-size-33);
10
+ padding: var(--sys-size-9);
11
+
12
+ header {
13
+ display: flex;
14
+ gap: var(--sys-size-8);
15
+ margin-bottom: var(--sys-size-6);
16
+ align-items: center;
17
+
18
+ h2 {
19
+ margin: 0;
20
+ color: var(--sys-color-on-surface);
21
+ font: var(--sys-typescale-headline5);
22
+ }
23
+
24
+ .header-icon-container {
25
+ background: linear-gradient(
26
+ 135deg,
27
+ var(--sys-color-gradient-primary),
28
+ var(--sys-color-gradient-tertiary)
29
+ );
30
+ border-radius: var(--sys-size-4);
31
+ min-height: var(--sys-size-14);
32
+ min-width: var(--sys-size-14);
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+
37
+ devtools-icon {
38
+ width: var(--sys-size-9);
39
+ height: var(--sys-size-9);
40
+ }
41
+ }
42
+ }
43
+
44
+ .reminder-container {
45
+ border-radius: var(--sys-size-6);
46
+ background-color: var(--sys-color-surface4);
47
+ padding: var(--sys-size-9);
48
+ gap: var(--sys-size-6);
49
+ display: flex;
50
+ flex-direction: column;
51
+
52
+ .reminder-item {
53
+ display: flex;
54
+ flex-direction: row;
55
+ align-items: center;
56
+ gap: var(--sys-size-5);
57
+ font: var(--sys-typescale-body4-regular);
58
+
59
+ devtools-icon.reminder-icon {
60
+ width: var(--sys-size-8);
61
+ height: var(--sys-size-8);
62
+ }
63
+ }
64
+ }
65
+
66
+ footer {
67
+ display: flex;
68
+ flex-direction: row;
69
+ align-items: flex-start;
70
+ justify-content: flex-end;
71
+ margin-top: var(--sys-size-8);
72
+ min-width: var(--sys-size-28);
73
+
74
+ .right-buttons {
75
+ display: flex;
76
+ gap: var(--sys-size-5);
77
+ }
78
+ }
79
+ }
@@ -96,6 +96,7 @@ export class TypeToAllowDialog {
96
96
 
97
97
  export {AiCodeCompletionTeaser} from './AiCodeCompletionTeaser.js';
98
98
  export * as AiCodeGenerationTeaser from './AiCodeGenerationTeaser.js';
99
+ export {AiCodeGenerationUpgradeDialog} from './AiCodeGenerationUpgradeDialog.js';
99
100
  export {AnnotationManager} from './AnnotationManager.js';
100
101
  export {FreDialog} from './FreDialog.js';
101
102
  export {GdpSignUpDialog} from './GdpSignUpDialog.js';
@@ -416,6 +416,7 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
416
416
  #eventListeners: Common.EventTarget.EventDescriptor[] = [];
417
417
  #isForWarning: boolean;
418
418
  #callShowTooltip = false;
419
+ #startTime = 0;
419
420
 
420
421
  constructor(uuid: string, consoleViewMessage: ConsoleViewMessage, element?: HTMLElement, view?: View) {
421
422
  super(element);
@@ -586,6 +587,13 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
586
587
  this.#abortController.abort();
587
588
  }
588
589
  if (this.#state === State.GENERATING || this.#state === State.PARTIAL_TEASER) {
590
+ if (this.#startTime) {
591
+ if (this.#mainText) {
592
+ Host.userMetrics.consoleInsightTeaserAbortedAfterFirstCharacter(performance.now() - this.#startTime);
593
+ } else {
594
+ Host.userMetrics.consoleInsightTeaserAbortedBeforeFirstCharacter(performance.now() - this.#startTime);
595
+ }
596
+ }
589
597
  this.#mainText = '';
590
598
  this.#state = State.READY;
591
599
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightTeaserGenerationAborted);
@@ -615,7 +623,7 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
615
623
  this.#state = State.GENERATING;
616
624
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightTeaserGenerationStarted);
617
625
  this.#timeoutId = setTimeout(this.#setSlow.bind(this), SLOW_GENERATION_CUTOFF_MILLISECONDS);
618
- const startTime = performance.now();
626
+ this.#startTime = performance.now();
619
627
  let teaserText = '';
620
628
  let firstChunkReceived = false;
621
629
  try {
@@ -626,7 +634,7 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
626
634
  this.requestUpdate();
627
635
  if (!firstChunkReceived) {
628
636
  firstChunkReceived = true;
629
- Host.userMetrics.consoleInsightTeaserFirstChunkGenerated(performance.now() - startTime);
637
+ Host.userMetrics.consoleInsightTeaserFirstChunkGenerated(performance.now() - this.#startTime);
630
638
  }
631
639
  }
632
640
  } catch (err) {
@@ -644,7 +652,13 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
644
652
  }
645
653
 
646
654
  clearTimeout(this.#timeoutId);
647
- Host.userMetrics.consoleInsightTeaserGenerated(performance.now() - startTime);
655
+ const duration = performance.now() - this.#startTime;
656
+ Host.userMetrics.consoleInsightTeaserGenerated(duration);
657
+ if (teaserText.length > 300) {
658
+ Host.userMetrics.consoleInsightLongTeaserGenerated(duration);
659
+ } else {
660
+ Host.userMetrics.consoleInsightShortTeaserGenerated(duration);
661
+ }
648
662
  this.#state = State.TEASER;
649
663
  this.#mainText = teaserText;
650
664
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightTeaserGenerationCompleted);
@@ -44,7 +44,6 @@ export class AffectedSourcesView extends AffectedResourcesView {
44
44
  // 'click' neither 'keydown' if that key is the 'Enter' key.
45
45
  // Also, this element has a context menu, so we should be able to
46
46
  // track when the user use the context menu too.
47
- // TODO(crbug.com/1108503): Add some mechanism to be able to add telemetry to this element.
48
47
  const anchorElement =
49
48
  Components.Linkifier.Linkifier.linkifyURL(url as Platform.DevToolsPath.UrlString, linkifierURLOptions);
50
49
  anchorElement.setAttribute('jslog', `${VisualLogging.link('source-location').track({click: true})}`);
@@ -270,7 +270,6 @@ export class IssuesPane extends UI.Widget.VBox {
270
270
  thirdPartySetting, i18nString(UIStrings.includeCookieIssuesCausedBy),
271
271
  i18nString(UIStrings.includeThirdpartyCookieIssues));
272
272
  rightToolbar.appendToolbarItem(this.#showThirdPartyCheckbox);
273
- this.setDefaultFocusedElement(this.#showThirdPartyCheckbox.element);
274
273
 
275
274
  rightToolbar.appendSeparator();
276
275
  const issueCounter = new IssueCounter.IssueCounter.IssueCounter();
@@ -459,9 +458,6 @@ export class IssuesPane extends UI.Widget.VBox {
459
458
  }
460
459
  } else {
461
460
  this.#issuesTree.element.hidden = true;
462
- if (this.#showThirdPartyCheckbox) {
463
- this.setDefaultFocusedElement(this.#showThirdPartyCheckbox.element);
464
- }
465
461
  // We alreay know that issesCount is zero here.
466
462
  const hasOnlyThirdPartyIssues =
467
463
  this.#issuesManager.numberOfAllStoredIssues() - this.#issuesManager.numberOfThirdPartyCookiePhaseoutIssues() >
@@ -374,9 +374,9 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
374
374
  if (!target?.classList.contains('network-fetch-timing-bar-clickable')) {
375
375
  return;
376
376
  }
377
- const isChecked = target.ariaChecked === 'false';
378
- target.ariaChecked = isChecked ? 'true' : 'false';
379
- if (!isChecked) {
377
+ const isExpanded = target.ariaExpanded === 'true';
378
+ target.ariaExpanded = isExpanded ? 'false' : 'true';
379
+ if (!isExpanded) {
380
380
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.NetworkPanelServiceWorkerRespondWith);
381
381
  }
382
382
  };
@@ -454,8 +454,8 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
454
454
  <tr>
455
455
  ${isClickable(range) ? html`<td
456
456
  tabindex=0
457
- role=switch
458
- aria-checked=false
457
+ role=button
458
+ aria-expanded=false
459
459
  @click=${onActivate}
460
460
  @keydown=${onActivate}
461
461
  class=network-fetch-timing-bar-clickable>
@@ -589,21 +589,6 @@ export class RequestTimingView extends UI.Widget.VBox {
589
589
  this.#view(input, {}, this.contentElement);
590
590
  }
591
591
 
592
- private onToggleFetchDetails(fetchDetailsElement: Element, event: Event): void {
593
- if (!event.target) {
594
- return;
595
- }
596
-
597
- const target = (event.target as Element);
598
- if (target.classList.contains('network-fetch-timing-bar-clickable')) {
599
- const expanded = target.getAttribute('aria-checked') === 'true';
600
- target.setAttribute('aria-checked', String(!expanded));
601
-
602
- fetchDetailsElement.classList.toggle('network-fetch-timing-bar-details-collapsed');
603
- fetchDetailsElement.classList.toggle('network-fetch-timing-bar-details-expanded');
604
- }
605
- }
606
-
607
592
  #fetchDetailsTree(): UI.TreeOutline.TreeOutlineInShadow|undefined {
608
593
  if (!this.#request?.fetchedViaServiceWorker) {
609
594
  return undefined;
@@ -145,13 +145,13 @@ table.network-timing-table > tr:not(.network-timing-table-header, .network-timin
145
145
  left: -12px;
146
146
  }
147
147
 
148
- tr:has([aria-checked="false"].network-fetch-timing-bar-clickable) ~ .router-evaluation-timing-bar-details,
149
- tr:has([aria-checked="false"].network-fetch-timing-bar-clickable) ~ .network-fetch-timing-bar-details {
148
+ tr:has([aria-expanded="false"].network-fetch-timing-bar-clickable) ~ .router-evaluation-timing-bar-details,
149
+ tr:has([aria-expanded="false"].network-fetch-timing-bar-clickable) ~ .network-fetch-timing-bar-details {
150
150
  display: none;
151
151
  }
152
152
 
153
- tr:has([aria-checked].network-fetch-timing-bar-clickable) ~ .router-evaluation-timing-bar-details,
154
- tr:has([aria-checked].network-fetch-timing-bar-clickable) ~ .network-fetch-timing-bar-details {
153
+ tr:has([aria-expanded="true"].network-fetch-timing-bar-clickable) ~ .router-evaluation-timing-bar-details,
154
+ tr:has([aria-expanded="true"].network-fetch-timing-bar-clickable) ~ .network-fetch-timing-bar-details {
155
155
  display: block;
156
156
  }
157
157
 
@@ -159,7 +159,7 @@ tr:has([aria-checked].network-fetch-timing-bar-clickable) ~ .network-fetch-timin
159
159
  background-color: var(--sys-color-state-focus-highlight);
160
160
  }
161
161
 
162
- .network-fetch-timing-bar-clickable[aria-checked="true"]::before {
162
+ .network-fetch-timing-bar-clickable[aria-expanded="true"]::before {
163
163
  transform: rotate(90deg);
164
164
  }
165
165
 
@@ -610,6 +610,7 @@ export class StepEditor extends LitElement {
610
610
  return html`
611
611
  <devtools-button
612
612
  title=${opts.title}
613
+ .accessibleLabel=${opts.title}
613
614
  .size=${Buttons.Button.Size.SMALL}
614
615
  .iconName=${opts.iconName}
615
616
  .variant=${Buttons.Button.Variant.ICON}
@@ -658,8 +659,9 @@ export class StepEditor extends LitElement {
658
659
  this.#renderedAttributes.add('type');
659
660
  // clang-format off
660
661
  return html`<div class="row attribute" data-attribute="type" jslog=${VisualLogging.treeItem('type')}>
661
- <div>type<span class="separator">:</span></div>
662
+ <div id="type">type<span class="separator">:</span></div>
662
663
  <devtools-suggestion-input
664
+ aria-labelledby="type"
663
665
  .disabled=${!editable || this.disabled}
664
666
  .options=${Object.values(Models.Schema.StepType)}
665
667
  .placeholder=${defaultValuesByAttribute.type}
@@ -678,9 +680,10 @@ export class StepEditor extends LitElement {
678
680
  }
679
681
  // clang-format off
680
682
  return html`<div class="row attribute" data-attribute=${attribute} jslog=${VisualLogging.treeItem(Platform.StringUtilities.toKebabCase(attribute))}>
681
- <div>${attribute}<span class="separator">:</span></div>
683
+ <div id=${attribute}>${attribute}<span class="separator">:</span></div>
682
684
  <devtools-suggestion-input
683
685
  .disabled=${this.disabled}
686
+ aria-labelledby=${attribute}
684
687
  .placeholder=${defaultValuesByAttribute[attribute].toString()}
685
688
  .value=${live(attributeValue)}
686
689
  .mimeType=${(() => {
@@ -723,13 +726,14 @@ export class StepEditor extends LitElement {
723
726
  return html`
724
727
  <div class="attribute" data-attribute="frame" jslog=${VisualLogging.treeItem('frame')}>
725
728
  <div class="row">
726
- <div>frame<span class="separator">:</span></div>
729
+ <div id="frame">frame<span class="separator">:</span></div>
727
730
  ${this.#renderDeleteButton('frame')}
728
731
  </div>
729
732
  ${this.state.frame.map((frame, index, frames) => {
730
733
  return html`
731
734
  <div class="padded row">
732
735
  <devtools-suggestion-input
736
+ aria-labelledby="frame"
733
737
  .disabled=${this.disabled}
734
738
  .placeholder=${defaultValuesByAttribute.frame[0].toString()}
735
739
  .value=${live(frame.toString())}
@@ -806,7 +810,7 @@ export class StepEditor extends LitElement {
806
810
  </div>
807
811
  ${this.state.selectors.map((selector, index, selectors) => {
808
812
  return html`<div class="padded row" data-selector-path=${index}>
809
- <div>selector #${index + 1}<span class="separator">:</span></div>
813
+ <div id="selector-${index}">selector #${index + 1}<span class="separator">:</span></div>
810
814
  ${this.#renderInlineButton({
811
815
  class: 'add-selector',
812
816
  title: i18nString(UIStrings.addSelector),
@@ -843,6 +847,7 @@ export class StepEditor extends LitElement {
843
847
  data-selector-path="${index}.${partIndex}"
844
848
  >
845
849
  <devtools-suggestion-input
850
+ aria-labelledby="selector-${index}"
846
851
  .disabled=${this.disabled}
847
852
  .placeholder=${defaultValuesByAttribute.selectors[0][0]}
848
853
  .value=${live(part)}
@@ -925,12 +930,13 @@ export class StepEditor extends LitElement {
925
930
  </div>
926
931
  ${this.state.assertedEvents.map((event, index) => {
927
932
  return html` <div class="padded row" jslog=${VisualLogging.treeItem('event-type')}>
928
- <div>type<span class="separator">:</span></div>
929
- <div>${event.type}</div>
933
+ <div id="event-type">type<span class="separator">:</span></div>
934
+ <div aria-labelledby="event-type">${event.type}</div>
930
935
  </div>
931
936
  <div class="padded row" jslog=${VisualLogging.treeItem('event-title')}>
932
- <div>title<span class="separator">:</span></div>
937
+ <div id="event-title">title<span class="separator">:</span></div>
933
938
  <devtools-suggestion-input
939
+ aria-labelledby="event-title"
934
940
  .disabled=${this.disabled}
935
941
  .placeholder=${defaultValuesByAttribute.assertedEvents[0].title}
936
942
  .value=${live(event.title ?? '')}
@@ -950,9 +956,10 @@ export class StepEditor extends LitElement {
950
956
  })}
951
957
  ></devtools-suggestion-input>
952
958
  </div>
953
- <div class="padded row" jslog=${VisualLogging.treeItem('event-url')}>
959
+ <div id="event-url" class="padded row" jslog=${VisualLogging.treeItem('event-url')}>
954
960
  <div>url<span class="separator">:</span></div>
955
961
  <devtools-suggestion-input
962
+ aria-labelledby="event-url"
956
963
  .disabled=${this.disabled}
957
964
  .placeholder=${defaultValuesByAttribute.assertedEvents[0].url}
958
965
  .value=${live(event.url ?? '')}
@@ -8,6 +8,7 @@ import * as i18n from '../../core/i18n/i18n.js';
8
8
  import type * as Platform from '../../core/platform/platform.js';
9
9
  import * as Root from '../../core/root/root.js';
10
10
  import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
11
+ import * as AiCodeGeneration from '../../models/ai_code_generation/ai_code_generation.js';
11
12
  import * as Buttons from '../../ui/components/buttons/buttons.js';
12
13
  import * as Input from '../../ui/components/input/input.js';
13
14
  import * as Switch from '../../ui/components/switch/switch.js';
@@ -121,7 +122,7 @@ const UIStrings = {
121
122
  /**
122
123
  * @description Text describing the 'Code suggestions' feature
123
124
  */
124
- helpUnderstandCodeSuggestions: 'Get help completing your code',
125
+ helpUnderstandCodeSuggestions: 'Write code faster with AI-powered suggestions',
125
126
  /**
126
127
  * @description Text which is a hyperlink to more documentation
127
128
  */
@@ -172,6 +173,21 @@ const UIStrings = {
172
173
  */
173
174
  asYouTypeCodeSuggestions:
174
175
  'As you type in the Console or Sources panel, you’ll get code suggestions. Press Tab to accept one.',
176
+ /**
177
+ * @description First item in the description of the 'Code suggestions' feature [updated]
178
+ */
179
+ asYouTypeRelevantDataIsBeingSentToGoogle:
180
+ 'As you type, relevant data is being sent to Google to generate code suggestions. Press Tab to accept.',
181
+ /**
182
+ * @description Second item in the description of the 'Code suggestions' feature [new]
183
+ */
184
+ describeCodeInComment:
185
+ 'In Console or Sources, describe the code you need in a comment, then press Ctrl+I to generate it.',
186
+ /**
187
+ * @description Second item in the description of the 'Code suggestions' feature [new]
188
+ */
189
+ describeCodeInCommentForMacOs:
190
+ 'In Console or Sources, describe the code you need in a comment, then press Cmd+I to generate it.',
175
191
  /**
176
192
  * @description Explainer for which data is being sent for the 'Code suggestions' feature
177
193
  */
@@ -520,12 +536,25 @@ export class AISettingsTab extends UI.Widget.VBox {
520
536
  }
521
537
 
522
538
  if (this.#aiCodeCompletionSetting) {
539
+ const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
540
+ const isAiCodeGenerationEnabled =
541
+ AiCodeGeneration.AiCodeGeneration.AiCodeGeneration.isAiCodeGenerationEnabled(devtoolsLocale.locale);
542
+ const settingItems = isAiCodeGenerationEnabled ?
543
+ [
544
+ {iconName: 'code', text: i18nString(UIStrings.asYouTypeRelevantDataIsBeingSentToGoogle)}, {
545
+ iconName: 'text-analysis',
546
+ text: Host.Platform.isMac() ? i18nString(UIStrings.describeCodeInCommentForMacOs) :
547
+ i18nString(UIStrings.describeCodeInComment)
548
+ }
549
+ ] :
550
+ [{iconName: 'code', text: i18nString(UIStrings.asYouTypeCodeSuggestions)}];
551
+
523
552
  const aiCodeCompletionData: AiSettingParams = {
524
553
  settingName: i18n.i18n.lockedString('Code suggestions'),
525
554
  iconName: 'text-analysis',
526
555
  settingDescription: i18nString(UIStrings.helpUnderstandCodeSuggestions),
527
556
  enableSettingText: i18nString(UIStrings.enableAiCodeSuggestions),
528
- settingItems: [{iconName: 'code', text: i18nString(UIStrings.asYouTypeCodeSuggestions)}],
557
+ settingItems,
529
558
  toConsiderSettingItems: [{
530
559
  iconName: 'google',
531
560
  text: noLogging ? i18nString(UIStrings.codeSuggestionsSendDataNoLogging) :
@@ -98,13 +98,15 @@ export class InplaceFormatterEditorAction implements EditorAction {
98
98
  if (!uiSourceCode) {
99
99
  return false;
100
100
  }
101
- if (uiSourceCode.project().canSetFileContent()) {
102
- return true;
103
- }
104
- if (Persistence.Persistence.PersistenceImpl.instance().binding(uiSourceCode) !== null) {
105
- return true;
101
+ // Only show Format button for editable files
102
+ if (!Persistence.Persistence.PersistenceImpl.instance().hasEditableContent(uiSourceCode)) {
103
+ return false;
106
104
  }
107
- return false;
105
+ // Only show Format button for JavaScript files. For other file types (JSON, CSS),
106
+ // the pretty-print toggle in the status bar should be used instead, which provides
107
+ // reversible formatting (fixes issue 378870233).
108
+ const mimeType = Common.ResourceType.ResourceType.simplifyContentType(uiSourceCode.mimeType());
109
+ return Common.ResourceType.ResourceType.isJavaScriptMimeType(mimeType);
108
110
  }
109
111
 
110
112
  private formatSourceInPlace(): void {
@@ -161,9 +161,15 @@ export class UISourceCodeFrame extends Common.ObjectWrapper
161
161
  this.#uiSourceCode, this.#boundOnBindingChanged);
162
162
  this.installMessageAndDecorationListeners();
163
163
  this.updateStyle();
164
- const canPrettyPrint = FormatterActions.FORMATTABLE_MEDIA_TYPES.includes(this.contentType) &&
165
- !this.#uiSourceCode.project().canSetFileContent() &&
166
- Persistence.Persistence.PersistenceImpl.instance().binding(this.#uiSourceCode) === null;
164
+ // Show pretty-print toggle if file type is formattable.
165
+ // For editable JavaScript files, the toggle is hidden because live edit fails on
166
+ // large whitespace changes. For non-JS files (JSON, CSS), the toggle can be shown
167
+ // because they don't have this issue (fixes issue 378870233).
168
+ const isFormattable = FormatterActions.FORMATTABLE_MEDIA_TYPES.includes(this.contentType);
169
+ const isEditable = Persistence.Persistence.PersistenceImpl.instance().hasEditableContent(this.#uiSourceCode);
170
+ // Check if the MIME type is JavaScript (not the resource type, which can be wrong for file system files)
171
+ const isJavaScript = Common.ResourceType.ResourceType.isJavaScriptMimeType(this.contentType);
172
+ const canPrettyPrint = isFormattable && (!isEditable || !isJavaScript);
167
173
  const autoPrettyPrint = !this.#uiSourceCode.contentType().isFromSourceMap();
168
174
  this.setCanPrettyPrint(canPrettyPrint, autoPrettyPrint);
169
175
  }
@@ -1540,6 +1540,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1540
1540
  }
1541
1541
 
1542
1542
  let blob = new Blob(blobParts, {type: 'application/json'});
1543
+ blobParts.length = 0; // Don't retain this large object for the remaining lifetime of this function.
1543
1544
 
1544
1545
  if (config.shouldCompress) {
1545
1546
  this.statusDialog.updateStatus(i18nString(UIStrings.compressingTraceForDownload));
@@ -1560,8 +1561,9 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1560
1561
  // blobParts.join('') === (await gzBlob.arrayBuffer().then(bytes => Common.Gzip.arrayBufferToString(bytes)))
1561
1562
  }
1562
1563
 
1564
+ const blobType = blob.type; // blob may be reassigned later.
1565
+
1563
1566
  // In some cases Base64.encode() can return undefined; see crbug.com/436482118 for details.
1564
- // TODO(crbug.com/436482118): understand this edge case and fix the Base64.encode method to not just return undefined.
1565
1567
  let bytesAsB64: string|null = null;
1566
1568
  try {
1567
1569
  // The maximum string length in v8 is `2 ** 29 - 23`, aka 538 MB.
@@ -1569,11 +1571,17 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
1569
1571
  this.statusDialog.updateStatus(i18nString(UIStrings.encodingTraceForDownload));
1570
1572
  this.statusDialog.updateProgressBar(i18nString(UIStrings.encodingTraceForDownload), 100);
1571
1573
  bytesAsB64 = await Common.Base64.encode(blob);
1572
- } catch {
1574
+ blob = new Blob(); // Don't retain this large object for the remaining lifetime of this function.
1575
+ } catch (err) {
1576
+ if (err instanceof Error && err.message.startsWith('failed to convert to base64')) {
1577
+ // Expected and handled below.
1578
+ } else {
1579
+ throw err;
1580
+ }
1573
1581
  }
1574
1582
 
1575
- if (bytesAsB64?.length) {
1576
- const contentData = new TextUtils.ContentData.ContentData(bytesAsB64, /* isBase64=*/ true, blob.type);
1583
+ if (bytesAsB64) {
1584
+ const contentData = new TextUtils.ContentData.ContentData(bytesAsB64, /* isBase64=*/ true, blobType);
1577
1585
  await Workspace.FileManager.FileManager.instance().save(fileName, contentData, /* forceSaveAs=*/ true);
1578
1586
  Workspace.FileManager.FileManager.instance().close(fileName);
1579
1587
  } else {
@@ -97,7 +97,7 @@ export class DuplicatedJavaScript extends BaseInsightComponent<DuplicatedJavaScr
97
97
  jslog=${VisualLogging.action(`timeline.treemap.${this.internalName}-insight`).track({
98
98
  click: true
99
99
  })}
100
- @click=${this.#openTreemap}
100
+ @click=${this.#openTreemap.bind(this)}
101
101
  >View Treemap</devtools-button>`;
102
102
  }
103
103
 
@@ -1,7 +1,7 @@
1
1
  Name: Dependencies sourced from the upstream `chromium` repository
2
2
  URL: https://chromium.googlesource.com/chromium/src
3
3
  Version: N/A
4
- Revision: c582925bb74faa4c014c64d1e3f809e8454755e7
4
+ Revision: 5dd7406e2cf875f110274e22c3bd287d32086055
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE