chrome-devtools-frontend 1.0.1668390 → 1.0.1669021

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 (192) hide show
  1. package/.agents/skills/devtools-ci/SKILL.md +65 -0
  2. package/.agents/skills/gerrit-cli/SKILL.md +59 -0
  3. package/.agents/skills/gerrit-cli/references/commands.md +93 -0
  4. package/.agents/skills/gerrit-cli/references/workflows.md +56 -0
  5. package/.agents/skills/gerrit-cli/scripts/gerrit_client_wrapper.py +47 -0
  6. package/.agents/skills/gerrit-cli/scripts/import_upstream.py +230 -0
  7. package/docs/contributing/infrastructure.md +7 -1
  8. package/front_end/core/host/AidaClient.ts +66 -47
  9. package/front_end/core/host/GcaClient.ts +4 -6
  10. package/front_end/core/host/ResourceLoader.ts +4 -2
  11. package/front_end/core/root/Runtime.ts +0 -5
  12. package/front_end/core/sdk/ConsoleModel.ts +3 -2
  13. package/front_end/core/sdk/DebuggerModel.ts +14 -6
  14. package/front_end/core/sdk/SDKSettings.ts +19 -0
  15. package/front_end/core/sdk/sdk-meta.ts +0 -58
  16. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  17. package/front_end/generated/protocol.ts +11 -3
  18. package/front_end/models/ai_assistance/AiUtils.ts +67 -4
  19. package/front_end/models/ai_assistance/StorageItem.ts +26 -5
  20. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +2 -19
  21. package/front_end/models/ai_code_generation/AiCodeGeneration.ts +2 -3
  22. package/front_end/models/trace/handlers/RendererHandler.ts +20 -4
  23. package/front_end/models/trace/types/File.ts +1 -0
  24. package/front_end/models/workspace/UISourceCode.ts +0 -10
  25. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +61 -182
  26. package/front_end/panels/ai_assistance/components/ChatInput.ts +25 -8
  27. package/front_end/panels/ai_assistance/components/ChatMessage.ts +13 -69
  28. package/front_end/panels/ai_assistance/components/ChatView.ts +14 -8
  29. package/front_end/panels/ai_assistance/components/chatMessage.css +2 -20
  30. package/front_end/panels/application/ApplicationPanelSidebar.ts +2 -2
  31. package/front_end/panels/application/ApplicationPanelTreeElement.ts +41 -3
  32. package/front_end/panels/application/ServiceWorkerUpdateCycleView.ts +116 -79
  33. package/front_end/panels/application/ServiceWorkersView.ts +8 -8
  34. package/front_end/panels/application/application.ts +2 -0
  35. package/front_end/panels/application/components/AdsView.ts +10 -6
  36. package/front_end/panels/application/preloading/PreloadingView.ts +53 -45
  37. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +111 -119
  38. package/front_end/panels/application/preloading/components/preloadingDetailsReportView.css +21 -23
  39. package/front_end/panels/application/serviceWorkerUpdateCycleView.css +105 -102
  40. package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +107 -96
  41. package/front_end/panels/common/AiCodeCompletionSummaryToolbar.ts +17 -19
  42. package/front_end/panels/common/AiCodeCompletionTeaser.ts +6 -6
  43. package/front_end/panels/common/AiCodeGenerationTeaser.ts +28 -26
  44. package/front_end/panels/common/common.ts +1 -1
  45. package/front_end/panels/console/ConsoleInsightTeaser.ts +3 -6
  46. package/front_end/panels/console/ConsoleView.ts +6 -4
  47. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  48. package/front_end/panels/console/console-meta.ts +28 -0
  49. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +1 -1
  50. package/front_end/panels/elements/StylesSidebarPane.ts +3 -2
  51. package/front_end/panels/emulation/DeviceModeWrapper.ts +18 -4
  52. package/front_end/panels/explain/components/ConsoleInsight.ts +4 -6
  53. package/front_end/panels/explain/explain-meta.ts +7 -49
  54. package/front_end/panels/network/NetworkDataGridNode.ts +1 -1
  55. package/front_end/panels/network/NetworkLogView.ts +1 -0
  56. package/front_end/panels/network/OriginalResourceChunkView.ts +340 -0
  57. package/front_end/panels/network/ResourceChunkView.ts +72 -46
  58. package/front_end/panels/network/ResourceDirectSocketChunkView.ts +3 -2
  59. package/front_end/panels/network/ResourceWebSocketFrameView.ts +3 -3
  60. package/front_end/panels/network/originalResourceChunkView.css +49 -0
  61. package/front_end/panels/screencast/ScreencastView.ts +401 -260
  62. package/front_end/panels/screencast/screencastView.css +113 -100
  63. package/front_end/panels/sensors/LocationsSettingsTab.ts +106 -122
  64. package/front_end/panels/sensors/locationsSettingsTab.css +4 -4
  65. package/front_end/panels/settings/AISettingsTab.ts +17 -100
  66. package/front_end/panels/snippets/ScriptSnippetFileSystem.ts +2 -2
  67. package/front_end/panels/snippets/SnippetsQuickOpen.ts +4 -4
  68. package/front_end/panels/sources/AddSourceMapURLDialog.ts +3 -3
  69. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +4 -3
  70. package/front_end/panels/sources/BreakpointEditDialog.ts +14 -14
  71. package/front_end/panels/sources/BreakpointsView.ts +14 -14
  72. package/front_end/panels/sources/CallStackSidebarPane.ts +6 -6
  73. package/front_end/panels/sources/CategorizedBreakpointL10n.ts +18 -18
  74. package/front_end/panels/sources/CoveragePlugin.ts +7 -7
  75. package/front_end/panels/sources/DebuggerPausedMessage.ts +23 -23
  76. package/front_end/panels/sources/DebuggerPlugin.ts +29 -29
  77. package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +2 -2
  78. package/front_end/panels/sources/GoToLineQuickOpen.ts +10 -10
  79. package/front_end/panels/sources/NavigatorView.ts +34 -27
  80. package/front_end/panels/sources/OutlineQuickOpen.ts +3 -3
  81. package/front_end/panels/sources/PersistenceActions.ts +9 -9
  82. package/front_end/panels/sources/ProfilePlugin.ts +1 -1
  83. package/front_end/panels/sources/ScopeChainSidebarPane.ts +5 -5
  84. package/front_end/panels/sources/SnippetsPlugin.ts +2 -2
  85. package/front_end/panels/sources/SourcesNavigator.ts +20 -18
  86. package/front_end/panels/sources/SourcesPanel.ts +26 -25
  87. package/front_end/panels/sources/SourcesView.ts +5 -6
  88. package/front_end/panels/sources/TabbedEditorContainer.ts +3 -3
  89. package/front_end/panels/sources/ThreadsSidebarPane.ts +1 -1
  90. package/front_end/panels/sources/UISourceCodeFrame.ts +0 -2
  91. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +7 -7
  92. package/front_end/panels/sources/components/HeadersView.ts +2 -2
  93. package/front_end/panels/sources/sources-meta.ts +109 -71
  94. package/front_end/panels/sources/sources.ts +0 -2
  95. package/front_end/panels/timeline/TimelineHistoryManager.ts +14 -3
  96. package/front_end/panels/timeline/TimelineLoader.ts +72 -42
  97. package/front_end/panels/timeline/TimelinePanel.ts +29 -4
  98. package/front_end/panels/timeline/timelineHistoryManager.css +4 -0
  99. package/front_end/third_party/chromium/README.chromium +1 -1
  100. package/front_end/third_party/puppeteer/README.chromium +2 -2
  101. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +187 -1
  102. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +91 -38
  103. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.d.ts +145 -2
  104. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.d.ts.map +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.js +0 -2
  106. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.js.map +1 -1
  107. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.d.ts +0 -2
  108. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.d.ts.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.js +0 -2
  110. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.js.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Dialog.d.ts +3 -2
  112. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Dialog.d.ts.map +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Dialog.js +8 -2
  114. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Dialog.js.map +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/JSHandle.d.ts +0 -2
  116. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/JSHandle.d.ts.map +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/JSHandle.js +0 -2
  118. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/JSHandle.js.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts +1 -3
  120. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js +0 -2
  122. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js.map +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.d.ts +0 -1
  124. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.d.ts.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.js +0 -1
  126. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.d.ts.map +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.js +2 -2
  129. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.js.map +1 -1
  130. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Browser.d.ts +5 -1
  131. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Browser.d.ts.map +1 -1
  132. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Browser.js +12 -0
  133. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Browser.js.map +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPResponse.js +4 -1
  136. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPResponse.js.map +1 -1
  137. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts +5 -1
  138. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts.map +1 -1
  139. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js +49 -0
  140. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js.map +1 -1
  141. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/EventEmitter.d.ts +0 -6
  142. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/EventEmitter.d.ts.map +1 -1
  143. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/EventEmitter.js +0 -6
  144. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/EventEmitter.js.map +1 -1
  145. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts +1 -1
  146. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts.map +1 -1
  147. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js +1 -1
  148. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js.map +1 -1
  149. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/util.d.ts.map +1 -1
  150. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/util.js +3 -0
  151. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/util.js.map +1 -1
  152. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.d.ts +0 -3
  153. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.d.ts.map +1 -1
  154. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.js +0 -3
  155. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.js.map +1 -1
  156. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  157. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  158. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/disposable.d.ts +2 -2
  159. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/disposable.js +2 -2
  160. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  161. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  162. package/front_end/third_party/puppeteer/package/lib/types.d.ts +187 -1
  163. package/front_end/third_party/puppeteer/package/package.json +5 -5
  164. package/front_end/third_party/puppeteer/package/src/api/Browser.ts +155 -2
  165. package/front_end/third_party/puppeteer/package/src/api/BrowserContext.ts +0 -2
  166. package/front_end/third_party/puppeteer/package/src/api/Dialog.ts +10 -2
  167. package/front_end/third_party/puppeteer/package/src/api/JSHandle.ts +0 -2
  168. package/front_end/third_party/puppeteer/package/src/api/Page.ts +1 -3
  169. package/front_end/third_party/puppeteer/package/src/api/Realm.ts +0 -1
  170. package/front_end/third_party/puppeteer/package/src/bidi/BidiOverCdp.ts +4 -2
  171. package/front_end/third_party/puppeteer/package/src/bidi/Browser.ts +17 -0
  172. package/front_end/third_party/puppeteer/package/src/bidi/HTTPResponse.ts +5 -4
  173. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +66 -0
  174. package/front_end/third_party/puppeteer/package/src/common/EventEmitter.ts +0 -6
  175. package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
  176. package/front_end/third_party/puppeteer/package/src/injected/util.ts +4 -1
  177. package/front_end/third_party/puppeteer/package/src/node/ScreenRecorder.ts +0 -3
  178. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  179. package/front_end/third_party/puppeteer/package/src/util/disposable.ts +2 -2
  180. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  181. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +9 -7
  182. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +7 -8
  183. package/front_end/ui/legacy/Dialog.ts +12 -2
  184. package/front_end/ui/legacy/TabbedPane.ts +7 -2
  185. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +40 -24
  186. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +1 -0
  187. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +8 -4
  188. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +14 -7
  189. package/front_end/ui/legacy/components/quick_open/CommandMenu.ts +11 -1
  190. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  191. package/package.json +1 -1
  192. package/front_end/panels/sources/AiWarningInfobarPlugin.ts +0 -78
@@ -76,7 +76,7 @@ export class StylesAiCodeCompletionProvider {
76
76
  aidaClient: this.#aidaClient,
77
77
  serverSideLoggingEnabled: !Root.Runtime.hostConfig.aidaAvailability?.disallowLogging,
78
78
  },
79
- this.#aiCodeCompletionConfig.panel,
79
+
80
80
  undefined, stopSequences);
81
81
  this.#aiCodeCompletionConfig.onFeatureEnabled();
82
82
  }
@@ -300,7 +300,8 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
300
300
  onSuggestionAccepted: this.#onAiCodeCompletionSuggestionAccepted.bind(this),
301
301
  onRequestTriggered: this.#onAiCodeCompletionRequestTriggered.bind(this),
302
302
  onResponseReceived: this.#onAiCodeCompletionResponseReceived.bind(this),
303
- panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
303
+ disclaimerTooltipId: DISCLAIMER_TOOLTIP_ID,
304
+ disclaimerTextVariant: 'styles',
304
305
  };
305
306
  this.aiCodeCompletionProvider =
306
307
  StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider.createInstance(this.aiCodeCompletionConfig);
@@ -1618,7 +1619,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
1618
1619
  citationsTooltipId: CITATIONS_TOOLTIP_ID,
1619
1620
  disclaimerTooltipId: DISCLAIMER_TOOLTIP_ID,
1620
1621
  spinnerTooltipId: SPINNER_TOOLTIP_ID,
1621
- panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
1622
+ disclaimerTextVariant: 'styles',
1622
1623
  });
1623
1624
  const containingPane = this.contentElement.enclosingNodeOrSelfWithClass('style-panes-wrapper') as HTMLElement;
1624
1625
  this.#aiCodeCompletionSummaryToolbarContainer =
@@ -138,6 +138,8 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
138
138
  throw new Error(`Unable to get box model of the node: ${new Error().stack}`);
139
139
  }
140
140
  const nodeBorderQuad = nodeBoxModel.border;
141
+ // Calculate the rendered bounding box from the border quad to account for CSS scaling and transforms (e.g. zoom or transform: scale).
142
+ const {minX, maxX, minY, maxY} = getQuadBoundingBox(nodeBorderQuad);
141
143
 
142
144
  // Get Layout Metrics to account for the Visual Viewport scroll and zoom.
143
145
  const metrics = await node.domModel().target().pageAgent().invoke_getLayoutMetrics();
@@ -155,10 +157,10 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
155
157
  // Assemble the final Clip.
156
158
  // The absolute coordinates are: Global (OOPiF) + Viewport Scroll + Local Node Position (Border Box).
157
159
  const clip = {
158
- x: oopifOffsetX + scrollX + nodeBorderQuad[0],
159
- y: oopifOffsetY + scrollY + nodeBorderQuad[1],
160
- width: nodeBoxModel.width,
161
- height: nodeBoxModel.height,
160
+ x: oopifOffsetX + scrollX + minX,
161
+ y: oopifOffsetY + scrollY + minY,
162
+ width: maxX - minX,
163
+ height: maxY - minY,
162
164
  scale: 1,
163
165
  };
164
166
 
@@ -249,3 +251,15 @@ async function getOopifOffset(target: SDK.Target.Target|null): Promise<{x: numbe
249
251
  y: iframeContentY + scrollY + parentOffset.y,
250
252
  };
251
253
  }
254
+
255
+ /**
256
+ * Calculate the axis-aligned bounding box for a Quad [x1, y1, x2, y2, x3, y3, x4, y4].
257
+ * This accounts for CSS scaling and transforms (e.g. zoom, transform: scale).
258
+ */
259
+ function getQuadBoundingBox(quad: Protocol.DOM.Quad): {minX: number, maxX: number, minY: number, maxY: number} {
260
+ const minX = Math.min(quad[0], quad[2], quad[4], quad[6]);
261
+ const maxX = Math.max(quad[0], quad[2], quad[4], quad[6]);
262
+ const minY = Math.min(quad[1], quad[3], quad[5], quad[7]);
263
+ const maxY = Math.max(quad[1], quad[3], quad[5], quad[7]);
264
+ return {minX, maxX, minY, maxY};
265
+ }
@@ -10,6 +10,7 @@ import * as Host from '../../../core/host/host.js';
10
10
  import * as i18n from '../../../core/i18n/i18n.js';
11
11
  import type * as Platform from '../../../core/platform/platform.js';
12
12
  import * as Root from '../../../core/root/root.js';
13
+ import * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
13
14
  import * as Marked from '../../../third_party/marked/marked.js';
14
15
  import * as Buttons from '../../../ui/components/buttons/buttons.js';
15
16
  import * as Input from '../../../ui/components/input/input.js';
@@ -861,12 +862,9 @@ export class ConsoleInsight extends UI.Widget.Widget {
861
862
  // off -> entrypoints are shown, and point to the AI setting panel where the setting can be turned on
862
863
  // on -> entrypoints are shown, and console insights can be generated
863
864
  #getConsoleInsightsEnabledSetting(): Common.Settings.Setting<boolean>|undefined {
864
- try {
865
- return Common.Settings.Settings.instance().moduleSetting('console-insights-enabled') as
866
- Common.Settings.Setting<boolean>;
867
- } catch {
868
- return;
869
- }
865
+ const result = Common.Settings.Settings.instance().maybeResolve(
866
+ AiAssistanceModel.AiUtils.consoleInsightsEnabledSettingDescriptor);
867
+ return 'setting' in result ? (result.setting as Common.Settings.Setting<boolean>) : undefined;
870
868
  }
871
869
 
872
870
  // off -> consent reminder is shown, unless the 'console-insights-enabled'-setting has been enabled in the current DevTools session
@@ -4,10 +4,11 @@
4
4
 
5
5
  import * as Common from '../../core/common/common.js';
6
6
  import * as i18n from '../../core/i18n/i18n.js';
7
- import type * as Platform from '../../core/platform/platform.js';
8
7
  import type * as Root from '../../core/root/root.js';
8
+ import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
9
9
  import * as Console from '../../panels/console/console.js';
10
10
  import * as UI from '../../ui/legacy/legacy.js';
11
+ import * as SettingUIRegistration from '../../ui/settings/settings.js';
11
12
 
12
13
  const UIStrings = {
13
14
  /**
@@ -27,27 +28,9 @@ const UIStrings = {
27
28
  * the settings tab.
28
29
  */
29
30
  enableConsoleInsights: 'Understand console messages with AI',
30
- /**
31
- * @description Message shown to the user if the DevTools locale is not
32
- * supported.
33
- */
34
- wrongLocale: 'To use this feature, set your language preference to English in DevTools settings.',
35
- /**
36
- * @description Message shown to the user if the user's region is not
37
- * supported.
38
- */
39
- geoRestricted: 'This feature is unavailable in your region.',
40
- /**
41
- * @description Message shown to the user if the enterprise policy does
42
- * not allow this feature.
43
- */
44
- policyRestricted: 'This setting is managed by your administrator.',
45
31
  } as const;
46
32
  const str_ = i18n.i18n.registerUIStrings('panels/explain/explain-meta.ts', UIStrings);
47
33
  const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
48
- const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
49
-
50
- const setting = 'console-insights-enabled';
51
34
 
52
35
  const actions = [
53
36
  {
@@ -92,11 +75,6 @@ const actions = [
92
75
  },
93
76
  ];
94
77
 
95
- function isLocaleRestricted(): boolean {
96
- const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
97
- return !devtoolsLocale.locale.startsWith('en-');
98
- }
99
-
100
78
  function isGeoRestricted(config?: Root.Runtime.HostConfig): boolean {
101
79
  return config?.aidaAvailability?.blockedByGeo === true;
102
80
  }
@@ -109,31 +87,11 @@ function isFeatureEnabled(config?: Root.Runtime.HostConfig): boolean {
109
87
  return (config?.aidaAvailability?.enabled && config?.devToolsConsoleInsights?.enabled) === true;
110
88
  }
111
89
 
112
- Common.Settings.registerSettingExtension({
113
- category: Common.Settings.SettingCategory.AI,
114
- settingName: setting,
115
- settingType: Common.Settings.SettingType.BOOLEAN,
116
- title: i18nLazyString(UIStrings.enableConsoleInsights),
117
- defaultValue: false,
118
- reloadRequired: false,
119
- condition: config => isFeatureEnabled(config),
120
- disabledCondition: config => {
121
- const reasons: Platform.UIString.LocalizedString[] = [];
122
- if (isGeoRestricted(config)) {
123
- reasons.push(i18nString(UIStrings.geoRestricted));
124
- }
125
- if (isPolicyRestricted(config)) {
126
- reasons.push(i18nString(UIStrings.policyRestricted));
127
- }
128
- if (isLocaleRestricted()) {
129
- reasons.push(i18nString(UIStrings.wrongLocale));
130
- }
131
- if (reasons.length > 0) {
132
- return {disabled: true, reasons};
133
- }
134
- return {disabled: false};
135
- },
136
- });
90
+ SettingUIRegistration.SettingUIRegistration.register(AiAssistanceModel.AiUtils.consoleInsightsEnabledSettingDescriptor,
91
+ {
92
+ category: Common.Settings.SettingCategory.AI,
93
+ title: i18nLazyString(UIStrings.enableConsoleInsights),
94
+ });
137
95
 
138
96
  for (const action of actions) {
139
97
  UI.ActionRegistration.registerActionExtension({
@@ -378,7 +378,7 @@ export interface RequestActivatedEvent {
378
378
  }
379
379
 
380
380
  export interface EventTypes {
381
- [Events.RequestSelected]: SDK.NetworkRequest.NetworkRequest;
381
+ [Events.RequestSelected]: SDK.NetworkRequest.NetworkRequest|null;
382
382
  [Events.RequestActivated]: RequestActivatedEvent;
383
383
  }
384
384
 
@@ -1575,6 +1575,7 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
1575
1575
 
1576
1576
  private reset(): void {
1577
1577
  this.dispatchEventToListeners(Events.RequestActivated, {showPanel: RequestPanelBehavior.HidePanel});
1578
+ this.dispatchEventToListeners(Events.RequestSelected, null);
1578
1579
 
1579
1580
  this.setHoveredNode(null);
1580
1581
  this.columnsInternal.reset();
@@ -0,0 +1,340 @@
1
+
2
+ // Copyright 2025 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
+ /* eslint-disable @devtools/no-imperative-dom-api */
6
+
7
+ import * as Common from '../../core/common/common.js';
8
+ import * as Host from '../../core/host/host.js';
9
+ import * as i18n from '../../core/i18n/i18n.js';
10
+ import * as Platform from '../../core/platform/platform.js';
11
+ import type * as SDK from '../../core/sdk/sdk.js';
12
+ import * as TextUtils from '../../core/text_utils/text_utils.js';
13
+ import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
14
+ import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
15
+ import * as UI from '../../ui/legacy/legacy.js';
16
+
17
+ import type {BinaryResourceView} from './BinaryResourceView.js';
18
+ import viewStyles from './originalResourceChunkView.css.js';
19
+
20
+ const UIStrings = {
21
+ /**
22
+ * @description Text in Event Source Messages View of the Network panel
23
+ */
24
+ data: 'Data',
25
+ /**
26
+ * @description Text in Messages View of the Network panel
27
+ */
28
+ length: 'Length',
29
+ /**
30
+ * @description Text that refers to the time
31
+ */
32
+ time: 'Time',
33
+ /**
34
+ * @description Text to clear everything
35
+ */
36
+ clearAll: 'Clear All',
37
+ /**
38
+ * @description Text to filter result items
39
+ */
40
+ filter: 'Filter',
41
+ /**
42
+ * @description Text in Messages View of the Network panel that shows if no message is selected for viewing its content
43
+ */
44
+ noMessageSelected: 'No message selected',
45
+ /**
46
+ * @description Text in Messages View of the Network panel
47
+ */
48
+ selectMessageToBrowseItsContent: 'Select message to browse its content.',
49
+ /**
50
+ * @description Text in Messages View of the Network panel
51
+ */
52
+ copyMessageD: 'Copy message…',
53
+ /**
54
+ * @description A context menu item in the Messages View of the Network panel
55
+ */
56
+ copyMessage: 'Copy message',
57
+ /**
58
+ * @description Text for everything
59
+ */
60
+ all: 'All',
61
+ /**
62
+ * @description Text in Messages View of the Network panel
63
+ */
64
+ send: 'Send',
65
+ /**
66
+ * @description Text in Messages View of the Network panel
67
+ */
68
+ receive: 'Receive',
69
+ } as const;
70
+ const str_ = i18n.i18n.registerUIStrings('panels/network/OriginalResourceChunkView.ts', UIStrings);
71
+ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
72
+ const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
73
+
74
+ export abstract class OriginalResourceChunkView<Chunk> extends UI.Widget.VBox {
75
+ private readonly splitWidget: UI.SplitWidget.SplitWidget;
76
+ private dataGrid: DataGrid.SortableDataGrid.SortableDataGrid<unknown>;
77
+ private readonly timeComparator: (arg0: DataGrid.SortableDataGrid.SortableDataGridNode<DataGridItem>,
78
+ arg1: DataGrid.SortableDataGrid.SortableDataGridNode<DataGridItem>) => number;
79
+ private readonly mainToolbar: UI.Toolbar.Toolbar;
80
+ private readonly clearAllButton: UI.Toolbar.ToolbarButton;
81
+ private readonly filterTypeCombobox: UI.Toolbar.ToolbarComboBox;
82
+ protected filterType: string|null = null;
83
+ private readonly filterTextInput: UI.Toolbar.ToolbarInput;
84
+ protected filterRegex: RegExp|null = null;
85
+ private readonly frameEmptyWidget: UI.EmptyWidget.EmptyWidget;
86
+ private currentSelectedNode?: DataGridItem|null;
87
+ readonly request: SDK.NetworkRequest.NetworkRequest;
88
+ private readonly messageFilterSetting: Common.Settings.Setting<string>;
89
+ private sidebarWidget: UI.Widget.Widget|null = null;
90
+
91
+ abstract getRequestChunks(): Chunk[];
92
+ abstract createGridItem(chunk: Chunk): DataGridItem;
93
+ abstract chunkFilter(chunk: Chunk): boolean;
94
+
95
+ constructor(request: SDK.NetworkRequest.NetworkRequest, messageFilterSettingKey: string,
96
+ splitWidgetSettingKey: string, dataGridDisplayName: Common.UIString.LocalizedString,
97
+ filterUsingRegexHint: Common.UIString.LocalizedString) {
98
+ super();
99
+ this.messageFilterSetting = Common.Settings.Settings.instance().createSetting(messageFilterSettingKey, '');
100
+ this.registerRequiredCSS(viewStyles);
101
+ this.request = request;
102
+ this.element.classList.add('resource-chunk-view');
103
+
104
+ this.splitWidget = new UI.SplitWidget.SplitWidget(false, true, splitWidgetSettingKey);
105
+ this.splitWidget.show(this.element);
106
+
107
+ const columns: DataGrid.DataGrid.ColumnDescriptor[] = this.getColumns();
108
+
109
+ this.dataGrid = new DataGrid.SortableDataGrid.SortableDataGrid({
110
+ displayName: dataGridDisplayName,
111
+ columns,
112
+ });
113
+ this.dataGrid.setRowContextMenuCallback((menu, node) => this.onRowContextMenu(menu, node));
114
+ this.dataGrid.setEnableAutoScrollToBottom(true);
115
+ this.dataGrid.setCellClass('resource-chunk-view-td');
116
+ this.timeComparator = (resourceChunkNodeTimeComparator as
117
+ (arg0: DataGrid.SortableDataGrid.SortableDataGridNode<DataGridItem>,
118
+ arg1: DataGrid.SortableDataGrid.SortableDataGridNode<DataGridItem>) => number);
119
+ this.dataGrid.sortNodes(this.timeComparator, false);
120
+ this.dataGrid.markColumnAsSortedBy('time', DataGrid.DataGrid.Order.Ascending);
121
+ this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SORTING_CHANGED, this.sortItems, this);
122
+
123
+ this.dataGrid.setName(splitWidgetSettingKey + '_datagrid');
124
+ this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SELECTED_NODE, event => {
125
+ void this.onChunkSelected(event);
126
+ }, this);
127
+ this.dataGrid.addEventListener(DataGrid.DataGrid.Events.DESELECTED_NODE, this.onChunkDeselected, this);
128
+
129
+ this.mainToolbar = document.createElement('devtools-toolbar');
130
+
131
+ this.clearAllButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.clearAll), 'clear');
132
+ this.clearAllButton.addEventListener(UI.Toolbar.ToolbarButton.Events.CLICK, this.clearChunks, this);
133
+ this.mainToolbar.appendToolbarItem(this.clearAllButton);
134
+
135
+ this.filterTypeCombobox =
136
+ new UI.Toolbar.ToolbarComboBox(this.onFilterTypeChanged.bind(this), i18nString(UIStrings.filter));
137
+ for (const filterItem of FILTER_TYPES) {
138
+ const option = this.filterTypeCombobox.createOption(filterItem.label(), filterItem.name);
139
+ this.filterTypeCombobox.addOption(option);
140
+ }
141
+ this.mainToolbar.appendToolbarItem(this.filterTypeCombobox);
142
+
143
+ this.filterTextInput = new UI.Toolbar.ToolbarFilter(filterUsingRegexHint, 0.4);
144
+ this.filterTextInput.addEventListener(UI.Toolbar.ToolbarInput.Event.TEXT_CHANGED, this.onFilterTextChanged, this);
145
+ const filter = this.messageFilterSetting.get();
146
+ if (filter) {
147
+ this.filterTextInput.setValue(filter);
148
+ }
149
+ this.mainToolbar.appendToolbarItem(this.filterTextInput);
150
+
151
+ const mainContainer = new UI.Widget.VBox();
152
+ mainContainer.element.appendChild(this.mainToolbar);
153
+ this.dataGrid.asWidget().show(mainContainer.element);
154
+ mainContainer.setMinimumSize(0, 72);
155
+ this.splitWidget.setMainWidget(mainContainer);
156
+
157
+ this.frameEmptyWidget = new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.noMessageSelected),
158
+ i18nString(UIStrings.selectMessageToBrowseItsContent));
159
+ this.sidebarWidget = this.frameEmptyWidget;
160
+ this.splitWidget.setSidebarWidget(this.sidebarWidget);
161
+
162
+ if (filter) {
163
+ this.applyFilter(filter);
164
+ }
165
+ }
166
+
167
+ private onRowContextMenu(contextMenu: UI.ContextMenu.ContextMenu,
168
+ node: DataGrid.DataGrid.DataGridNode<unknown>): void {
169
+ const item = node as DataGridItem;
170
+ const binaryView = item.binaryView();
171
+ if (binaryView) {
172
+ binaryView.addCopyToContextMenu(contextMenu, i18nString(UIStrings.copyMessageD));
173
+ } else {
174
+ const dataVal = item.data.data;
175
+ const textToCopy = typeof dataVal === 'string' ? dataVal : item.dataText();
176
+ contextMenu.clipboardSection().appendItem(
177
+ i18nString(UIStrings.copyMessage),
178
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText.bind(
179
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance, textToCopy),
180
+ {jslogContext: 'copy'});
181
+ }
182
+ contextMenu.footerSection().appendItem(i18nString(UIStrings.clearAll), this.clearChunks.bind(this),
183
+ {jslogContext: 'clear-all'});
184
+ }
185
+
186
+ getColumns(): DataGrid.DataGrid.ColumnDescriptor[] {
187
+ return [
188
+ {id: 'data', title: i18nString(UIStrings.data), sortable: false, weight: 88},
189
+ {
190
+ id: 'length',
191
+ title: i18nString(UIStrings.length),
192
+ sortable: false,
193
+ align: DataGrid.DataGrid.Align.RIGHT,
194
+ weight: 5,
195
+ },
196
+ {id: 'time', title: i18nString(UIStrings.time), sortable: true, weight: 7},
197
+ ];
198
+ }
199
+
200
+ chunkAdded(chunk: Chunk): void {
201
+ if (!this.chunkFilter(chunk)) {
202
+ return;
203
+ }
204
+ this.dataGrid.insertChild(this.createGridItem(chunk));
205
+ }
206
+
207
+ private clearChunks(): void {
208
+ // TODO(allada): actually remove frames from request.
209
+ clearChunkOffsets.set(this.request, this.getRequestChunks().length);
210
+ this.performUpdate();
211
+ }
212
+
213
+ private onFilterTypeChanged(): void {
214
+ const val = (this.filterTypeCombobox.selectedOption() as HTMLOptionElement).value;
215
+ this.filterType = val === 'all' ? null : val;
216
+ this.performUpdate();
217
+ }
218
+
219
+ private onFilterTextChanged(): void {
220
+ const text = this.filterTextInput.value();
221
+ this.messageFilterSetting.set(text);
222
+ this.applyFilter(text);
223
+ }
224
+
225
+ private applyFilter(text: string): void {
226
+ if (text) {
227
+ try {
228
+ this.filterRegex = new RegExp(text, 'i');
229
+ } catch {
230
+ this.filterRegex = new RegExp(Platform.StringUtilities.escapeForRegExp(text), 'i');
231
+ }
232
+ } else {
233
+ this.filterRegex = null;
234
+ }
235
+ this.performUpdate();
236
+ }
237
+
238
+ private async onChunkSelected(event: Common.EventTarget.EventTargetEvent<DataGrid.DataGrid.DataGridNode<unknown>>):
239
+ Promise<void> {
240
+ this.currentSelectedNode = (event.data as DataGridItem);
241
+ await this.updateSidebar();
242
+ }
243
+
244
+ private onChunkDeselected(): void {
245
+ this.currentSelectedNode = null;
246
+ void this.updateSidebar();
247
+ }
248
+
249
+ async updateSidebar(): Promise<void> {
250
+ if (!this.currentSelectedNode) {
251
+ this.sidebarWidget = null;
252
+ this.updateSidebarWidget();
253
+ return;
254
+ }
255
+
256
+ const content = this.currentSelectedNode.dataText();
257
+
258
+ const binaryView = this.currentSelectedNode.binaryView();
259
+ if (binaryView) {
260
+ this.sidebarWidget = binaryView;
261
+ this.updateSidebarWidget();
262
+ return;
263
+ }
264
+
265
+ const jsonView = await SourceFrame.JSONView.JSONView.createView(content);
266
+ if (jsonView) {
267
+ this.sidebarWidget = jsonView;
268
+ this.updateSidebarWidget();
269
+ return;
270
+ }
271
+
272
+ this.sidebarWidget = new SourceFrame.ResourceSourceFrame.ResourceSourceFrame(
273
+ TextUtils.StaticContentProvider.StaticContentProvider.fromString(this.request.url(),
274
+ this.request.resourceType(), content),
275
+ '');
276
+ this.updateSidebarWidget();
277
+ }
278
+
279
+ private updateSidebarWidget(): void {
280
+ const activeSidebar = this.sidebarWidget || this.frameEmptyWidget;
281
+ if (this.splitWidget.sidebarWidget() !== activeSidebar) {
282
+ this.splitWidget.setSidebarWidget(activeSidebar);
283
+ }
284
+ }
285
+
286
+ override performUpdate(): void {
287
+ this.dataGrid.rootNode().removeChildren();
288
+ let chunks = this.getRequestChunks();
289
+ const offset = clearChunkOffsets.get(this.request) || 0;
290
+ chunks = chunks.slice(offset).filter(this.chunkFilter.bind(this));
291
+ chunks.forEach(chunk => this.dataGrid.insertChild(this.createGridItem(chunk)));
292
+
293
+ this.updateSidebarWidget();
294
+ }
295
+
296
+ refresh(): void {
297
+ this.performUpdate();
298
+ }
299
+
300
+ private sortItems(): void {
301
+ this.dataGrid.sortNodes(this.timeComparator, !this.dataGrid.isSortOrderAscending());
302
+ }
303
+
304
+ getDataGridForTest(): DataGrid.SortableDataGrid.SortableDataGrid<unknown> {
305
+ return this.dataGrid;
306
+ }
307
+
308
+ getSplitWidgetForTest(): UI.SplitWidget.SplitWidget {
309
+ return this.splitWidget;
310
+ }
311
+
312
+ getFilterInputForTest(): UI.Toolbar.ToolbarInput {
313
+ return this.filterTextInput;
314
+ }
315
+ getClearAllButtonForTest(): UI.Toolbar.ToolbarButton {
316
+ return this.clearAllButton;
317
+ }
318
+ getFilterTypeComboboxForTest(): UI.Toolbar.ToolbarComboBox {
319
+ return this.filterTypeCombobox;
320
+ }
321
+ }
322
+
323
+ const FILTER_TYPES: UI.FilterBar.Item[] = [
324
+ {name: 'all', label: i18nLazyString(UIStrings.all), jslogContext: 'all'},
325
+ {name: 'send', label: i18nLazyString(UIStrings.send), jslogContext: 'send'},
326
+ {name: 'receive', label: i18nLazyString(UIStrings.receive), jslogContext: 'receive'},
327
+ ];
328
+
329
+ export abstract class DataGridItem extends DataGrid.SortableDataGrid.SortableDataGridNode<unknown> {
330
+ abstract binaryView(): BinaryResourceView|null;
331
+ abstract getTime(): number;
332
+ abstract dataText(): string;
333
+ abstract isTextFrame?: boolean;
334
+ }
335
+
336
+ function resourceChunkNodeTimeComparator(a: DataGridItem, b: DataGridItem): number {
337
+ return a.getTime() - b.getTime();
338
+ }
339
+
340
+ const clearChunkOffsets = new WeakMap<SDK.NetworkRequest.NetworkRequest, number>();