chrome-devtools-frontend 1.0.1529904 → 1.0.1531367

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 (131) hide show
  1. package/eslint.config.mjs +1 -1
  2. package/front_end/core/common/Worker.ts +10 -2
  3. package/front_end/core/host/AidaClient.ts +3 -3
  4. package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -2
  5. package/front_end/core/sdk/NetworkManager.ts +180 -42
  6. package/front_end/core/sdk/SourceMap.ts +6 -1
  7. package/front_end/core/sdk/SourceMapScopesInfo.ts +73 -7
  8. package/front_end/entrypoints/main/main-meta.ts +2 -0
  9. package/front_end/entrypoints/trace_app/trace_app.ts +1 -0
  10. package/front_end/generated/SupportedCSSProperties.js +7 -0
  11. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatterBounds.snapshot.txt +4 -0
  12. package/front_end/models/ai_assistance/performance/AICallTree.ts +2 -3
  13. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +3 -3
  14. package/front_end/models/bindings/CompilerScriptMapping.ts +16 -14
  15. package/front_end/models/formatter/FormatterWorkerPool.ts +17 -1
  16. package/front_end/models/javascript_metadata/NativeFunctions.js +8 -2
  17. package/front_end/models/trace/ModelImpl.ts +8 -3
  18. package/front_end/models/trace/handlers/MetaHandler.ts +9 -1
  19. package/front_end/models/trace/types/Configuration.ts +1 -0
  20. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +1 -1
  21. package/front_end/panels/browser_debugger/browser_debugger-meta.ts +2 -1
  22. package/front_end/panels/changes/CombinedDiffView.ts +1 -2
  23. package/front_end/panels/console/ConsoleInsightTeaser.ts +120 -59
  24. package/front_end/panels/console/ConsolePrompt.ts +1 -1
  25. package/front_end/panels/console/ConsoleSidebar.ts +3 -3
  26. package/front_end/panels/console/ConsoleViewMessage.ts +7 -5
  27. package/front_end/panels/console/consoleInsightTeaser.css +0 -4
  28. package/front_end/panels/elements/ElementsTreeOutline.ts +1 -2
  29. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +137 -37
  30. package/front_end/panels/mobile_throttling/ThrottlingPresets.ts +1 -1
  31. package/front_end/panels/network/BlockedURLsPane.ts +30 -6
  32. package/front_end/panels/network/NetworkLogView.ts +135 -33
  33. package/front_end/panels/network/blockedURLsPane.css +5 -0
  34. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +1 -1
  35. package/front_end/panels/sources/SourcesPanel.ts +5 -0
  36. package/front_end/panels/sources/sources-meta.ts +14 -12
  37. package/front_end/panels/sources/sourcesView.css +1 -0
  38. package/front_end/panels/timeline/TimelinePanel.ts +1 -0
  39. package/front_end/panels/timeline/TimelineSelectorStatsView.ts +1 -2
  40. package/front_end/panels/timeline/TimelineTreeView.ts +3 -3
  41. package/front_end/panels/timeline/TimelineUIUtils.ts +16 -16
  42. package/front_end/services/tracing/FreshRecording.ts +4 -0
  43. package/front_end/third_party/chromium/README.chromium +1 -1
  44. package/front_end/third_party/puppeteer/README.chromium +2 -2
  45. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
  46. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js +16 -0
  47. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js.map +1 -1
  48. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts +2 -2
  49. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
  50. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +9 -4
  51. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
  52. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserConnector.d.ts.map +1 -1
  53. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserConnector.js +2 -2
  54. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserConnector.js.map +1 -1
  55. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConnectOptions.d.ts +7 -0
  56. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConnectOptions.d.ts.map +1 -1
  57. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/util.js +1 -1
  58. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/util.js.map +1 -1
  59. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  60. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
  61. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js +12 -5
  62. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js.map +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.js +1 -1
  64. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.js.map +1 -1
  65. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  66. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  67. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  68. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  69. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +7 -0
  70. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts.map +1 -0
  71. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +13 -0
  72. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js.map +1 -0
  73. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +7 -0
  74. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +40 -14
  75. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js +16 -0
  76. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js.map +1 -1
  77. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts +2 -2
  78. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
  79. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +9 -4
  80. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
  81. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserConnector.d.ts.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserConnector.js +2 -2
  83. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserConnector.js.map +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConnectOptions.d.ts +7 -0
  85. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConnectOptions.d.ts.map +1 -1
  86. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/util.js +1 -1
  87. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/util.js.map +1 -1
  88. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
  89. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js +12 -5
  90. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js.map +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.js +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.js.map +1 -1
  93. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  94. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  95. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +7 -0
  97. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts.map +1 -0
  98. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +10 -0
  99. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js.map +1 -0
  100. package/front_end/third_party/puppeteer/package/lib/types.d.ts +7 -0
  101. package/front_end/third_party/puppeteer/package/package.json +4 -4
  102. package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +18 -0
  103. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +9 -1
  104. package/front_end/third_party/puppeteer/package/src/cdp/BrowserConnector.ts +2 -0
  105. package/front_end/third_party/puppeteer/package/src/common/ConnectOptions.ts +8 -0
  106. package/front_end/third_party/puppeteer/package/src/common/util.ts +1 -1
  107. package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +16 -5
  108. package/front_end/third_party/puppeteer/package/src/node/NodeWebSocketTransport.ts +1 -1
  109. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  110. package/front_end/third_party/puppeteer/package/src/util/version.ts +10 -0
  111. package/front_end/third_party/puppeteer/puppeteer-tsconfig.json +1 -1
  112. package/front_end/ui/components/icon_button/Icon.docs.ts +78 -0
  113. package/front_end/ui/components/markdown_view/CodeBlock.ts +2 -2
  114. package/front_end/ui/components/text_editor/config.ts +3 -3
  115. package/front_end/ui/components/tooltips/Tooltip.ts +9 -4
  116. package/front_end/ui/legacy/UIUtils.ts +12 -0
  117. package/front_end/ui/visual_logging/KnownContextValues.ts +6 -0
  118. package/package.json +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +0 -5
  120. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts.map +0 -1
  121. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +0 -8
  122. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js.map +0 -1
  123. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +0 -5
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts.map +0 -1
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +0 -5
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js.map +0 -1
  127. package/front_end/third_party/puppeteer/package/src/generated/version.ts +0 -4
  128. package/front_end/ui/components/copy_to_clipboard/copyToClipboard.ts +0 -19
  129. package/front_end/ui/components/copy_to_clipboard/copy_to_clipboard.ts +0 -5
  130. package/front_end/ui/components/docs/icon_component/basic.html +0 -40
  131. package/front_end/ui/components/docs/icon_component/basic.ts +0 -68
@@ -257,10 +257,10 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
257
257
 
258
258
  async #generateSampleForRequest(request: Host.AidaClient.CompletionRequest, cursor: number): Promise<{
259
259
  suggestionText: string,
260
- sampleId: number,
261
260
  fromCache: boolean,
262
261
  citations: Host.AidaClient.Citation[],
263
262
  rpcGlobalId?: Host.AidaClient.RpcGlobalId,
263
+ sampleId?: number,
264
264
  }|null> {
265
265
  const {response, fromCache} = await this.#completeCodeCached(request);
266
266
  debugLog('At cursor position', cursor, {request, response, fromCache});
@@ -417,7 +417,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
417
417
  this.#aidaRequestCache = {request, response};
418
418
  }
419
419
 
420
- #registerUserImpression(rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId: number, latency: number): void {
420
+ #registerUserImpression(rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number): void {
421
421
  const seconds = Math.floor(latency / 1_000);
422
422
  const remainingMs = latency % 1_000;
423
423
  const nanos = Math.floor(remainingMs * 1_000_000);
@@ -443,7 +443,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
443
443
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionSuggestionDisplayed);
444
444
  }
445
445
 
446
- registerUserAcceptance(rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId: number): void {
446
+ registerUserAcceptance(rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId?: number): void {
447
447
  void this.#aidaClient.registerClientEvent({
448
448
  corresponding_aida_rpc_global_id: rpcGlobalId,
449
449
  disable_user_content_logging: true,
@@ -296,28 +296,30 @@ export class CompilerScriptMapping implements DebuggerSourceMapping {
296
296
  const {sourceMap, script} = sourceMapAndScript;
297
297
  const {lineNumber, columnNumber} = script.relativeLocationToRawLocation(frame);
298
298
 
299
- if (!sourceMap.hasInlinedFrames(lineNumber, columnNumber) && !sourceMap.isOutlinedFrame(lineNumber, columnNumber)) {
300
- // No outlining or inlining: Get the original function name and map the call-site.
301
- const mapping = sourceMap.findEntry(lineNumber, columnNumber);
302
- if (!mapping?.sourceURL) {
299
+ if (!sourceMap.isOutlinedFrame(lineNumber, columnNumber)) {
300
+ const frames = sourceMap.translateCallSite(lineNumber, columnNumber);
301
+ if (!frames.length) {
303
302
  return false;
304
303
  }
305
304
 
306
- const originalName = sourceMap.findOriginalFunctionName({line: lineNumber, column: columnNumber});
307
305
  rawFrames.shift();
306
+ const result: typeof translatedFrames[0] = [];
307
+ translatedFrames.push(result);
308
+
308
309
  const project = this.#sourceMapToProject.get(sourceMap);
309
- const uiSourceCode = project?.uiSourceCodeForURL(mapping.sourceURL);
310
- translatedFrames.push([{
311
- line: mapping.sourceLineNumber,
312
- column: mapping.sourceColumnNumber,
313
- name: originalName ?? undefined,
314
- uiSourceCode: uiSourceCode ?? undefined,
315
- url: uiSourceCode ? undefined : mapping.sourceURL
316
- }]);
310
+ for (const frame of frames) {
311
+ // Switch out url for UISourceCode where we have it.
312
+ const uiSourceCode = frame.url ? project?.uiSourceCodeForURL(frame.url) : undefined;
313
+ result.push({
314
+ ...frame,
315
+ url: uiSourceCode ? undefined : frame.url,
316
+ uiSourceCode: uiSourceCode ?? undefined,
317
+ });
318
+ }
319
+
317
320
  return true;
318
321
  }
319
322
 
320
- // TODO(crbug.com/433162438): Expand inlined frames.
321
323
  // TODO(crbug.com/433162438): Consolidate outlined frames.
322
324
  return false;
323
325
  }
@@ -7,7 +7,7 @@ import * as FormatterActions from '../../entrypoints/formatter_worker/FormatterA
7
7
 
8
8
  export {DefinitionKind, ScopeKind, type ScopeTreeNode} from '../../entrypoints/formatter_worker/FormatterActions.js';
9
9
 
10
- let formatterWorkerPoolInstance: FormatterWorkerPool;
10
+ let formatterWorkerPoolInstance: FormatterWorkerPool|undefined;
11
11
 
12
12
  export class FormatterWorkerPool {
13
13
  private taskQueue: Task[];
@@ -26,6 +26,22 @@ export class FormatterWorkerPool {
26
26
  return formatterWorkerPoolInstance;
27
27
  }
28
28
 
29
+ dispose(): void {
30
+ for (const task of this.taskQueue) {
31
+ console.error('rejecting task');
32
+ task.errorCallback(new Event('Worker terminated'));
33
+ }
34
+ for (const [worker, task] of this.workerTasks.entries()) {
35
+ task?.errorCallback(new Event('Worker terminated'));
36
+ worker.terminate(/* immediately=*/ true);
37
+ }
38
+ }
39
+
40
+ static removeInstance(): void {
41
+ formatterWorkerPoolInstance?.dispose();
42
+ formatterWorkerPoolInstance = undefined;
43
+ }
44
+
29
45
  private createWorker(): Common.Worker.WorkerWrapper {
30
46
  const worker = Common.Worker.WorkerWrapper.fromURL(
31
47
  new URL('../../entrypoints/formatter_worker/formatter_worker-entrypoint.js', import.meta.url));
@@ -687,7 +687,7 @@ export const NativeFunctions = [
687
687
  {
688
688
  name: "toJSON",
689
689
  signatures: [["?key"]],
690
- receivers: ["Date"]
690
+ receivers: ["Date","CSPViolationReportBody","ReportBody","CoopAccessViolationReportBody","DeprecationReportBody","DocumentPolicyViolationReportBody","IntegrityViolationReportBody","InterventionReportBody","PermissionsPolicyViolationReportBody","TestReportBody"]
691
691
  },
692
692
  {
693
693
  name: "parse",
@@ -6041,7 +6041,13 @@ export const NativeFunctions = [
6041
6041
  },
6042
6042
  {
6043
6043
  name: "waitUntil",
6044
- signatures: [["f"]]
6044
+ signatures: [["f"]],
6045
+ receivers: ["ExtendableEvent"]
6046
+ },
6047
+ {
6048
+ name: "waitUntil",
6049
+ signatures: [["promise"]],
6050
+ receivers: ["ViewTransition"]
6045
6051
  },
6046
6052
  {
6047
6053
  name: "respondWith",
@@ -81,8 +81,13 @@ export class Model extends EventTarget {
81
81
  * });
82
82
  * void this.traceModel.parse(events);
83
83
  **/
84
- async parse(traceEvents: readonly Types.Events.Event[], config?: Types.Configuration.ParseOptions): Promise<void> {
85
- const metadata = config?.metadata || {};
84
+ async parse(traceEvents: readonly Types.Events.Event[], config: Types.Configuration.ParseOptions = {}):
85
+ Promise<void> {
86
+ if (config.showAllEvents === undefined) {
87
+ config.showAllEvents = this.#config.showAllEvents;
88
+ }
89
+
90
+ const metadata = config.metadata || {};
86
91
  // During parsing, periodically update any listeners on each processors'
87
92
  // progress (if they have any updates).
88
93
  const onTraceUpdate = (event: Event): void => {
@@ -98,7 +103,7 @@ export class Model extends EventTarget {
98
103
  try {
99
104
  // Wait for all outstanding promises before finishing the async execution,
100
105
  // but perform all tasks in parallel.
101
- await this.#processor.parse(traceEvents, config ?? {});
106
+ await this.#processor.parse(traceEvents, config);
102
107
  if (!this.#processor.data) {
103
108
  throw new Error('processor did not parse trace');
104
109
  }
@@ -6,6 +6,10 @@ import * as Platform from '../../../core/platform/platform.js';
6
6
  import * as Helpers from '../helpers/helpers.js';
7
7
  import * as Types from '../types/types.js';
8
8
 
9
+ import type {FinalizeOptions} from './types.js';
10
+
11
+ let config: {showAllEvents: boolean};
12
+
9
13
  // We track the renderer processes we see in each frame on the way through the trace.
10
14
  let rendererProcessesByFrameId: FrameProcessData = new Map();
11
15
 
@@ -349,7 +353,9 @@ export function handleEvent(event: Types.Events.Event): void {
349
353
  }
350
354
  }
351
355
 
352
- export async function finalize(): Promise<void> {
356
+ export async function finalize(options?: FinalizeOptions): Promise<void> {
357
+ config = {showAllEvents: Boolean(options?.showAllEvents)};
358
+
353
359
  // We try to set the minimum time by finding the event with the smallest
354
360
  // timestamp. However, if we also got a timestamp from the
355
361
  // TracingStartedInBrowser event, we should always use that.
@@ -431,6 +437,7 @@ export async function finalize(): Promise<void> {
431
437
  }
432
438
 
433
439
  export interface MetaHandlerData {
440
+ config: {showAllEvents: boolean};
434
441
  traceIsGeneric: boolean;
435
442
  traceBounds: Types.Timing.TraceWindowMicro;
436
443
  browserProcessId: Types.Events.ProcessID;
@@ -494,6 +501,7 @@ export type FrameProcessData =
494
501
 
495
502
  export function data(): MetaHandlerData {
496
503
  return {
504
+ config,
497
505
  traceBounds,
498
506
  browserProcessId,
499
507
  browserThreadId,
@@ -66,6 +66,7 @@ export function configToCacheKey(config: Configuration): string {
66
66
  }
67
67
 
68
68
  export interface ParseOptions {
69
+ showAllEvents?: boolean;
69
70
  /**
70
71
  * If the trace was just recorded on the current page, rather than an imported file.
71
72
  * TODO(paulirish): Maybe remove. This is currently unused by the Processor and Handlers
@@ -1187,7 +1187,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1187
1187
 
1188
1188
  contextMenu.defaultSection().appendCheckboxItem(title, () => {
1189
1189
  void this.#openHistoricConversation(conversation);
1190
- }, {checked: (this.#conversation === conversation)});
1190
+ }, {checked: (this.#conversation === conversation), jslogContext: 'freestyler.history-item'});
1191
1191
  }
1192
1192
 
1193
1193
  const historyEmpty = contextMenu.defaultSection().items.length === 0;
@@ -215,6 +215,7 @@ UI.ViewManager.registerViewExtension({
215
215
  commandPrompt: i18nLazyString(UIStrings.showOverrides),
216
216
  order: 4,
217
217
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
218
+ condition: () => !Root.Runtime.Runtime.isTraceApp(),
218
219
  async loadView() {
219
220
  const Sources = await loadSourcesModule();
220
221
  return Sources.SourcesNavigator.OverridesNavigatorView.instance();
@@ -228,7 +229,7 @@ UI.ViewManager.registerViewExtension({
228
229
  commandPrompt: i18nLazyString(UIStrings.showContentScripts),
229
230
  order: 5,
230
231
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
231
- condition: () => Root.Runtime.getPathName() !== '/bundled/worker_app.html',
232
+ condition: () => Root.Runtime.getPathName() !== '/bundled/worker_app.html' && !Root.Runtime.Runtime.isTraceApp(),
232
233
  async loadView() {
233
234
  const Sources = await loadSourcesModule();
234
235
  return new Sources.SourcesNavigator.ContentScriptsNavigatorView();
@@ -10,7 +10,6 @@ import type * as Workspace from '../../models/workspace/workspace.js';
10
10
  import * as WorkspaceDiff from '../../models/workspace_diff/workspace_diff.js';
11
11
  import type * as Diff from '../../third_party/diff/diff.js';
12
12
  import * as Buttons from '../../ui/components/buttons/buttons.js';
13
- import * as CopyToClipboard from '../../ui/components/copy_to_clipboard/copy_to_clipboard.js';
14
13
  import type * as DiffView from '../../ui/components/diff_view/diff_view.js';
15
14
  import * as UI from '../../ui/legacy/legacy.js';
16
15
  import * as Lit from '../../ui/lit/lit.js';
@@ -168,7 +167,7 @@ export class CombinedDiffView extends UI.Widget.Widget {
168
167
  return;
169
168
  }
170
169
 
171
- CopyToClipboard.copyTextToClipboard(content.text, i18nString(UIStrings.copied));
170
+ UI.UIUtils.copyTextToClipboard(content.text, i18nString(UIStrings.copied));
172
171
  this.#copiedFiles[fileUrl] = true;
173
172
  this.requestUpdate();
174
173
  setTimeout(() => {
@@ -25,7 +25,11 @@ const UIStringsNotTranslate = {
25
25
  /**
26
26
  * @description Link text in the disclaimer dialog, linking to a settings page containing more information
27
27
  */
28
- learnMore: 'Learn more about AI summaries',
28
+ learnMore: 'Learn more',
29
+ /**
30
+ * @description Link text in the Console Insights Teaser info tooltip, linking to an explainer on how data is being used in this feature
31
+ */
32
+ learnMoreAboutAiSummaries: 'Learn more about AI summaries',
29
33
  /**
30
34
  * @description Description of the console insights feature
31
35
  */
@@ -57,6 +61,10 @@ const UIStringsNotTranslate = {
57
61
  * @description Header text during loading state while an AI summary is being generated
58
62
  */
59
63
  summarizing: 'Summarizing…',
64
+ /**
65
+ * @description Header text during longer lasting loading state while an AI summary is being generated
66
+ */
67
+ summarizingTakesABitLonger: 'Summarizing takes a bit longer…',
60
68
  /**
61
69
  * @description Label for an animation shown while an AI response is being generated
62
70
  */
@@ -69,6 +77,14 @@ const UIStringsNotTranslate = {
69
77
  * @description Label for a checkbox which turns off the teaser explanation feature
70
78
  */
71
79
  dontShow: 'Don’t show',
80
+ /**
81
+ * @description Aria-label for an infor-button triggering a tooltip with more info about data usage
82
+ */
83
+ learnDataUsage: 'Learn more about how your data is used',
84
+ /**
85
+ * @description Header text if there was an error during AI summary generation
86
+ */
87
+ summaryNotAvailable: 'Summary not available',
72
88
  } as const;
73
89
 
74
90
  const lockedString = i18n.i18n.lockedString;
@@ -76,6 +92,7 @@ const lockedString = i18n.i18n.lockedString;
76
92
  const CODE_SNIPPET_WARNING_URL = 'https://support.google.com/legal/answer/13505487';
77
93
  const DATA_USAGE_URL = 'https://developer.chrome.com/docs/devtools/ai-assistance/get-started#data-use';
78
94
  const EXPLAIN_TEASER_ACTION_ID = 'explain.console-message.teaser';
95
+ const SLOW_GENERATION_CUTOFF_MILLISECONDS = 3500;
79
96
 
80
97
  interface ViewInput {
81
98
  onTellMeMoreClick: (event: Event) => void;
@@ -87,6 +104,8 @@ interface ViewInput {
87
104
  isInactive: boolean;
88
105
  dontShowChanged: (e: Event) => void;
89
106
  hasTellMeMoreButton: boolean;
107
+ isSlowGeneration: boolean;
108
+ isError: boolean;
90
109
  }
91
110
 
92
111
  export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLElement): void => {
@@ -96,6 +115,51 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
96
115
  }
97
116
 
98
117
  const showPlaceholder = !Boolean(input.mainText);
118
+ const renderFooter = (): Lit.LitTemplate => {
119
+ // clang-format off
120
+ return html`
121
+ <div class="tooltip-footer">
122
+ ${input.hasTellMeMoreButton ? html`
123
+ <devtools-button
124
+ title=${lockedString(UIStringsNotTranslate.tellMeMore)}
125
+ .jslogContext=${'insights-teaser-tell-me-more'},
126
+ .variant=${Buttons.Button.Variant.PRIMARY}
127
+ @click=${input.onTellMeMoreClick}
128
+ >
129
+ <devtools-icon class="lightbulb-icon" name="lightbulb-spark"></devtools-icon>
130
+ ${lockedString(UIStringsNotTranslate.tellMeMore)}
131
+ </devtools-button>
132
+ ` : Lit.nothing}
133
+ ${showPlaceholder ? Lit.nothing : html`
134
+ <devtools-button
135
+ .iconName=${'info'}
136
+ .variant=${Buttons.Button.Variant.ICON}
137
+ aria-details=${'teaser-info-tooltip-' + input.uuid}
138
+ aria-label=${lockedString(UIStringsNotTranslate.learnDataUsage)}
139
+ ></devtools-button>
140
+ <devtools-tooltip id=${'teaser-info-tooltip-' + input.uuid} variant="rich">
141
+ <div class="info-tooltip-text">${lockedString(UIStringsNotTranslate.infoTooltipText)}</div>
142
+ <div class="learn-more">
143
+ <x-link
144
+ class="devtools-link"
145
+ title=${lockedString(UIStringsNotTranslate.learnMoreAboutAiSummaries)}
146
+ href=${DATA_USAGE_URL}
147
+ jslog=${VisualLogging.link().track({click: true, keydown:'Enter|Space'}).context('explain.teaser.learn-more')}
148
+ >${lockedString(UIStringsNotTranslate.learnMoreAboutAiSummaries)}</x-link>
149
+ </div>
150
+ </devtools-tooltip>
151
+ `}
152
+ <devtools-checkbox
153
+ aria-label=${lockedString(UIStringsNotTranslate.dontShow)}
154
+ @change=${input.dontShowChanged}
155
+ jslog=${VisualLogging.toggle('explain.teaser.dont-show').track({ change: true })}>
156
+ ${lockedString(UIStringsNotTranslate.dontShow)}
157
+ </devtools-checkbox>
158
+ </div>
159
+ `;
160
+ // clang-format on
161
+ };
162
+
99
163
  // clang-format off
100
164
  render(html`
101
165
  <style>${consoleInsightTeaserStyles}</style>
@@ -107,62 +171,36 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
107
171
  prefer-span-left
108
172
  >
109
173
  <div class="teaser-tooltip-container">
110
- ${showPlaceholder ? html`
111
- <h2 tabindex="-1">${lockedString(UIStringsNotTranslate.summarizing)}</h2>
112
- <div
113
- role="presentation"
114
- aria-label=${lockedString(UIStringsNotTranslate.loading)}
115
- class="loader"
116
- style="clip-path: url(${'#clipPath-' + input.uuid});"
117
- >
118
- <svg width="100%" height="52">
119
- <defs>
120
- <clipPath id=${'clipPath-' + input.uuid}>
121
- <rect x="0" y="0" width="100%" height="12" rx="8"></rect>
122
- <rect x="0" y="20" width="100%" height="12" rx="8"></rect>
123
- <rect x="0" y="40" width="100%" height="12" rx="8"></rect>
124
- </clipPath>
125
- </defs>
126
- </svg>
127
- </div>
128
- ` : html`
129
- <h2 tabindex="-1">${input.headerText}</h2>
130
- <div>${input.mainText}</div>
131
- <div class="tooltip-footer">
132
- ${input.hasTellMeMoreButton ? html`
133
- <devtools-button
134
- title=${lockedString(UIStringsNotTranslate.tellMeMore)}
135
- .jslogContext=${'insights-teaser-tell-me-more'},
136
- .variant=${Buttons.Button.Variant.PRIMARY}
137
- @click=${input.onTellMeMoreClick}
138
- >
139
- <devtools-icon class="lightbulb-icon" name="lightbulb-spark"></devtools-icon>
140
- ${lockedString(UIStringsNotTranslate.tellMeMore)}
141
- </devtools-button>
142
- ` : Lit.nothing}
143
- <devtools-icon
144
- name="info"
145
- class="info-icon"
146
- aria-details=${'teaser-info-tooltip-' + input.uuid}
147
- ></devtools-icon>
148
- <devtools-tooltip id=${'teaser-info-tooltip-' + input.uuid} variant="rich">
149
- <div class="info-tooltip-text">${lockedString(UIStringsNotTranslate.infoTooltipText)}</div>
150
- <div class="learn-more">
151
- <x-link
152
- class="devtools-link"
153
- title=${lockedString(UIStringsNotTranslate.learnMore)}
154
- href=${DATA_USAGE_URL}
155
- jslog=${VisualLogging.link().track({click: true, keydown:'Enter|Space'}).context('explain.teaser.learn-more')}
156
- >${lockedString(UIStringsNotTranslate.learnMore)}</x-link>
157
- </div>
158
- </devtools-tooltip>
159
- <devtools-checkbox
160
- @change=${input.dontShowChanged}
161
- jslog=${VisualLogging.toggle('explain.teaser.dont-show').track({ change: true })}>
162
- ${lockedString(UIStringsNotTranslate.dontShow)}
163
- </devtools-checkbox>
164
- </div>
165
- `}
174
+ ${input.isError ? html`
175
+ <h2>${lockedString(UIStringsNotTranslate.summaryNotAvailable)}</h2>
176
+ ` :
177
+ showPlaceholder ? html`
178
+ <h2>${input.isSlowGeneration ?
179
+ lockedString(UIStringsNotTranslate.summarizingTakesABitLonger) :
180
+ lockedString(UIStringsNotTranslate.summarizing)
181
+ }</h2>
182
+ <div
183
+ role="presentation"
184
+ aria-label=${lockedString(UIStringsNotTranslate.loading)}
185
+ class="loader"
186
+ style="clip-path: url(${'#clipPath-' + input.uuid});"
187
+ >
188
+ <svg width="100%" height="52">
189
+ <defs>
190
+ <clipPath id=${'clipPath-' + input.uuid}>
191
+ <rect x="0" y="0" width="100%" height="12" rx="8"></rect>
192
+ <rect x="0" y="20" width="100%" height="12" rx="8"></rect>
193
+ <rect x="0" y="40" width="100%" height="12" rx="8"></rect>
194
+ </clipPath>
195
+ </defs>
196
+ </svg>
197
+ </div>
198
+ ` : html`
199
+ <h2>${input.headerText}</h2>
200
+ <div>${input.mainText}</div>
201
+ `
202
+ }
203
+ ${input.isError || input.isSlowGeneration || !showPlaceholder ? renderFooter() : Lit.nothing}
166
204
  </div>
167
205
  </devtools-tooltip>
168
206
  `, target);
@@ -182,6 +220,9 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
182
220
  #consoleViewMessage: ConsoleViewMessage;
183
221
  #isInactive = false;
184
222
  #abortController: null|AbortController = null;
223
+ #isSlow = false;
224
+ #timeoutId: ReturnType<typeof setTimeout>|null = null;
225
+ #isError = false;
185
226
 
186
227
  constructor(uuid: string, consoleViewMessage: ConsoleViewMessage, element?: HTMLElement, view?: View) {
187
228
  super(element);
@@ -275,6 +316,9 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
275
316
  this.#abortController.abort();
276
317
  }
277
318
  this.#isGenerating = false;
319
+ if (this.#timeoutId) {
320
+ clearTimeout(this.#timeoutId);
321
+ }
278
322
  }
279
323
 
280
324
  setInactive(isInactive: boolean): void {
@@ -285,8 +329,14 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
285
329
  this.requestUpdate();
286
330
  }
287
331
 
332
+ #setSlow(): void {
333
+ this.#isSlow = true;
334
+ this.requestUpdate();
335
+ }
336
+
288
337
  async #generateTeaserText(): Promise<void> {
289
338
  this.#isGenerating = true;
339
+ this.#timeoutId = setTimeout(this.#setSlow.bind(this), SLOW_GENERATION_CUTOFF_MILLISECONDS);
290
340
  let teaserText = '';
291
341
  try {
292
342
  for await (const chunk of this.#getOnDeviceInsight()) {
@@ -296,12 +346,16 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
296
346
  // Ignore `AbortError` errors, which are thrown on mouse leave.
297
347
  if (err.name !== 'AbortError') {
298
348
  console.error(err.name, err.message);
349
+ this.#isError = true;
299
350
  }
300
351
  this.#isGenerating = false;
352
+ clearTimeout(this.#timeoutId);
353
+ this.requestUpdate();
301
354
  return;
302
355
  }
303
356
 
304
- // TODO(crbug.com/443618746): Add user-facing error message instead of staying in loading state
357
+ clearTimeout(this.#timeoutId);
358
+ this.#isGenerating = false;
305
359
  let responseObject = {
306
360
  header: null,
307
361
  explanation: null,
@@ -310,10 +364,15 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
310
364
  responseObject = JSON.parse(teaserText);
311
365
  } catch (err) {
312
366
  console.error(err.name, err.message);
367
+ this.#isError = true;
368
+ this.requestUpdate();
369
+ return;
313
370
  }
314
371
  this.#headerText = responseObject.header || '';
315
372
  this.#mainText = responseObject.explanation || '';
316
- this.#isGenerating = false;
373
+ if (!this.#headerText || !this.#mainText) {
374
+ this.#isError = true;
375
+ }
317
376
  this.requestUpdate();
318
377
  }
319
378
 
@@ -363,6 +422,8 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
363
422
  !Common.Settings.Settings.instance().moduleSetting('console-insight-teasers-enabled').get(),
364
423
  dontShowChanged: this.#dontShowChanged.bind(this),
365
424
  hasTellMeMoreButton: this.#hasTellMeMoreButton(),
425
+ isSlowGeneration: this.#isSlow,
426
+ isError: this.#isError,
366
427
  },
367
428
  undefined, this.contentElement);
368
429
  }
@@ -396,7 +396,7 @@ export class ConsolePrompt extends Common.ObjectWrapper.eventMixin<EventTypes, t
396
396
  if (accepted) {
397
397
  this.dispatchEventToListeners(
398
398
  Events.AI_CODE_COMPLETION_SUGGESTION_ACCEPTED, {citations: this.aiCodeCompletionCitations});
399
- if (suggestion?.rpcGlobalId && suggestion?.sampleId) {
399
+ if (suggestion?.rpcGlobalId) {
400
400
  this.aiCodeCompletion?.registerUserAcceptance(suggestion.rpcGlobalId, suggestion.sampleId);
401
401
  }
402
402
  }
@@ -52,7 +52,7 @@ const str_ = i18n.i18n.registerUIStrings('panels/console/ConsoleSidebar.ts', UIS
52
52
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
53
53
  const {render, html, nothing, Directives} = Lit;
54
54
 
55
- const enum GroupName {
55
+ export const enum GroupName {
56
56
  CONSOLE_API = 'user message',
57
57
  ALL = 'message',
58
58
  ERROR = 'error',
@@ -112,7 +112,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
112
112
  <ul role="group" hidden>
113
113
  ${group.urlGroups.values().map(urlGroup => html`
114
114
  <li
115
- ${Directives.ref(element => element && nodeFilterMap.set(element, group.filter))}
115
+ ${Directives.ref(element => element && nodeFilterMap.set(element, urlGroup.filter))}
116
116
  role="treeitem"
117
117
  ?selected=${urlGroup.filter === input.selectedFilter}
118
118
  title=${urlGroup.url ?? ''}>
@@ -126,7 +126,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
126
126
  target);
127
127
  };
128
128
 
129
- class ConsoleFilterGroup {
129
+ export class ConsoleFilterGroup {
130
130
  readonly urlGroups = new Map<string|null, {filter: ConsoleFilter, url: string|null, count: number}>();
131
131
  messageCount = 0;
132
132
  readonly name: GroupName;
@@ -380,7 +380,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
380
380
  wasShown(): void {
381
381
  this.isVisibleInternal = true;
382
382
  if (this.elementInternal) {
383
- this.#teaser?.show(this.elementInternal);
383
+ this.#teaser?.show(this.elementInternal, this.consoleRowWrapper);
384
384
  }
385
385
  }
386
386
 
@@ -1343,14 +1343,14 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1343
1343
  return this.contentElementInternal;
1344
1344
  }
1345
1345
 
1346
- #onMouseEnter(_event: MouseEvent): void {
1346
+ #startTeaserGeneration(): void {
1347
1347
  if (this.#teaser &&
1348
1348
  Common.Settings.Settings.instance().moduleSetting('console-insight-teasers-enabled').getIfNotDisabled()) {
1349
1349
  this.#teaser.maybeGenerateTeaser();
1350
1350
  }
1351
1351
  }
1352
1352
 
1353
- #onMouseLeave(): void {
1353
+ #abortTeaserGeneration(): void {
1354
1354
  this.#teaser?.abortTeaserGeneration();
1355
1355
  }
1356
1356
 
@@ -1361,8 +1361,10 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1361
1361
  this.elementInternal = document.createElement('div');
1362
1362
  this.elementInternal.tabIndex = -1;
1363
1363
  this.elementInternal.addEventListener('keydown', (this.onKeyDown.bind(this) as EventListener));
1364
- this.elementInternal.addEventListener('mouseenter', this.#onMouseEnter.bind(this));
1365
- this.elementInternal.addEventListener('mouseleave', this.#onMouseLeave.bind(this));
1364
+ this.elementInternal.addEventListener('mouseenter', this.#startTeaserGeneration.bind(this));
1365
+ this.elementInternal.addEventListener('focusin', this.#startTeaserGeneration.bind(this));
1366
+ this.elementInternal.addEventListener('mouseleave', this.#abortTeaserGeneration.bind(this));
1367
+ this.elementInternal.addEventListener('focusout', this.#abortTeaserGeneration.bind(this));
1366
1368
  this.updateMessageElement();
1367
1369
  this.elementInternal.classList.toggle('console-adjacent-user-command-result', this.#adjacentUserCommandResult);
1368
1370
  return this.elementInternal;
@@ -72,10 +72,6 @@
72
72
  display: flex;
73
73
  align-items: center;
74
74
 
75
- .info-icon {
76
- margin-left: var(--sys-size-4);
77
- }
78
-
79
75
  devtools-checkbox {
80
76
  margin-left: auto;
81
77
  }
@@ -41,7 +41,6 @@ import * as Badges from '../../models/badges/badges.js';
41
41
  import * as Elements from '../../models/elements/elements.js';
42
42
  import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
43
43
  import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
44
- import * as CopyToClipboard from '../../ui/components/copy_to_clipboard/copy_to_clipboard.js';
45
44
  import * as IssueCounter from '../../ui/components/issue_counter/issue_counter.js';
46
45
  import * as UI from '../../ui/legacy/legacy.js';
47
46
  import {html, nothing, render} from '../../ui/lit/lit.js';
@@ -736,7 +735,7 @@ export class ElementsTreeOutline extends
736
735
  }
737
736
  void node.getOuterHTML(includeShadowRoots).then(outerHTML => {
738
737
  if (outerHTML !== null) {
739
- CopyToClipboard.copyTextToClipboard(outerHTML);
738
+ UI.UIUtils.copyTextToClipboard(outerHTML);
740
739
  }
741
740
  });
742
741
  this.setClipboardData({node, isCut});