chrome-devtools-frontend 1.0.1582745 → 1.0.1585538

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 (127) hide show
  1. package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
  2. package/front_end/core/host/InspectorFrontendHostStub.ts +2 -0
  3. package/front_end/core/root/Runtime.ts +12 -11
  4. package/front_end/core/sdk/CSSMatchedStyles.ts +3 -0
  5. package/front_end/core/sdk/CSSMetadata.ts +3 -0
  6. package/front_end/core/sdk/NetworkManager.ts +63 -115
  7. package/front_end/entrypoint_template.html +1 -5
  8. package/front_end/entrypoints/main/MainImpl.ts +1 -0
  9. package/front_end/generated/Deprecation.ts +21 -0
  10. package/front_end/generated/InspectorBackendCommands.ts +5 -3
  11. package/front_end/generated/SupportedCSSProperties.js +6 -2
  12. package/front_end/generated/protocol-mapping.d.ts +2 -1
  13. package/front_end/generated/protocol-proxy-api.d.ts +2 -1
  14. package/front_end/generated/protocol.ts +14 -0
  15. package/front_end/models/ai_assistance/AiConversation.ts +34 -2
  16. package/front_end/models/ai_assistance/BuiltInAi.ts +1 -2
  17. package/front_end/models/ai_assistance/agents/AiAgent.ts +3 -10
  18. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +1 -1
  19. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +17 -9
  20. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +0 -24
  21. package/front_end/models/ai_code_generation/AiCodeGeneration.ts +5 -0
  22. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +16 -8
  23. package/front_end/models/computed_style/ComputedStyleModel.ts +20 -15
  24. package/front_end/models/greendev/Prototypes.ts +1 -5
  25. package/front_end/models/issues_manager/CorsIssue.ts +2 -9
  26. package/front_end/models/issues_manager/descriptions/corsLocalNetworkAccessPermissionDenied.md +2 -2
  27. package/front_end/models/javascript_metadata/NativeFunctions.js +20 -0
  28. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +28 -39
  29. package/front_end/panels/ai_assistance/components/ChatInput.ts +73 -95
  30. package/front_end/panels/ai_assistance/components/ChatMessage.ts +4 -2
  31. package/front_end/panels/ai_assistance/components/ChatView.ts +0 -2
  32. package/front_end/panels/autofill/AutofillView.ts +4 -8
  33. package/front_end/panels/common/AiCodeGenerationTeaser.ts +37 -8
  34. package/front_end/panels/console/ConsoleView.ts +1 -2
  35. package/front_end/panels/console/ConsoleViewMessage.ts +18 -11
  36. package/front_end/panels/elements/ComputedStyleWidget.ts +80 -48
  37. package/front_end/panels/elements/ElementStatePaneWidget.ts +1 -1
  38. package/front_end/panels/elements/ElementsPanel.ts +18 -5
  39. package/front_end/panels/elements/ElementsTreeElement.ts +459 -435
  40. package/front_end/panels/elements/EventListenersWidget.ts +2 -4
  41. package/front_end/panels/elements/NodeStackTraceWidget.ts +1 -3
  42. package/front_end/panels/elements/PropertiesWidget.ts +1 -2
  43. package/front_end/panels/elements/StylePropertyTreeElement.ts +18 -2
  44. package/front_end/panels/elements/computedStyleWidget.css +25 -0
  45. package/front_end/panels/issues/AffectedResourcesView.ts +1 -2
  46. package/front_end/panels/network/NetworkDataGridNode.ts +0 -8
  47. package/front_end/panels/network/NetworkLogView.ts +64 -105
  48. package/front_end/panels/network/RequestConditionsDrawer.ts +168 -233
  49. package/front_end/panels/network/network-meta.ts +4 -27
  50. package/front_end/panels/settings/SettingsScreen.ts +12 -4
  51. package/front_end/panels/settings/WorkspaceSettingsTab.ts +1 -1
  52. package/front_end/panels/snippets/SnippetsQuickOpen.ts +6 -9
  53. package/front_end/panels/sources/CallStackSidebarPane.ts +6 -8
  54. package/front_end/panels/sources/DebuggerPlugin.ts +2 -1
  55. package/front_end/panels/sources/GoToLineQuickOpen.ts +0 -4
  56. package/front_end/panels/sources/OpenFileQuickOpen.ts +0 -4
  57. package/front_end/panels/sources/OutlineQuickOpen.ts +0 -4
  58. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +3 -1
  59. package/front_end/panels/sources/sources-meta.ts +9 -6
  60. package/front_end/panels/timeline/TimelineFlameChartView.ts +0 -12
  61. package/front_end/panels/timeline/TimelinePanel.ts +35 -15
  62. package/front_end/panels/timeline/components/Sidebar.ts +21 -0
  63. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +1 -20
  64. package/front_end/panels/timeline/components/insights/InsightRenderer.ts +0 -1
  65. package/front_end/third_party/chromium/README.chromium +1 -1
  66. package/front_end/third_party/puppeteer/README.chromium +2 -2
  67. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts +1 -1
  68. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js +1 -1
  70. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  71. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
  72. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js +2 -3
  73. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js.map +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +2 -2
  75. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +2 -2
  76. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/encoding.d.ts.map +1 -1
  77. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/encoding.js +5 -3
  78. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/encoding.js.map +1 -1
  79. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  81. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +8 -6
  82. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts +1 -1
  83. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js +1 -1
  85. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  86. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
  87. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js +2 -3
  88. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js.map +1 -1
  89. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +2 -2
  90. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +2 -2
  91. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/encoding.d.ts.map +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/encoding.js +5 -3
  93. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/encoding.js.map +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  96. package/front_end/third_party/puppeteer/package/package.json +4 -4
  97. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +1 -1
  98. package/front_end/third_party/puppeteer/package/src/bidi/core/BrowsingContext.ts +2 -2
  99. package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +4 -3
  100. package/front_end/third_party/puppeteer/package/src/revisions.ts +2 -2
  101. package/front_end/third_party/puppeteer/package/src/util/encoding.ts +5 -3
  102. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  103. package/front_end/ui/components/linkifier/LinkifierImpl.ts +3 -0
  104. package/front_end/ui/components/linkifier/LinkifierUtils.ts +3 -0
  105. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +8 -0
  106. package/front_end/ui/components/text_editor/AiCodeGenerationParser.ts +29 -7
  107. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +42 -18
  108. package/front_end/ui/components/text_editor/config.ts +6 -0
  109. package/front_end/ui/legacy/InspectorView.ts +41 -15
  110. package/front_end/ui/legacy/Toolbar.ts +12 -4
  111. package/front_end/ui/legacy/UIUtils.ts +56 -7
  112. package/front_end/ui/legacy/components/quick_open/CommandMenu.ts +4 -3
  113. package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +2 -1
  114. package/front_end/ui/legacy/components/quick_open/HelpQuickOpen.ts +8 -2
  115. package/front_end/ui/legacy/components/quick_open/QuickOpen.ts +8 -8
  116. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +12 -9
  117. package/front_end/ui/legacy/components/utils/Linkifier.ts +116 -87
  118. package/front_end/ui/legacy/legacy.ts +0 -2
  119. package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
  120. package/mcp/HostBindings.ts +3 -0
  121. package/package.json +1 -1
  122. package/front_end/models/issues_manager/descriptions/corsInsecurePrivateNetwork.md +0 -10
  123. package/front_end/models/issues_manager/descriptions/corsPreflightAllowPrivateNetworkError.md +0 -10
  124. package/front_end/models/issues_manager/descriptions/corsPrivateNetworkPermissionDenied.md +0 -10
  125. package/front_end/panels/elements/computedStyleSidebarPane.css +0 -18
  126. package/front_end/ui/legacy/Floaty.ts +0 -438
  127. package/front_end/ui/legacy/floaty.css +0 -77
@@ -178,8 +178,6 @@ export class ChromeLauncher extends BrowserLauncher {
178
178
  'MediaRouter',
179
179
  'OptimizationHints',
180
180
  'RenderDocument', // https://crbug.com/444150315
181
- 'IPH_ReadingModePageActionLabel', // b/479237585
182
- 'ReadAnythingOmniboxChip', // b/479237585
183
181
  ...(turnOnExperimentalFeaturesForTesting
184
182
  ? []
185
183
  : [
@@ -247,7 +245,10 @@ export class ChromeLauncher extends BrowserLauncher {
247
245
  enableExtensions = false,
248
246
  } = options;
249
247
  if (userDataDir) {
250
- chromeArguments.push(`--user-data-dir=${path.resolve(userDataDir)}`);
248
+ // If absolute (for any platform) path is given, we should not resolve it.
249
+ chromeArguments.push(
250
+ `--user-data-dir=${path.posix.isAbsolute(userDataDir) || path.win32.isAbsolute(userDataDir) ? userDataDir : path.resolve(userDataDir)}`,
251
+ );
251
252
  }
252
253
  if (devtools) {
253
254
  chromeArguments.push('--auto-open-devtools-for-tabs');
@@ -8,7 +8,7 @@
8
8
  * @internal
9
9
  */
10
10
  export const PUPPETEER_REVISIONS = Object.freeze({
11
- chrome: '145.0.7632.46',
12
- 'chrome-headless-shell': '145.0.7632.46',
11
+ chrome: '145.0.7632.67',
12
+ 'chrome-headless-shell': '145.0.7632.67',
13
13
  firefox: 'stable_147.0.3',
14
14
  });
@@ -12,9 +12,11 @@ export function stringToTypedArray(
12
12
  base64Encoded = false,
13
13
  ): Uint8Array {
14
14
  if (base64Encoded) {
15
- // TODO: use
16
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64
17
- // once available.
15
+ if ('fromBase64' in Uint8Array) {
16
+ // @ts-expect-error fromBase64 is newer than the types we use.
17
+ return Uint8Array.fromBase64(string);
18
+ }
19
+ // TODO: remove Buffer in v26 when it becomes LTS.
18
20
  if (typeof Buffer === 'function') {
19
21
  return Buffer.from(string, 'base64');
20
22
  }
@@ -6,5 +6,5 @@
6
6
 
7
7
  // If moved update release-please config
8
8
  // x-release-please-start-version
9
- export const packageVersion = '24.37.2';
9
+ export const packageVersion = '24.37.3';
10
10
  // x-release-please-end
@@ -31,6 +31,9 @@ export class LinkifierClick extends Event {
31
31
  }
32
32
  }
33
33
 
34
+ /**
35
+ * @deprecated do not use
36
+ */
34
37
  export class Linkifier extends HTMLElement {
35
38
  readonly #shadow = this.attachShadow({mode: 'open'});
36
39
  #url: Platform.DevToolsPath.UrlString = Platform.DevToolsPath.EmptyUrlString;
@@ -5,6 +5,9 @@
5
5
  import type * as Platform from '../../../core/platform/platform.js';
6
6
  import * as Bindings from '../../../models/bindings/bindings.js';
7
7
 
8
+ /**
9
+ * @deprecated do not use
10
+ */
8
11
  export function linkText(url: Platform.DevToolsPath.UrlString, lineNumber?: number): string {
9
12
  if (url) {
10
13
  const displayName = Bindings.ResourceUtils.displayNameForURL(url);
@@ -18,6 +18,7 @@ import {
18
18
  acceptAiAutoCompleteSuggestion,
19
19
  aiAutoCompleteSuggestion,
20
20
  aiAutoCompleteSuggestionState,
21
+ AiSuggestionSource,
21
22
  hasActiveAiSuggestion,
22
23
  setAiAutoCompleteSuggestion,
23
24
  showCompletionHint,
@@ -201,6 +202,12 @@ export class AiCodeCompletionProvider {
201
202
  if (!this.#aiCodeCompletion || !this.#editor || !hasActiveAiSuggestion(this.#editor.state)) {
202
203
  return false;
203
204
  }
205
+ if (this.#editor.state.field(aiAutoCompleteSuggestionState)?.source === AiSuggestionSource.GENERATION) {
206
+ // If the suggestion is from code generation, we don't want to
207
+ // dismiss it here. The user should use the code generation
208
+ // provider's keymap to dismiss the suggestion.
209
+ return false;
210
+ }
204
211
  this.#editor.dispatch({
205
212
  effects: setAiAutoCompleteSuggestion.of(null),
206
213
  });
@@ -347,6 +354,7 @@ export class AiCodeCompletionProvider {
347
354
  startTime,
348
355
  clearCachedRequest: this.clearCache.bind(this),
349
356
  onImpression: this.#aiCodeCompletion?.registerUserImpression.bind(this.#aiCodeCompletion),
357
+ source: AiSuggestionSource.COMPLETION,
350
358
  })
351
359
  });
352
360
  }
@@ -4,7 +4,7 @@
4
4
 
5
5
  import * as CodeMirror from '../../../third_party/codemirror.next/codemirror.next.js';
6
6
 
7
- const LINE_COMMENT_PATTERN = /^(?:\/\/|#)\s*/;
7
+ const LINE_COMMENT_PATTERN = /^(?:\/\/|#)\s*/gm;
8
8
  const BLOCK_COMMENT_START_PATTERN = /^\/\*+\s*/;
9
9
  const BLOCK_COMMENT_END_PATTERN = /\s*\*+\/$/;
10
10
  const BLOCK_COMMENT_LINE_PREFIX_PATTERN = /^\s*\*\s?/;
@@ -51,7 +51,7 @@ function resolveCommentNode(state: CodeMirror.EditorState, cursorPosition: numbe
51
51
  return;
52
52
  }
53
53
 
54
- function extractBlockComment(rawText: string): string|undefined {
54
+ function extractBlockCommentText(rawText: string): string|undefined {
55
55
  // Remove /* and */, whitespace, and common leading asterisks on new lines
56
56
  if (!rawText.match(BLOCK_COMMENT_START_PATTERN)) {
57
57
  return;
@@ -66,8 +66,29 @@ function extractBlockComment(rawText: string): string|undefined {
66
66
  return cleaned;
67
67
  }
68
68
 
69
- function extractLineComment(rawText: string): string {
70
- return rawText.replace(LINE_COMMENT_PATTERN, '').trim();
69
+ function extractLineComment(node: CodeMirror.SyntaxNode, state: CodeMirror.EditorState): CommentNodeInfo|undefined {
70
+ let firstNode = node;
71
+ let lastNode = node;
72
+
73
+ let prev = node.prevSibling;
74
+ while (prev?.type.name.includes('LineComment')) {
75
+ firstNode = prev;
76
+ prev = prev.prevSibling;
77
+ }
78
+
79
+ let next = node.nextSibling;
80
+ while (next?.type.name.includes('LineComment')) {
81
+ lastNode = next;
82
+ next = next.nextSibling;
83
+ }
84
+
85
+ // Extract all lines between the first and last identified node
86
+ const fullRawText = state.doc.sliceString(firstNode.from, lastNode.to);
87
+
88
+ // Process each line to remove prefixes (// or #)
89
+ const concatenatedText = fullRawText.replaceAll(LINE_COMMENT_PATTERN, '').replace(/\n\s*\n/g, '\n').trim();
90
+
91
+ return concatenatedText ? {text: concatenatedText, to: lastNode.to} : undefined;
71
92
  }
72
93
 
73
94
  export class AiCodeGenerationParser {
@@ -80,9 +101,10 @@ export class AiCodeGenerationParser {
80
101
  const rawText = state.doc.sliceString(node.from, node.to);
81
102
  let text = '';
82
103
  if (nodeType.includes('LineComment')) {
83
- text = extractLineComment(rawText);
84
- } else if (nodeType.includes('BlockComment')) {
85
- text = extractBlockComment(rawText) ?? '';
104
+ return extractLineComment(node, state);
105
+ }
106
+ if (nodeType.includes('BlockComment')) {
107
+ text = extractBlockCommentText(rawText) ?? '';
86
108
  } else {
87
109
  text = rawText;
88
110
  }
@@ -19,6 +19,7 @@ import {
19
19
  acceptAiAutoCompleteSuggestion,
20
20
  aiAutoCompleteSuggestion,
21
21
  aiAutoCompleteSuggestionState,
22
+ AiSuggestionSource,
22
23
  hasActiveAiSuggestion,
23
24
  setAiAutoCompleteSuggestion,
24
25
  } from './config.js';
@@ -159,6 +160,12 @@ export class AiCodeGenerationProvider {
159
160
  return false;
160
161
  }
161
162
  if (hasActiveAiSuggestion(this.#editor.state)) {
163
+ if (this.#editor.state.field(aiAutoCompleteSuggestionState)?.source === AiSuggestionSource.COMPLETION) {
164
+ // If the suggestion is from code completion, we don't want to
165
+ // dismiss it here. The user should use the code completion
166
+ // provider's keymap to dismiss the suggestion.
167
+ return false;
168
+ }
162
169
  this.#dismissTeaserAndSuggestion();
163
170
  return true;
164
171
  }
@@ -175,20 +182,11 @@ export class AiCodeGenerationProvider {
175
182
  },
176
183
  {
177
184
  key: 'Tab',
178
- run: (): boolean => {
179
- if (!this.#aiCodeGeneration || !this.#editor || !hasActiveAiSuggestion(this.#editor.state)) {
180
- return false;
181
- }
182
- const {accepted, suggestion} = acceptAiAutoCompleteSuggestion(this.#editor.editor);
183
- if (!accepted) {
184
- return false;
185
- }
186
- if (suggestion?.rpcGlobalId) {
187
- this.#aiCodeGeneration.registerUserAcceptance(suggestion.rpcGlobalId, suggestion.sampleId);
188
- }
189
- this.#aiCodeGenerationConfig?.onSuggestionAccepted(this.#aiCodeGenerationCitations);
190
- return true;
191
- },
185
+ run: this.#acceptAiSuggestion.bind(this),
186
+ },
187
+ {
188
+ key: 'Enter',
189
+ run: this.#acceptAiSuggestion.bind(this),
192
190
  },
193
191
  {
194
192
  any: (_view: unknown, event: KeyboardEvent) => {
@@ -241,6 +239,21 @@ export class AiCodeGenerationProvider {
241
239
  });
242
240
  }
243
241
 
242
+ #acceptAiSuggestion(): boolean {
243
+ if (!this.#aiCodeGeneration || !this.#editor || !hasActiveAiSuggestion(this.#editor.state)) {
244
+ return false;
245
+ }
246
+ const {accepted, suggestion} = acceptAiAutoCompleteSuggestion(this.#editor.editor);
247
+ if (!accepted) {
248
+ return false;
249
+ }
250
+ if (suggestion?.rpcGlobalId) {
251
+ this.#aiCodeGeneration.registerUserAcceptance(suggestion.rpcGlobalId, suggestion.sampleId);
252
+ }
253
+ this.#aiCodeGenerationConfig?.onSuggestionAccepted(this.#aiCodeGenerationCitations);
254
+ return true;
255
+ }
256
+
244
257
  #activateTeaser(update: CodeMirror.ViewUpdate): void {
245
258
  const currentTeaserMode = update.state.field(aiCodeGenerationTeaserModeState);
246
259
  if (currentTeaserMode === AiCodeGenerationTeaserMode.ACTIVE) {
@@ -335,12 +348,13 @@ export class AiCodeGenerationProvider {
335
348
  this.#editor.dispatch({
336
349
  effects: [
337
350
  setAiAutoCompleteSuggestion.of({
338
- text: '\n' + suggestionText,
351
+ text: '\n' + suggestionText + '\n',
339
352
  from: commentNodeInfo.to,
340
353
  rpcGlobalId: generationResponse.metadata.rpcGlobalId,
341
354
  sampleId: topSample.sampleId,
342
355
  startTime,
343
356
  onImpression: this.#aiCodeGeneration?.registerUserImpression.bind(this.#aiCodeGeneration),
357
+ source: AiSuggestionSource.GENERATION,
344
358
  }),
345
359
  setAiCodeGenerationTeaserMode.of(AiCodeGenerationTeaserMode.ACTIVE)
346
360
  ]
@@ -441,9 +455,19 @@ function aiCodeGenerationTeaserExtension(teaser: PanelCommon.AiCodeGenerationTea
441
455
  // Required for mouse hover to propagate to the info button in teaser.
442
456
  return (event.target instanceof Node && teaser.contentElement.contains(event.target));
443
457
  },
444
- mousedown(event: MouseEvent): boolean {
445
- // Required for mouse click to propagate to the info tooltip in teaser.
446
- return (event.target instanceof Node && teaser.contentElement.contains(event.target));
458
+ mousedown(event: MouseEvent, view: CodeMirror.EditorView): boolean {
459
+ if (!(event.target instanceof Node) || !teaser.contentElement.contains(event.target)) {
460
+ return false;
461
+ }
462
+ // On mouse click, move the cursor position to the end of the line.
463
+ const cursorPosition = view.state.selection.main.head;
464
+ const line = view.state.doc.lineAt(cursorPosition);
465
+ if (cursorPosition !== line.to) {
466
+ view.dispatch({selection: {anchor: line.to, head: line.to}});
467
+ }
468
+ // Explicitly focus the editor.
469
+ view.focus();
470
+ return true;
447
471
  },
448
472
  keydown(event: KeyboardEvent): boolean {
449
473
  if (!UI.KeyboardShortcut.KeyboardShortcut.eventHasCtrlEquivalentKey(event) ||
@@ -483,6 +483,11 @@ export function contentIncludingHint(view: CM.EditorView): string {
483
483
 
484
484
  export const setAiAutoCompleteSuggestion = CM.StateEffect.define<ActiveSuggestion|null>();
485
485
 
486
+ export const enum AiSuggestionSource {
487
+ COMPLETION = 'completion',
488
+ GENERATION = 'generation',
489
+ }
490
+
486
491
  export interface ActiveSuggestion {
487
492
  text: string;
488
493
  from: number;
@@ -491,6 +496,7 @@ export interface ActiveSuggestion {
491
496
  startTime: number;
492
497
  onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number) => void;
493
498
  clearCachedRequest?: () => void;
499
+ source: AiSuggestionSource;
494
500
  }
495
501
 
496
502
  export const aiAutoCompleteSuggestionState = CM.StateField.define<ActiveSuggestion|null>({
@@ -8,7 +8,6 @@ import * as Host from '../../core/host/host.js';
8
8
  import * as i18n from '../../core/i18n/i18n.js';
9
9
  import * as Root from '../../core/root/root.js';
10
10
  import * as SDK from '../../core/sdk/sdk.js';
11
- import * as GreenDev from '../../models/greendev/greendev.js';
12
11
  import * as Buttons from '../../ui/components/buttons/buttons.js';
13
12
  import {createIcon, type Icon} from '../kit/kit.js';
14
13
  import * as VisualLogging from '../visual_logging/visual_logging.js';
@@ -20,7 +19,6 @@ import type {Context} from './Context.js';
20
19
  import type {ContextMenu} from './ContextMenu.js';
21
20
  import {Dialog} from './Dialog.js';
22
21
  import {DockController, DockState, Events as DockControllerEvents} from './DockController.js';
23
- import {Floaty} from './Floaty.js';
24
22
  import {GlassPane} from './GlassPane.js';
25
23
  import {Infobar, Type as InfobarType} from './Infobar.js';
26
24
  import {KeyboardShortcut} from './KeyboardShortcut.js';
@@ -54,6 +52,14 @@ const UIStrings = {
54
52
  * @description Title of an action that reloads the DevTools
55
53
  */
56
54
  reloadDevtools: 'Reload DevTools',
55
+ /**
56
+ * @description Title of an action that restarts Chrome
57
+ */
58
+ restartChrome: 'Restart Chrome',
59
+ /**
60
+ * @description Confirmation dialog text for restarting Chrome
61
+ */
62
+ areYouSureYouWantToRestartChrome: 'Are you sure you want to restart Chrome?',
57
63
  /**
58
64
  * @description Text for context menu action to move a tab to the main tab bar
59
65
  */
@@ -155,6 +161,7 @@ export class InspectorView extends VBox implements ViewLocationResolver {
155
161
  private focusRestorer?: WidgetFocusRestorer|null;
156
162
  private ownerSplitWidget?: SplitWidget;
157
163
  private reloadRequiredInfobar?: Infobar;
164
+ #chromeRestartRequiredInfobar?: Infobar;
158
165
  #debuggedTabReloadRequiredInfobar?: Infobar;
159
166
  #selectOverrideFolderInfobar?: Infobar;
160
167
  #resizeObserver: ResizeObserver;
@@ -362,10 +369,6 @@ export class InspectorView extends VBox implements ViewLocationResolver {
362
369
  this.element.style.setProperty('--devtools-window-top', `${rect.top}px`);
363
370
  this.element.style.setProperty('--devtools-window-bottom', `${window.innerHeight - rect.bottom}px`);
364
371
  this.element.style.setProperty('--devtools-window-height', `${rect.height}px`);
365
-
366
- if (Floaty.exists()) {
367
- Floaty.instance().setDevToolsRect(rect);
368
- }
369
372
  }
370
373
 
371
374
  override wasShown(): void {
@@ -376,13 +379,6 @@ export class InspectorView extends VBox implements ViewLocationResolver {
376
379
  DockController.instance().addEventListener(
377
380
  DockControllerEvents.DOCK_SIDE_CHANGED, this.#applyDrawerOrientationForDockSide, this);
378
381
  this.#applyDrawerOrientationForDockSide();
379
-
380
- if (GreenDev.Prototypes.instance().isEnabled('inDevToolsFloaty')) {
381
- Floaty.instance({
382
- forceNew: true,
383
- document: this.element.ownerDocument,
384
- });
385
- }
386
382
  }
387
383
 
388
384
  override willHide(): void {
@@ -676,7 +672,7 @@ export class InspectorView extends VBox implements ViewLocationResolver {
676
672
  }
677
673
 
678
674
  displayReloadRequiredWarning(message: string): void {
679
- if (!this.reloadRequiredInfobar) {
675
+ if (!this.reloadRequiredInfobar && !this.#chromeRestartRequiredInfobar) {
680
676
  const infobar = new Infobar(
681
677
  InfobarType.INFO, message,
682
678
  [
@@ -693,7 +689,37 @@ export class InspectorView extends VBox implements ViewLocationResolver {
693
689
  this.attachInfobar(infobar);
694
690
  this.reloadRequiredInfobar = infobar;
695
691
  infobar.setCloseCallback(() => {
696
- delete this.reloadRequiredInfobar;
692
+ this.reloadRequiredInfobar = undefined;
693
+ });
694
+ }
695
+ }
696
+
697
+ displayChromeRestartRequiredWarning(message: string): void {
698
+ if (this.reloadRequiredInfobar) {
699
+ this.reloadRequiredInfobar.dispose();
700
+ }
701
+ if (!this.#chromeRestartRequiredInfobar) {
702
+ const infobar = new Infobar(
703
+ InfobarType.INFO, message,
704
+ [
705
+ {
706
+ text: i18nString(UIStrings.restartChrome),
707
+ delegate: () => {
708
+ if (confirm(i18nString(UIStrings.areYouSureYouWantToRestartChrome))) {
709
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.requestRestart();
710
+ }
711
+ },
712
+ dismiss: false,
713
+ buttonVariant: Buttons.Button.Variant.PRIMARY,
714
+ jslogContext: 'main.chrome-restart-chrome',
715
+ },
716
+ ],
717
+ undefined, 'reload-required');
718
+ infobar.setParentView(this);
719
+ this.attachInfobar(infobar);
720
+ this.#chromeRestartRequiredInfobar = infobar;
721
+ infobar.setCloseCallback(() => {
722
+ this.#chromeRestartRequiredInfobar = undefined;
697
723
  });
698
724
  }
699
725
  }
@@ -835,7 +835,7 @@ export class ToolbarInputElement extends HTMLElement {
835
835
 
836
836
  item?: ToolbarInput;
837
837
  datalist: HTMLDataListElement|null = null;
838
- value: string|undefined = undefined;
838
+ #value: string|undefined = undefined;
839
839
  #disabled = false;
840
840
 
841
841
  connectedCallback(): void {
@@ -862,8 +862,8 @@ export class ToolbarInputElement extends HTMLElement {
862
862
  /* shrinkFactor=*/ undefined, tooltip, this.datalist ? this.#onAutocomplete.bind(this) : undefined,
863
863
  /* dynamicCompletions=*/ undefined, jslogContext, this);
864
864
  }
865
- if (this.value) {
866
- this.item.setValue(this.value);
865
+ if (this.#value) {
866
+ this.item.setValue(this.#value);
867
867
  }
868
868
  if (this.#disabled) {
869
869
  this.item.setEnabled(false);
@@ -894,7 +894,7 @@ export class ToolbarInputElement extends HTMLElement {
894
894
  if (this.item && this.item.value() !== newValue) {
895
895
  this.item.setValue(newValue, true);
896
896
  } else {
897
- this.value = newValue;
897
+ this.#value = newValue;
898
898
  }
899
899
  } else if (name === 'disabled') {
900
900
  this.#disabled = typeof newValue === 'string';
@@ -904,6 +904,14 @@ export class ToolbarInputElement extends HTMLElement {
904
904
  }
905
905
  }
906
906
 
907
+ get value(): string {
908
+ return this.item ? this.item.value() : (this.#value ?? '');
909
+ }
910
+
911
+ set value(value: string) {
912
+ this.setAttribute('value', value);
913
+ }
914
+
907
915
  set disabled(disabled: boolean) {
908
916
  if (disabled) {
909
917
  this.setAttribute('disabled', '');
@@ -697,19 +697,42 @@ export class ElementFocusRestorer {
697
697
  export function runCSSAnimationOnce(element: Element, className: string): void {
698
698
  function animationEndCallback(): void {
699
699
  element.classList.remove(className);
700
- element.removeEventListener('webkitAnimationEnd', animationEndCallback, false);
700
+ element.removeEventListener('animationend', animationEndCallback, false);
701
701
  element.removeEventListener('animationcancel', animationEndCallback, false);
702
702
  }
703
703
 
704
- if (element.classList.contains(className)) {
705
- element.classList.remove(className);
706
- }
707
-
708
- element.addEventListener('webkitAnimationEnd', animationEndCallback, false);
704
+ // Remove class if it exists.
705
+ element.classList.toggle(className, /* force=*/ false);
706
+ element.addEventListener('animationend', animationEndCallback, false);
709
707
  element.addEventListener('animationcancel', animationEndCallback, false);
710
708
  element.classList.add(className);
711
709
  }
712
710
 
711
+ class AnimateOnDirective extends Lit.Directive.Directive {
712
+ #previousValue = false;
713
+
714
+ render(_condition: boolean, _className: string): void {
715
+ return undefined; // Directives don't have to render HTML
716
+ }
717
+
718
+ override update(part: Lit.Directive.ElementPart, [condition, className]: [boolean, string]): void {
719
+ const el = part.element as HTMLElement;
720
+
721
+ // Only trigger if the condition transitioned from false -> true
722
+ if (condition && !this.#previousValue) {
723
+ this.#animate(el, className);
724
+ }
725
+
726
+ this.#previousValue = condition;
727
+ }
728
+
729
+ #animate(el: HTMLElement, className: string): void {
730
+ runCSSAnimationOnce(el, className);
731
+ }
732
+ }
733
+
734
+ export const animateOn = Lit.Directive.directive(AnimateOnDirective);
735
+
713
736
  export function measurePreferredSize(element: Element, containerElement?: Element|null): Geometry.Size {
714
737
  const oldParent = element.parentElement;
715
738
  const oldNextSibling = element.nextSibling;
@@ -1530,6 +1553,7 @@ export function createFileSelectorElement(callback: (arg0: File) => void, accept
1530
1553
  }
1531
1554
 
1532
1555
  export const MaxLengthForDisplayedURLs = 150;
1556
+ export const MaxLengthForDisplayedURLsInConsole = 40;
1533
1557
 
1534
1558
  export class MessageDialog {
1535
1559
  static async show(header: string, message: string, where?: Element|Document, jslogContext?: string): Promise<void> {
@@ -2193,13 +2217,29 @@ export const bindCheckboxImpl = function(
2193
2217
  };
2194
2218
  };
2195
2219
 
2220
+ export type BindToSettingOpts = ((newSettingValue: string) => boolean)|{
2221
+ validator?: (newSettingValue: string) => boolean,
2222
+ jslog?: boolean,
2223
+ };
2196
2224
  export const bindToSetting =
2197
2225
  (settingOrName: string|Common.Settings.Setting<boolean|string>|Common.Settings.RegExpSetting,
2198
- stringValidator?: (newSettingValue: string) => boolean): ReturnType<typeof Directives.ref> => {
2226
+ optionsOrValidator?: BindToSettingOpts): ReturnType<typeof Directives.ref> => {
2199
2227
  const setting = typeof settingOrName === 'string' ?
2200
2228
  Common.Settings.Settings.instance().moduleSetting(settingOrName) :
2201
2229
  settingOrName;
2202
2230
 
2231
+ let stringValidator: ((newSettingValue: string) => boolean)|undefined;
2232
+ let jslog = true;
2233
+ if (typeof optionsOrValidator === 'function') {
2234
+ stringValidator = optionsOrValidator;
2235
+ } else if (optionsOrValidator) {
2236
+ stringValidator = optionsOrValidator.validator;
2237
+ if (optionsOrValidator.jslog !== undefined) {
2238
+ jslog = optionsOrValidator.jslog;
2239
+ }
2240
+ }
2241
+
2242
+ const jslogBuilder = jslog ? VisualLogging.toggle(setting.name).track({change: true}) : null;
2203
2243
  // We can't use `setValue` as the change listener directly, otherwise we won't
2204
2244
  // be able to remove it again.
2205
2245
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -2214,6 +2254,9 @@ export const bindToSetting =
2214
2254
  setting.removeChangeListener(settingChanged);
2215
2255
  return;
2216
2256
  }
2257
+ if (jslogBuilder) {
2258
+ e.setAttribute('jslog', jslogBuilder.toString());
2259
+ }
2217
2260
 
2218
2261
  setting.addChangeListener(settingChanged);
2219
2262
  setValue =
@@ -2229,6 +2272,9 @@ export const bindToSetting =
2229
2272
  return;
2230
2273
  }
2231
2274
 
2275
+ if (jslogBuilder) {
2276
+ e.setAttribute('jslog', jslogBuilder.toString());
2277
+ }
2232
2278
  setting.addChangeListener(settingChanged);
2233
2279
  setValue = bindInput(e as HTMLInputElement, setting.set.bind(setting), (value: string) => {
2234
2280
  try {
@@ -2249,6 +2295,9 @@ export const bindToSetting =
2249
2295
  return;
2250
2296
  }
2251
2297
 
2298
+ if (jslogBuilder) {
2299
+ e.setAttribute('jslog', jslogBuilder.toString());
2300
+ }
2252
2301
  setting.addChangeListener(settingChanged);
2253
2302
  setValue = bindInput(
2254
2303
  e as HTMLInputElement, setting.set.bind(setting), stringValidator ?? (() => true), /* numeric */ false);
@@ -275,8 +275,8 @@ export const enum PanelOrDrawer {
275
275
  export class CommandMenuProvider extends Provider {
276
276
  private commands: Command[];
277
277
 
278
- constructor(commandsForTest: Command[] = []) {
279
- super('command');
278
+ constructor(jslogContext: string, commandsForTest: Command[] = []) {
279
+ super(jslogContext);
280
280
  this.commands = commandsForTest;
281
281
  }
282
282
 
@@ -455,8 +455,9 @@ export class ShowActionDelegate implements UI.ActionRegistration.ActionDelegate
455
455
  registerProvider({
456
456
  prefix: '>',
457
457
  iconName: 'chevron-right',
458
- provider: () => Promise.resolve(new CommandMenuProvider()),
458
+ provider: (jslogContext: string) => Promise.resolve(new CommandMenuProvider(jslogContext)),
459
459
  helpTitle: () => i18nString(UIStrings.runCommand),
460
460
  titlePrefix: () => i18nString(UIStrings.run),
461
461
  titleSuggestion: () => i18nString(UIStrings.command),
462
+ jslogContext: 'command',
462
463
  });
@@ -657,8 +657,9 @@ export function getRegisteredProviders(): ProviderRegistration[] {
657
657
  export interface ProviderRegistration {
658
658
  prefix: string;
659
659
  iconName: string;
660
- provider: () => Promise<Provider>;
660
+ provider: (jslogContext: string) => Promise<Provider>;
661
661
  helpTitle: (() => string);
662
662
  titlePrefix: (() => string);
663
663
  titleSuggestion?: (() => string);
664
+ jslogContext: string;
664
665
  }
@@ -24,11 +24,16 @@ export class HelpQuickOpen extends Provider {
24
24
  }
25
25
 
26
26
  private async addProvider(extension: ProviderRegistration): Promise<void> {
27
+ // We want to exclude Help menu as we are already in it.
28
+ if (extension.prefix === '?') {
29
+ return;
30
+ }
31
+
27
32
  this.providers.push({
28
33
  prefix: extension.prefix || '',
29
34
  iconName: extension.iconName,
30
35
  title: extension.helpTitle(),
31
- jslogContext: (await extension.provider()).jslogContext,
36
+ jslogContext: extension.jslogContext,
32
37
  });
33
38
  }
34
39
 
@@ -69,8 +74,9 @@ export class HelpQuickOpen extends Provider {
69
74
  registerProvider({
70
75
  prefix: '?',
71
76
  iconName: 'help',
72
- provider: () => Promise.resolve(new HelpQuickOpen('help')),
77
+ provider: jslogContext => Promise.resolve(new HelpQuickOpen(jslogContext)),
73
78
  helpTitle: () => 'Help',
74
79
  titlePrefix: () => 'Help',
75
80
  titleSuggestion: undefined,
81
+ jslogContext: 'help'
76
82
  });
@@ -5,7 +5,12 @@
5
5
  import * as i18n from '../../../../core/i18n/i18n.js';
6
6
  import type * as UI from '../../legacy.js';
7
7
 
8
- import {FilteredListWidget, getRegisteredProviders, type Provider} from './FilteredListWidget.js';
8
+ import {
9
+ FilteredListWidget,
10
+ getRegisteredProviders,
11
+ type Provider,
12
+ type ProviderRegistration
13
+ } from './FilteredListWidget.js';
9
14
 
10
15
  const UIStrings = {
11
16
  /**
@@ -42,19 +47,14 @@ export class QuickOpenImpl {
42
47
  filteredListWidget.setQuery(query);
43
48
  }
44
49
 
45
- private addProvider(extension: {
46
- prefix: string,
47
- provider: () => Promise<Provider>,
48
- titlePrefix: () => string,
49
- titleSuggestion?: (() => string),
50
- }): void {
50
+ private addProvider(extension: ProviderRegistration): void {
51
51
  const prefix = extension.prefix;
52
52
  if (prefix === null) {
53
53
  return;
54
54
  }
55
55
  this.prefixes.push(prefix);
56
56
  this.providers.set(prefix, {
57
- provider: extension.provider,
57
+ provider: () => extension.provider(extension.jslogContext),
58
58
  titlePrefix: extension.titlePrefix,
59
59
  titleSuggestion: extension.titleSuggestion,
60
60
  });